`import pm.ensure` bound the submodule onto the package, shadowing the facade's `pm.ensure()` function for every later caller in the process (photon's sidecar start hit `'module' object is not callable`). The module is pm.install now; the function keeps its name. The facade resolves through `__import__` rather than `importlib.import_module` so a test that patches import_module globally does not break attribute access on pm. tools/lazy_deps.py returns to the 16-line stop_for_relaunch shim the branch wrote (an origin/main merge had replaced it with main's 775-line implementation); the project-metadata tests follow. update_cmd re-exports the four old_updater_deps names the shim tests resolve through hermes_cli.update_cmd.
59 lines
2.4 KiB
Python
59 lines
2.4 KiB
Python
"""Pinned tool acquisition for PM's private Python engine; never worker API."""
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from pm import paths
|
|
from pm.lock import Facts
|
|
from pm.package import InstallError
|
|
from pm.registry import get_package
|
|
from pm.store import Store, current_target
|
|
|
|
|
|
def _toolchain(*, realize: bool = True, explicit: bool = False) -> tuple[Path, Path] | None:
|
|
"""Resolve uv and Python without host discovery or recursive worker dispatch.
|
|
|
|
A read-only probe never installs. Windows bundle builds need a verified
|
|
writable interpreter so their venv redirectors can run outside the MSIX.
|
|
"""
|
|
from pm.install import (
|
|
_install, _installed_location, _lockfile, _refuse_lazy,
|
|
ensure, lazy_installs_allowed, sealed,
|
|
)
|
|
|
|
if realize:
|
|
ensure("uv", explicit=explicit)
|
|
|
|
lockfile = _lockfile()
|
|
target = current_target()
|
|
binaries = {}
|
|
for name in ("uv", "python"):
|
|
package = get_package(name)
|
|
location = _installed_location(package, lockfile, target)
|
|
if location is None:
|
|
if not realize:
|
|
return None
|
|
raise InstallError(name, "pinned tool is unavailable", "run `hermes pm install`")
|
|
if name == "python" and target.startswith("win32") and sealed():
|
|
writable = paths.writable_store_root()
|
|
if location[1].root != writable:
|
|
copied = _installed_location(package, lockfile, target, verify=explicit, roots=(writable,))
|
|
if copied is None:
|
|
if not realize:
|
|
return None
|
|
if not explicit and not lazy_installs_allowed():
|
|
raise _refuse_lazy(name, "a writable Python is required for bundled builds")
|
|
copy_store = Store(writable)
|
|
copy_facts = Facts(writable / "facts.json")
|
|
_install(package, lockfile, copy_facts, copy_store, target, copy_from=location)
|
|
copied = copy_facts, copy_store
|
|
location = copied
|
|
facts, store = location
|
|
binary = package.binary(store.entry(facts.get(name)["entry"]), target)
|
|
if binary is None or not binary.is_file():
|
|
if not realize:
|
|
return None
|
|
raise InstallError(name, "installed binary is missing", "run `hermes pm install`")
|
|
binaries[name] = binary
|
|
return binaries["uv"], binaries["python"]
|