Registries
- class todd.registries.PartialRegistryMeta[source]
Bases:
RegistryMeta
- class todd.registries.Registry[source]
Bases:
objectBase registry.
To create custom registry, inherit from the
Registryclass:>>> class CatRegistry(Registry): pass
- data = {}
- class todd.registries.RegistryMeta[source]
Bases:
UserDict[str,Item],NonInstantiableMetaMeta class for registries.
Underneath, registries are simply dictionaries:
>>> class Cat(metaclass=RegistryMeta): pass >>> class BritishShorthair: pass >>> Cat['british shorthair'] = BritishShorthair >>> Cat['british shorthair'] <class '...BritishShorthair'>
In this example,
Catis a registry and the “british shorthair” is a category in the registry.BritishShorthairis an object or class that is associated to the “british shorthair” category.For convenience, users can also access registries via higher level APIs, such as ‘
register_’ and ‘build’. These provide easier interfaces to register and retrieve instances:>>> class Persian: pass >>> Cat.register_('persian')(Persian) <class '...Persian'> >>> Cat.build(Config(type='persian')) <...Persian object at ...>
Registries can be subclassed as well to create specializations or child registries:
>>> class HairlessCat(Cat): pass >>> Cat.child('HairlessCat') <HairlessCat >
In the example above,
HairlessCatcan be seen as a subcategory or specialization ofCat. This allows to organize instances into a hierarchically structured registry.- build(config, **kwargs)[source]
Call the registered object to construct a new instance.
- Parameters:
config (Config) – build parameters.
kwargs – default configuration.
- Returns:
The built instance.
- Return type:
The
typeentry ofconfigspecifies the name of the registered object to be built. The other entries ofconfigwill be passed to the object’s call method.>>> class Cat(metaclass=RegistryMeta): pass >>> @Cat.register_() ... def tabby(name: str) -> str: ... return f'Tabby {name}' >>> Cat.build(Config(type='tabby', name='Garfield')) 'Tabby Garfield'
Keyword arguments are the default configuration:
>>> Cat.build( ... Config(type='tabby'), ... name='Garfield', ... ) 'Tabby Garfield'
Override
_build()for customization:>>> class DomesticCat(Cat): ... @classmethod ... def _build(cls, item: Item, config: Config): ... return item, config >>> @DomesticCat.register_() ... class Maine: pass >>> DomesticCat.build(Config(type='Maine', name='maine'), age=1.2) (<class '...Maine'>, {'age': 1.2, 'name': 'maine'})
If the object has a property named
build_pre_hook, the config is converted before construction:>>> @Cat.register_() ... class Persian: ... def __init__(self, friend: str) -> None: ... self.friend = friend ... @classmethod ... def build_pre_hook( ... cls, ... config: Config, ... registry: RegistryMeta, ... item: Item, ... ) -> Config: ... config.friend = config.friend.type ... return config >>> persian = Cat.build( ... Config(type='Persian'), ... friend=dict(type='Siamese'), ... ) >>> persian.friend 'Siamese'
- child(key)[source]
Retrieve a direct or indirect derived child registry.
Given a dot-separated string of subclass names, this method searches for the specified child registry within its inheritance tree and returns the matching child class.
- Parameters:
key (str) – A string of dot-separated subclass names.
- Raises:
ValueError – If no subclass or more than one subclass with the specified name exists.
- Returns:
The specified child registry.
- Return type:
- parse(key)[source]
Parse
key.- Returns:
The child registry and the corresponding type.
- Parameters:
key (str)
- Return type:
- register_(*args, force=False, build_pre_hook=None)[source]
Register classes or functions to the registry.
- Parameters:
- Returns:
Wrapper function.
- Return type:
Callable[[T], T]
The decorator can be applied to both classes and functions:
>>> class Cat(metaclass=RegistryMeta): pass >>> @Cat.register_() ... class Munchkin: pass >>> @Cat.register_() ... def munchkin() -> str: ... return 'munchkin'
If no arguments are given, the name of the object being registered is used as the key:
>>> Cat['Munchkin'] <class '...Munchkin'> >>> Cat['munchkin'] <function munchkin at ...>
It is possible to register an object with multiple names:
>>> @Cat.register_('British Longhair', 'british longhair') ... class BritishLonghair: pass >>> 'British Longhair' in Cat True >>> 'british longhair' in Cat True
It also allows one to specify child registries as part of the key during registration:
>>> class HairlessCat(Cat): pass >>> @Cat.register_('HairlessCat.CanadianHairless') ... def canadian_hairless() -> str: ... return 'canadian hairless' >>> HairlessCat <HairlessCat CanadianHairless=<function canadian_hairless at ...>>
If ‘forced’ is True and an item of the same name exists, the new item will replace the old one in the registry:
>>> class AnotherMunchkin: pass >>> Cat.register_('Munchkin')(AnotherMunchkin) Traceback (most recent call last): ... KeyError: 'Munchkin' >>> Cat.register_('Munchkin', force=True)(AnotherMunchkin) <class '...AnotherMunchkin'> >>> Cat['Munchkin'] <class '...AnotherMunchkin'>
build_pre_hookcan be bind to objects during registration:>>> build_pre_hook = lambda c, r, i: c >>> @Cat.register_(build_pre_hook=build_pre_hook) ... class Maine: pass >>> Maine.build_pre_hook is build_pre_hook True