diff --git a/stix2/__init__.py b/stix2/__init__.py
index 904af9c..18c0b33 100644
--- a/stix2/__init__.py
+++ b/stix2/__init__.py
@@ -5,22 +5,24 @@
 from . import exceptions
 from .bundle import Bundle
 from .observables import (URL, AlternateDataStream, ArchiveExt, Artifact,
-                          AutonomousSystem, Directory, DomainName,
-                          EmailAddress, EmailMessage, EmailMIMEComponent, File,
-                          HTTPRequestExt, ICMPExt, IPv4Address, IPv6Address,
-                          MACAddress, Mutex, NetworkTraffic, NTFSExt, PDFExt,
-                          Process, RasterImageExt, SocketExt, Software, TCPExt,
+                          AutonomousSystem, CustomObservable, Directory,
+                          DomainName, EmailAddress, EmailMessage,
+                          EmailMIMEComponent, File, HTTPRequestExt, ICMPExt,
+                          IPv4Address, IPv6Address, MACAddress, Mutex,
+                          NetworkTraffic, NTFSExt, PDFExt, Process,
+                          RasterImageExt, SocketExt, Software, TCPExt,
                           UNIXAccountExt, UserAccount, WindowsPEBinaryExt,
                           WindowsPEOptionalHeaderType, WindowsPESection,
                           WindowsProcessExt, WindowsRegistryKey,
                           WindowsRegistryValueType, WindowsServiceExt,
-                          X509Certificate, X509V3ExtenstionsType)
+                          X509Certificate, X509V3ExtenstionsType,
+                          parse_observable)
 from .other import (TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE,
                     ExternalReference, GranularMarking, KillChainPhase,
                     MarkingDefinition, StatementMarking, TLPMarking)
-from .sdo import (AttackPattern, Campaign, CourseOfAction, Identity, Indicator,
-                  IntrusionSet, Malware, ObservedData, Report, ThreatActor,
-                  Tool, Vulnerability)
+from .sdo import (AttackPattern, Campaign, CourseOfAction, CustomObject,
+                  Identity, Indicator, IntrusionSet, Malware, ObservedData,
+                  Report, ThreatActor, Tool, Vulnerability)
 from .sro import Relationship, Sighting
 from .utils import get_dict
 from .version import __version__
@@ -43,59 +45,6 @@ OBJ_MAP = {
     'vulnerability': Vulnerability,
 }
 
