Skip to content

Registry

Base class for all registries in the BFM framework.

Generic Registry with lazy autodiscovery.

Example usage:

from bfm.core.registry import Registry

items = Registry() # create a registry for the current package

@items.register("my_item")
class MyItem:
    def __init__(self, number: int):
        ...

my_item = items.resolve("my_item", number=4)

Registry

Bases: Generic[T]

Create a registry for all items in a package.

Parameters:

Name Type Description Default
package Optional[str]

Dotted path of the package to scan for items (modules under it should import and call @register). If no package is specified, the caller's package will be used.

None
relative bool

If True, the package is treated as relative to the caller's package.

True
Source code in bfm/core/registry.py
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
class Registry(Generic[T]):
    """
    Create a registry for all items in a package.

    Args:
        package (Optional[str]): Dotted path of the package to scan for items
            (modules under it should import and call @register). If no package is specified, the caller's package will be used.
        relative (bool): If True, the package is treated as relative to the caller's package.
    """
    def __init__(self, package: Optional[str] = None, relative: bool = True):
        if package is None:
            base_pkg = _caller_package()
        elif relative:
            base_pkg = f"{_caller_package()}.{package}"
        else:
            base_pkg = package

        self._store: Dict[str, Factory] = {}
        self._aliases: Dict[str, str] = {}
        self._autodiscover = _make_autodiscover(base_pkg)

    def register(self, name: str, *aliases: str) -> Callable[[Factory], Factory]:
        """Register item under a canonical name and optional aliases."""
        def decorator(factory: Factory) -> Factory:
            canon = name.strip().lower()
            if canon in self._store or canon in self._aliases:
                raise KeyError(f"Key {name!r} already registered")
            self._store[canon] = factory
            for alias in aliases:
                a = alias.strip().lower()
                if a in self._store or a in self._aliases:
                    raise KeyError(f"Alias {alias!r} already registered")
                self._aliases[a] = canon  # map alias -> canonical key
            return factory
        return decorator

    def get(self, name: str) -> Factory:
        """Get a factory by name."""
        self._autodiscover()
        key = name.strip().lower()
        key = self._aliases.get(key, key)
        try:
            return self._store[key]
        except KeyError as e:
            raise KeyError(
                f"Unknown key {name!r}. Available: {self.list()}"
            ) from e


    def resolve(self, name: str, **kwargs) -> T:
        """Instantiate by name with kwargs."""
        factory = self.get(name)
        return factory(**kwargs)

    def contains(self, name: str) -> bool:
        """Return True if the registry contains the given name."""
        self._autodiscover()
        key = name.strip().lower()
        return key in self._store or key in self._aliases

    def list(self) -> List[str]:
        """Canonical keys (not aliases)."""
        self._autodiscover()
        return sorted(self._store.keys())

    def list_aliases(self) -> Dict[str, str]:
        """alias → canonical mapping."""
        self._autodiscover()
        return self._aliases

contains(name)

Return True if the registry contains the given name.

Source code in bfm/core/registry.py
122
123
124
125
126
def contains(self, name: str) -> bool:
    """Return True if the registry contains the given name."""
    self._autodiscover()
    key = name.strip().lower()
    return key in self._store or key in self._aliases

get(name)

Get a factory by name.

Source code in bfm/core/registry.py
104
105
106
107
108
109
110
111
112
113
114
def get(self, name: str) -> Factory:
    """Get a factory by name."""
    self._autodiscover()
    key = name.strip().lower()
    key = self._aliases.get(key, key)
    try:
        return self._store[key]
    except KeyError as e:
        raise KeyError(
            f"Unknown key {name!r}. Available: {self.list()}"
        ) from e

list()

Canonical keys (not aliases).

Source code in bfm/core/registry.py
128
129
130
131
def list(self) -> List[str]:
    """Canonical keys (not aliases)."""
    self._autodiscover()
    return sorted(self._store.keys())

list_aliases()

alias → canonical mapping.

Source code in bfm/core/registry.py
133
134
135
136
def list_aliases(self) -> Dict[str, str]:
    """alias → canonical mapping."""
    self._autodiscover()
    return self._aliases

register(name, *aliases)

Register item under a canonical name and optional aliases.

Source code in bfm/core/registry.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
def register(self, name: str, *aliases: str) -> Callable[[Factory], Factory]:
    """Register item under a canonical name and optional aliases."""
    def decorator(factory: Factory) -> Factory:
        canon = name.strip().lower()
        if canon in self._store or canon in self._aliases:
            raise KeyError(f"Key {name!r} already registered")
        self._store[canon] = factory
        for alias in aliases:
            a = alias.strip().lower()
            if a in self._store or a in self._aliases:
                raise KeyError(f"Alias {alias!r} already registered")
            self._aliases[a] = canon  # map alias -> canonical key
        return factory
    return decorator

resolve(name, **kwargs)

Instantiate by name with kwargs.

Source code in bfm/core/registry.py
117
118
119
120
def resolve(self, name: str, **kwargs) -> T:
    """Instantiate by name with kwargs."""
    factory = self.get(name)
    return factory(**kwargs)