2018-07-10 20:54:17 +02:00
|
|
|
from collections import OrderedDict
|
|
|
|
|
2020-03-22 03:22:36 +01:00
|
|
|
from .base import _cls_init
|
Make extension instances work the same as other objects, with
respect to properties. Before, properties were declared on
toplevel-property-extension extensions as if they were going
to be used in the normal way (as actual properties on instances
of the extension), but they were not used that way, and there
was some ugly hackage to make it work. Despite the fact that
property instances were given during extension registration,
they were not used to typecheck, set defaults, etc on toplevel
property extension properties.
I changed how registration and object initialization works with
respect to properties associated with extensions. Now,
extensions work the same as any other object and code is
cleaner. Property instances associated with registered toplevel
extensions are used to enforce requirements like any other
object.
Added some unit tests specifically for property cleaning for
extensions.
Property order (for those contexts where it matters) is updated
to be spec-defined, toplevel extension, custom.
2021-07-06 20:27:40 +02:00
|
|
|
from .properties import EnumProperty
|
2021-01-09 04:08:33 +01:00
|
|
|
from .registration import (
|
2021-07-10 00:11:11 +02:00
|
|
|
_register_extension, _register_marking, _register_object,
|
|
|
|
_register_observable,
|
2018-07-13 17:10:05 +02:00
|
|
|
)
|
2021-07-10 00:11:11 +02:00
|
|
|
from .registry import class_for_type
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
|
2020-04-02 20:15:45 +02:00
|
|
|
def _get_properties_dict(properties):
|
|
|
|
try:
|
|
|
|
return OrderedDict(properties)
|
|
|
|
except TypeError as e:
|
2021-02-18 18:26:54 +01:00
|
|
|
raise ValueError(
|
|
|
|
"properties must be dict-like, e.g. a list "
|
|
|
|
"containing tuples. For example, "
|
|
|
|
"[('property1', IntegerProperty())]",
|
|
|
|
) from e
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
|
2020-04-02 20:15:45 +02:00
|
|
|
def _custom_object_builder(cls, type, properties, version, base_class):
|
|
|
|
prop_dict = _get_properties_dict(properties)
|
|
|
|
|
|
|
|
class _CustomObject(cls, base_class):
|
2020-03-19 15:40:35 +01:00
|
|
|
|
2018-07-10 20:54:17 +02:00
|
|
|
_type = type
|
2020-04-02 20:15:45 +02:00
|
|
|
_properties = prop_dict
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
2020-03-22 03:22:36 +01:00
|
|
|
base_class.__init__(self, **kwargs)
|
2018-10-17 13:34:15 +02:00
|
|
|
_cls_init(cls, self, kwargs)
|
2020-11-11 00:32:58 +01:00
|
|
|
ext = getattr(self, 'with_extension', None)
|
|
|
|
if ext and version != '2.0':
|
|
|
|
if 'extensions' not in self._inner:
|
|
|
|
self._inner['extensions'] = {}
|
2021-07-10 00:11:11 +02:00
|
|
|
self._inner['extensions'][ext] = class_for_type(ext, version, "extensions")()
|
2018-07-10 20:54:17 +02:00
|
|
|
|
2020-07-27 03:08:19 +02:00
|
|
|
_CustomObject.__name__ = cls.__name__
|
|
|
|
|
2018-07-10 20:54:17 +02:00
|
|
|
_register_object(_CustomObject, version=version)
|
|
|
|
return _CustomObject
|
|
|
|
|
|
|
|
|
2020-03-22 03:22:36 +01:00
|
|
|
def _custom_marking_builder(cls, type, properties, version, base_class):
|
2020-04-02 20:15:45 +02:00
|
|
|
prop_dict = _get_properties_dict(properties)
|
2020-03-19 19:16:48 +01:00
|
|
|
|
2020-03-22 03:22:36 +01:00
|
|
|
class _CustomMarking(cls, base_class):
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
_type = type
|
2020-04-02 20:15:45 +02:00
|
|
|
_properties = prop_dict
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
2020-03-22 03:22:36 +01:00
|
|
|
base_class.__init__(self, **kwargs)
|
2020-11-11 03:09:17 +01:00
|
|
|
_cls_init(cls, self, kwargs)
|
2018-07-10 20:54:17 +02:00
|
|
|
|
2020-07-27 03:08:19 +02:00
|
|
|
_CustomMarking.__name__ = cls.__name__
|
|
|
|
|
2018-07-10 20:54:17 +02:00
|
|
|
_register_marking(_CustomMarking, version=version)
|
|
|
|
return _CustomMarking
|
|
|
|
|
|
|
|
|
2020-03-22 03:22:36 +01:00
|
|
|
def _custom_observable_builder(cls, type, properties, version, base_class, id_contrib_props=None):
|
2020-03-04 20:46:55 +01:00
|
|
|
if id_contrib_props is None:
|
|
|
|
id_contrib_props = []
|
|
|
|
|
2020-04-02 20:15:45 +02:00
|
|
|
prop_dict = _get_properties_dict(properties)
|
2018-07-10 20:54:17 +02:00
|
|
|
|
2020-04-02 20:15:45 +02:00
|
|
|
class _CustomObservable(cls, base_class):
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
_type = type
|
2020-04-02 20:15:45 +02:00
|
|
|
_properties = prop_dict
|
2020-02-25 03:11:42 +01:00
|
|
|
if version != '2.0':
|
|
|
|
_id_contributing_properties = id_contrib_props
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
2020-03-22 03:22:36 +01:00
|
|
|
base_class.__init__(self, **kwargs)
|
2018-10-17 13:34:15 +02:00
|
|
|
_cls_init(cls, self, kwargs)
|
2020-11-11 00:32:58 +01:00
|
|
|
ext = getattr(self, 'with_extension', None)
|
|
|
|
if ext and version != '2.0':
|
|
|
|
if 'extensions' not in self._inner:
|
|
|
|
self._inner['extensions'] = {}
|
2021-07-10 00:11:11 +02:00
|
|
|
self._inner['extensions'][ext] = class_for_type(ext, version, "extensions")()
|
2018-07-10 20:54:17 +02:00
|
|
|
|
2020-07-27 03:08:19 +02:00
|
|
|
_CustomObservable.__name__ = cls.__name__
|
|
|
|
|
2018-07-10 20:54:17 +02:00
|
|
|
_register_observable(_CustomObservable, version=version)
|
|
|
|
return _CustomObservable
|
|
|
|
|
|
|
|
|
2020-11-11 00:32:58 +01:00
|
|
|
def _custom_extension_builder(cls, type, properties, version, base_class):
|
Make extension instances work the same as other objects, with
respect to properties. Before, properties were declared on
toplevel-property-extension extensions as if they were going
to be used in the normal way (as actual properties on instances
of the extension), but they were not used that way, and there
was some ugly hackage to make it work. Despite the fact that
property instances were given during extension registration,
they were not used to typecheck, set defaults, etc on toplevel
property extension properties.
I changed how registration and object initialization works with
respect to properties associated with extensions. Now,
extensions work the same as any other object and code is
cleaner. Property instances associated with registered toplevel
extensions are used to enforce requirements like any other
object.
Added some unit tests specifically for property cleaning for
extensions.
Property order (for those contexts where it matters) is updated
to be spec-defined, toplevel extension, custom.
2021-07-06 20:27:40 +02:00
|
|
|
|
|
|
|
properties = _get_properties_dict(properties)
|
|
|
|
toplevel_properties = None
|
|
|
|
|
|
|
|
# Auto-create an "extension_type" property from the class attribute, if
|
|
|
|
# it exists. How to treat the other properties which were given depends on
|
|
|
|
# the extension type.
|
|
|
|
extension_type = getattr(cls, "extension_type", None)
|
|
|
|
if extension_type:
|
|
|
|
# I suppose I could also go with a plain string property, since the
|
|
|
|
# value is fixed... but an enum property seems more true to the
|
|
|
|
# property's semantics. Also, I can't import a vocab module for the
|
|
|
|
# enum values without circular import errors. :(
|
|
|
|
extension_type_prop = EnumProperty(
|
|
|
|
[
|
|
|
|
"new-sdo", "new-sco", "new-sro", "property-extension",
|
2021-07-07 02:40:50 +02:00
|
|
|
"toplevel-property-extension",
|
Make extension instances work the same as other objects, with
respect to properties. Before, properties were declared on
toplevel-property-extension extensions as if they were going
to be used in the normal way (as actual properties on instances
of the extension), but they were not used that way, and there
was some ugly hackage to make it work. Despite the fact that
property instances were given during extension registration,
they were not used to typecheck, set defaults, etc on toplevel
property extension properties.
I changed how registration and object initialization works with
respect to properties associated with extensions. Now,
extensions work the same as any other object and code is
cleaner. Property instances associated with registered toplevel
extensions are used to enforce requirements like any other
object.
Added some unit tests specifically for property cleaning for
extensions.
Property order (for those contexts where it matters) is updated
to be spec-defined, toplevel extension, custom.
2021-07-06 20:27:40 +02:00
|
|
|
],
|
|
|
|
required=False,
|
|
|
|
fixed=extension_type,
|
|
|
|
)
|
|
|
|
|
|
|
|
nested_properties = {
|
2021-07-07 02:40:50 +02:00
|
|
|
"extension_type": extension_type_prop,
|
Make extension instances work the same as other objects, with
respect to properties. Before, properties were declared on
toplevel-property-extension extensions as if they were going
to be used in the normal way (as actual properties on instances
of the extension), but they were not used that way, and there
was some ugly hackage to make it work. Despite the fact that
property instances were given during extension registration,
they were not used to typecheck, set defaults, etc on toplevel
property extension properties.
I changed how registration and object initialization works with
respect to properties associated with extensions. Now,
extensions work the same as any other object and code is
cleaner. Property instances associated with registered toplevel
extensions are used to enforce requirements like any other
object.
Added some unit tests specifically for property cleaning for
extensions.
Property order (for those contexts where it matters) is updated
to be spec-defined, toplevel extension, custom.
2021-07-06 20:27:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if extension_type == "toplevel-property-extension":
|
|
|
|
toplevel_properties = properties
|
|
|
|
else:
|
|
|
|
nested_properties.update(properties)
|
|
|
|
|
|
|
|
else:
|
|
|
|
nested_properties = properties
|
2018-07-10 20:54:17 +02:00
|
|
|
|
2020-03-22 03:22:36 +01:00
|
|
|
class _CustomExtension(cls, base_class):
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
_type = type
|
Make extension instances work the same as other objects, with
respect to properties. Before, properties were declared on
toplevel-property-extension extensions as if they were going
to be used in the normal way (as actual properties on instances
of the extension), but they were not used that way, and there
was some ugly hackage to make it work. Despite the fact that
property instances were given during extension registration,
they were not used to typecheck, set defaults, etc on toplevel
property extension properties.
I changed how registration and object initialization works with
respect to properties associated with extensions. Now,
extensions work the same as any other object and code is
cleaner. Property instances associated with registered toplevel
extensions are used to enforce requirements like any other
object.
Added some unit tests specifically for property cleaning for
extensions.
Property order (for those contexts where it matters) is updated
to be spec-defined, toplevel extension, custom.
2021-07-06 20:27:40 +02:00
|
|
|
_properties = nested_properties
|
|
|
|
if extension_type == "toplevel-property-extension":
|
|
|
|
_toplevel_properties = toplevel_properties
|
2018-07-10 20:54:17 +02:00
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
2020-03-22 03:22:36 +01:00
|
|
|
base_class.__init__(self, **kwargs)
|
2018-10-17 13:34:15 +02:00
|
|
|
_cls_init(cls, self, kwargs)
|
2018-07-10 20:54:17 +02:00
|
|
|
|
2020-07-27 03:08:19 +02:00
|
|
|
_CustomExtension.__name__ = cls.__name__
|
|
|
|
|
2020-11-11 00:32:58 +01:00
|
|
|
_register_extension(_CustomExtension, version=version)
|
2018-07-10 20:54:17 +02:00
|
|
|
return _CustomExtension
|