Files
ComfyAssets-ComfyUI_PromptM…/tests/test_packaging.py
T
Vito Sansevero 5093cb213f chore: valid packaging metadata, flake8 config file, ignore local config with secrets
pyproject.toml carried requirements.txt comment lines as dependencies, which
fails PEP 508 parsing. flake8 never read [tool.flake8] from pyproject, so the
settings move to .flake8 and pre-commit runs the full rule set. config.json
(holds the CivitAI API key and machine paths) and other local artifacts are
now ignored. coverage joins the dev requirements.
2026-10-08 18:01:34 -07:00

101 lines
3.3 KiB
Python

"""Packaging and repository hygiene contracts.
These guard the metadata that ComfyUI-Manager, the Comfy Registry and
``pip install .`` consume, and the ignore rules that keep local secrets
(``config.json`` holds the CivitAI API key) out of the repository.
"""
import os
import re
import unittest
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# PEP 508 requirement: name, optional extras, optional version spec.
_VERSION_CLAUSE = r"[<>=!~]=?\s*[A-Za-z0-9.*+!-]+\s*"
_REQUIREMENT = re.compile(
r"^[A-Za-z0-9][A-Za-z0-9._-]*" # distribution name
r"(\[[A-Za-z0-9,._-]+\])?\s*" # optional extras
r"(" + _VERSION_CLAUSE + r"(,\s*" + _VERSION_CLAUSE + r")*)?$" # version spec
)
def _read(name):
with open(os.path.join(ROOT, name), encoding="utf-8") as fh:
return fh.read()
def _pyproject():
try:
import tomllib # Python 3.11+
except ImportError: # pragma: no cover - exercised on 3.10 only
tomllib = None
text = _read("pyproject.toml")
if tomllib is not None:
return tomllib.loads(text)
# Minimal fallback for 3.10: pull the dependency list out with a regex.
match = re.search(r"dependencies\s*=\s*\[(.*?)\]", text, re.S)
deps = re.findall(r'"([^"]*)"', match.group(1)) if match else []
return {
"project": {
"dependencies": deps,
"requires-python": (
re.search(r'requires-python\s*=\s*"([^"]+)"', text).group(1)
if "requires-python" in text
else None
),
},
"build-system": {} if "[build-system]" in text else None,
}
class PyprojectContract(unittest.TestCase):
def test_dependencies_are_valid_requirements(self):
deps = _pyproject()["project"]["dependencies"]
self.assertTrue(deps, "dependencies must not be empty")
for dep in deps:
self.assertRegex(dep, _REQUIREMENT, f"not a PEP 508 requirement: {dep!r}")
def test_dependencies_match_requirements_txt(self):
deps = set(_pyproject()["project"]["dependencies"])
wanted = {
line.split("#", 1)[0].strip()
for line in _read("requirements.txt").splitlines()
if line.split("#", 1)[0].strip()
}
self.assertEqual(deps, wanted)
def test_requires_python_floor_is_3_10(self):
self.assertEqual(_pyproject()["project"]["requires-python"], ">=3.10")
def test_build_system_is_declared(self):
self.assertIsNotNone(_pyproject().get("build-system"))
class IgnoreRulesContract(unittest.TestCase):
def test_local_secrets_and_artifacts_are_ignored(self):
patterns = {
line.strip()
for line in _read(".gitignore").splitlines()
if line.strip() and not line.startswith("#")
}
for required in (
"config.json",
"resume.sh",
"*.backup_*",
"promptmanager_logs/",
):
self.assertIn(required, patterns)
class LintConfigContract(unittest.TestCase):
def test_flake8_reads_its_own_config_file(self):
# flake8 ignores pyproject.toml, so the settings must live in .flake8.
text = _read(".flake8")
self.assertIn("max-line-length = 88", text)
self.assertIn("E203", text)
if __name__ == "__main__":
unittest.main()