-OBJ_MAP_OBSERVABLE = {
-    'artifact': Artifact,
-    'autonomous-system': AutonomousSystem,
-    'directory': Directory,
-    'domain-name': DomainName,
-    'email-address': EmailAddress,
-    'email-message': EmailMessage,
-    'file': File,
-    'ipv4-addr': IPv4Address,
-    'ipv6-addr': IPv6Address,
-    'mac-addr': MACAddress,
-    'mutex': Mutex,
-    'network-traffic': NetworkTraffic,
-    'process': Process,
-    'software': Software,
-    'url': URL,
-    'user-account': UserAccount,
-    'windows-registry-key': WindowsRegistryKey,
-    'x509-certificate': X509Certificate,
-}
-
-EXT_MAP_FILE = {
-    'archive-ext': ArchiveExt,
-    'ntfs-ext': NTFSExt,
-    'pdf-ext': PDFExt,
-    'raster-image-ext': RasterImageExt,
-    'windows-pebinary-ext': WindowsPEBinaryExt
-}
-
-EXT_MAP_NETWORK_TRAFFIC = {
-    'http-request-ext': HTTPRequestExt,
-    'icmp-ext': ICMPExt,
-    'socket-ext': SocketExt,
-    'tcp-ext': TCPExt,
-}
-
-EXT_MAP_PROCESS = {
-    'windows-process-ext': WindowsProcessExt,
-    'windows-service-ext': WindowsServiceExt,
-}
-
-EXT_MAP_USER_ACCOUNT = {
-    'unix-account-ext': UNIXAccountExt,
-}
-
-EXT_MAP = {
-    'file': EXT_MAP_FILE,
-    'network-traffic': EXT_MAP_NETWORK_TRAFFIC,
-    'process': EXT_MAP_PROCESS,
-    'user-account': EXT_MAP_USER_ACCOUNT,
-
-}
-
 
 def parse(data, allow_custom=False):
     """Deserialize a string or file-like object into a STIX object.
@@ -120,47 +69,8 @@ def parse(data, allow_custom=False):
     return obj_class(allow_custom=allow_custom, **obj)
 
 
-def parse_observable(data, _valid_refs=[], allow_custom=False):
-    """Deserialize a string or file-like object into a STIX Cyber Observable object.
-
-    Args:
-        data: The STIX 2 string to be parsed.
-        _valid_refs: A list of object references valid for the scope of the object being parsed.
-        allow_custom: Whether to allow custom properties or not. Default: False.
-
-    Returns:
-        An instantiated Python STIX Cyber Observable object.
-    """
-
-    obj = get_dict(data)
-    obj['_valid_refs'] = _valid_refs
-
-    if 'type' not in obj:
-        raise exceptions.ParseError("Can't parse object with no 'type' property: %s" % str(obj))
-    try:
-        obj_class = OBJ_MAP_OBSERVABLE[obj['type']]
-    except KeyError:
-        raise exceptions.ParseError("Can't parse unknown object type '%s'! For custom observables, use the CustomObservable decorator." % obj['type'])
-
-    if 'extensions' in obj and obj['type'] in EXT_MAP:
-        for name, ext in obj['extensions'].items():
-            if name not in EXT_MAP[obj['type']]:
-                raise exceptions.ParseError("Can't parse Unknown extension type '%s' for object type '%s'!" % (name, obj['type']))
-            ext_class = EXT_MAP[obj['type']][name]
-            obj['extensions'][name] = ext_class(allow_custom=allow_custom, **obj['extensions'][name])
-
-    return obj_class(allow_custom=allow_custom, **obj)
-
-
 def _register_type(new_type):
     """Register a custom STIX Object type.
     """
 
     OBJ_MAP[new_type._type] = new_type
-
-
-def _register_observable(new_observable):
-    """Register a custom STIX Cyber Observable type.
-    """
-
-    OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable
diff --git a/stix2/observables.py b/stix2/observables.py
index a8f3b67..e38e298 100644
--- a/stix2/observables.py
+++ b/stix2/observables.py
@@ -5,16 +5,72 @@ embedded in Email Message objects, inherit from _STIXBase instead of Observable
 and do not have a '_type' attribute.
 """
 
-import stix2
-
 from .base import _Extension, _Observable, _STIXBase
-from .exceptions import AtLeastOnePropertyError, DependentPropertiesError
+from .exceptions import (AtLeastOnePropertyError, DependentPropertiesError,
+                         ParseError)
 from .properties import (BinaryProperty, BooleanProperty, DictionaryProperty,
-                         EmbeddedObjectProperty, EnumProperty,
-                         ExtensionsProperty, FloatProperty, HashesProperty,
-                         HexProperty, IntegerProperty, ListProperty,
-                         ObjectReferenceProperty, StringProperty,
-                         TimestampProperty, TypeProperty)
+                         EmbeddedObjectProperty, EnumProperty, FloatProperty,
+                         HashesProperty, HexProperty, IntegerProperty,
+                         ListProperty, ObjectReferenceProperty, Property,
+                         StringProperty, TimestampProperty, TypeProperty)
+from .utils import get_dict
+
+
+class ObservableProperty(Property):
+
+    def clean(self, value):
+        try:
+            dictified = get_dict(value)
+        except ValueError:
+            raise ValueError("The observable property must contain a dictionary")
+        if dictified == {}:
+            raise ValueError("The dictionary property must contain a non-empty dictionary")
+
+        valid_refs = dict((k, v['type']) for (k, v) in dictified.items())
+
+        # from .__init__ import parse_observable  # avoid circular import
+        for key, obj in dictified.items():
+            parsed_obj = parse_observable(obj, valid_refs)
+            if not issubclass(type(parsed_obj), _Observable):
+                raise ValueError("Objects in an observable property must be "
+                                 "Cyber Observable Objects")
+            dictified[key] = parsed_obj
+
+        return dictified
+
+
+class ExtensionsProperty(DictionaryProperty):
+    """ Property for representing extensions on Observable objects
+    """
+
+    def __init__(self, enclosing_type=None, required=False):
+        self.enclosing_type = enclosing_type
+        super(ExtensionsProperty, self).__init__(required)
+
+    def clean(self, value):
+        try:
+            dictified = get_dict(value)
+        except ValueError:
+            raise ValueError("The extensions property must contain a dictionary")
+        if dictified == {}:
+            raise ValueError("The dictionary property must contain a non-empty dictionary")
+
+        if self.enclosing_type in EXT_MAP:
+            specific_type_map = EXT_MAP[self.enclosing_type]
+            for key, subvalue in dictified.items():
+                if key in specific_type_map:
+                    cls = specific_type_map[key]
+                    if type(subvalue) is dict:
+                        dictified[key] = cls(**subvalue)
+                    elif type(subvalue) is cls:
+                        dictified[key] = subvalue
+                    else:
+                        raise ValueError("Cannot determine extension type.")
+                else:
+                    raise ValueError("The key used in the extensions dictionary is not an extension type name")
+        else:
+            raise ValueError("The enclosing type has no extensions defined")
+        return dictified
 
 
 class Artifact(_Observable):
