From 5093cb213fb0127e1fdf39cc02f51648b56bc0fb Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Wed, 7 Oct 2026 18:33:47 -0700 Subject: [PATCH] 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. --- .coveragerc | 3 ++ .flake8 | 4 ++ .gitignore | 6 +++ .pre-commit-config.yaml | 2 +- pyproject.toml | 12 ++--- requirements-dev.txt | 3 ++ requirements.txt | 30 ++---------- tests/test_packaging.py | 100 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 127 insertions(+), 33 deletions(-) create mode 100644 .flake8 create mode 100644 tests/test_packaging.py diff --git a/.coveragerc b/.coveragerc index 9eded8d..fd37943 100644 --- a/.coveragerc +++ b/.coveragerc @@ -14,6 +14,9 @@ omit = */node_modules/* */static/* */media/* + */htmlcov/* + restart_gallery.py + standalone_tagger.py branch = true parallel = true diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..8283733 --- /dev/null +++ b/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 88 +extend-ignore = E203, W503 +exclude = reference/, .git, __pycache__, web/, venv/, htmlcov/, build/, dist/ diff --git a/.gitignore b/.gitignore index 59734d7..c335b78 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,12 @@ AGENTS.md CLAUDE.md # Local files +# Local PromptManager state (config.json holds API keys and machine paths) +config.json +resume.sh +*.backup_* +promptmanager_logs/ +custom_data/ data/ docs/ logs/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b69bc2..d7efa4e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: flake8 name: flake8 - entry: flake8 --select=E9,F63,F7,F82 --show-source --exclude=reference/,web/ + entry: flake8 --show-source language: system types: [python] diff --git a/pyproject.toml b/pyproject.toml index 188eef9..c177f4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,12 @@ name = "promptmanager" description = "A powerful ComfyUI custom node that extends the standard text encoder with persistent prompt storage, advanced search capabilities, and an automatic image gallery system using SQLite." version = "3.2.4" license = {file = "LICENSE"} -dependencies = ["# Core dependencies for PromptManager", "# Note: Most dependencies are already included with ComfyUI", "# Already included with Python standard library:", "# - sqlite3", "# - hashlib", "# - json", "# - datetime", "# - os", "# - typing", "# - threading", "# - uuid", "# Required for gallery functionality:", "watchdog>=2.1.0 # For file system monitoring", "Pillow>=8.0.0 # For image metadata extraction (usually included with ComfyUI)", "# Optional dependencies for enhanced search functionality:", "# fuzzywuzzy[speedup]>=0.18.0 # For fuzzy string matching (optional)", "# sqlalchemy>=1.4.0 # For advanced ORM features (optional)", "# Development dependencies (optional):", "# pytest>=6.0.0 # For running tests", "# black>=22.0.0 # For code formatting", "# flake8>=4.0.0 # For linting", "# mypy>=0.910 # For type checking"] +requires-python = ">=3.10" +dependencies = ["watchdog>=2.1.0", "Pillow>=8.0.0"] + +[build-system] +requires = ["setuptools>=61"] +build-backend = "setuptools.build_meta" [project.urls] Repository = "https://github.com/ComfyAssets/ComfyUI_PromptManager" @@ -18,10 +23,5 @@ Icon = "https://avatars.githubusercontent.com/u/213204677?s=200" line-length = 88 target-version = ["py310"] -[tool.flake8] -max-line-length = 88 -extend-ignore = ["E203", "W503"] -exclude = ["reference/", ".git", "__pycache__", "web/", "venv/"] - [tool.bandit] exclude_dirs = ["tests", "reference"] diff --git a/requirements-dev.txt b/requirements-dev.txt index f2539a6..9acf917 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,6 +3,9 @@ watchdog>=2.1.0 Pillow>=8.0.0 aiohttp>=3.8.0 +# Tests and coverage +coverage>=7.0 + # Code quality black>=24.0.0 flake8>=7.0.0 diff --git a/requirements.txt b/requirements.txt index 815e196..f5f32b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,26 +1,4 @@ -# Core dependencies for PromptManager -# Note: Most dependencies are already included with ComfyUI - -# Already included with Python standard library: -# - sqlite3 -# - hashlib -# - json -# - datetime -# - os -# - typing -# - threading -# - uuid - -# Required for gallery functionality: -watchdog>=2.1.0 # For file system monitoring -Pillow>=8.0.0 # For image metadata extraction (usually included with ComfyUI) - -# Optional dependencies for enhanced search functionality: -# fuzzywuzzy[speedup]>=0.18.0 # For fuzzy string matching (optional) -# sqlalchemy>=1.4.0 # For advanced ORM features (optional) - -# Development dependencies (optional): -# pytest>=6.0.0 # For running tests -# black>=22.0.0 # For code formatting -# flake8>=4.0.0 # For linting -# mypy>=0.910 # For type checking \ No newline at end of file +# Runtime dependencies for PromptManager. +# aiohttp, numpy and torch come from ComfyUI itself and are not listed here. +watchdog>=2.1.0 # Output directory monitoring +Pillow>=8.0.0 # Image metadata extraction and thumbnails diff --git a/tests/test_packaging.py b/tests/test_packaging.py new file mode 100644 index 0000000..8f7925c --- /dev/null +++ b/tests/test_packaging.py @@ -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()