Rework ListProperty, fix merging issues

stix2.1
clenk 2017-04-14 10:42:17 -04:00
parent bc8bdccece
commit 35981025c5
4 changed files with 41 additions and 45 deletions

View File

@ -12,7 +12,7 @@ COMMON_PROPERTIES = {
'external_references': Property(), 'external_references': Property(),
'revoked': BooleanProperty(), 'revoked': BooleanProperty(),
'created_by_ref': ReferenceProperty(type="identity"), 'created_by_ref': ReferenceProperty(type="identity"),
'object_marking_refs': ListProperty(ReferenceProperty, element_type="marking-definition"), 'object_marking_refs': ListProperty(ReferenceProperty(type="marking-definition")),
'granular_markings': ListProperty(Property) 'granular_markings': ListProperty(Property)
} }

View File

@ -5,14 +5,21 @@ from .properties import IDProperty, TypeProperty, ListProperty, ReferencePropert
from .utils import NOW from .utils import NOW
class GranularMarking(_STIXBase):
_properties = {
'marking_ref': ReferenceProperty(required=True, type="marking-definition"),
'selectors': ListProperty(SelectorProperty, required=True),
}
class MarkingDefinition(_STIXBase): class MarkingDefinition(_STIXBase):
_type = 'marking-definition' _type = 'marking-definition'
_properties = { _properties = {
'created': Property(default=lambda: NOW), 'created': Property(default=lambda: NOW),
'external_references': Property(), 'external_references': Property(),
'created_by_ref': ReferenceProperty(type="identity"), 'created_by_ref': ReferenceProperty(type="identity"),
'object_marking_refs': ListProperty(ReferenceProperty, element_type="marking-definition"), 'object_marking_refs': ListProperty(ReferenceProperty(type="marking-definition")),
'granular_marking': ListProperty(Property, element_type="granular-marking"), 'granular_marking': ListProperty(GranularMarking),
'type': TypeProperty(_type), 'type': TypeProperty(_type),
'id': IDProperty(_type), 'id': IDProperty(_type),
'definition_type': Property(), 'definition_type': Property(),
@ -20,13 +27,6 @@ class MarkingDefinition(_STIXBase):
} }
class GranularMarking(_STIXBase):
_properties = {
'marking_ref': ReferenceProperty(required=True, type="marking-definition"),
'selectors': ListProperty(SelectorProperty, required=True),
}
class TLPMarking(_STIXBase): class TLPMarking(_STIXBase):
# TODO: don't allow the creation of any other TLPMarkings than the ones below # TODO: don't allow the creation of any other TLPMarkings than the ones below
_properties = { _properties = {

View File

@ -4,6 +4,7 @@ from six import PY2
import datetime as dt import datetime as dt
import pytz import pytz
from dateutil import parser from dateutil import parser
import inspect
from .base import _STIXBase from .base import _STIXBase
@ -77,45 +78,31 @@ class Property(object):
pass pass
return value return value
def __call__(self, value=None):
if value is not None:
return value
class ListProperty(Property): class ListProperty(Property):
def __init__(self, contained, element_type=None, **kwargs): def __init__(self, contained, **kwargs):
""" """
contained should be a type whose constructor creates an object from the value Contained should be a function which returns an object from the value.
""" """
if contained == StringProperty: if contained == StringProperty:
self.contained = StringProperty().string_type self.contained = StringProperty().string_type
elif contained == BooleanProperty: elif contained == BooleanProperty:
self.contained = bool self.contained = bool
elif inspect.isclass(contained) and issubclass(contained, Property):
# If it's a class and not an instance, instantiate it so that
# validate() can be called on it, and ListProperty.validate() will
# use __call__ when it appends the item.
self.contained = contained()
else: else:
self.contained = contained self.contained = contained
self.element_type = element_type
super(ListProperty, self).__init__(**kwargs) super(ListProperty, self).__init__(**kwargs)
def validate(self, value): def validate(self, value):
try:
list_ = self.clean(value)
except ValueError:
raise
# STIX spec forbids empty lists
if len(list_) < 1:
raise ValueError("must not be empty.")
try:
for item in list_:
self.contained.validate(item)
except ValueError:
raise
except AttributeError:
# type of list has no validate() function (eg. built in Python types)
# TODO Should we raise an error here?
pass
return list_
def clean(self, value):
try: try:
iter(value) iter(value)
except TypeError: except TypeError:
@ -124,14 +111,23 @@ class ListProperty(Property):
result = [] result = []
for item in value: for item in value:
try: try:
if type(item) is dict: valid = self.contained.validate(item)
result.append(self.contained(**item)) except ValueError:
elif isinstance(item, ReferenceProperty): raise
result.append(self.contained(type=self.element_type)) except AttributeError:
# type of list has no validate() function (eg. built in Python types)
# TODO Should we raise an error here?
valid = item
if type(valid) is dict:
result.append(self.contained(**valid))
else: else:
result.append(self.contained(item)) result.append(self.contained(valid))
except TypeError:
raise ValueError("the type of objects in the list must have a constructor that creates an object from the value.") # STIX spec forbids empty lists
if len(result) < 1:
raise ValueError("must not be empty.")
return result return result

View File

@ -45,8 +45,8 @@ class Sighting(_STIXBase):
'last_seen': Property(), 'last_seen': Property(),
'count': Property(), 'count': Property(),
'sighting_of_ref': ReferenceProperty(required=True), 'sighting_of_ref': ReferenceProperty(required=True),
'observed_data_refs': ListProperty(ReferenceProperty, element_type="observed-data"), 'observed_data_refs': ListProperty(ReferenceProperty(type="observed-data")),
'where_sighted_refs': ListProperty(ReferenceProperty, element_type="identity"), 'where_sighted_refs': ListProperty(ReferenceProperty(type="identity")),
'summary': Property(), 'summary': Property(),
}) })