Skip to content

loader

loader

Implementation of Gilbert algorithm backend loader.

Loader

Backend loader class.

Source code in cssfinder/algorithm/backend/loader.py
class Loader:
    """Backend loader class."""

    BACKEND_NAME_REGEX: ClassVar[re.Pattern] = re.compile(
        r"cssfinder(_|-)backend(_|-)[a-z0-9_\-]+",
        re.IGNORECASE,
    )

    def __init__(self) -> None:
        self.reload()

    def reload(self) -> None:
        """Load all backends available in python environment.

        This is automatically called by constructor to load all backends. You can use it
        to refresh list of loaded backends.

        """
        self.backends: dict[tuple[str, Precision], Type[BackendBase]] = {}

        for dist in importlib.import_module("pkg_resources").working_set:
            if self.BACKEND_NAME_REGEX.match(dist.project_name) is None:
                continue

            module_name = dist.project_name.replace("-", "_")

            module = importlib.import_module(module_name)
            module_meta = metadata.metadata(module_name)

            export_backend = getattr(module, "export_backend", None)

            if export_backend is None:
                continue

            backends = export_backend()

            if not isinstance(backends, dict):
                logging.critical(
                    "Backend %r unsupported export format %r, expected <class 'dict'>.",
                    module_name,
                    type(backends),
                )
                continue

            self._extend_backend_index(module_name, module_meta, backends)

    def _extend_backend_index(
        self,
        module_name: str,
        module_meta: metadata.PackageMetadata,  # type: ignore[name-defined]
        backends: Any,
    ) -> None:
        for key, value in backends.items():
            if not isinstance(key, tuple) or len(key) != LEN_KEY_TUPLE:
                logging.critical(
                    "Backend %r -> %r unsupported key format, expected key to be "
                    "tuple[str, Precision], got %r.",
                    module_name,
                    value,
                    key,
                )
                continue

            name, precision = key

            if not isinstance(name, str):
                logging.critical(
                    "Backend %r -> %r unsupported key format, expected key to be "
                    "tuple[str, Precision], got %r.",
                    module_name,
                    value,
                    key,
                )
                continue

            if not isinstance(precision, Precision):
                logging.critical(
                    "Backend %r -> %r unsupported key format, expected key to be "
                    "tuple[str, Precision], got %r.",
                    module_name,
                    value,
                    key,
                )
                continue

            if len(getattr(value, "author", "")) == 0:
                value.author = module_meta["Author"]

            self.backends[(name.casefold(), precision)] = value

    @classmethod
    @lru_cache(maxsize=1)
    def new(cls) -> Self:
        """Get instance of Loader."""
        return cls()

    def get_backend(self, name: str, precision: Precision) -> Type[BackendBase]:
        """Query set of available backends with provided properties and return backend
        class if there is one meeting expectations.
        """
        try:
            return self.backends[(name.casefold(), precision)]
        except KeyError as exc:
            msg = (
                f"There is no backend with name={name!r} and precision="
                f"{precision.name!r} currently installed."
            )
            raise BackendNotAvailableError(msg) from exc

    def get_rich_table(self) -> Table:
        """Create rich Table object containing information about available backends."""
        table = Table(title="Available backends", show_lines=True)
        table.add_column("Name", justify="right", no_wrap=True, style="deep_sky_blue1")
        table.add_column("Precision", justify="center", no_wrap=True)
        table.add_column("Author", justify="center", no_wrap=False)
        table.add_column("Source", justify="left", no_wrap=False)
        table.add_column("Description", justify="left", no_wrap=False)

        for key, value in self.backends.items():
            try:
                (name, precision), cls = key, value
                table.add_row(
                    name,
                    precision.name,
                    getattr(cls, "author", ""),
                    f"{cls.__module__}.{cls.__qualname__}",
                    getattr(cls, "description", ""),
                )
            except (TypeError, ValueError):  # noqa: PERF203
                logging.warning("Failed to display information about backed %r", value)

        return table

reload

reload() -> None

Load all backends available in python environment.

This is automatically called by constructor to load all backends. You can use it to refresh list of loaded backends.

Source code in cssfinder/algorithm/backend/loader.py
def reload(self) -> None:
    """Load all backends available in python environment.

    This is automatically called by constructor to load all backends. You can use it
    to refresh list of loaded backends.

    """
    self.backends: dict[tuple[str, Precision], Type[BackendBase]] = {}

    for dist in importlib.import_module("pkg_resources").working_set:
        if self.BACKEND_NAME_REGEX.match(dist.project_name) is None:
            continue

        module_name = dist.project_name.replace("-", "_")

        module = importlib.import_module(module_name)
        module_meta = metadata.metadata(module_name)

        export_backend = getattr(module, "export_backend", None)

        if export_backend is None:
            continue

        backends = export_backend()

        if not isinstance(backends, dict):
            logging.critical(
                "Backend %r unsupported export format %r, expected <class 'dict'>.",
                module_name,
                type(backends),
            )
            continue

        self._extend_backend_index(module_name, module_meta, backends)

new cached classmethod

new() -> Self

Get instance of Loader.

Source code in cssfinder/algorithm/backend/loader.py
@classmethod
@lru_cache(maxsize=1)
def new(cls) -> Self:
    """Get instance of Loader."""
    return cls()

get_backend

get_backend(
    name: str, precision: Precision
) -> Type[BackendBase]

Query set of available backends with provided properties and return backend class if there is one meeting expectations.

Source code in cssfinder/algorithm/backend/loader.py
def get_backend(self, name: str, precision: Precision) -> Type[BackendBase]:
    """Query set of available backends with provided properties and return backend
    class if there is one meeting expectations.
    """
    try:
        return self.backends[(name.casefold(), precision)]
    except KeyError as exc:
        msg = (
            f"There is no backend with name={name!r} and precision="
            f"{precision.name!r} currently installed."
        )
        raise BackendNotAvailableError(msg) from exc

get_rich_table

get_rich_table() -> Table

Create rich Table object containing information about available backends.

Source code in cssfinder/algorithm/backend/loader.py
def get_rich_table(self) -> Table:
    """Create rich Table object containing information about available backends."""
    table = Table(title="Available backends", show_lines=True)
    table.add_column("Name", justify="right", no_wrap=True, style="deep_sky_blue1")
    table.add_column("Precision", justify="center", no_wrap=True)
    table.add_column("Author", justify="center", no_wrap=False)
    table.add_column("Source", justify="left", no_wrap=False)
    table.add_column("Description", justify="left", no_wrap=False)

    for key, value in self.backends.items():
        try:
            (name, precision), cls = key, value
            table.add_row(
                name,
                precision.name,
                getattr(cls, "author", ""),
                f"{cls.__module__}.{cls.__qualname__}",
                getattr(cls, "description", ""),
            )
        except (TypeError, ValueError):  # noqa: PERF203
            logging.warning("Failed to display information about backed %r", value)

    return table

BackendNotAvailableError

Bases: KeyError

Raised when backend with specified features can not be found.

Source code in cssfinder/algorithm/backend/loader.py
class BackendNotAvailableError(KeyError):
    """Raised when backend with specified features can not be found."""