Files
wildminder-ComfyUI-KEEP/tests/test_package_metadata.py
T
WildAi ba503f2068 build(deps): declare only what the ComfyUI host does not ship
The host's requirements.txt provides torch, torchvision, numpy, einops, pyyaml, Pillow, scipy, tqdm and requests; the pack now declares only opencv-python-headless - the vendored architectures and the four LANCZOS4 resizes need cv2, and no GUI call exists anywhere in the pack or the vendored tree, so the headless wheel suffices (no libGL/Qt in a server install). requests was a phantom: only the vendored basicsr download helper imports it. The dependency guards move to the host-guarantee policy (closure coverage = declared + host-provided, pinned to the host's requirement lines, exhaustive in both directions).
2026-10-25 23:07:07 +03:00

192 lines
7.0 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``) - under the host-guarantee
policy that set is the one dependency the ComfyUI host does not ship.
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
import re
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"
# ---------------------------------------------------------------------------
# P6.5 - the preconditions of publish.yml
# ---------------------------------------------------------------------------
#: The four keys the Comfy Registry reads from ``[tool.comfy]``.
REQUIRED_COMFY_KEYS = ("PublisherId", "DisplayName", "Icon", "requires-comfyui")
#: The magic bytes of a png file.
PNG_MAGIC = b"\x89PNG\r\n\x1a\n"
#: A version range of the form ``>=1.2.3`` (the registry wants a range).
VERSION_SPECIFIER_PATTERN = re.compile(r"^(>=|>|<=|<|==|!=)?\s*\d+(\.\d+)*$")
@pytest.mark.unit
def test_every_registry_key_has_a_non_empty_value(pyproject):
"""Every key of ``[tool.comfy]`` carries a non-empty value.
P6.5: the key being present is not enough - the registry publishes an
entry with an empty publisher or an empty display name, so every value
must really say something.
"""
comfy = pyproject.get("tool", {}).get("comfy") or {}
for key in REQUIRED_COMFY_KEYS:
assert key in comfy, f"[tool.comfy] has no {key}"
value = comfy[key]
assert isinstance(value, str) and value.strip(), (
f"[tool.comfy].{key} is empty - the registry entry would be incomplete"
)
@pytest.mark.unit
def test_the_icon_is_a_readable_png(pyproject):
"""The ``Icon`` is a real png file of the repository.
The registry renders the icon; a file that is not a png (or an empty
one) breaks the entry - and the asset is committed, it must never be
deleted from the repository.
"""
comfy = pyproject.get("tool", {}).get("comfy") or {}
icon = comfy.get("Icon", "")
asset = REPO_ROOT / icon
assert asset.is_file(), f"the icon {icon!r} is not in the repository"
data = asset.read_bytes()
assert data[:8] == PNG_MAGIC, f"the icon {icon!r} is not a png file"
assert len(data) > len(PNG_MAGIC), f"the icon {icon!r} is empty"
@pytest.mark.unit
def test_the_comfyui_requirement_is_a_version_range(pyproject):
"""``requires-comfyui`` is a version range the registry understands."""
comfy = pyproject.get("tool", {}).get("comfy") or {}
requirement = str(comfy.get("requires-comfyui", ""))
assert VERSION_SPECIFIER_PATTERN.match(requirement), (
f"[tool.comfy].requires-comfyui is not a version range: {requirement!r}"
)
@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()
)
@pytest.mark.unit
def test_the_declared_set_is_the_slimmed_set(pyproject):
"""The host-guarantee policy: the pack declares ``opencv-python-headless``.
The host's own requirements.txt ships torch, torchvision, numpy, einops,
pyyaml, Pillow, scipy, tqdm and requests - the pack declares only the one
image dependency the host does not provide (OpenCV, headless wheel).
"""
declared = set(pyproject["project"]["dependencies"])
assert declared == {"opencv-python-headless"}, sorted(declared)