Files
slic/slic/utils/registry.py
T
2023-04-11 12:43:35 +02:00

72 lines
2.0 KiB
Python

import inspect
import weakref
from .utils import typename
class RegistryMeta(type):
"""
Metaclass containing the registry logic
In most cases, it will be more convenient to inherit from Registry instead of using RegistryMeta directly
"""
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace) # creates the class
cls.__signature__ = inspect.signature(cls.__init__) # restore the constructor signature (instead of that of __call__ below)
cls.__instances__ = weakref.WeakSet()
def __call__(cls, *args, **kwargs):
inst = super().__call__(*args, **kwargs) # creates the instance (calls __new__ and __init__ methods)
cls.__instances__.add(inst)
return inst
class Registry(object, metaclass=RegistryMeta):
"""
Helper class that allows adding registry functionality via inheritance
Does nothing but set RegistryMeta as metaclass
"""
pass
def instances(reg, recursive=True, weak=False):
"""
Return a set of all instances of reg
If recursive=True also include instances of subclasses of reg
If weak=True return weakref.WeakSet instead of set
"""
res = _collect_instances(reg, recursive=recursive)
if not weak:
res = set(res)
return res
def _collect_instances(reg, recursive=True):
"""
Return a weakref.WeakSet of all instances of reg
If recursive=True also include instances of subclasses of reg
"""
_check_registry(reg)
instances = reg.__instances__.copy()
if recursive:
for subcls in reg.__subclasses__():
instances |= _collect_instances(subcls, recursive=recursive)
return instances
def _check_registry(reg):
"""
Try whether reg has __instances__ attribute, if missing raise TypeError
"""
try:
reg.__instances__
except AttributeError as exc:
tname = typename(reg)
cname = reg.__name__
raise TypeError(f"{tname} object '{cname}' has no registry functionality") from exc