diff --git a/stix2/base.py b/stix2/base.py index db4b8c3..3b383f8 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -4,7 +4,7 @@ import collections import datetime as dt import json -from .exceptions import InvalidValueError, MissingFieldsError +from .exceptions import ExtraFieldsError, InvalidValueError, MissingFieldsError from .utils import format_datetime, get_timestamp, NOW __all__ = ['STIXJSONEncoder', '_STIXBase'] @@ -53,7 +53,7 @@ class _STIXBase(collections.Mapping): # Detect any keyword arguments not allowed for a specific type extra_kwargs = list(set(kwargs) - set(cls._properties)) if extra_kwargs: - raise TypeError("unexpected keyword arguments: " + str(extra_kwargs)) + raise ExtraFieldsError(cls, extra_kwargs) required_fields = get_required_properties(cls._properties) missing_kwargs = set(required_fields) - set(kwargs) diff --git a/stix2/exceptions.py b/stix2/exceptions.py index 138eb18..d63891e 100644 --- a/stix2/exceptions.py +++ b/stix2/exceptions.py @@ -17,7 +17,7 @@ class InvalidValueError(STIXError, ValueError): class MissingFieldsError(STIXError, ValueError): - """Missing required field(s) when construting STIX object.""" + """Missing required field(s) when constructing STIX object.""" def __init__(self, cls, fields): super(MissingFieldsError, self).__init__() @@ -28,3 +28,17 @@ class MissingFieldsError(STIXError, ValueError): msg = "Missing required field(s) for {0}: ({1})." return msg.format(self.cls.__name__, ", ".join(x for x in self.fields)) + + +class ExtraFieldsError(STIXError, TypeError): + """Extra field(s) were provided when constructing STIX object.""" + + def __init__(self, cls, fields): + super(ExtraFieldsError, self).__init__() + self.cls = cls + self.fields = sorted(list(fields)) + + def __str__(self): + msg = "Unexpected field(s) for {0}: ({1})." + return msg.format(self.cls.__name__, + ", ".join(x for x in self.fields)) diff --git a/stix2/test/test_indicator.py b/stix2/test/test_indicator.py index 5c42556..cb64d40 100644 --- a/stix2/test/test_indicator.py +++ b/stix2/test/test_indicator.py @@ -132,9 +132,12 @@ def test_cannot_assign_to_indicator_attributes(indicator): def test_invalid_kwarg_to_indicator(): - with pytest.raises(TypeError) as excinfo: + with pytest.raises(stix2.exceptions.ExtraFieldsError) as excinfo: stix2.Indicator(my_custom_property="foo", **INDICATOR_KWARGS) - assert str(excinfo.value) == "unexpected keyword arguments: ['my_custom_property']" + + assert excinfo.value.cls == stix2.Indicator + assert excinfo.value.fields == ['my_custom_property'] + assert str(excinfo.value) == "Unexpected field(s) for Indicator: (my_custom_property)." def test_created_modified_time_are_identical_by_default(): diff --git a/stix2/test/test_malware.py b/stix2/test/test_malware.py index 6c5dbd2..bce2447 100644 --- a/stix2/test/test_malware.py +++ b/stix2/test/test_malware.py @@ -96,6 +96,9 @@ def test_cannot_assign_to_malware_attributes(malware): def test_invalid_kwarg_to_malware(): - with pytest.raises(TypeError) as excinfo: + with pytest.raises(stix2.exceptions.ExtraFieldsError) as excinfo: stix2.Malware(my_custom_property="foo", **MALWARE_KWARGS) - assert str(excinfo.value) == "unexpected keyword arguments: ['my_custom_property']" + + assert excinfo.value.cls == stix2.Malware + assert excinfo.value.fields == ['my_custom_property'] + assert str(excinfo.value) == "Unexpected field(s) for Malware: (my_custom_property)." diff --git a/stix2/test/test_relationship.py b/stix2/test/test_relationship.py index e4fa17e..c0478d8 100644 --- a/stix2/test/test_relationship.py +++ b/stix2/test/test_relationship.py @@ -105,9 +105,12 @@ def test_cannot_assign_to_relationship_attributes(relationship): def test_invalid_kwarg_to_relationship(): - with pytest.raises(TypeError) as excinfo: + with pytest.raises(stix2.exceptions.ExtraFieldsError) as excinfo: stix2.Relationship(my_custom_property="foo", **RELATIONSHIP_KWARGS) - assert str(excinfo.value) == "unexpected keyword arguments: ['my_custom_property']" in str(excinfo) + + assert excinfo.value.cls == stix2.Relationship + assert excinfo.value.fields == ['my_custom_property'] + assert str(excinfo.value) == "Unexpected field(s) for Relationship: (my_custom_property)." def test_create_relationship_from_objects_rather_than_ids(indicator, malware): diff --git a/stix2/test/test_sighting.py b/stix2/test/test_sighting.py index fb1d941..11f7449 100644 --- a/stix2/test/test_sighting.py +++ b/stix2/test/test_sighting.py @@ -75,9 +75,12 @@ def test_sighting_type_must_be_sightings(): def test_invalid_kwarg_to_sighting(): - with pytest.raises(TypeError) as excinfo: + with pytest.raises(stix2.exceptions.ExtraFieldsError) as excinfo: stix2.Sighting(my_custom_property="foo", **SIGHTING_KWARGS) - assert str(excinfo.value) == "unexpected keyword arguments: ['my_custom_property']" in str(excinfo) + + assert excinfo.value.cls == stix2.Sighting + assert excinfo.value.fields == ['my_custom_property'] + assert str(excinfo.value) == "Unexpected field(s) for Sighting: (my_custom_property)." def test_create_sighting_from_objects_rather_than_ids(malware): # noqa: F811