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):
"""
``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: