Files
hermes-agent/tests/pm/test_feature_inventory.py
ethernet f2db4349e8 fix(pm): inventory features in the staged interpreter
The builder's imported modules could mark an empty dependency tree as
installed. Probe every anchor in one isolated target process. Require
all anchors for a multi-module extra, and process only the selected
tree's .pth files so editable packages retain their launch behavior.

The native builder passes its staged Python explicitly and stops before
manifest publication when the inventory fails. Correct the Hindsight
and Teams anchors using the namespaces in their locked wheels.

Verified: 31 tests passed, 3 host skips. A real target child records its
identity, and a caller mutation back to the builder Python fails the
regression. Both downloaded SDK wheels match uv.lock and pass inventory
and availability checks. Ruff and added-comment checks passed.

No full native package or signing run is claimed.
2026-09-09 21:47:54 -04:00

75 lines
3.1 KiB
Python

"""Feature inventory reads the selected dependency tree, not the builder."""
import json
import os
from pathlib import Path
import subprocess
import sys
import packaging
import pytest
import pm.extras as extras
import pm.features as features
from hermes_cli.runtime_paths import site_packages
def test_inventory_uses_the_target_and_requires_every_anchor(tmp_path, monkeypatch):
target_root = tmp_path / "target"
subprocess.run(
[sys.executable, "-m", "venv", "--without-pip", str(target_root)],
capture_output=True, check=True, timeout=60,
)
target = target_root / ("Scripts/python.exe" if os.name == "nt" else "bin/python")
dependencies = tmp_path / "dependencies"
site = site_packages(dependencies)
site.mkdir(parents=True)
witness = tmp_path / "child.json"
package = site / "inventory_anchor"
package.mkdir()
(package / "__init__.py").write_text(
"import json, pathlib, sys\n"
f"pathlib.Path({str(witness)!r}).write_text(json.dumps(sys.executable), encoding='utf-8')\n",
encoding="utf-8",
)
(package / "present.py").write_text("VALUE = 'target'\n", encoding="utf-8")
(site / "one_part.py").write_text("", encoding="utf-8")
editable = tmp_path / "editable"
editable.mkdir()
(editable / "editable_anchor.py").write_text("", encoding="utf-8")
(site / "editable.pth").write_text(str(editable) + "\n", encoding="utf-8")
launches = tmp_path / "launches.jsonl"
(site / "launches.pth").write_text(
f"import json, pathlib, sys; p = pathlib.Path({str(launches)!r}); "
"text = p.read_text(encoding='utf-8') if p.exists() else ''; "
"p.write_text(text + json.dumps(sys.executable) + '\\n', encoding='utf-8')\n",
encoding="utf-8",
)
mapping = {
"complete": "inventory_anchor.present",
"partial": ("one_part", "absent_part"),
"host-only": "packaging",
"editable": "editable_anchor",
}
repo = tmp_path / "source"
repo.mkdir()
(repo / "pyproject.toml").write_text(
"[project.optional-dependencies]\n" + "".join(f'"{name}"=[]\n' for name in mapping),
encoding="utf-8",
)
monkeypatch.setattr(extras, "ANCHORS", mapping)
before_path = list(sys.path)
before_env = dict(os.environ)
assert packaging.__file__ and "packaging" in sys.modules
result = features.installed_extras(repo, dependencies, python_exe=target)
assert result == ["complete", "editable"]
assert Path(json.loads(witness.read_text(encoding="utf-8"))) == target
assert [Path(json.loads(line)) for line in launches.read_text(encoding="utf-8").splitlines()] == [target]
assert "inventory_anchor" not in sys.modules
assert sys.path == before_path
assert dict(os.environ) == before_env
(site / "absent_part.py").write_text("", encoding="utf-8")
assert features.installed_extras(repo, dependencies, python_exe=target) == ["complete", "editable", "partial"]
with pytest.raises(features.FeatureProbeError, match="feature inventory failed"):
features.installed_extras(repo, dependencies, python_exe=tmp_path / "missing-python")