Revamp ListProperty so its logic makes more sense.
parent
9d05c9d3e2
commit
bc51cd47bd
|
@ -189,15 +189,29 @@ class ListProperty(Property):
|
|||
|
||||
def __init__(self, contained, **kwargs):
|
||||
"""
|
||||
``contained`` should be a function which returns an object from the value.
|
||||
``contained`` should be a Property class or instance, or a _STIXBase
|
||||
subclass.
|
||||
"""
|
||||
if inspect.isclass(contained) and issubclass(contained, Property):
|
||||
# If it's a class and not an instance, instantiate it so that
|
||||
# clean() can be called on it, and ListProperty.clean() will
|
||||
# use __call__ when it appends the item.
|
||||
self.contained = contained()
|
||||
else:
|
||||
self.contained = None
|
||||
|
||||
if inspect.isclass(contained):
|
||||
# Property classes are instantiated; _STIXBase subclasses are left
|
||||
# as-is.
|
||||
if issubclass(contained, Property):
|
||||
self.contained = contained()
|
||||
elif issubclass(contained, _STIXBase):
|
||||
self.contained = contained
|
||||
|
||||
elif isinstance(contained, Property):
|
||||
self.contained = contained
|
||||
|
||||
if not self.contained:
|
||||
raise TypeError(
|
||||
"Invalid list element type: {}".format(
|
||||
str(contained),
|
||||
),
|
||||
)
|
||||
|
||||
super(ListProperty, self).__init__(**kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
|
@ -209,40 +223,28 @@ class ListProperty(Property):
|
|||
if isinstance(value, (_STIXBase, string_types)):
|
||||
value = [value]
|
||||
|
||||
result = []
|
||||
for item in value:
|
||||
try:
|
||||
valid = self.contained.clean(item)
|
||||
except ValueError:
|
||||
raise
|
||||
except AttributeError:
|
||||
# type of list has no clean() function (eg. built in Python types)
|
||||
# TODO Should we raise an error here?
|
||||
valid = item
|
||||
if isinstance(self.contained, Property):
|
||||
result = [
|
||||
self.contained.clean(item)
|
||||
for item in value
|
||||
]
|
||||
|
||||
if type(self.contained) is EmbeddedObjectProperty:
|
||||
obj_type = self.contained.type
|
||||
elif type(self.contained).__name__ == "STIXObjectProperty":
|
||||
# ^ this way of checking doesn't require a circular import
|
||||
# valid is already an instance of a python-stix2 class; no need
|
||||
# to turn it into a dictionary and then pass it to the class
|
||||
# constructor again
|
||||
result.append(valid)
|
||||
continue
|
||||
elif type(self.contained) is DictionaryProperty:
|
||||
obj_type = dict
|
||||
else:
|
||||
obj_type = self.contained
|
||||
else: # self.contained must be a _STIXBase subclass
|
||||
result = []
|
||||
for item in value:
|
||||
if isinstance(item, self.contained):
|
||||
valid = item
|
||||
|
||||
elif isinstance(item, Mapping):
|
||||
# attempt a mapping-like usage...
|
||||
valid = self.contained(**item)
|
||||
|
||||
if isinstance(valid, Mapping):
|
||||
try:
|
||||
valid._allow_custom
|
||||
except AttributeError:
|
||||
result.append(obj_type(**valid))
|
||||
else:
|
||||
result.append(obj_type(allow_custom=True, **valid))
|
||||
else:
|
||||
result.append(obj_type(valid))
|
||||
raise ValueError("Can't create a {} out of {}".format(
|
||||
self.contained._type, str(item),
|
||||
))
|
||||
|
||||
result.append(valid)
|
||||
|
||||
# STIX spec forbids empty lists
|
||||
if len(result) < 1:
|
||||
|
|
Loading…
Reference in New Issue