跳转至

Registry

Bases: NestedDict

Registry for components.

Notes

Registry inherits from NestedDict.

Therefore, Registry comes in a nested structure by nature. You could create a sub-registry by simply calling registry.sub_registry = Registry, and access through registry.sub_registry.register().

Examples:

Python Console Session
>>> registry = Registry()
>>> @registry.register
... @registry.register("Module1")
... class Module:
...     def __init__(self, a, b):
...         self.a = a
...         self.b = b
>>> module = registry.register(Module, "Module2")
>>> registry
Registry(
  ('Module1'): <class 'chanfig.registry.Module'>
  ('Module'): <class 'chanfig.registry.Module'>
  ('Module2'): <class 'chanfig.registry.Module'>
)
>>> module = registry.register(Module, "Module")
Traceback (most recent call last):
ValueError: Component with name Module already registered.
>>> registry.lookup("Module")
<class 'chanfig.registry.Module'>
>>> config = {"module": {"name": "Module", "a": 1, "b": 2}}
>>> # registry.register(Module)
>>> module = registry.build(config["module"])
>>> type(module)
<class 'chanfig.registry.Module'>
>>> module.a
1
>>> module.b
2
Source code in chanfig/registry.py
Python
class Registry(NestedDict):
    """
    `Registry` for components.

    Notes:
        `Registry` inherits from `NestedDict`.

        Therefore, `Registry` comes in a nested structure by nature.
        You could create a sub-registry by simply calling `registry.sub_registry = Registry`,
        and access through `registry.sub_registry.register()`.

    Examples:
        >>> registry = Registry()
        >>> @registry.register
        ... @registry.register("Module1")
        ... class Module:
        ...     def __init__(self, a, b):
        ...         self.a = a
        ...         self.b = b
        >>> module = registry.register(Module, "Module2")
        >>> registry
        Registry(
          ('Module1'): <class 'chanfig.registry.Module'>
          ('Module'): <class 'chanfig.registry.Module'>
          ('Module2'): <class 'chanfig.registry.Module'>
        )
        >>> module = registry.register(Module, "Module")
        Traceback (most recent call last):
        ValueError: Component with name Module already registered.
        >>> registry.lookup("Module")
        <class 'chanfig.registry.Module'>
        >>> config = {"module": {"name": "Module", "a": 1, "b": 2}}
        >>> # registry.register(Module)
        >>> module = registry.build(config["module"])
        >>> type(module)
        <class 'chanfig.registry.Module'>
        >>> module.a
        1
        >>> module.b
        2
    """

    override: bool = False

    def __init__(self, override: bool = False):
        super().__init__()
        self.setattr("override", override)

    def register(self, component: Any = None, name: Optional[Any] = None) -> Callable:
        r"""
        Register a new component.

        Args:
            component: The component to register.
            name: The name of the component.

        Returns:
            component: The registered component.
                Registered component are expected to be `Callable`.

        Raises:
            ValueError: If the component with the same name already registered and `Registry.override=False`.

        Examples:
            >>> registry = Registry()
            >>> @registry.register
            ... @registry.register("Module1")
            ... class Module:
            ...     def __init__(self, a, b):
            ...         self.a = a
            ...         self.b = b
            >>> module = registry.register(Module, "Module2")
            >>> registry
            Registry(
              ('Module1'): <class 'chanfig.registry.Module'>
              ('Module'): <class 'chanfig.registry.Module'>
              ('Module2'): <class 'chanfig.registry.Module'>
            )
        """

        if name in self and not self.override:
            raise ValueError(f"Component with name {name} already registered.")

        # Registry.register()
        if name is not None:
            self.set(name, component)
            return component  # type: ignore
        # @Registry.register
        if callable(component) and name is None:
            self.set(component.__name__, component)
            return component

        # @Registry.register()
        def decorator(name: Optional[Any] = None):
            @wraps(self.register)
            def wrapper(component):
                if name is None:
                    self.set(component.__name__, component)
                else:
                    self.set(name, component)
                return component

            return wrapper

        return decorator(component)

    def lookup(self, name: str) -> Any:
        r"""
        Lookup for a component.

        Args:
            name:

        Returns:
            (Any): The component.

        Raises:
            KeyError: If the component is not registered.

        Examples:
            >>> registry = Registry()
            >>> @registry.register
            ... class Module:
            ...     def __init__(self, a, b):
            ...         self.a = a
            ...         self.b = b
            >>> registry.lookup("Module")
            <class 'chanfig.registry.Module'>
        """

        return self.get(name)

    def build(self, name: Union[str, Mapping], *args, **kwargs) -> Any:
        r"""
        Build a component.

        Args:
            name (str | Mapping):
                If its a `Mapping`, it must contain `"name"` as a member, the rest will be treated as `**kwargs`.
                Note that values in `kwargs` will override values in `name` if its a `Mapping`.
            *args: The arguments to pass to the component.
            **kwargs: The keyword arguments to pass to the component.

        Returns:
            (Any):

        Raises:
            KeyError: If the component is not registered.

        Examples:
            >>> registry = Registry()
            >>> @registry.register
            ... class Module:
            ...     def __init__(self, a, b):
            ...         self.a = a
            ...         self.b = b
            >>> config = {"module": {"name": "Module", "a": 1, "b": 2}}
            >>> # registry.register(Module)
            >>> module = registry.build(**config["module"])
            >>> type(module)
            <class 'chanfig.registry.Module'>
            >>> module.a
            1
            >>> module.b
            2
            >>> module = registry.build(config["module"], a=2)
            >>> module.a
            2
        """

        if isinstance(name, Mapping):
            name = deepcopy(name)
            name, kwargs = name.pop("name"), dict(name, **kwargs)  # type: ignore
        return self.get(name)(*args, **kwargs)  # type: ignore

    def __wrapped__(self, *args, **kwargs):
        pass

