Revamp ListProperty so its logic makes more sense.

pull/1/head
Michael Chisholm 2020-06-17 16:11:30 -04:00
parent 9d05c9d3e2
commit bc51cd47bd
1 changed files with 40 additions and 38 deletions

View File

@ -189,15 +189,29 @@ class ListProperty(Property):
def __init__(self, contained, **kwargs): 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): self.contained = None
# If it's a class and not an instance, instantiate it so that
# clean() can be called on it, and ListProperty.clean() will if inspect.isclass(contained):
# use __call__ when it appends the item. # Property classes are instantiated; _STIXBase subclasses are left
self.contained = contained() # as-is.
else: if issubclass(contained, Property):
self.contained = contained()
elif issubclass(contained, _STIXBase):
self.contained = contained
elif isinstance(contained, Property):
self.contained = contained self.contained = contained
if not self.contained:
raise TypeError(
"Invalid list element type: {}".format(
str(contained),
),
)
super(ListProperty, self).__init__(**kwargs) super(ListProperty, self).__init__(**kwargs)
def clean(self, value): def clean(self, value):
@ -209,40 +223,28 @@ class ListProperty(Property):
if isinstance(value, (_STIXBase, string_types)): if isinstance(value, (_STIXBase, string_types)):
value = [value] value = [value]
result = [] if isinstance(self.contained, Property):
for item in value: result = [
try: self.contained.clean(item)
valid = self.contained.clean(item) for item in value
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 type(self.contained) is EmbeddedObjectProperty: else: # self.contained must be a _STIXBase subclass
obj_type = self.contained.type result = []
elif type(self.contained).__name__ == "STIXObjectProperty": for item in value:
# ^ this way of checking doesn't require a circular import if isinstance(item, self.contained):
# valid is already an instance of a python-stix2 class; no need valid = item
# to turn it into a dictionary and then pass it to the class
# constructor again elif isinstance(item, Mapping):
result.append(valid) # attempt a mapping-like usage...
continue valid = self.contained(**item)
elif type(self.contained) is DictionaryProperty:
obj_type = dict
else:
obj_type = self.contained
if isinstance(valid, Mapping):
try:
valid._allow_custom
except AttributeError:
result.append(obj_type(**valid))
else: else:
result.append(obj_type(allow_custom=True, **valid)) raise ValueError("Can't create a {} out of {}".format(
else: self.contained._type, str(item),
result.append(obj_type(valid)) ))
result.append(valid)
# STIX spec forbids empty lists # STIX spec forbids empty lists
if len(result) < 1: if len(result) < 1: