All 7 P0 review findings were verified by execution and fixed. F1 (medium) - the compat scanner modelled only the basicsr/archs eager scan. The vendored basicsr also scans data/, losses/ and models/ eagerly (basicsr/__init__.py:3-11 imports all of them), so the closure missed 32 files that the repaired package really imports (incl. models/keep_model.py and models/keep_gan_model.py, both with 'import pdb' at line 4). The scanner now models all four scans plus 'from <package> import <submodule>': closure 100 -> 132 files, findings 8 -> 10, and 0 runtime-loaded vendored files are missing from the closure (verified on a temp copy of modules/deps). The audit doc's opposite claim is corrected and P2.4 in the plan now has to rewrite basicsr/__init__.py and prove 'import basicsr' still succeeds after pruning (otherwise ModuleNotFoundError is swallowed into DummyArchRegistry). F2 (medium) - the Asian manifest entry is now decided (P0.4 section 4.1): url 404, sha256 null, sha256_prefix '4765ebe0', unverified true, available false, required FALSE (a required entry would break the default KEEP model through P5.3's fail-fast rule). Plan P5.0/P5.1/P5.3 and the weights scanner were aligned. F3 (low) - the plan's section 8 decision 1, the B3 baseline row, Goal 5, the risk table and P5.5 carried the superseded GMFlow premise; they now match the P0.4 decision (the shipped checkpoint carries the flownet weights; the GMFlow file is defensive and resolved only when the checkpoint has no flownet.* keys). F4 (low) - the P0.1 fixture asserted rc == 0 before checking the probe's fatal report, so the documented skip was unreachable. It now handles the probe's exit code 2 + fatal report and skips with a reason. F5 (low) - the baseline-import doc claimed all eight stub symbols fire in the ffmpeg-blocked run; it is 7 of 8 (loader_face_restore_helper_is_dummy does not fire - the real facelib imports fine). F6 (low) - the scanner's exit-code contract (0 = no findings, 1 = findings) is documented in the tool docstring and in the audit doc. F7 (low) - the root conftest registered '__init__' and the invalid directory basename; it now registers the plan's alias 'ComfyUI_KEEP' and provides execute_package_init() so the V3 entrypoint is executed rather than bypassed. P1.2 is specified to replace that bootstrap. Gates: pytest tests/ -q -> 37 passed, 1 xfailed; scan_compat.py --quiet -> closure 132, 10 findings, exit 1; baseline_probe.py -> import ok / model build fails (unchanged baseline); scan_weights.py -> 0 of 8 present.
140 lines
4.9 KiB
Python
140 lines
4.9 KiB
Python
"""P0 - the root conftest's package-alias bootstrap.
|
|
|
|
The plan (P1.2) mandates the package alias ``ComfyUI_KEEP`` (with
|
|
``submodule_search_locations`` and ``__path__`` set) and requires that the
|
|
**node tests execute** the root ``__init__.py`` - the V3 entrypoint of
|
|
P3.4/P4.4. The P0 bootstrap therefore has to
|
|
|
|
* register the package under the plan's alias - and **not** under the
|
|
repository directory basename, which is not a valid identifier,
|
|
* offer a way to execute the real entry point instead of the
|
|
register-without-execute stub, and
|
|
* really execute it when a ComfyUI tree is available.
|
|
|
|
The bootstrap must not be bypassed: a package alias that is registered but
|
|
never executed would silently skip the V3 entrypoint in every node test.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
CONFTEST = REPO_ROOT / "conftest.py"
|
|
|
|
EXPECTED_ALIAS = "ComfyUI_KEEP"
|
|
EXPECTED_NODE_IDS = [
|
|
"KEEP_FaceUpscaleImage",
|
|
"KEEP_ModelLoader",
|
|
"KEEP_ProcessImageSequence",
|
|
]
|
|
|
|
|
|
def _load_conftest():
|
|
spec = importlib.util.spec_from_file_location("keep_root_conftest", CONFTEST)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def conftest_module():
|
|
return _load_conftest()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_plan_alias_is_registered(conftest_module):
|
|
"""The package is registered under the alias the plan names."""
|
|
assert conftest_module.PACKAGE_ALIAS == EXPECTED_ALIAS
|
|
alias_module = sys.modules.get(EXPECTED_ALIAS)
|
|
assert alias_module is not None, f"{EXPECTED_ALIAS} is not registered"
|
|
assert list(alias_module.__path__) == [str(REPO_ROOT)]
|
|
search_locations = alias_module.__spec__.submodule_search_locations
|
|
assert list(search_locations) == [str(REPO_ROOT)]
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_directory_basename_alias_is_not_registered(conftest_module):
|
|
"""The invalid-identifier alias of the old bootstrap is gone."""
|
|
assert REPO_ROOT.name not in sys.modules, (
|
|
f"{REPO_ROOT.name!r} must not be registered: it is not a valid "
|
|
"identifier and is not the alias the plan specifies"
|
|
)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_conftest_provides_an_execute_hook(conftest_module):
|
|
"""There must be a way to execute the root __init__.py (P3.4/P4.4)."""
|
|
assert callable(conftest_module.execute_package_init)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_execute_package_init_runs_the_real_entrypoint(tmp_path):
|
|
"""Executing the alias really runs the root __init__.py.
|
|
|
|
The execution needs ComfyUI on ``sys.path`` (``folder_paths``,
|
|
``comfy.utils``); without a ComfyUI tree the test skips with a reason.
|
|
"""
|
|
sys.path.insert(0, str(REPO_ROOT / "tools"))
|
|
import baseline_probe # noqa: PLC0415 - the probe owns the root resolution
|
|
|
|
comfyui_root = baseline_probe.resolve_comfyui_root(None)
|
|
if comfyui_root is None:
|
|
pytest.skip(
|
|
"no ComfyUI source tree found: set COMFYUI_ROOT to enable the "
|
|
"package-entrypoint execution"
|
|
)
|
|
|
|
out_path = tmp_path / "entrypoint.json"
|
|
script = tmp_path / "run_entrypoint.py"
|
|
script.write_text(
|
|
"import importlib.util, json, sys\n"
|
|
f"sys.path.insert(0, {str(REPO_ROOT)!r})\n"
|
|
f"spec = importlib.util.spec_from_file_location('keep_root_conftest', {str(CONFTEST)!r})\n"
|
|
"module = importlib.util.module_from_spec(spec)\n"
|
|
"spec.loader.exec_module(module)\n"
|
|
"package = module.execute_package_init()\n"
|
|
"with open(sys.argv[1], 'w', encoding='utf-8') as handle:\n"
|
|
" json.dump({\n"
|
|
" 'module_name': package.__name__,\n"
|
|
" 'has_logger': hasattr(package, 'logger'),\n"
|
|
" 'node_ids': sorted(getattr(package, 'NODE_CLASS_MAPPINGS', {})),\n"
|
|
" }, handle)\n",
|
|
encoding="utf-8",
|
|
)
|
|
result = subprocess.run(
|
|
[sys.executable, str(script), str(out_path)],
|
|
cwd=str(REPO_ROOT),
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=600,
|
|
env=_environ_with_comfyui(comfyui_root),
|
|
)
|
|
assert out_path.is_file(), (
|
|
f"the entrypoint script did not write its result (rc={result.returncode})\n"
|
|
f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}"
|
|
)
|
|
data = json.loads(out_path.read_text(encoding="utf-8"))
|
|
assert data["module_name"] == EXPECTED_ALIAS
|
|
assert data["has_logger"] is True, (
|
|
"the executed package must define the logger that modules/* imports "
|
|
"via 'from .. import logger'"
|
|
)
|
|
assert data["node_ids"] == EXPECTED_NODE_IDS
|
|
|
|
|
|
def _environ_with_comfyui(comfyui_root: str) -> dict:
|
|
import os # noqa: PLC0415 - local import keeps the module import list short
|
|
|
|
env = dict(os.environ)
|
|
env["PYTHONPATH"] = os.pathsep.join(
|
|
[comfyui_root, env.get("PYTHONPATH", "")]
|
|
).rstrip(os.pathsep)
|
|
return env
|