Entity store and decorators

The entity store class provides functions to register entity instances in an entity store.

It also allow entity classes to be registered at class-level in a “base store”. These entity classes will be instantiated when the entity store gets instantiated, and the resulting instances will be registered.

It also allows “register mappings” to be defined, they allow objects passed to register functions to be transformed based on a mapping. When looking for a mapping, register functions will compare their argument to the mapping key (using issubclass, or isinstance), and use the corresponding mapping value to get the object that will be registered.

Additionally, register mapping keys can be iterables (list or tuples), in which case the register functions will compare their argument to any of the elements in the mapping key, and match even if only a single item in the mapping key matches the argument.

The base store is copied on each class definition, using a metaclass, so that using register functions that class-level won’t alter the base store of other class definitions.

This module also contains a provides() decorator, that decorates a entity store class, adding an object to its base store.

Doctests that use functionality in EntityStore can be seen in other classes (in particular django_crucrudile.routers.Router). They may help to get a good idea of what the entity, entity store and entity graph concepts mean.

Decorators

django_crucrudile.entities.store.provides(provided, **kwargs)[source]

Return a decorator that uses EntityStore.register_class() to register the given object in the base store.

Parameters:provided (object) – Class (or object) to register in the base store. This can be an object since it may be transformed by EntityStore.register_apply_map()

Entity store

class django_crucrudile.entities.store.BaseStoreMetaclassMixin(name, bases, attrs)[source]

Bases: builtins.type

Allows EntityStore to use different _base_register_map and _base_register_map class-level mappings (list instance) for each class definitions. (cls instantiation)

Inheritance diagram of BaseStoreMetaclassMixin

>>> class Store(metaclass=BaseStoreMetaclassMixin):
...   pass
>>>
>>> class FailStore:
...   _fail_store = []
>>>
>>> class NewStore(Store):
...   pass
>>>
>>> class FailNewStore(FailStore):
...   pass
>>> (NewStore._base_register_map is
...  Store._base_register_map)
False
>>> (NewStore._base_register_class_map is
...  Store._base_register_class_map)
False
>>> (FailNewStore._fail_store is
...  FailStore._fail_store)
True
class django_crucrudile.entities.store.EntityStoreMetaclassMixin(name, bases, attrs)[source]

Bases: builtins.type

Allows EntityStore to use a different _base_store store (list instance) for each class definitions (cls instantiation)

Inheritance diagram of EntityStoreMetaclassMixin

>>> class Store(metaclass=EntityStoreMetaclassMixin):
...   pass
>>>
>>> class FailStore:
...   _fail_store = []
>>>
>>> class NewStore(Store):
...   pass
>>>
>>> class FailNewStore(FailStore):
...   pass
>>> (NewStore._base_store is
...  Store._base_store)
False
>>> (FailNewStore._fail_store is
...  FailStore._fail_store)
True
class django_crucrudile.entities.store.EntityStoreMetaclass(name, bases, attrs)[source]

Bases: django_crucrudile.entities.store.EntityStoreMetaclassMixin, django_crucrudile.entities.store.BaseStoreMetaclassMixin, abc.ABCMeta

Use the entity store and base store metaclass mixins, that handle creating a new instance of the stores for each class definition.

See EntityStoreMetaclassMixin and BaseStoreMetaclassMixin for more information.

Note

Also subclasses abc.ABCMeta because it will be used as the metaclass for an entity, and entity are abstract classes, which needs the âbc.ABCMeta base class.

Inheritance diagram of EntityStoreMetaclass

class django_crucrudile.entities.store.EntityStore[source]

Bases: builtins.object

Provides an entity store, and a register() method that registers entities in the entity store.

The subclass implementation of patterns() should iterate over the entity store.

Inheritance diagram of EntityStore

static register_apply_map(entity, mapping, transform_kwargs=None, silent=True)[source]

Apply mapping of value in mapping if entity is subclass (issubclass()) or instance (isinstance()) of key