register(component=None, name=None)

Register a new component.

Parameters:

Name Type Description Default
component Any

The component to register.

None
name Optional[Any]

The name of the component.

None

Returns:

Name Type Description
component Callable

The registered component. Registered component are expected to be Callable.

Raises:

Type Description
ValueError

If the component with the same name already registered and Registry.override=False.

Examples:

Python Console Session
>>> registry = Registry()
>>> @registry.register
... @registry.register("Module1")
... class Module:
...     def __init__(self, a, b):
...         self.a = a
...         self.b = b
>>> module = registry.register(Module, "Module2")
>>> registry
Registry(
  ('Module1'): <class 'chanfig.registry.Module'>
  ('Module'): <class 'chanfig.registry.Module'>
  ('Module2'): <class 'chanfig.registry.Module'>
)
Source code in chanfig/registry.py
Python
def register(self, component: Any = None, name: Optional[Any] = None) -> Callable:
    r"""
    Register a new component.

    Args:
        component: The component to register.
        name: The name of the component.

    Returns:
        component: The registered component.
            Registered component are expected to be `Callable`.

    Raises:
        ValueError: If the component with the same name already registered and `Registry.override=False`.

    Examples:
        >>> registry = Registry()
        >>> @registry.register
        ... @registry.register("Module1")
        ... class Module:
        ...     def __init__(self, a, b):
        ...         self.a = a
        ...         self.b = b
        >>> module = registry.register(Module, "Module2")
        >>> registry
        Registry(
          ('Module1'): <class 'chanfig.registry.Module'>
          ('Module'): <class 'chanfig.registry.Module'>
          ('Module2'): <class 'chanfig.registry.Module'>
        )
    """

    if name in self and not self.override:
        raise ValueError(f"Component with name {name} already registered.")

    # Registry.register()
    if name is not None:
        self.set(name, component)
        return component  # type: ignore
    # @Registry.register
    if callable(component) and name is None:
        self.set(component.__name__, component)
        return component

    # @Registry.register()
    def decorator(name: Optional[Any] = None):
        @wraps(self.register)
        def wrapper(component):
            if name is None:
                self.set(component.__name__, component)
            else:
                self.set(name, component)
            return component

        return wrapper

    return decorator(component)

lookup(name)

Lookup for a component.

Parameters:

Name Type Description Default
name str required

Returns:

Type Description
Any

The component.

Raises:

Type Description
KeyError

If the component is not registered.

Examples:

Python Console Session
>>> registry = Registry()
>>> @registry.register
... class Module:
...     def __init__(self, a, b):
...         self.a = a
...         self.b = b
>>> registry.lookup("Module")
<class 'chanfig.registry.Module'>
Source code in chanfig/registry.py
Python
def lookup(self, name: str) -> Any:
    r"""
    Lookup for a component.

    Args:
        name:

    Returns:
        (Any): The component.

    Raises:
        KeyError: If the component is not registered.

    Examples:
        >>> registry = Registry()
        >>> @registry.register
        ... class Module:
        ...     def __init__(self, a, b):
        ...         self.a = a
        ...         self.b = b
        >>> registry.lookup("Module")
        <class 'chanfig.registry.Module'>
    """

    return self.get(name)

build(name, *args, **kwargs)

Build a component.

Parameters:

Name Type Description Default
name str | Mapping

If its a Mapping, it must contain "name" as a member, the rest will be treated as **kwargs. Note that values in kwargs will override values in name if its a Mapping.

required
*args

The arguments to pass to the component.

()
**kwargs

The keyword arguments to pass to the component.

{}

Returns:

Type Description
Any

Raises:

Type Description
KeyError

If the component is not registered.

Examples:

Python Console Session
>>> registry = Registry()
>>> @registry.register
... class Module:
...     def __init__(self, a, b):
...         self.a = a
...         self.b = b
>>> config = {"module": {"name": "Module", "a": 1, "b": 2}}
>>> # registry.register(Module)
>>> module = registry.build(**config["module"])
>>> type(module)
<class 'chanfig.registry.Module'>
>>> module.a
1
>>> module.b
2
>>> module = registry.build(config["module"], a=2)
>>> module.a
2
Source code in chanfig/registry.py
Python
def build(self, name: Union[str, Mapping], *args, **kwargs) -> Any:
    r"""
    Build a component.

    Args:
        name (str | Mapping):
            If its a `Mapping`, it must contain `"name"` as a member, the rest will be treated as `**kwargs`.
            Note that values in `kwargs` will override values in `name` if its a `Mapping`.
        *args: The arguments to pass to the component.
        **kwargs: The keyword arguments to pass to the component.

    Returns:
        (Any):

    Raises:
        KeyError: If the component is not registered.

    Examples:
        >>> registry = Registry()
        >>> @registry.register
        ... class Module:
        ...     def __init__(self, a, b):
        ...         self.a = a
        ...         self.b = b
        >>> config = {"module": {"name": "Module", "a": 1, "b": 2}}
        >>> # registry.register(Module)
        >>> module = registry.build(**config["module"])
        >>> type(module)
        <class 'chanfig.registry.Module'>
        >>> module.a
        1
        >>> module.b
        2
        >>> module = registry.build(config["module"], a=2)
        >>> module.a
        2
    """

    if isinstance(name, Mapping):
        name = deepcopy(name)
        name, kwargs = name.pop("name"), dict(name, **kwargs)  # type: ignore
    return self.get(name)(*args, **kwargs)  # type: ignore

最后更新: 2023-05-20 15:08:43