Source code for lories.application.interface

# -*- coding: utf-8 -*-
"""
lories.application.interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~


"""

from __future__ import annotations

from collections.abc import Callable
from typing import Optional, Type, TypeVar

from lories._core._configurations import Configurations  # noqa
from lories._core._data import DataContext, _DataContext, _DataManager  # noqa
from lories.core import ConfigurationError, Registry, ResourceError
from lories.core.configs.configurator import Configurator, ConfiguratorMeta


# noinspection PyShadowingBuiltins
def register_interface_type(
    type: str,
    *alias: str,
    factory: Callable[[DataContext, Configurations], InterfaceType] = None,
    replace: bool = False,
) -> Callable[[Type[InterfaceType]], Type[InterfaceType]]:
    # noinspection PyShadowingNames
    def _register(cls: Type[InterfaceType]) -> Type[InterfaceType]:
        registry.register(cls, type, *alias, factory=factory, replace=replace)
        return cls

    return _register


[docs] class InterfaceMeta(ConfiguratorMeta): def __call__(cls, context: DataContext, configs: Configurations, **kwargs) -> InterfaceType: global _instance _type = configs.get("type", default="default").lower() _cls = cls._get_class(_type) if cls != _cls: return _cls(context, configs, **kwargs) if _instance is None: _instance = super().__call__(context, configs, **kwargs) return _instance # noinspection PyMethodMayBeStatic, PyShadowingBuiltins def _get_class(cls: Type[InterfaceType], type: str) -> Type[InterfaceType]: if type == "default": return cls elif registry.has_type(type): registration = registry.from_type(type) return registration.type raise InterfaceException(f"Unknown interface type '{type}'")
[docs] class Interface(Configurator, metaclass=InterfaceMeta): TYPE: str = "interface" __context: _DataContext # noinspection PyUnresolvedReferences def __init__(self, context: DataContext, configs: Configurations, **kwargs) -> None: super().__init__(configs, **kwargs) self.__context = self._assert_context(context) @classmethod def _assert_context(cls, context: DataContext) -> DataContext: if context is None or not isinstance(context, _DataManager): raise ResourceError(f"Invalid '{cls.__name__}' context: {type(context)}") return context @classmethod def _assert_configs(cls, configs: Optional[Configurations]) -> Optional[Configurations]: if configs is None: raise ConfigurationError(f"Invalid '{cls.__name__}' configurations: {type(configs)}") return super()._assert_configs(configs) @property def context(self) -> DataContext: return self.__context def start(self, *args, **kwargs) -> None: pass
[docs] class InterfaceException(ResourceError): """ Raise if an error occurred accessing the interface. """
InterfaceType = TypeVar("InterfaceType", bound=Interface) # FIXME: Add global variable typing again once Python >= 3.9 is a requirement # _instance: Optional[InterfaceType] = None _instance = None registry = Registry[Interface]()