Source code for id_translation.dio._resolve

import logging
from typing import Any

from rics.misc import get_public_module, tname

from ..types import IdType, NameType, SourceType, TranslatableT
from ._data_structure_io import DataStructureIO
from ._dict import DictIO
from ._pandas import PandasIO
from ._sequence import SequenceIO
from ._set import SetIO
from ._single_value import SingleValueIO
from .exceptions import UntranslatableTypeError

AnyDataStructureIO = DataStructureIO[Any, Any, Any, Any]

_DEFAULT_IMPLEMENTATIONS: list[type[AnyDataStructureIO]] = [
    DictIO,
    SetIO,
    PandasIO,
    SequenceIO,
    SingleValueIO,
]
_RESOLUTION_ORDER: list[type[AnyDataStructureIO]] = [*_DEFAULT_IMPLEMENTATIONS]
LOGGER = logging.getLogger(__package__)


_ENTRYPOINT_GROUP: str = "id_translation.dio"
"""Alias of the ``__init__.ENTRYPOINT_GROUP`` attribute.

Background:
    https://github.com/sphinx-doc/sphinx/issues/6495#issuecomment-1058033697
    https://github.com/sphinx-doc/sphinx/issues/12020
"""


[docs] def resolve_io( arg: TranslatableT, **kwargs: Any, ) -> DataStructureIO[TranslatableT, NameType, SourceType, IdType]: """Get an IO instance for `arg`. Args: arg: An argument to get IO for. **kwargs: Keyword arguments for the IO class. Returns: A data structure IO instance for `arg`. Raises: UntranslatableTypeError: If no suitable IO implementation could be found. See Also: The :func:`register_io` function. """ for io_class in _RESOLUTION_ORDER: if io_class.handles_type(arg): return _initialize(arg, io_class, kwargs) raise UntranslatableTypeError(type(arg))
def _initialize( arg: TranslatableT, io_class: type[DataStructureIO[TranslatableT, NameType, SourceType, IdType]], kwargs: dict[str, Any], ) -> DataStructureIO[TranslatableT, NameType, SourceType, IdType]: try: io = io_class(**kwargs) with_kwargs = True except TypeError: io = io_class() with_kwargs = False if LOGGER.isEnabledFor(logging.DEBUG): from rics.misc import format_kwargs pretty_arg = tname(arg, prefix_classname=True) pretty_class = f"{_pretty_io_name(io_class)}({format_kwargs(kwargs)})" if with_kwargs else "" index = _RESOLUTION_ORDER.index(io_class) LOGGER.debug(f"Using rank-{index} implementation {pretty_class} for translatable of type='{pretty_arg}'.") return io
[docs] def get_resolution_order(*, real: bool = False) -> list[type[AnyDataStructureIO]]: """Returns known :class:`.DataStructureIO` implementations. Args: real: If ``True``, return the actual list instead of a copy. Returns: A list of IO implementations. """ return _RESOLUTION_ORDER if real else list(_RESOLUTION_ORDER)
[docs] def register_io(io: type[AnyDataStructureIO]) -> None: """Register a new IO implementation. Classes are polled through :meth:`.DataStructureIO.handles_type` in reverse insertion order (new implementations are polled first). Re-registering an implementation again will move it to the first position in the search order. Args: io: A :class:`.DataStructureIO` type. """ if io in _RESOLUTION_ORDER: _RESOLUTION_ORDER.remove(io) _RESOLUTION_ORDER.insert(0, io) if LOGGER.isEnabledFor(logging.DEBUG): LOGGER.debug(f"Registered custom IO implementation: '{_pretty_io_name(io)}'.")
def _pretty_io_name(io: type[AnyDataStructureIO]) -> str: return get_public_module(io, resolve_reexport=True) + "." + tname(io, prefix_classname=True)
[docs] def is_registered(io: type[AnyDataStructureIO]) -> bool: """Return IO implementation registration status. Instances should register themselves using :func:`register_io` or :meth:`.DataStructureIO.is_registered`. Args: io: A :class:`.DataStructureIO` type. """ return io in _RESOLUTION_ORDER
[docs] def load_integrations() -> None: """Discover, load and register entrypoint integrations. Reset the registry, then load entrypoints in the :const:`{_ENTRYPOINT_GROUP!r} <id_translation.dio.ENTRYPOINT_GROUP>` entrypoint group (see :py:func:`importlib.metadata.entry_points` for details). Will skip integrations that raise :class:`ImportError` when loaded. Raises: TypeError: If an integration does not inherit from :class:`.DataStructureIO`. """ from importlib.metadata import entry_points from time import perf_counter global _RESOLUTION_ORDER # noqa: PLW0603 start = perf_counter() LOGGER.debug("Initializing %s integrations in group='%s'.", DataStructureIO.__name__, _ENTRYPOINT_GROUP) _RESOLUTION_ORDER = [*_DEFAULT_IMPLEMENTATIONS] n_total = 0 n_ok = 0 for ep in entry_points(group=_ENTRYPOINT_GROUP): n_total += 1 try: cls = ep.load() except ImportError as e: LOGGER.debug("Failed to import entrypoint=%r: %r.", ep, e) continue if not issubclass(cls, DataStructureIO): msg = f"Bad entrypoint={ep!r}: {cls} is not a subtype of {DataStructureIO.__name__}. " raise TypeError(msg) cls.register() n_ok += 1 millis = round(1000 * (perf_counter() - start)) LOGGER.debug("Imported and registered %i/%i integrations in %i milliseconds.", n_ok, n_total, millis)
if load_integrations.__doc__: load_integrations.__doc__ = load_integrations.__doc__.format(_ENTRYPOINT_GROUP=_ENTRYPOINT_GROUP)