Parameters:
  • entity (object or class) – Object to pass to found mappings
  • mapping (dict) – Register mapping, used to get callable to pass entity to
  • transform_kwargs (dict) – Extra keyword arguments to pass to the found transform functions (mapping keys)
  • silent – If set to False, will fail if not matching mapping was found.
Raises LookupError:
 

If silent is False, and no matching mapping was found

>>> from mock import Mock
>>>
>>> class Class:
...   pass
>>> class SubClass(Class):
...   pass
>>> class OtherClass:
...   pass
>>>
>>> instance = SubClass()

With instance :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   instance,
...   {Class: class_mock}
... )
>>> class_mock.assert_called_once_with(instance)

With instance, and default mapping :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   instance,
...   {None: class_mock}
... )
>>> class_mock.assert_called_once_with(instance)

With instance and iterable bases :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   instance,
...   {(OtherClass, Class): class_mock}
... )
>>> class_mock.assert_called_once_with(instance)

With instance and iterable bases (no matching base) :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   instance,
...   {(OtherClass, ): class_mock}
... )
>>> applied is instance
True
>>> class_mock.called
False

With instance and iterable bases (no matching base, not silent) :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   instance,
...   {(OtherClass, ): class_mock},
...   silent=False
... )
... 
Traceback (most recent call last):
  ...
LookupError: Could not find matching key in register
mapping. Used test 'isinstance', register mapping bases are
'OtherClass', tested against 'SubClass'

With subclass :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   SubClass,
...   {Class: class_mock}
... )
>>> class_mock.assert_called_once_with(SubClass)

With subclass and iterable bases (no matching base) :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   SubClass,
...   {(OtherClass, ): class_mock}
... )
>>> applied is SubClass
True
>>> class_mock.called
False

With subclass and single bases (no matching base, not silent) :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   SubClass,
...   {OtherClass: class_mock},
...   silent=False
... )
... 
Traceback (most recent call last):
  ...
LookupError: Could not find matching key in register
mapping. Used test 'issubclass', register mapping bases are
'OtherClass', tested against 'SubClass'

With subclass and no mappings (not silent) :

>>> class_mock = Mock()
>>> applied = EntityStore.register_apply_map(
...   SubClass,
...   {},
...   silent=False
... )
... 
Traceback (most recent call last):
  ...
LookupError: Could not find matching key in register
mapping. Used test 'issubclass', register mapping bases are
'', tested against 'SubClass'
classmethod get_register_class_map()[source]

Mapping of type to function that will be evaluated (with entity) when calling register. See register_class() and register_apply_map().

Overriding implementations must call the base implementation (using super(), usually), so that the base mappings set by set_register_class_mapping() can be returned.

The base implementation returns a copy of the stored mapping, so overriding implementations may append to the return value.

Warning

The matching mapping will be used. This is why this method must return an collections.OrderedDict, so that the adding order is used.

See also

For doctests that use this member, see django_crucrudile.entities.store.EntityStore.register_class()

classmethod get_register_class_map_kwargs()[source]

Arguments passed when applying register map, in register_class()

See also

For doctests that use this member, see django_crucrudile.entities.store.EntityStore.register_class()

get_register_map()[source]

Mapping of type to function that will be evaluated (with entity) when calling register. See register() and register_apply_map()

Overriding implementations MUST call the base implementation (using super(), usually), so that the base mappings set by set_register_mapping() can be returned.

The base implementation returns a copy of the stored mapping, so overriding implementations may append to the return value.

Warning

The matching mapping will be used. This is why this method must return an collections.OrderedDict, so that the adding order is used.

See also

For doctests that use this member, see django_crucrudile.entities.store.EntityStore.register()

get_register_map_kwargs()[source]

Arguments passed when applying register map, in register()

See also

For doctests that use this member, see django_crucrudile.entities.store.EntityStore.register()

classmethod set_register_class_mapping(key, value)[source]

