Source code for rics.translation.offline._format_applier

from abc import ABC, abstractmethod
from typing import Any, Collection, Dict, Generic, List, Union

from rics._internal_support.types import NO_DEFAULT, NoDefault
from rics.translation.offline._format import Format
from rics.translation.offline._magic_dict import MagicDict
from rics.translation.offline.types import (
    IdType,
    NameType,
    PlaceholdersTuple,
    PlaceholderTranslations,
    SourceType,
    TranslatedIds,
)
from rics.utility.misc import tname


[docs]class FormatApplier(ABC, Generic[IdType, NameType, SourceType]): """Base class for application of ``Format`` specifications. Args: placeholder_translations: Matrix of ID translation components returned by fetchers. default: Default values for each key in `placeholders`. required_placeholders: Placeholder names which must be present in `default`. None=all. Raises: ValueError: If `default` is given and any placeholder names are missing. See Also: :class:`rics.translation.offline._format.Format` """ def __init__( self, placeholder_translations: PlaceholderTranslations, default: Union[NoDefault, Dict[str, Any]] = NO_DEFAULT, required_placeholders: Collection[str] = None, ) -> None: self._source = placeholder_translations.source self._placeholder_names = placeholder_translations.placeholders if default is not NO_DEFAULT: required_defaults = set( placeholder_translations.placeholders if required_placeholders is None else required_placeholders ) required_defaults.discard("id") missing = required_defaults.difference(default) if missing: raise ValueError(f"Placeholder names {sorted(missing)} not present in {default=}.") self._default = default self._n_ids = len(placeholder_translations.records) def __call__( self, fmt: Format, placeholders: PlaceholdersTuple = None, default_fmt: Format = None ) -> MagicDict[IdType]: """Translate IDs. Args: fmt: Translation format to use. placeholders: Placeholders to include in the formatted output. None=as many as possible. default_fmt: Alternative format for default translation. Returns: A dict ``{idx: translated_id}``. """ if placeholders is None: # Use as many placeholders as possible. placeholders = tuple(filter(self._placeholder_names.__contains__, fmt.placeholders)) fstring = fmt.fstring(placeholders, self.positional) real_translations = self._apply(fstring, placeholders) if default_fmt is None: default_fstring = fstring else: placeholders = tuple(filter(self._placeholder_names.__contains__, default_fmt.placeholders)) default_fstring = default_fmt.fstring(placeholders, self.positional) return MagicDict.make(real_translations, default_fstring, placeholders, self._default) @abstractmethod def _apply(self, fstring: str, placeholders: PlaceholdersTuple) -> TranslatedIds: """Apply fstring to all IDs. The abstract class delegates ``__apply__``-invocations to this method after some input validation. Args: fstring: A format string. placeholders: Keys needed for the fstring, in the order in which they appear. Returns: A dict ``{idx: translated_id}``. """ @property def positional(self) -> bool: """If True, names are stripped from fstring placeholders.""" return True @property def source(self) -> SourceType: """Return translation source.""" return self._source # pragma: no cover @property def placeholders(self) -> List[str]: """Return placeholder names in sorted order.""" return list(self._placeholder_names) # pragma: no cover def __len__(self) -> int: return self._n_ids # pragma: no cover def __repr__(self) -> str: placeholders = tuple(self._placeholder_names) source = self._source return f"{tname(self)}({len(self)} IDs, {placeholders=}, {source=})"
[docs]class DefaultFormatApplier(FormatApplier): """Default format applier implementation.""" def __init__( self, placeholder_translations: PlaceholderTranslations, default: Union[NoDefault, Dict[str, Any]] = NO_DEFAULT, required_placeholders: Collection[str] = None, ) -> None: super().__init__(placeholder_translations, default, required_placeholders) self._pht = placeholder_translations def _apply(self, fstring: str, placeholders: PlaceholdersTuple) -> TranslatedIds: if self._placeholder_names == placeholders: return {record[self._pht.id_pos]: fstring.format(*record) for record in self._pht.records} else: pos = tuple(map(self._placeholder_names.index, placeholders)) return {record[self._pht.id_pos]: fstring.format(*(record[i] for i in pos)) for record in self._pht.records}