@@ -590,9 +646,101 @@ class X509Certificate(_Observable):
     }
 
 
+OBJ_MAP_OBSERVABLE = {
+    'artifact': Artifact,
+    'autonomous-system': AutonomousSystem,
+    'directory': Directory,
+    'domain-name': DomainName,
+    'email-address': EmailAddress,
+    'email-message': EmailMessage,
+    'file': File,
+    'ipv4-addr': IPv4Address,
+    'ipv6-addr': IPv6Address,
+    'mac-addr': MACAddress,
+    'mutex': Mutex,
+    'network-traffic': NetworkTraffic,
+    'process': Process,
+    'software': Software,
+    'url': URL,
+    'user-account': UserAccount,
+    'windows-registry-key': WindowsRegistryKey,
+    'x509-certificate': X509Certificate,
+}
+
+EXT_MAP_FILE = {
+    'archive-ext': ArchiveExt,
+    'ntfs-ext': NTFSExt,
+    'pdf-ext': PDFExt,
+    'raster-image-ext': RasterImageExt,
+    'windows-pebinary-ext': WindowsPEBinaryExt
+}
+
+EXT_MAP_NETWORK_TRAFFIC = {
+    'http-request-ext': HTTPRequestExt,
+    'icmp-ext': ICMPExt,
+    'socket-ext': SocketExt,
+    'tcp-ext': TCPExt,
+}
+
+EXT_MAP_PROCESS = {
+    'windows-process-ext': WindowsProcessExt,
+    'windows-service-ext': WindowsServiceExt,
+}
+
+EXT_MAP_USER_ACCOUNT = {
+    'unix-account-ext': UNIXAccountExt,
+}
+
+EXT_MAP = {
+    'file': EXT_MAP_FILE,
+    'network-traffic': EXT_MAP_NETWORK_TRAFFIC,
+    'process': EXT_MAP_PROCESS,
+    'user-account': EXT_MAP_USER_ACCOUNT,
+
+}
+
+
+def parse_observable(data, _valid_refs=[], allow_custom=False):
+    """Deserialize a string or file-like object into a STIX Cyber Observable object.
+
+    Args:
+        data: The STIX 2 string to be parsed.
+        _valid_refs: A list of object references valid for the scope of the object being parsed.
+        allow_custom: Whether to allow custom properties or not. Default: False.
+
+    Returns:
+        An instantiated Python STIX Cyber Observable object.
+    """
+
+    obj = get_dict(data)
+    obj['_valid_refs'] = _valid_refs
+
+    if 'type' not in obj:
+        raise ParseError("Can't parse object with no 'type' property: %s" % str(obj))
+    try:
+        obj_class = OBJ_MAP_OBSERVABLE[obj['type']]
+    except KeyError:
+        raise ParseError("Can't parse unknown object type '%s'! For custom observables, use the CustomObservable decorator." % obj['type'])
+
+    if 'extensions' in obj and obj['type'] in EXT_MAP:
+        for name, ext in obj['extensions'].items():
+            if name not in EXT_MAP[obj['type']]:
+                raise ParseError("Can't parse Unknown extension type '%s' for object type '%s'!" % (name, obj['type']))
+            ext_class = EXT_MAP[obj['type']][name]
+            obj['extensions'][name] = ext_class(allow_custom=allow_custom, **obj['extensions'][name])
+
+    return obj_class(allow_custom=allow_custom, **obj)
+
+
+def _register_observable(new_observable):
+    """Register a custom STIX Cyber Observable type.
+    """
+
+    OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable
+
+
 def CustomObservable(type='x-custom-observable', properties={}):
     """Custom STIX Cyber Observable type decorator
-
     """
 
     def custom_builder(cls):