Set a base register class mapping, that will be returned (possibly with other mappings) by get_register_class_map().

Parameters:
  • key (class or tuple of classes) – Register class mapping bases
  • value (callable) – Register class mapping value
>>> from mock import Mock
>>> mock_mapping_func = Mock()
>>>
>>> class Class:
...   pass
>>> class Store(EntityStore):
...   pass
>>>
>>>
>>> Store.set_register_class_mapping(
...   Class, mock_mapping_func
... )
>>> Store.get_register_class_map() == (
...   {Class: mock_mapping_func}
... )
True
classmethod set_register_mapping(key, value)[source]

Set a base register mapping, that will be returned (possibly with other mappings) by get_register_map().

Parameters:
  • key (class or tuple of classes) – Register mapping bases
  • value (callable) – Register mapping value
>>> from mock import Mock
>>> mock_mapping_func = Mock()
>>>
>>> class Class:
...   pass
>>>
>>> class Store(EntityStore):
...   pass
>>>
>>> Store.set_register_mapping(
...   Class, mock_mapping_func
... )
>>> Store().get_register_map() == (
...   {Class: mock_mapping_func}
... )
True
classmethod register_class(register_cls, map_kwargs=None)[source]

Add a route class to _base_store, appling mapping from get_register_class_map() where required. This route class will be instantiated (with kwargs from get_base_store_kwargs()) when the Router is itself instiated, using register_base_store().

Parameters:
  • register_cls – Object to register (usually Route or Router classes, but could be anything because of possible mapping in get_register_class_map_kwargs())
  • map_kwargs (dict) – Argument to pass to mapping value if entity gets transformed.
Returns:

The registered class, transformed by class register mappings if there was a matching mapping

Return type:

class

>>> from mock import Mock
>>> mock_entity_instance = Mock()
>>> mock_entity = Mock()
>>> mock_entity.side_effect = [mock_entity_instance]
>>> mock_mapping_func = Mock()
>>> mock_mapping_func.side_effect = [mock_entity]
>>>
>>> class Class:
...  pass
>>>
>>> class Store(EntityStore):
...   @classmethod
...   def get_register_class_map(self):
...     return {Class: mock_mapping_func}
>>>
>>> Store.register_class(Class) is mock_entity
True
>>>
>>> Store._base_store == [mock_entity]
True
>>>
>>> store = Store()
>>> store._store == [mock_entity_instance]
True
register(entity, map_kwargs=None)[source]

Register routed entity, applying mapping from get_register_map() where required

Parameters:
Returns:

The registered entity, transformed by register mappings if there was a matching mapping

Return type:

django_crucrudile.entities.Entity

>>> from mock import Mock
>>> mock_entity_instance = Mock()
>>> mock_mapping_func = Mock()
>>> mock_mapping_func.side_effect = [mock_entity_instance]
>>>
>>> class Class:
...  pass
>>> instance = Class()
>>>
>>> class Store(EntityStore):
...   @classmethod
...   def get_register_map(self):
...     return {Class: mock_mapping_func}
>>>
>>> store = Store()
>>> store.register(instance) == mock_entity_instance
True
>>> store._store == [mock_entity_instance]
True
get_base_store_kwargs()[source]

Arguments passed when instantiating entity classes in _base_store

Returns:Keyword arguments
Return type:dict
>>> from mock import Mock
>>> mock_entity = Mock()
>>>
>>> class Store(EntityStore):
...   def get_base_store_kwargs(self):
...     return {'x': mock_entity}
>>>
>>> Store.register_class(lambda x: x) is not None
True
>>>
>>> store = Store()
>>> store._store == [mock_entity]
True
register_base_store()[source]

Instantiate entity classes in _base_store, using arguments from get_base_store_kwargs()

>>> class Store(EntityStore):
...   pass
>>>
>>> Store.register_class(lambda: None) is not None
True
>>>
>>> store = Store()
>>> store._store
[None]