146 lines
5.2 KiB
Python
146 lines
5.2 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 asyncio, 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"
|
|
"async def collect():\n"
|
|
" extension = await package.comfy_entrypoint()\n"
|
|
" await extension.on_load()\n"
|
|
" node_list = await extension.get_node_list()\n"
|
|
" return sorted(cls.GET_SCHEMA().node_id for cls in node_list)\n"
|
|
"node_ids = asyncio.run(collect())\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': node_ids,\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
|