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.
This commit is contained in:
Vito Sansevero
2026-10-08 18:01:34 -07:00
parent 6c7e4d5b35
commit 5093cb213f
8 changed files with 127 additions and 33 deletions
+100
View File
@@ -0,0 +1,100 @@
"""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()