"""P4 pkt. 5 — the console entry points are part of the FROZEN install surface. The README's central claim is "download -> run". Until now every documented invocation went through ``uv run python -m portfolio_optimiser.``, which works but is not an install surface: nothing in the distribution metadata promised a command. This test pins the two commands that the demo and the framework CLI are reached by. Why read ``importlib.metadata`` and not ``pyproject.toml``: a ``[project.scripts]`` line that has never been ``uv sync``-ed is a claim, not a command. The distribution metadata is what a fresh clone materializes after ``uv sync``, so it is the only reading that can fail when the surface is merely *declared*. The declaration is checked too (the TOML is the source the metadata is built from), but the metadata assert is the load-bearing one. Scope, stated so it is a decision and not an oversight: exactly TWO commands are exposed. ``run`` is the framework CLI (three documented modes) and ``simulation`` is the offline end-to-end proof the README points a newcomer at. ``costsim`` / ``hitl`` / ``preflight`` keep the ``-m`` form — they are operator utilities, not the product's front door, and every name added here is a name the freeze has to carry. """ from __future__ import annotations import importlib import importlib.metadata from pathlib import Path import pytest _DIST = "portfolio-optimiser" # command name -> "module:function" target, verbatim as it must appear in the metadata. _EXPECTED: dict[str, str] = { "portfolio-optimiser": "portfolio_optimiser.run:main", "portfolio-optimiser-demo": "portfolio_optimiser.simulation:main", } def _console_scripts() -> dict[str, str]: """The installed distribution's console scripts, as ``{name: "module:function"}``.""" return { ep.name: ep.value for ep in importlib.metadata.distribution(_DIST).entry_points if ep.group == "console_scripts" } @pytest.mark.parametrize(("name", "target"), sorted(_EXPECTED.items())) def test_console_script_is_installed(name: str, target: str) -> None: """T-P4.5a: the command exists in the INSTALLED distribution and points at the right target. RED when the ``[project.scripts]`` entry is removed (or when it is added to the TOML without a re-sync — which is the same failure a fresh clone would hit for real). """ scripts = _console_scripts() assert name in scripts, ( f"console script {name!r} is not installed; found {sorted(scripts)}. " "Declare it under [project.scripts] in pyproject.toml and re-run `uv sync`." ) assert scripts[name] == target @pytest.mark.parametrize("name", sorted(_EXPECTED)) def test_console_script_target_resolves(name: str) -> None: """T-P4.5b: the INSTALLED target actually imports and is callable — a typo'd module or function name installs a command that only fails when the operator runs it, which on demo day is on stage. Resolves what the distribution says, not what this file expects: resolving ``_EXPECTED`` would only ever re-check a constant against itself.""" target = _console_scripts()[name] module_name, _, func_name = target.partition(":") module = importlib.import_module(module_name) entry = getattr(module, func_name, None) assert callable(entry), f"{target} (behind {name}) does not resolve to a callable" def test_pyproject_declares_exactly_these_scripts() -> None: """T-P4.5c: the declaration in ``pyproject.toml`` matches the installed set exactly. Guards the drift direction the metadata assert cannot see: a script installed from an older sync but since deleted from the TOML would leave a command that a fresh clone never gets. """ pyproject = Path(__file__).resolve().parents[1] / "pyproject.toml" try: import tomllib except ModuleNotFoundError: # pragma: no cover - Python 3.10 has no tomllib pytest.skip("tomllib is 3.11+; the installed-metadata asserts cover the same surface") declared = tomllib.loads(pyproject.read_text(encoding="utf-8"))["project"]["scripts"] assert declared == _EXPECTED