Source code for embedl_deploy._internal.core.backend
# Copyright (C) 2026 Embedl AB
"""Backend discovery and selection."""
import importlib
from collections.abc import Sequence
from dataclasses import dataclass
from pathlib import Path
from embedl_deploy._internal.core.pattern import Pattern
_INTERNAL_DIR = Path(__file__).resolve().parent.parent
[docs]
@dataclass(frozen=True)
class Backend:
"""A collection of patterns for a specific hardware target."""
#: Short identifier, matching the package directory name.
name: str
#: Structural rewrite patterns, applied iteratively.
conversion_patterns: Sequence[Pattern]
#: Fusion patterns, applied in a single pass after conversions.
fusion_patterns: Sequence[Pattern]
#: SmoothQuant preparation patterns.
smooth_patterns: Sequence[Pattern]
#: Q/DQ stub insertion patterns for quantization.
quantized_patterns: Sequence[Pattern]
class _BackendState:
"""Module-level mutable state for backend discovery and selection."""
#: The currently selected backend.
backend: Backend | None = None
#: Cached discovery result.
backends: list[Backend] | None = None
@classmethod
def reset(cls) -> None:
"""Clear cached discovery results and the active backend."""
cls.backend = None
cls.backends = None
[docs]
def discover_backends() -> list[Backend]:
"""Return all installed backends.
Results are cached after the first call.
:returns:
List of discovered :class:`~embedl_deploy.backend.Backend`
instances.
"""
backends = _BackendState.backends
if backends is None:
backends = []
for entry in sorted(_INTERNAL_DIR.iterdir()):
if (
not entry.is_dir()
or entry.name.startswith("_")
or entry.name == "core"
):
continue
module_path = f"embedl_deploy._internal.{entry.name}.backend"
try:
mod = importlib.import_module(module_path)
except ModuleNotFoundError as e:
if e.name == module_path:
continue
raise
backend = getattr(mod, "BACKEND", None)
if isinstance(backend, Backend):
backends.append(backend)
_BackendState.backends = backends
return list(backends)
[docs]
def get_backend() -> Backend:
"""Return the active backend, discovering it if necessary.
If no backend has been set via :func:`set_backend`, the installed
backends are discovered automatically. When exactly one is found
it becomes the active backend.
:returns:
The active :class:`Backend`.
:raises RuntimeError:
If no backends are installed, or if multiple backends are
installed and none has been explicitly selected.
"""
backend = _BackendState.backend
if backend is None:
backends = discover_backends()
if len(backends) == 0:
raise RuntimeError(
"No backends found — install at least one backend"
)
if len(backends) > 1:
names = ", ".join(sorted(b.name for b in backends))
raise RuntimeError(
f"Multiple backends found ({names}). "
"Call set_backend() to select one."
)
backend = backends[0]
_BackendState.backend = backend
return backend
[docs]
def set_backend(name: str) -> None:
"""Select the active backend by name.
:param name:
The name of a discovered backend (e.g. ``"tensorrt"``).
:raises ValueError:
If `name` does not match any installed backend.
"""
backend_map = {b.name: b for b in discover_backends()}
if name not in backend_map:
available = ", ".join(sorted(backend_map)) or "(none)"
raise ValueError(
f"Backend {name!r} not found. Available backends: {available}"
)
_BackendState.backend = backend_map[name]