mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
4a1edec018
Use the `name` class attribute to build the registry when discovering subclasses of `Pipe`, `Analysis` and `Container`.
63 lines
2.0 KiB
Python
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())}"
|
|
)
|