Skip to content

symfonic.cli.examples

examples

symfonic examples -- copy a runnable example into the user's project.

Examples are not importable modules shipped in the wheel; they are bundled as data under symfonic/cli/example_data/ (via a build-time hatch force-include mapping the repo-root examples/ tree). This command copies a curated example out into the caller's working directory so an installed-only consumer -- someone who ran pip install symfonic-core and never cloned the repo -- can run it in seconds, without us shipping the whole codebase inside the package.

Two resolution roots are supported so the command behaves identically in a wheel install and in a source checkout / editable install:

  1. Packaged data -- symfonic/cli/example_data/ (present in built wheels).
  2. Repo checkout fallback -- the sibling examples/ tree at the repo root (present in editable installs and when running the tests).

Both roots carry the same relative layout for the curated set, so the :data:CURATED specs resolve against either without branching.

ExampleSpec dataclass

ExampleSpec(name: str, summary: str, run: str, srcdir: str | None = None, srcfile: str | None = None, requires: str | None = None, domain: str | None = None)

A curated, copy-out example.

srcdir and srcfile are mutually exclusive and are given relative to the resolved examples root. Exactly one must be set.

domain class-attribute instance-attribute

domain: str | None = None

The :data:JOURNEY_DOMAINS rung this example is the canonical answer for, or None for the older single-topic examples. Exactly one spec may claim a domain — an example set where two files both claim to be the memory example is a set with no canonical memory example.

requires class-attribute instance-attribute

requires: str | None = None

Human note on prerequisites (extra + credentials), or None for a base-install example that runs on MockModelProvider.

ExamplesError

Bases: RuntimeError

Raised when an example cannot be listed or copied.

add_example

add_example(name: str, dest_dir: Path, *, root: Path | None = None, force: bool = False) -> Path

Copy the curated example name into dest_dir/<name>/.

Returns the created target directory. Raises :class:ExamplesError for an unknown name, a missing source, or an existing target when force is False.

Source code in symfonic/cli/examples.py
def add_example(
    name: str,
    dest_dir: Path,
    *,
    root: Path | None = None,
    force: bool = False,
) -> Path:
    """Copy the curated example ``name`` into ``dest_dir/<name>/``.

    Returns the created target directory. Raises :class:`ExamplesError` for an
    unknown name, a missing source, or an existing target when ``force`` is
    False.
    """
    spec = CURATED.get(name)
    if spec is None:
        known = ", ".join(CURATED)
        raise ExamplesError(
            f"Unknown example {name!r}. Available: {known}. "
            "Run 'symfonic examples list' to see them."
        )

    src_root = root if root is not None else resolve_examples_root()
    target = dest_dir / name

    if target.exists():
        if not force:
            raise ExamplesError(
                f"{target} already exists. Pass --force to overwrite."
            )
        shutil.rmtree(target)

    if spec.srcdir is not None:
        source = src_root / spec.srcdir
        if not source.is_dir():
            raise ExamplesError(f"Example source not found: {source}")
        shutil.copytree(source, target, ignore=_IGNORE)
    else:
        assert spec.srcfile is not None  # guaranteed by __post_init__
        source = src_root / spec.srcfile
        if not source.is_file():
            raise ExamplesError(f"Example source not found: {source}")
        target.mkdir(parents=True, exist_ok=True)
        shutil.copy2(source, target / source.name)

    return target

available_examples

available_examples() -> list[ExampleSpec]

Return the curated examples in stable declaration order.

Source code in symfonic/cli/examples.py
def available_examples() -> list[ExampleSpec]:
    """Return the curated examples in stable declaration order."""
    return list(CURATED.values())

journeys

journeys() -> list[ExampleSpec]

Return the twelve journey rungs, in ladder order.

Ordered by :data:JOURNEY_DOMAINS rather than by declaration, so the ladder has exactly one definition. Raises when a domain has no spec — silently returning eleven rungs would be the failure worth catching.

Source code in symfonic/cli/examples.py
def journeys() -> list[ExampleSpec]:
    """Return the twelve journey rungs, in ladder order.

    Ordered by :data:`JOURNEY_DOMAINS` rather than by declaration, so the
    ladder has exactly one definition. Raises when a domain has no spec —
    silently returning eleven rungs would be the failure worth catching.
    """
    by_domain = {spec.domain: spec for spec in CURATED.values() if spec.domain}
    missing = [domain for domain in JOURNEY_DOMAINS if domain not in by_domain]
    if missing:
        raise ExamplesError(f"no curated journey for domain(s): {missing}")
    return [by_domain[domain] for domain in JOURNEY_DOMAINS]

resolve_examples_root

resolve_examples_root() -> Path

Locate the directory that holds the curated example sources.

Prefers the packaged example_data (wheel installs); falls back to the repo-root examples/ tree (editable installs / source checkouts).

Source code in symfonic/cli/examples.py
def resolve_examples_root() -> Path:
    """Locate the directory that holds the curated example sources.

    Prefers the packaged ``example_data`` (wheel installs); falls back to the
    repo-root ``examples/`` tree (editable installs / source checkouts).
    """
    packaged = resources.files("symfonic.cli").joinpath("example_data")
    try:
        if packaged.is_dir():
            return Path(str(packaged))
    except (FileNotFoundError, ModuleNotFoundError):  # pragma: no cover
        pass

    cli_dir = Path(str(resources.files("symfonic.cli"))).resolve()
    # cli_dir == <repo>/src/symfonic/cli  ->  parents[2] == <repo>
    repo_examples = cli_dir.parents[2] / "examples"
    if repo_examples.is_dir():
        return repo_examples

    raise ExamplesError(
        "Bundled examples not found. Reinstall symfonic-core, or run this "
        "command from a source checkout of the repository."
    )