Source code for foundry.target

"""Target plugin protocol and discovery.

A *target* is the glue between foundry's generic engine and a
concrete framework (FastAPI + SQLAlchemy in kiln's case).  A
target is pure data:

* the pydantic schema its config files validate against,
* the directory of Jinja templates its renderers reference,
* and an optional directory of jsonnet ``.libsonnet`` files
  configs can import under the ``<name>/...`` prefix.

Everything else -- loading, engine, registry, assembler, and
output -- lives in foundry.  Targets are discovered at CLI
startup via the ``foundry.targets`` entry-point group.  The CLI
auto-selects the only installed target, or routes by
``--target`` when multiple are present.
"""

from __future__ import annotations

import importlib.metadata
from dataclasses import dataclass
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pathlib import Path

    from foundry.config import FoundryConfig


ENTRY_POINT_GROUP = "foundry.targets"


[docs] @dataclass(frozen=True) class Target: """A concrete code-generation target. Attributes: name: Short identifier, used for ``--target`` dispatch when multiple targets are installed and as the jsonnet stdlib import prefix. language: Language-identifier the target generates for (e.g. ``"python"``). Passed to :func:`foundry.imports.format_imports` so the assembler renders import blocks in the right syntax. Targets declare their formatter under the ``foundry.import_formatters`` entry-point group. schema: :class:`~foundry.config.FoundryConfig` subclass the target's config files validate against. Foundry's loader instantiates this. template_dir: Directory of Jinja templates the target's renderers reference. Foundry builds the Jinja environment rooted here. jsonnet_stdlib_dir: Optional directory of jsonnet ``.libsonnet`` files exposed to configs as ``<name>/...`` imports. ``None`` when the target ships no stdlib. """ name: str language: str schema: type[FoundryConfig] template_dir: Path jsonnet_stdlib_dir: Path | None = None
[docs] def discover_targets() -> list[Target]: """Load every :class:`Target` registered under ``foundry.targets``. Returns: All installed targets, in entry-point discovery order. """ eps = importlib.metadata.entry_points(group=ENTRY_POINT_GROUP) return [ep.load() for ep in eps]