@@ -608,7 +756,7 @@ def CustomObservable(type='x-custom-observable', properties={}):
                 _Observable.__init__(self, **kwargs)
                 cls.__init__(self, **kwargs)
 
-        stix2._register_observable(_Custom)
+        _register_observable(_Custom)
         return _Custom
 
     return custom_builder
diff --git a/stix2/properties.py b/stix2/properties.py
index 80e5345..35c239a 100644
--- a/stix2/properties.py
+++ b/stix2/properties.py
@@ -7,7 +7,7 @@ import uuid
 
 from six import text_type
 
-from .base import _Observable, _STIXBase
+from .base import _STIXBase
 from .exceptions import DictionaryKeyError
 from .utils import get_dict, parse_into_datetime
 
@@ -220,29 +220,6 @@ class TimestampProperty(Property):
         return parse_into_datetime(value, self.precision)
 
 
-class ObservableProperty(Property):
-
-    def clean(self, value):
-        try:
-            dictified = get_dict(value)
-        except ValueError:
-            raise ValueError("The observable property must contain a dictionary")
-        if dictified == {}:
-            raise ValueError("The dictionary property must contain a non-empty dictionary")
-
-        valid_refs = dict((k, v['type']) for (k, v) in dictified.items())
-
-        from .__init__ import parse_observable  # avoid circular import
-        for key, obj in dictified.items():
-            parsed_obj = parse_observable(obj, valid_refs)
-            if not issubclass(type(parsed_obj), _Observable):
-                raise ValueError("Objects in an observable property must be "
-                                 "Cyber Observable Objects")
-            dictified[key] = parsed_obj
-
-        return dictified
-
-
 class DictionaryProperty(Property):
 
     def clean(self, value):
@@ -393,35 +370,3 @@ class EnumProperty(StringProperty):
         if value not in self.allowed:
             raise ValueError("value '%s' is not valid for this enumeration." % value)
         return self.string_type(value)
-
-
-class ExtensionsProperty(DictionaryProperty):
-    def __init__(self, enclosing_type=None, required=False):
-        self.enclosing_type = enclosing_type
-        super(ExtensionsProperty, self).__init__(required)
-
-    def clean(self, value):
-        try:
-            dictified = get_dict(value)
-        except ValueError:
-            raise ValueError("The extensions property must contain a dictionary")
-        if dictified == {}:
-            raise ValueError("The dictionary property must contain a non-empty dictionary")
-
-        from .__init__ import EXT_MAP  # avoid circular import
-        if self.enclosing_type in EXT_MAP:
-            specific_type_map = EXT_MAP[self.enclosing_type]
-            for key, subvalue in dictified.items():
-                if key in specific_type_map:
-                    cls = specific_type_map[key]
-                    if type(subvalue) is dict:
-                        dictified[key] = cls(**subvalue)
-                    elif type(subvalue) is cls:
-                        dictified[key] = subvalue
-                    else:
-                        raise ValueError("Cannot determine extension type.")
-                else:
-                    raise ValueError("The key used in the extensions dictionary is not an extension type name")
-        else:
-            raise ValueError("The enclosing type has no extensions defined")
-        return dictified
diff --git a/stix2/sdo.py b/stix2/sdo.py
index 1ec3b21..8115b9d 100644
--- a/stix2/sdo.py
+++ b/stix2/sdo.py
@@ -4,10 +4,11 @@ import stix2
 
 from .base import _STIXBase
 from .common import COMMON_PROPERTIES
+from .observables import ObservableProperty
 from .other import KillChainPhase
 from .properties import (IDProperty, IntegerProperty, ListProperty,
-                         ObservableProperty, ReferenceProperty, StringProperty,
-                         TimestampProperty, TypeProperty)
+                         ReferenceProperty, StringProperty, TimestampProperty,
+                         TypeProperty)
 from .utils import NOW
 
 
diff --git a/tox.ini b/tox.ini
index 69ae434..b1265ec 100644
--- a/tox.ini
+++ b/tox.ini
@@ -30,7 +30,9 @@ max-line-length=160
 
 [testenv:isort-check]
 deps = isort
