registry - python object management¶
You can use these classes to manage collections of python objects or classes. Registries provide a unified interface to validate, store, search and filter python objects and classes.
For class registry in general you need to specify a list of accepted base classes by defining
get_base_classes() which is required. You can also want to change
default registry key function get_key() which uses class __name__
by default.
import abc
from typing import Type
class BaseConverter(abc.ABC):
data_type: str
@abc.abstractmethod
def convert(self, data):
...
class ConvertersRegistry(ClassRegistry[str, Type[BaseConverter]]):
@classmethod
def get_base_classes(cls):
return (BaseConverter,)
def get_key(self, obj):
return obj.data_type
CONVERTERS = ConvertersRegistry()
Then you can register new classes anywhere in your code.
class XMLConverter(BaseConverter):
data_type = 'xml'
def convert(self, data):
...
CONVERTERS.register(XMLConverter)
You can now dynamically load your classes in your code.
def convert_data(data, data_type):
if data_type in CONVERTERS:
conv = CONVERTERS[data_type]()
return conv.convert(data)
else:
raise NotFound('Unsupported data type.')
- class ClassRegistry[source]¶
Bases:
Registry,Generic[_Key,_Obj],ABCA default registry for classes.
It can be used to register a set of classes for dynamic object initialization based on class names or other parameters.
To create your own registry you need to define
get_base_classes()method returning a tuple of base classesd. All newly registered classes then must be a subclass of these bases. Additionaly you may want to configure at which keys your classes will be stored by changingget_key()method. It uses __name__ of a class by default.It’s also a nice idea to provide a generic type hint for your registry key and item types in square brackets.
>>> class BaseC(abc.ABC): ... name: str ... value: int
>>> class Classes(ClassRegistry[str, type[BaseC]]): ... @classmethod ... def get_base_classes(cls): ... return (BaseC,) ... ... def get_key(self, obj: type[BaseC]) -> str: ... return obj.name # not required, the registry uses `__name__` by default
When you have your registry configured, you can initialize a registry object and start adding your classes! There are a few methods such as
register(),register_from_module()andregister_from_namespace()to help you with registering classes.>>> reg = Classes()
>>> class C(BaseC): ... name = 'my_class' ... value = 1
>>> reg.register(C) 'my_class'
>>> reg.register_from_namespace({'other_class': C}, use_key_names=True) frozenset({'other_class'})
You can access registered classes by their keys or search for them using
find()andfind_all()methods.>>> reg['my_class'].value 1
>>> reg.find(condition=lambda o: o.value > 0).__name__ 'C'
You can also find subclasses of a spacific class(es) using
find_subclass()andfind_subclasses()special methods.>>> reg.find_subclass(BaseC).__name__ 'C'
- find_subclasses(*bases: Collection[_Obj] | _Obj) Generator[_Obj, None, None][source]¶
Find all subclasses matching bases. A shortcut to find_all method.
- find_subclass(*bases: Collection[_Obj] | _Obj) _Obj[source]¶
Find a first subclass matching bases. A shortcut to find method.
- __init__(objects: dict = <factory>, raise_if_exists: bool = False) None¶
- can_register(obj, /) bool¶
Check if an object can be registered.
- clear() None¶
Unlink all registered objects. Use it with caution.
- find(condition: Callable[[Any], bool]) _Obj¶
Find an object matching a condition.
- find_all(condition: Callable[[Any], bool]) Generator[_Obj, None, None]¶
Find all objects matching a condition.
- get(k[, d]) D[k] if k in D, else d. d defaults to None.¶
- items() a set-like object providing a view on D's items¶
- keys() a set-like object providing a view on D's keys¶
- register(obj: _Obj, /, name: _Key = None) _Key¶
Register an object in the registry and return a key under which it has been registered.
- Parameters:
obj – object to register
name – provide a custom name (not recommended)
- Raises:
RegistrationFailed – if an object can’t be registered
- Returns:
object key in the registry
- register_from_module(module: object, *, use_key_names: bool = False) frozenset[_Key]¶
Register classes from current object.
- Parameters:
module – any object with __dict__
use_key_names – use namespace key names instead of a registry name function
- Returns:
a set of registered keys
- register_from_namespace(namespace: Mapping[_Key, _Obj], *, use_key_names: bool = False) frozenset[_Key]¶
Register all supported objects from an arbitrary mapping.
Incompatible objects will be ignored. Returns a set of registered keys.
- Parameters:
namespace – any mapping
use_key_names – use namespace key names instead of a registry name function
- Returns:
a set of registered keys
- register_many(obj: Collection[_Obj], /) tuple[_Key, ...]¶
Register multiple objects at once.
- Parameters:
obj – objects
- Raises:
RegistrationFailed – if any of the objects can’t be registered
- Returns:
a tuple of object keys
- values() an object providing a view on D's values¶
- class ObjectRegistry[source]¶
Bases:
Registry,Generic[_Key,_Obj],ABCPython objects registry.
It can be used to store specific objects in a single mapping (for example for storing application services in a single service registry).
>>> class BaseC(abc.ABC): ... name: str ... ... @staticmethod ... def get_value(): return 1 ... ... def __repr__(self): return f'<[{self.name}]>'
The initialization process and overall workflow is similar to
ClassRegistrywith the only difference being that it stores objects instead of classes.>>> class Objects(ObjectRegistry[str, BaseC]): ... ... @classmethod ... def get_base_classes(cls): ... return (BaseC,) ... ... def get_key(self, obj: BaseC) -> str: ... return obj.name # not necessary, the registry uses `__name__` by default
>>> reg = Objects()
You can register objects and dynamically access them by their identifiers.
>>> class C(BaseC): ... name = 'C_name' >>> reg.register(C()) 'C_name'
>>> reg['C_name'].get_value() 1
You can register objects from a namespace (any dictionary) using either the registry name function or names used in this dictionary (see
register_from_namespace).>>> reg.register_from_namespace({'Other_name': C()}, use_key_names=True) frozenset({'Other_name'})
Standard mapping methods also work for registry classes.
>>> 'Other_name' in reg True
>>> del reg['Other_name']
You can also find instances of a class(es) using
find_instance()andfind_instances()special methods.>>> reg.find_instance(BaseC) <[C_name]>
- find_instances(*bases: Collection[type[_Obj]] | type[_Obj]) Generator[_Obj, None, None][source]¶
Find all subclasses matching bases. A shortcut to find_all method.
- find_instance(*bases: Collection[type[_Obj]] | type[_Obj]) _Obj | None[source]¶
Find a first subclass matching bases. A shortcut to find method.
- get_key(obj: _Obj) _Key[source]¶
Get a name by which a registered class will be referenced in the mapping.
- __init__(objects: dict = <factory>, raise_if_exists: bool = False) None¶
- can_register(obj, /) bool¶
Check if an object can be registered.
- clear() None¶
Unlink all registered objects. Use it with caution.
- find(condition: Callable[[Any], bool]) _Obj¶
Find an object matching a condition.
- find_all(condition: Callable[[Any], bool]) Generator[_Obj, None, None]¶
Find all objects matching a condition.
- get(k[, d]) D[k] if k in D, else d. d defaults to None.¶
- items() a set-like object providing a view on D's items¶
- keys() a set-like object providing a view on D's keys¶
- register(obj: _Obj, /, name: _Key = None) _Key¶
Register an object in the registry and return a key under which it has been registered.
- Parameters:
obj – object to register
name – provide a custom name (not recommended)
- Raises:
RegistrationFailed – if an object can’t be registered
- Returns:
object key in the registry
- register_from_module(module: object, *, use_key_names: bool = False) frozenset[_Key]¶
Register classes from current object.
- Parameters:
module – any object with __dict__
use_key_names – use namespace key names instead of a registry name function
- Returns:
a set of registered keys
- register_from_namespace(namespace: Mapping[_Key, _Obj], *, use_key_names: bool = False) frozenset[_Key]¶
Register all supported objects from an arbitrary mapping.
Incompatible objects will be ignored. Returns a set of registered keys.
- Parameters:
namespace – any mapping
use_key_names – use namespace key names instead of a registry name function
- Returns:
a set of registered keys
- register_many(obj: Collection[_Obj], /) tuple[_Key, ...]¶
Register multiple objects at once.
- Parameters:
obj – objects
- Raises:
RegistrationFailed – if any of the objects can’t be registered
- Returns:
a tuple of object keys
- values() an object providing a view on D's values¶
- class FunctionRegistry[source]¶
Bases:
Registry[str,Callable]A very simple function registry.
You can use it to store and dynamically access functions by their identifiers.
>>> reg = FunctionRegistry() >>> def inc_2(x: int): return x * 2 >>> reg.register(inc_2) 'inc_2'
>>> reg['inc_2'](1) 2
- get_key(obj: Callable) _Key[source]¶
Get a name by which a registered class will be referenced in the mapping.
- __init__(objects: dict = <factory>, raise_if_exists: bool = False) None¶
- can_register(obj, /) bool¶
Check if an object can be registered.
- clear() None¶
Unlink all registered objects. Use it with caution.
- find(condition: Callable[[Any], bool]) _Obj¶
Find an object matching a condition.
- find_all(condition: Callable[[Any], bool]) Generator[_Obj, None, None]¶
Find all objects matching a condition.
- get(k[, d]) D[k] if k in D, else d. d defaults to None.¶
- items() a set-like object providing a view on D's items¶
- keys() a set-like object providing a view on D's keys¶
- register(obj: _Obj, /, name: _Key = None) _Key¶
Register an object in the registry and return a key under which it has been registered.
- Parameters:
obj – object to register
name – provide a custom name (not recommended)
- Raises:
RegistrationFailed – if an object can’t be registered
- Returns:
object key in the registry
- register_from_module(module: object, *, use_key_names: bool = False) frozenset[_Key]¶
Register classes from current object.
- Parameters:
module – any object with __dict__
use_key_names – use namespace key names instead of a registry name function
- Returns:
a set of registered keys
- register_from_namespace(namespace: Mapping[_Key, _Obj], *, use_key_names: bool = False) frozenset[_Key]¶
Register all supported objects from an arbitrary mapping.
Incompatible objects will be ignored. Returns a set of registered keys.
- Parameters:
namespace – any mapping
use_key_names – use namespace key names instead of a registry name function
- Returns:
a set of registered keys
- register_many(obj: Collection[_Obj], /) tuple[_Key, ...]¶
Register multiple objects at once.
- Parameters:
obj – objects
- Raises:
RegistrationFailed – if any of the objects can’t be registered
- Returns:
a tuple of object keys
- values() an object providing a view on D's values¶
- class RegistrationFailed[source]¶
Bases:
ValueError,RegistryErrorObject cannot be registered in this registry.