Files
Giacomo Vercesi 4a1edec018 get_registry: use name for selected classes
Use the `name` class attribute to build the registry when discovering
subclasses of `Pipe`, `Analysis` and `Container`.
2025-11-26 14:59:43 +01:00

63 lines
2.0 KiB
Python

#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
# The singleton registry of subclasses for all classes decorated with `registry`
_REGISTRY_SINGLETON: dict[type, dict[str, type]] = {}
def get_registry[T](cls: type[T]) -> dict[str, type[T]]:
"""
Get the registry of subclasses for a given class which was decorated with
`registry`.
"""
if cls not in _REGISTRY_SINGLETON:
raise TypeError(f'"{cls}" is not a registered class')
# Clone to avoid mutation
return dict(_REGISTRY_SINGLETON[cls])
def get_singleton[T](cls: type[T]) -> type[T]:
"""
Get the singleton subclass for a given class which was decorated with
`registry`.
"""
ty_registry = get_registry(cls)
if len(ty_registry) != 1:
raise ValueError(
f"Expected exactly one singleton for {cls}, but found "
f"{len(ty_registry)}: {list(ty_registry.keys())}"
)
# Get the single value from the registry
return next(iter(ty_registry.values()))
def register_all_subclasses(cls: type, *, singleton: bool = False, use_name: bool = False) -> None:
"""
Register all subclasses of the given class `cls` in the global registry.
"""
if cls not in _REGISTRY_SINGLETON:
_REGISTRY_SINGLETON[cls] = {}
def find_leafs(c: type) -> list[type]:
"""
Recursively find all leaf subclasses of a given class `c`.
"""
subclasses = c.__subclasses__()
if not subclasses:
return [c]
leafs = []
for subclass in subclasses:
leafs.extend(find_leafs(subclass))
return leafs
for leaf in find_leafs(cls):
key = leaf.name if use_name else leaf.__name__ # type: ignore[attr-defined]
_REGISTRY_SINGLETON[cls][key] = leaf
if singleton and len(_REGISTRY_SINGLETON[cls]) > 1:
raise ValueError(
f"Expected exactly one singleton for {cls}, but found "
f"{len(_REGISTRY_SINGLETON[cls])}: {list(_REGISTRY_SINGLETON[cls].keys())}"
)