Fix typos, add to Property class documentation, small performance

boosts, and let strings and booleans in a ListProperty be handled by
__call__().
stix2.1
clenk 2017-04-24 16:33:59 -04:00
parent 76acd8c0c2
commit fe4c4d78fc
3 changed files with 34 additions and 29 deletions

View File

@ -13,12 +13,7 @@ from .utils import get_dict
from . import exceptions from . import exceptions
def parse(data): OBJ_MAP = {
"""Deserialize a string or file-like object into a STIX object"""
obj = get_dict(data)
obj_map = {
'attack-pattern': AttackPattern, 'attack-pattern': AttackPattern,
'campaign': Campaign, 'campaign': Campaign,
'course-of-action': CourseOfAction, 'course-of-action': CourseOfAction,
@ -36,12 +31,18 @@ def parse(data):
'vulnerability': Vulnerability, 'vulnerability': Vulnerability,
} }
def parse(data):
"""Deserialize a string or file-like object into a STIX object"""
obj = get_dict(data)
if 'type' not in obj: if 'type' not in obj:
# TODO parse external references, kill chain phases, and granular markings # TODO parse external references, kill chain phases, and granular markings
pass pass
else: else:
try: try:
obj_class = obj_map[obj['type']] obj_class = OBJ_MAP[obj['type']]
return obj_class(**obj) return obj_class(**obj)
except KeyError: except KeyError:
# TODO handle custom objects # TODO handle custom objects

View File

@ -39,7 +39,7 @@ class TLPMarking(_STIXBase):
class StatementMarking(_STIXBase): class StatementMarking(_STIXBase):
_properties = { _properties = {
'statement': Property(required=True) 'statement': StringProperty(required=True)
} }
def __init__(self, statement=None, **kwargs): def __init__(self, statement=None, **kwargs):

View File

@ -42,9 +42,15 @@ class Property(object):
to use the same default value, so calling now() for each field-- to use the same default value, so calling now() for each field--
likely several microseconds apart-- does not work. likely several microseconds apart-- does not work.
Subclasses can instead provide a lambda function for `default as a keyword Subclasses can instead provide a lambda function for `default` as a keyword
argument. `clean` should not be provided as a lambda since lambdas cannot argument. `clean` should not be provided as a lambda since lambdas cannot
raise their own exceptions. raise their own exceptions.
When instantiating Properties, `required` and `default` should not be used
together. `default` implies that the field is required in the specification
so this function will be used to supply a value if none is provided.
`required` means that the user must provide this; it is required in the
specification and we can't or don't want to create a default value.
""" """
def _default_clean(self, value): def _default_clean(self, value):
@ -66,7 +72,9 @@ class Property(object):
return value return value
def __call__(self, value=None): def __call__(self, value=None):
if value is not None: """Used by ListProperty to handle lists that have been defined with
either a class or an instance.
"""
return value return value
@ -76,11 +84,7 @@ class ListProperty(Property):
""" """
Contained should be a function which returns an object from the value. Contained should be a function which returns an object from the value.
""" """
if contained == StringProperty: if inspect.isclass(contained) and issubclass(contained, Property):
self.contained = StringProperty().string_type
elif contained == BooleanProperty:
self.contained = bool
elif inspect.isclass(contained) and issubclass(contained, Property):
# If it's a class and not an instance, instantiate it so that # If it's a class and not an instance, instantiate it so that
# clean() can be called on it, and ListProperty.clean() will # clean() can be called on it, and ListProperty.clean() will
# use __call__ when it appends the item. # use __call__ when it appends the item.
@ -191,7 +195,7 @@ class TimestampProperty(Property):
return value return value
else: else:
# Add a time component # Add a time component
return dt.datetime.combine(value, dt.time(), tzinfo=pytz.timezone('US/Eastern')) return dt.datetime.combine(value, dt.time(), tzinfo=pytz.utc)
# value isn't a date or datetime object so assume it's a string # value isn't a date or datetime object so assume it's a string
try: try: