Skip to content

Registry

coola.registry

Experimental package with registry implementations.

coola.registry.Registry

Bases: Generic[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.Registry.clear

clear() -> None

Remove all entries from the registry.

This method empties the registry, leaving it in the same state as a newly created empty registry. This operation cannot be undone.

Example
>>> from coola.registry import Registry
>>> registry = Registry[str, int]({"key1": 42, "key2": 100})
>>> len(registry)
2
>>> registry.clear()
>>> len(registry)
0
>>> registry.has("key1")
False

coola.registry.Registry.equal

equal(other: object, equal_nan: bool = False) -> bool

Indicate if two objects are equal or not.

Parameters:

Name Type Description Default
other object

The object to compare with.

required
equal_nan bool

If True, then two NaNs will be considered equal.

False

Returns:

Type Description
bool

True if the two objects are equal, otherwise False.

Example
>>> from coola.registry import Registry
>>> registry1 = Registry[str, int]({"key1": 42, "key2": 100})
>>> registry2 = Registry[str, int]({"key1": 42, "key2": 100})
>>> registry3 = Registry[str, int]({"key1": 42})
>>> registry1.equal(registry2)
True
>>> registry1.equal(registry3)
False

coola.registry.Registry.get

get(key: K, default: V | None = None) -> V | None

Retrieve the value associated with a key.

This method performs a lookup in the registry and returns the corresponding value.

Parameters:

Name Type Description Default
key K

The key whose value should be retrieved.

required
default V | None

Value to return if the key does not exist.

None

Returns:

Type Description
V | None

The value associated with the specified key.

Example
>>> from coola.registry import Registry
>>> registry = Registry[str, int]({"key1": 42, "key2": 100})
>>> registry.get("key1")
42
>>> registry.get("missing")
None

coola.registry.Registry.has

has(key: K) -> bool

Check whether a key is registered in the registry.

This method provides a safe way to test for key existence without risking a KeyError exception.

Parameters:

Name Type Description Default
key K

The key to check for existence.

required

Returns:

Type Description
bool

True if the key exists in the registry, False otherwise.

Example
>>> from coola.registry import Registry
>>> registry = Registry[str, int]({"key1": 42, "key2": 100})
>>> registry.has("key1")
True
>>> registry.has("missing")
False

coola.registry.Registry.register

register(
    key: K, value: V, exist_ok: bool = False
) -> None

Register a new key-value pair in the registry.

By default, this method raises an error if you try to register a key that already exists. This prevents accidental overwriting of values. Set exist_ok=True to allow overwriting.

Parameters:

Name Type Description Default
key K

The key to register. Must be hashable.

required
value V

The value to associate with the key.

required
exist_ok bool

Controls behavior when the key already exists. If False (default), raises RuntimeError for duplicate keys. If True, silently overwrites the existing value.

False

Raises:

Type Description
RuntimeError

If the key is already registered and exist_ok is False. The error message provides guidance on how to resolve the conflict.

Example

Basic registration:

>>> from coola.registry import Registry
>>> registry = Registry[str, int]()
>>> registry.register("key1", 42)
>>> registry.get("key1")
42

Attempting to register a duplicate key:

>>> registry.register("key1", 100)  # doctest: +SKIP
RuntimeError: A value is already registered for 'key1'...

Overwriting with exist_ok:

>>> registry.register("key1", 100, exist_ok=True)
>>> registry.get("key1")
100

coola.registry.Registry.register_many

register_many(
    mapping: Mapping[K, V], exist_ok: bool = False
) -> None

Register multiple key-value pairs in a single operation.

This is a convenience method for bulk registration. It iterates through the provided mapping and registers each key-value pair. All registrations follow the same exist_ok policy. The operation is atomic when exist_ok is False - if any key already exists, no changes are made.

Parameters:

Name Type Description Default
mapping Mapping[K, V]

A dictionary or mapping containing the key-value pairs to register. The keys and values must match the registry's type parameters.

required
exist_ok bool

Controls behavior when any key already exists. If False (default), raises error on the first duplicate key. If True, overwrites all existing values without error.

False

Raises:

Type Description
RuntimeError

If exist_ok is False and any key in the mapping is already registered. The error occurs on the first duplicate encountered, and no partial registration occurs.

Example

Registering multiple entries at once:

>>> from coola.registry import Registry
>>> registry = Registry[str, int]()
>>> registry.register_many({"key1": 42, "key2": 100, "key3": 7})
>>> registry.get("key1")
42
>>> registry.get("key2")
100
>>> len(registry)
3

Bulk update with exist_ok:

>>> registry.register_many({"key1": 1, "key4": 4}, exist_ok=True)
>>> registry.get("key1")
1
>>> registry.get("key4")
4

coola.registry.Registry.unregister

unregister(key: K) -> V

Remove a key-value pair from the registry and return the value.

This method removes the specified key from the registry and returns the value that was associated with it. This allows you to retrieve the value one last time before it's removed.

Parameters:

Name Type Description Default
key K

The key to unregister and remove from the registry.

required

Returns:

Type Description
V

The value that was associated with the key before removal.

Raises:

Type Description
KeyError

If the key is not registered. The error message includes the key that was not found.

Example
>>> from coola.registry import Registry
>>> registry = Registry[str, int]({"key1": 42, "key2": 100})
>>> registry.has("key1")
True
>>> value = registry.unregister("key1")
>>> value
42
>>> registry.has("key1")
False

coola.registry.TypeRegistry

Bases: 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 cache for type resolution to optimize performance when repeatedly resolving the same types.

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[type, T]

Internal dictionary storing the type-value pairs.

_cache dict[type, T]

Cached version 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.clear

clear() -> None

Remove all entries from the registry.

This method empties the registry, leaving it in the same state as a newly created empty registry. This operation cannot be undone.

Example
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[str]({int: "I am an integer", float: "I am a float"})
>>> len(registry)
2
>>> registry.clear()
>>> len(registry)
0
>>> registry.has(int)
False
>>> registry.has(float)
False

coola.registry.TypeRegistry.equal

equal(other: Any, equal_nan: bool = False) -> bool

Indicate if two registries are equal.

Two registries are considered equal if they contain the same type-value mappings. The comparison is order-independent since dictionaries are unordered collections.

Parameters:

Name Type Description Default
other Any

The object to compare with.

required
equal_nan bool

If True, then two NaN values will be considered equal when comparing values.

False

Returns:

Type Description
bool

True if the two registries are equal, otherwise False.

Example
>>> from coola.registry import TypeRegistry
>>> registry1 = TypeRegistry[str]({int: "I am an integer", float: "I am a float"})
>>> registry2 = TypeRegistry[str]({int: "I am an integer", float: "I am a float"})
>>> registry3 = TypeRegistry[str]({int: "I am an integer"})
>>> registry1.equal(registry2)
True
>>> registry1.equal(registry3)
False

coola.registry.TypeRegistry.get

get(dtype: type, default: T | None = None) -> T

Retrieve the value associated with a type.

This method performs a direct lookup in the registry and returns the corresponding value. If the type doesn't exist, a KeyError is raised with a descriptive message. For inheritance-based lookup, use the resolve() method instead.

Parameters:

Name Type Description Default
dtype type

The type whose value should be retrieved.

required
default T | None

Value to return if the key does not exist.

None

Returns:

Type Description
T

The value associated with the specified type.

Example
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[int]()
>>> registry.register(str, 42)
>>> registry.get(str)
42
>>> registry.get(int)  # doctest: +SKIP
KeyError: "Key <class 'int'> is not registered"

coola.registry.TypeRegistry.has

has(dtype: type) -> bool

Check whether a type is registered in the registry.

This method provides a safe way to test for type existence without risking a KeyError exception. It only checks for direct type matches; it does not check parent types via MRO.

Parameters:

Name Type Description Default
dtype type

The type to check for existence.

required

Returns:

Type Description
bool

True if the type exists in the registry, False otherwise.

Example
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[int]()
>>> registry.register(str, 42)
>>> registry.has(str)
True
>>> registry.has(int)
False

coola.registry.TypeRegistry.register

register(
    dtype: type, value: T, exist_ok: bool = False
) -> None

Register a new type-value pair in the registry.

By default, this method raises an error if you try to register a type that already exists. This prevents accidental overwriting of values. Set exist_ok=True to allow overwriting.

Registering a new type clears the internal resolution cache to ensure that subsequent resolve() calls use the updated registry state.

Parameters:

Name Type Description Default
dtype type

The type to register. Must be a Python type object.

required
value T

The value to associate with the type.

required
exist_ok bool

Controls behavior when the type already exists. If False (default), raises RuntimeError for duplicate types. If True, silently overwrites the existing value.

False

Raises:

Type Description
RuntimeError

If the type is already registered and exist_ok is False. The error message provides guidance on how to resolve the conflict.

Example

Basic registration:

>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[int]()
>>> registry.register(str, 42)
>>> registry.get(str)
42

Attempting to register a duplicate type:

>>> registry.register(str, 100)  # doctest: +SKIP
RuntimeError: A value is already registered for '<class 'str'>'...

Overwriting with exist_ok:

>>> registry.register(str, 100, exist_ok=True)
>>> registry.get(str)
100

coola.registry.TypeRegistry.register_many

register_many(
    mapping: Mapping[type, T], exist_ok: bool = False
) -> None

Register multiple type-value pairs in a single operation.

This is a convenience method for bulk registration. It iterates through the provided mapping and registers each type-value pair. All registrations follow the same exist_ok policy. The operation is atomic when exist_ok is False - if any type already exists, no changes are made.

Registering new types clears the internal resolution cache to ensure that subsequent resolve() calls use the updated registry state.

Parameters:

Name Type Description Default
mapping Mapping[type, T]

A dictionary or mapping containing the type-value pairs to register. The keys must be Python type objects and values must match the registry's type parameter.

required
exist_ok bool

Controls behavior when any type already exists. If False (default), raises error on the first duplicate type. If True, overwrites all existing values without error.

False

Raises:

Type Description
RuntimeError

If exist_ok is False and any type in the mapping is already registered. The error occurs before any registration is performed, ensuring no partial updates.

Example

Registering multiple entries at once:

>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[int]()
>>> registry.register_many({str: 42, float: 100, list: 7})
>>> registry.get(str)
42
>>> registry.get(float)
100
>>> len(registry)
3

Bulk update with exist_ok:

>>> registry.register_many({str: 1, dict: 4}, exist_ok=True)
>>> registry.get(str)
1
>>> registry.get(dict)
4

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.

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'

coola.registry.TypeRegistry.unregister

unregister(dtype: type) -> T

Remove a type-value pair from the registry and return the value.

This method removes the specified type from the registry and returns the value that was associated with it. This allows you to retrieve the value one last time before it's removed.

Unregistering a type clears the internal resolution cache to ensure that subsequent resolve() calls reflect the updated registry state.

Parameters:

Name Type Description Default
dtype type

The type to unregister and remove from the registry.

required

Returns:

Type Description
T

The value that was associated with the type before removal.

Raises:

Type Description
KeyError

If the type is not registered. The error message includes the type that was not found.

Example
>>> from coola.registry import TypeRegistry
>>> registry = TypeRegistry[str]({int: "I am an integer"})
>>> registry.has(int)
True
>>> value = registry.unregister(int)
>>> value
'I am an integer'
>>> registry.has(int)
False