-commands = isort -rc stix2 examples -c -df
+commands =
+    isort -rc stix2 examples -df
+    isort -rc stix2 examples -c
 
 [travis]
 python =

Can't add custom observables to Observed Data object
diff --git a/stix2/test/test_custom.py b/stix2/test/test_custom.py
index 1a816bd..60e982c 100644
--- a/stix2/test/test_custom.py
+++ b/stix2/test/test_custom.py
@@ -2,6 +2,8 @@ import pytest
 
 import stix2
 
+from .constants import FAKE_TIME
+
 
 def test_identity_custom_property():
     with pytest.raises(ValueError):
@@ -166,3 +168,15 @@ def test_observable_custom_property_allowed():
         allow_custom=True,
     )
     assert no.x_foo == "bar"
+
+
+def test_observed_data_with_custom_observable_object():
+    no = NewObservable(property1='something')
+    ob_data = stix2.ObservedData(
+        first_observed=FAKE_TIME,
+        last_observed=FAKE_TIME,
+        number_observed=1,
+        objects={'0': no},
+        allow_custom=True,
+    )
+    assert ob_data.objects['0'].property1 == 'something'
diff --git a/stix2/test/test_properties.py b/stix2/test/test_properties.py
index 5395a9f..01daebf 100644
--- a/stix2/test/test_properties.py
+++ b/stix2/test/test_properties.py
@@ -2,13 +2,13 @@ import pytest
 
 from stix2 import TCPExt
 from stix2.exceptions import AtLeastOnePropertyError, DictionaryKeyError
-from stix2.observables import EmailMIMEComponent
+from stix2.observables import EmailMIMEComponent, ExtensionsProperty
 from stix2.properties import (BinaryProperty, BooleanProperty,
                               DictionaryProperty, EmbeddedObjectProperty,
-                              EnumProperty, ExtensionsProperty, HashesProperty,
-                              HexProperty, IDProperty, IntegerProperty,
-                              ListProperty, Property, ReferenceProperty,
-                              StringProperty, TimestampProperty, TypeProperty)
+                              EnumProperty, HashesProperty, HexProperty,
+                              IDProperty, IntegerProperty, ListProperty,
+                              Property, ReferenceProperty, StringProperty,
+                              TimestampProperty, TypeProperty)
 
 from .constants import FAKE_TIME
 

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov coverage
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
babel==2.17.0
bump2version==1.0.1
bumpversion==0.6.0
cachetools==5.5.2
certifi==2025.1.31
cfgv==3.4.0
chardet==5.2.0
charset-normalizer==3.4.1
colorama==0.4.6
coverage==7.8.0
distlib==0.3.9
docutils==0.21.2
exceptiongroup==1.2.2
filelock==3.18.0
identify==2.6.9
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
Jinja2==3.1.6
MarkupSafe==3.0.2
nodeenv==1.9.1
packaging==24.2
platformdirs==4.3.7
pluggy==1.5.0
pre_commit==4.2.0
Pygments==2.19.1
pyproject-api==1.9.0
pytest==8.3.5
pytest-cov==6.0.0
python-dateutil==2.9.0.post0
pytz==2025.2
PyYAML==6.0.2
requests==2.32.3
six==1.17.0
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-prompt==1.8.0
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
-e git+https://github.com/oasis-open/cti-python-stix2.git@6f680be8a65028c303bae38bbe1fa0a2d08852a8#egg=stix2
tomli==2.2.1
tox==4.25.0
typing_extensions==4.13.0
urllib3==2.3.0
virtualenv==20.29.3
zipp==3.21.0

name: cti-python-stix2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - babel==2.17.0
      - bump2version==1.0.1
      - bumpversion==0.6.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cfgv==3.4.0
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - colorama==0.4.6
      - coverage==7.8.0
      - distlib==0.3.9
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - identify==2.6.9
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - nodeenv==1.9.1
      - packaging==24.2
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pre-commit==4.2.0
      - pygments==2.19.1
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyyaml==6.0.2
      - requests==2.32.3
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-prompt==1.8.0
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - tox==4.25.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - virtualenv==20.29.3
      - zipp==3.21.0
prefix: /opt/conda/envs/cti-python-stix2

