parent
858a9752df
commit
f09960d7ff
|
@ -270,10 +270,8 @@ class _STIXBase(collections.Mapping):
|
||||||
overridden: indent=4, separators=(",", ": "), item_sort_key=sort_by.
|
overridden: indent=4, separators=(",", ": "), item_sort_key=sort_by.
|
||||||
"""
|
"""
|
||||||
if pretty:
|
if pretty:
|
||||||
properties = self.object_properties()
|
|
||||||
|
|
||||||
def sort_by(element):
|
def sort_by(element):
|
||||||
return find_property_index(self, properties, element)
|
return find_property_index(self, *element)
|
||||||
|
|
||||||
kwargs.update({'indent': 4, 'separators': (",", ": "), 'item_sort_key': sort_by})
|
kwargs.update({'indent': 4, 'separators': (",", ": "), 'item_sort_key': sort_by})
|
||||||
|
|
||||||
|
|
|
@ -178,8 +178,7 @@ def test_deduplicate(stix_objs1):
|
||||||
def test_find_property_index(object, tuple_to_find, expected_index):
|
def test_find_property_index(object, tuple_to_find, expected_index):
|
||||||
assert stix2.utils.find_property_index(
|
assert stix2.utils.find_property_index(
|
||||||
object,
|
object,
|
||||||
[],
|
*tuple_to_find
|
||||||
tuple_to_find
|
|
||||||
) == expected_index
|
) == expected_index
|
||||||
|
|
||||||
|
|
||||||
|
@ -208,4 +207,4 @@ def test_find_property_index(object, tuple_to_find, expected_index):
|
||||||
}, ('key_one', 1), 0)
|
}, ('key_one', 1), 0)
|
||||||
])
|
])
|
||||||
def test_iterate_over_values(dict_value, tuple_to_find, expected_index):
|
def test_iterate_over_values(dict_value, tuple_to_find, expected_index):
|
||||||
assert stix2.utils._iterate_over_values(dict_value.values(), tuple_to_find) == expected_index
|
assert stix2.utils._find_property_in_seq(dict_value.values(), *tuple_to_find) == expected_index
|
||||||
|
|
133
stix2/utils.py
133
stix2/utils.py
|
@ -165,87 +165,74 @@ def _get_dict(data):
|
||||||
raise ValueError("Cannot convert '%s' to dictionary." % str(data))
|
raise ValueError("Cannot convert '%s' to dictionary." % str(data))
|
||||||
|
|
||||||
|
|
||||||
def _iterate_over_values(dict_values, tuple_to_find):
|
def _find(seq, val):
|
||||||
"""Loop recursively over dictionary values"""
|
"""
|
||||||
from .base import _STIXBase
|
Search sequence 'seq' for val. This behaves like str.find(): if not found,
|
||||||
for pv in dict_values:
|
-1 is returned instead of throwing an exception.
|
||||||
if isinstance(pv, list):
|
|
||||||
for item in pv:
|
:param seq: The sequence to search
|
||||||
if isinstance(item, _STIXBase):
|
:param val: The value to search for
|
||||||
index = find_property_index(
|
:return: The index of the value if found, or -1 if not found
|
||||||
item,
|
"""
|
||||||
item.object_properties(),
|
try:
|
||||||
tuple_to_find
|
return seq.index(val)
|
||||||
)
|
except ValueError:
|
||||||
if index is not None:
|
return -1
|
||||||
return index
|
|
||||||
elif isinstance(item, dict):
|
|
||||||
for idx, val in enumerate(sorted(item)):
|
|
||||||
if (tuple_to_find[0] == val and
|
|
||||||
item.get(val) == tuple_to_find[1]):
|
|
||||||
return idx
|
|
||||||
elif isinstance(pv, dict):
|
|
||||||
if pv.get(tuple_to_find[0]) is not None:
|
|
||||||
for idx, item in enumerate(sorted(pv.keys())):
|
|
||||||
if ((item == tuple_to_find[0] and str.isdigit(item)) and
|
|
||||||
(pv[item] == tuple_to_find[1])):
|
|
||||||
return int(tuple_to_find[0])
|
|
||||||
elif pv[item] == tuple_to_find[1]:
|
|
||||||
return idx
|
|
||||||
for item in pv.values():
|
|
||||||
if isinstance(item, _STIXBase):
|
|
||||||
index = find_property_index(
|
|
||||||
item,
|
|
||||||
item.object_properties(),
|
|
||||||
tuple_to_find
|
|
||||||
)
|
|
||||||
if index is not None:
|
|
||||||
return index
|
|
||||||
elif isinstance(item, dict):
|
|
||||||
index = find_property_index(
|
|
||||||
item,
|
|
||||||
item.keys(),
|
|
||||||
tuple_to_find
|
|
||||||
)
|
|
||||||
if index is not None:
|
|
||||||
return index
|
|
||||||
|
|
||||||
|
|
||||||
def find_property_index(obj, properties, tuple_to_find):
|
def _find_property_in_seq(seq, search_key, search_value):
|
||||||
"""Recursively find the property in the object model, return the index
|
"""
|
||||||
according to the ``properties`` OrderedDict when working with `stix2`
|
Helper for find_property_index(): search for the property in all elements
|
||||||
objects. If it's a list look for individual objects. Returns and integer
|
of the given sequence.
|
||||||
indicating its location.
|
|
||||||
|
|
||||||
Notes:
|
:param seq: The sequence
|
||||||
This method is intended to pretty print `stix2` properties for better
|
:param search_key: Property name to find
|
||||||
visual feedback when working with the library.
|
:param search_value: Property value to find
|
||||||
|
:return: A property index, or -1 if the property was not found
|
||||||
|
"""
|
||||||
|
idx = -1
|
||||||
|
for elem in seq:
|
||||||
|
idx = find_property_index(elem, search_key, search_value)
|
||||||
|
if idx >= 0:
|
||||||
|
break
|
||||||
|
|
||||||
Warnings:
|
return idx
|
||||||
This method may not be able to produce the same output if called
|
|
||||||
multiple times and makes a best effort attempt to print the properties
|
|
||||||
according to the STIX technical specification.
|
|
||||||
|
|
||||||
See Also:
|
|
||||||
py:meth:`stix2.base._STIXBase.serialize` for more information.
|
|
||||||
|
|
||||||
|
def find_property_index(obj, search_key, search_value):
|
||||||
|
"""
|
||||||
|
Search (recursively) for the given key and value in the given object.
|
||||||
|
Return an index for the key, relative to whatever object it's found in.
|
||||||
|
|
||||||
|
:param obj: The object to search (list, dict, or stix object)
|
||||||
|
:param search_key: A search key
|
||||||
|
:param search_value: A search value
|
||||||
|
:return: An index; -1 if the key and value aren't found
|
||||||
"""
|
"""
|
||||||
from .base import _STIXBase
|
from .base import _STIXBase
|
||||||
try:
|
|
||||||
if isinstance(obj, _STIXBase):
|
# Special-case keys which are numbers-as-strings, e.g. for cyber-observable
|
||||||
if tuple_to_find[1] in obj._inner.values():
|
# mappings. Use the int value of the key as the index.
|
||||||
return properties.index(tuple_to_find[0])
|
if search_key.isdigit():
|
||||||
elif isinstance(obj, dict):
|
return int(search_key)
|
||||||
for idx, val in enumerate(sorted(obj)):
|
|
||||||
if (tuple_to_find[0] == val and
|
if isinstance(obj, _STIXBase):
|
||||||
obj.get(val) == tuple_to_find[1]):
|
if search_key in obj and obj[search_key] == search_value:
|
||||||
return idx
|
idx = _find(obj.object_properties(), search_key)
|
||||||
raise ValueError
|
else:
|
||||||
except ValueError:
|
idx = _find_property_in_seq(obj.values(), search_key, search_value)
|
||||||
if isinstance(obj, _STIXBase):
|
elif isinstance(obj, dict):
|
||||||
return _iterate_over_values(obj._inner.values(), tuple_to_find)
|
if search_key in obj and obj[search_key] == search_value:
|
||||||
elif isinstance(obj, dict):
|
idx = _find(sorted(obj), search_key)
|
||||||
return _iterate_over_values(obj.values(), tuple_to_find)
|
else:
|
||||||
|
idx = _find_property_in_seq(obj.values(), search_key, search_value)
|
||||||
|
elif isinstance(obj, list):
|
||||||
|
idx = _find_property_in_seq(obj, search_key, search_value)
|
||||||
|
else:
|
||||||
|
# Don't know how to search this type
|
||||||
|
idx = -1
|
||||||
|
|
||||||
|
return idx
|
||||||
|
|
||||||
|
|
||||||
def new_version(data, **kwargs):
|
def new_version(data, **kwargs):
|
||||||
|
|
Loading…
Reference in New Issue