Five review findings of the P3 phase, each fixed at its root:
1. (medium) The P3.7 metadata test imported `tomllib` at module level: the
**3.10 CI job** (the declared `requires-python >=3.10` minimum) died
during collection, so the registry-metadata assertions never ran on 3.10.
The parser import is now guarded (`tomllib` -> `tomli`, the package the
3.10 job installs); without any parser the module *skips* instead of
dying. `pyproject.toml` gained the test extra
`tomli>=2.0; python_version < '3.11'`.
Proof: a 3.10 simulation (the stdlib `tomllib` refused for the test
module, `tomli` on sys.path) -> 6 passed; the control without `tomli`
-> 6 skipped (no collection error).
2. (medium) The P3.5 "primary-root-first multi-root" resolution was not
wired into the production load path: `resolve_model_file` (the only
`get_full_path_or_raise` caller) was used by tests only, so a weight in
a secondary model root was downloaded into the primary root again.
`src/keep_paths.py` now has `find_model_file()` (the multi-root lookup
through `folder_paths.get_full_path_or_raise`) and `resolve_model_root()`
(the root the weights really live in); `load_file_from_url_comfy()` - the
production path of `src/keep_model_loader.py:107` - uses the lookup, and
the facelib root follows the weights (the facelib helper builds its
paths from a single root). New tests prove that the production path
uses a weight of an extra model root and that the primary root wins.
The `models_dir` grep guard is no longer a blanket exemption: only the
registration in `src/keep_paths.py` may use the attribute.
3. (low) `[tool.comfy].Icon` was an empty string and the test only checked
that the key exists. The preview asset **is** committed
(`git cat-file -s HEAD:assets/keep-preview.png` -> 93279 bytes); only the
working copy was missing (an uncommitted local deletion, restored from
HEAD - no asset change is in this commit). The key now points at
`assets/keep-preview.png` and the test asserts that the value is not
empty and names a file that is really in the repository.
4. (low) `tests/test_package_entrypoint.py` hard-coded the V1 state and
would have gone red (not xfail) when P4.4 flips the root `__init__.py`
to `comfy_entrypoint`. The assertions now follow the entry point that is
really there: exactly **one** mapping style (V1 XOR V3). The mocked
smoke test of `tests/test_package_import.py` got the same treatment; the
headless variant is P4.4's job (its test list names it).
5. (low) The plan's §3 rule ("`comfy.*` imports inside `src/` are lazy
(function-level) so the pack imports without a ComfyUI server") was
violated and unguarded. The `comfy` imports of `src/keep_model_loader.py`
and `src/keep_processor.py` are function-level now; the vendored facelib
helper (which imports `comfy` itself) is imported lazily through a module
`__getattr__` (PEP 562), so `loader.FaceRestoreHelper` still resolves to
the vendored class. Structure **guard (f)** (`tests/test_structure.py`)
forbids a module-level `comfy`/`comfy_api` import in `src/**` (with the
self-test the guards file demands), and the new
`tests/test_lazy_imports.py` proves at runtime that the engines import
while every `comfy` import is blocked.
Gate after the commit:
python.exe -m pytest -q tests -m "unit or mock_integration"
-> 153 passed, 1 skipped, 5 deselected, 3 xfailed
COMFYUI_ROOT=C:/_Dev/ComfyUI_dev/ComfyUI-source/ComfyUI python.exe
-m pytest -q tests -m "unit or mock_integration or headless"
-> 158 passed, 1 skipped, 3 xfailed
Details: docs/2026-10-23-p3-review-findings.md
121 lines
4.1 KiB
Python
121 lines
4.1 KiB
Python
"""P3.7 - the registry metadata of the pack.
|
|
|
|
``pyproject.toml`` is the metadata the ComfyUI Registry reads. The test
|
|
parses it with ``tomllib`` (the standard library since Python 3.11) and
|
|
asserts that the metadata is complete and that the dependency list is the
|
|
true runtime set of P2.6 (``requirements.txt``).
|
|
|
|
The parser import is **guarded**: the pack supports Python 3.10
|
|
(``requires-python = ">=3.10"``), where ``tomllib`` does not exist. The
|
|
3.10 CI job installs ``tomli`` (the same parser under its old name), so the
|
|
metadata is asserted on 3.10 as well - the module never dies during
|
|
collection.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
try: # Python 3.11+
|
|
import tomllib
|
|
except ModuleNotFoundError: # Python 3.10 - the CI job installs ``tomli``
|
|
try:
|
|
import tomli as tomllib # type: ignore[no-redef]
|
|
except ModuleNotFoundError: # no TOML parser at all
|
|
tomllib = None # type: ignore[assignment]
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
PYPROJECT = REPO_ROOT / "pyproject.toml"
|
|
REQUIREMENTS = REPO_ROOT / "requirements.txt"
|
|
|
|
#: The metadata of the pack (P3.7).
|
|
EXPECTED_VERSION = "2.0.0"
|
|
EXPECTED_REQUIRES_PYTHON = ">=3.10"
|
|
EXPECTED_COMFY = {
|
|
"PublisherId": "wildai",
|
|
"DisplayName": "KEEP",
|
|
"requires-comfyui": ">=0.28.0",
|
|
}
|
|
|
|
#: The preview asset of the registry entry (P3.7 - the ``Icon`` key).
|
|
EXPECTED_ICON = "assets/keep-preview.png"
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def pyproject() -> dict:
|
|
assert PYPROJECT.is_file(), f"missing {PYPROJECT}"
|
|
if tomllib is None:
|
|
pytest.skip(
|
|
"no TOML parser available - install ``tomli`` on Python 3.10 "
|
|
"(the CI job does)"
|
|
)
|
|
with PYPROJECT.open("rb") as handle:
|
|
return tomllib.load(handle)
|
|
|
|
|
|
def _requirement_entries() -> set[str]:
|
|
return {
|
|
line.strip()
|
|
for line in REQUIREMENTS.read_text(encoding="utf-8").splitlines()
|
|
if line.strip() and not line.strip().startswith("#")
|
|
}
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_the_pyproject_parses(pyproject):
|
|
"""The metadata is parseable (tomllib on Python 3.11+, tomli on 3.10)."""
|
|
assert "project" in pyproject
|
|
assert pyproject["project"]["name"] == "ComfyUI-KEEP"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_the_version_is_the_release_version(pyproject):
|
|
"""The pack is version ``2.0.0``."""
|
|
assert pyproject["project"]["version"] == EXPECTED_VERSION
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_the_python_requirement_is_declared(pyproject):
|
|
"""The pack supports Python 3.10 and newer."""
|
|
assert pyproject["project"]["requires-python"] == EXPECTED_REQUIRES_PYTHON
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_the_comfy_metadata_is_complete(pyproject):
|
|
"""Every ``[tool.comfy]`` key of the registry is present."""
|
|
comfy = pyproject.get("tool", {}).get("comfy")
|
|
assert comfy is not None, "pyproject.toml has no [tool.comfy] table"
|
|
for key, value in EXPECTED_COMFY.items():
|
|
assert key in comfy, f"[tool.comfy] has no {key}"
|
|
assert comfy[key] == value, f"[tool.comfy].{key}: {comfy[key]!r} != {value!r}"
|
|
assert "Icon" in comfy, "[tool.comfy] has no Icon"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_the_icon_points_at_the_preview_asset(pyproject):
|
|
"""The ``Icon`` is not an empty string - it points at the preview asset.
|
|
|
|
An empty ``Icon`` passes the "the key exists" check above, but the
|
|
registry entry has no preview then: the value must name a file that is
|
|
really in the repository.
|
|
"""
|
|
comfy = pyproject.get("tool", {}).get("comfy") or {}
|
|
icon = comfy.get("Icon", "")
|
|
assert isinstance(icon, str) and icon.strip(), (
|
|
f"[tool.comfy].Icon is empty - the registry entry would have no preview"
|
|
)
|
|
assert icon == EXPECTED_ICON, icon
|
|
asset = REPO_ROOT / icon
|
|
assert asset.is_file(), f"the icon {icon!r} is not in the repository"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_the_dependencies_are_the_true_runtime_set(pyproject):
|
|
"""The declared dependencies are exactly the ones of ``requirements.txt``."""
|
|
declared = set(pyproject["project"]["dependencies"])
|
|
assert declared == _requirement_entries(), sorted(
|
|
declared ^ _requirement_entries()
|
|
)
|