stix2/test/test_custom.py::test_observed_data_with_custom_observable_object
stix2/test/test_properties.py::test_hashes_property_valid[value0]
stix2/test/test_custom.py::test_identity_custom_property stix2/test/test_custom.py::test_identity_custom_property_invalid stix2/test/test_custom.py::test_identity_custom_property_allowed stix2/test/test_custom.py::test_parse_identity_custom_property[{\n stix2/test/test_custom.py::test_custom_object_type stix2/test/test_custom.py::test_parse_custom_object_type stix2/test/test_custom.py::test_custom_observable_object stix2/test/test_custom.py::test_parse_custom_observable_object stix2/test/test_custom.py::test_observable_custom_property stix2/test/test_custom.py::test_observable_custom_property_invalid stix2/test/test_custom.py::test_observable_custom_property_allowed stix2/test/test_properties.py::test_property stix2/test/test_properties.py::test_basic_clean stix2/test/test_properties.py::test_property_default stix2/test/test_properties.py::test_fixed_property stix2/test/test_properties.py::test_list_property stix2/test/test_properties.py::test_string_property stix2/test/test_properties.py::test_type_property stix2/test/test_properties.py::test_id_property stix2/test/test_properties.py::test_integer_property_valid[2] stix2/test/test_properties.py::test_integer_property_valid[-1] stix2/test/test_properties.py::test_integer_property_valid[3.14] stix2/test/test_properties.py::test_integer_property_valid[False] stix2/test/test_properties.py::test_integer_property_invalid[something] stix2/test/test_properties.py::test_integer_property_invalid[value1] stix2/test/test_properties.py::test_boolean_property_valid[True0] stix2/test/test_properties.py::test_boolean_property_valid[False0] stix2/test/test_properties.py::test_boolean_property_valid[True1] stix2/test/test_properties.py::test_boolean_property_valid[False1] stix2/test/test_properties.py::test_boolean_property_valid[true] stix2/test/test_properties.py::test_boolean_property_valid[false] stix2/test/test_properties.py::test_boolean_property_valid[TRUE] stix2/test/test_properties.py::test_boolean_property_valid[FALSE] stix2/test/test_properties.py::test_boolean_property_valid[T] stix2/test/test_properties.py::test_boolean_property_valid[F] stix2/test/test_properties.py::test_boolean_property_valid[t] stix2/test/test_properties.py::test_boolean_property_valid[f] stix2/test/test_properties.py::test_boolean_property_valid[1] stix2/test/test_properties.py::test_boolean_property_valid[0] stix2/test/test_properties.py::test_boolean_property_invalid[abc] stix2/test/test_properties.py::test_boolean_property_invalid[value1] stix2/test/test_properties.py::test_boolean_property_invalid[value2] stix2/test/test_properties.py::test_boolean_property_invalid[2] stix2/test/test_properties.py::test_boolean_property_invalid[-1] stix2/test/test_properties.py::test_reference_property stix2/test/test_properties.py::test_timestamp_property_valid[2017-01-01T12:34:56Z] stix2/test/test_properties.py::test_timestamp_property_valid[2017-01-01 stix2/test/test_properties.py::test_timestamp_property_valid[Jan stix2/test/test_properties.py::test_timestamp_property_invalid stix2/test/test_properties.py::test_binary_property stix2/test/test_properties.py::test_hex_property stix2/test/test_properties.py::test_dictionary_property_valid[d0] stix2/test/test_properties.py::test_dictionary_property_valid[d1] stix2/test/test_properties.py::test_dictionary_property_invalid[d0] stix2/test/test_properties.py::test_dictionary_property_invalid[d1] stix2/test/test_properties.py::test_dictionary_property_invalid[d2] stix2/test/test_properties.py::test_hashes_property_valid[value1] stix2/test/test_properties.py::test_hashes_property_invalid[value0] stix2/test/test_properties.py::test_hashes_property_invalid[value1] stix2/test/test_properties.py::test_embedded_property stix2/test/test_properties.py::test_enum_property stix2/test/test_properties.py::test_extension_property_valid stix2/test/test_properties.py::test_extension_property_invalid[1] stix2/test/test_properties.py::test_extension_property_invalid[data1] stix2/test/test_properties.py::test_extension_property_invalid_type stix2/test/test_properties.py::test_extension_at_least_one_property_constraint
tox.ini stix2/properties.py stix2/__init__.py stix2/sdo.py stix2/observables.py
tox.ini stix2/properties.py stix2/__init__.py stix2/sdo.py stix2/observables.py