Registry
coola.registry ¶
General-purpose registry primitives used across the package.
coola.registry.BaseTypeDispatchRegistry ¶
Bases: MultilineDisplayMixin, Generic[V]
Base class for registries that dispatch a single handler based on data type.
This class maintains a mapping from Python types to handler
instances (e.g. equality testers, hashers, transformers) and uses
the Method Resolution Order (MRO) for type lookup, via an internal
TypeRegistry. When resolving a handler for some data, the most
specific registered handler for the data's type is used, falling
back to parent types (or a default handler, if one is registered
for object) if needed.
Subclasses typically expose their own, more specifically named
has_<x>/find_<x> wrappers around has/find plus a
domain-specific entry point (e.g. hash, transform), but the
registration and lookup machinery itself lives entirely here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_state
|
dict[type, V] | None
|
Optional initial mapping of types to handlers. If provided, the state is copied to prevent external mutations. |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
_state |
TypeRegistry[V]
|
Internal |
coola.registry.BaseTypeDispatchRegistry.find ¶
find(data_type: type) -> V
Find the appropriate handler for a given type.
Uses the Method Resolution Order (MRO) to find the most
specific registered handler. For example, if a handler is
registered for Sequence but not for list, lists will
use the Sequence handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_type
|
type
|
The Python type to find a handler for. |
required |
Returns:
| Type | Description |
|---|---|
V
|
The most specific registered handler for this type, |
V
|
resolved via MRO, or the default handler if no match is |
V
|
found. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If no handler is registered for |
Note
Results are cached internally (see TypeRegistry.resolve)
so repeated lookups for the same type are fast. The cache
is invalidated automatically by register/register_many.
coola.registry.BaseTypeDispatchRegistry.has ¶
has(data_type: type) -> bool
Check if a handler is explicitly registered for the given type.
Note that this only checks for direct registration. Even if
this returns False, find may still return a handler
via MRO lookup or the default handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_type
|
type
|
The type to check. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
coola.registry.BaseTypeDispatchRegistry.register ¶
register(
data_type: type, value: V, exist_ok: bool = False
) -> None
Register a handler for a given data type.
The internal type-lookup cache is automatically cleared after registration to ensure consistency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_type
|
type
|
The Python type to register (e.g., |
required |
value
|
V
|
The handler instance that handles this type. |
required |
exist_ok
|
bool
|
If |
False
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the type is already registered and
|
coola.registry.BaseTypeDispatchRegistry.register_many ¶
register_many(
mapping: Mapping[type, V], exist_ok: bool = False
) -> None
Register multiple handlers at once.
This is a convenience method for bulk registration that
internally calls register for each type-handler pair.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mapping
|
Mapping[type, V]
|
Dictionary mapping Python types to handler instances. |
required |
exist_ok
|
bool
|
If |
False
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If any type is already registered and
|
coola.registry.Registry ¶
Bases: BaseRegistry[K, V]
A thread-safe generic key-value registry for storing and managing typed mappings.
The Registry class provides a type-safe container for registering and retrieving values by key. It supports all standard dictionary operations through operator overloading and provides additional methods for safe registration and querying. All operations are protected by a lock to ensure thread safety in concurrent environments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_state
|
dict[K, V] | None
|
An optional dictionary to initialize the registry with. If provided, a copy is made to prevent external modifications. Defaults to None, which creates an empty registry. |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
_state |
dict[K, V]
|
Internal dictionary storing the key-value pairs. |
_lock |
RLock
|
Threading lock for synchronizing access to the registry. |
Example
Basic usage with registration and retrieval:
>>> from coola.registry import Registry
>>> registry = Registry[str, int]()
>>> registry.register("key1", 42)
>>> registry.get("key1")
42
>>> registry
Registry(
(key1): 42
)
Using dictionary-style operations:
>>> from coola.registry import Registry
>>> registry = Registry[str, int]()
>>> registry["key2"] = 100
>>> "key2" in registry
True
>>> del registry["key2"]
Initializing with existing data:
>>> from coola.registry import Registry
>>> registry = Registry[str, int](initial_state={"a": 1, "b": 2})
>>> len(registry)
2
coola.registry.TypeRegistry ¶
Bases: BaseRegistry[type, T], Generic[T]
A thread-safe type-based registry for storing and retrieving values.
The TypeRegistry class provides a thread-safe container for mapping Python types to values. It supports standard dictionary operations through operator overloading and provides methods for safe registration and querying.
The registry uses the Method Resolution Order (MRO) for type lookup through
the resolve() method. When resolving a type, it automatically selects the
most specific registered type, walking up the inheritance hierarchy if needed.
This makes it ideal for type-based dispatching systems.
The registry includes an internal LRU (least-recently-used) cache for
type resolution, bounded to _MAX_CACHE_SIZE (1024) entries, to
optimize performance when repeatedly resolving the same types without
growing unbounded.
Note
resolve() walks dtype.__mro__, which reflects real (static)
inheritance only. Virtual subclasses registered via
abc.ABCMeta.register() do not appear in __mro__, so
registering a value for an ABC does not make resolve() match
that ABC's virtual subclasses even though isinstance would
report them as instances of the ABC. See resolve() for details.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_state
|
dict[type, T] | None
|
An optional dictionary to initialize the registry with. If provided, a copy is made to prevent external modifications. Defaults to None, which creates an empty registry. |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
_state |
dict[K, V]
|
Internal dictionary storing the type-value pairs. |
_cache |
LRUCache[type, T]
|
Bounded LRU cache of type resolution lookups for performance. |
_lock |
RLock
|
Threading lock for synchronizing access to both state and cache. |
Example
Basic usage with registration and retrieval:
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[str]()
>>> registry.register(int, "I am an integer")
>>> registry.get(int)
'I am an integer'
>>> registry
TypeRegistry(
(<class 'int'>): I am an integer
)
Using dictionary-style operations:
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[str]()
>>> registry[str] = "I am a string"
>>> str in registry
True
>>> registry[str]
'I am a string'
>>> del registry[str]
>>> str in registry
False
Initializing with existing data:
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[int](initial_state={str: 100, float: 200})
>>> len(registry)
2
>>> registry.get(str)
100
Using resolve() with inheritance (MRO lookup):
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[str]()
>>> registry.register(object, "I am an object")
>>> registry.register(int, "I am an integer")
>>> # Direct match
>>> registry.resolve(int)
'I am an integer'
>>> # Falls back to parent type via MRO
>>> registry.resolve(bool) # bool inherits from int
'I am an integer'
>>> # Falls back to object
>>> registry.resolve(str)
'I am an object'
Bulk registration:
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[str]()
>>> registry.register_many({int: "integer", float: "float", str: "string"})
>>> len(registry)
3
>>> registry.get(float)
'float'
coola.registry.TypeRegistry.resolve ¶
resolve(dtype: type) -> T
Resolve a type to its associated value using MRO lookup.
This method finds the most appropriate value for a given type by walking the Method Resolution Order (MRO). It first checks for a direct match, then searches through parent types in MRO order to find the most specific registered type.
Results are cached internally to optimize performance for repeated lookups of the same type.
Note
Resolution walks dtype.__mro__, i.e. real (static)
inheritance only. Virtual subclasses registered with
abc.ABCMeta.register() do not appear in __mro__, so
registering a value for an ABC does not make this method
resolve any of that ABC's virtual subclasses, even though
isinstance(instance_of_virtual_subclass, the_abc) is
True. To make a virtual subclass resolve to a value, either
register the subclass itself or a real (non-virtual) ancestor of
it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dtype
|
type
|
The type to resolve. |
required |
Returns:
| Type | Description |
|---|---|
T
|
The value associated with the type or its nearest registered |
T
|
parent type in the MRO. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If no matching type is found in the registry, including parent types in the MRO. |
Example
Basic resolution with inheritance:
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[str]()
>>> registry.register(object, "base")
>>> registry.register(int, "integer")
>>> # Direct match
>>> registry.resolve(int)
'integer'
>>> # bool inherits from int, so resolves to int's value
>>> registry.resolve(bool)
'integer'
>>> # str inherits from object, so resolves to object's value
>>> registry.resolve(str)
'base'
Resolution with custom classes:
>>> from coola.registry import TypeRegistry
>>> class Animal:
... pass
...
>>> class Dog(Animal):
... pass
...
>>> class Poodle(Dog):
... pass
...
>>> registry = TypeRegistry[str]()
>>> registry.register(Animal, "animal")
>>> registry.register(Dog, "dog")
>>> registry.resolve(Dog)
'dog'
>>> registry.resolve(Poodle) # Resolves to parent Dog
'dog'