* fix: eliminate all identified broken windows before Ollama implementation - pyproject.toml: add requires-python>=3.11, real description, remove dead [project.scripts] entry (no main() exists), add system/integration markers - __init__.py: replace pytest-in-sys.modules guard with comfy-in-sys.modules (checks the actual condition; cleaner semantics) - tests/conftest.py: remove duplicate module-level class definitions and the aiohttp mock (real aiohttp is installed; mock blocked integration tests) - circuit_breaker.py: remove copy-pasted INPUT_TYPES boilerplate docstring; logger.debug → logger.warning for ComfyUI-absent branch (degraded state) - random_choice.py: remove copy-pasted INPUT_TYPES boilerplate and dead triple-quoted string literal; fix bare re-raise to log before propagating - format_string.py: print() → logger.warning(); remove # type: ignore on two dict assignments; remove cargo-culted # noqa: F401 (ruff doesn't flag) - scripts/take_screenshots.py: remove unused h_pad and v_pad parameters All 76 tests pass; ruff clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * design(006): full DESIGN phase artefacts for Ollama model integration Adds spec, plan, tasks, 6 BDD feature files, ADRs, and epic file for spec 006-ollama-model-integration (14 nodes ported from darth-veitcher/comfyui-ollama-model-manager, Issue #1 fix, logging harmonisation, live-service integration tests). - specs/006-ollama-model-integration/{spec,plan,tasks}.md - specs/006-ollama-model-integration/features/us{1-6}_*.feature - specs/006-ollama-model-integration/{.beacon.toml,checklists/} - project-management/ADRs/ADR-004-aiohttp-over-httpx-for-ollama.md - project-management/ADRs/ADR-005-ollama-host-config-via-client-node.md - project-management/Roadmap/epics/ollama-integration.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * chore(006): Phase 1 setup — Ollama fixtures, Justfile recipes, test skeleton - conftest.py: add ollama_host (session), ollama_available (session), skip_if_no_ollama fixtures for @pytest.mark.integration tests - Justfile: add test, test-unit, test-integration, test-system recipes - tests/test_ollama.py: empty skeleton with module docstring and lazy-import block (uncommented phase-by-phase as ollama.py is built) Closes T001 (system marker — done in broken-windows commit), T002, T003, T004. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * feat(006): Phase 3 foundational — ollama.py, ollama.js, __init__ wiring (T011-T014) - src/comfydv/ollama.py: OllamaClientType, _run_async, _fetch_models, _post_json, _DEFAULT_MODELS (populated at import), /dv/ollama/models route, all 14 node classes (US1-US6) with correct ComfyUI contract - src/js/ollama.js: app.registerExtension for OllamaModelSelector/LoadModel/ ChatCompletion — refreshModelDropdown + ⟳ refresh button - src/comfydv/__init__.py: register all 14 Ollama nodes in NODE_CLASS_MAPPINGS and NODE_DISPLAY_NAME_MAPPINGS Closes T011, T012, T013, T014. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * test(006): full Ollama test suite — T015-T031 all US TDD-T commits (T-T032) Add tests/test_ollama.py with 6 test classes covering all 14 nodes: - TestUS1OllamaConnection: client type, custom host, unreachable error - TestUS2ModelSelection: fetch list, selector output, COMBO type, empty fallback - TestUS3ModelLifecycle: COMBO type, empty-model guard, load/unload integration - TestUS4ChatCompletion: COMBO type, single-turn, multi-turn, history growth - TestUS5ComposableOptions: all 7 option nodes + chaining + deterministic - TestUS6HistoryInspection: debug output, length counts - TestNodeContracts: parametrised over all 14 nodes for ComfyUI contract Also remove tests/__init__.py — its presence caused pytest to walk up past the repo root and add the parent directory to sys.path, making the root-level __init__.py win the 'comfydv' namespace over src/comfydv/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * style: ruff format test_ollama.py Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * feat(006): T032/T034 — extend packaging tests and manager entry for 14 Ollama nodes Update EXPECTED_NODENAMES in test_packaging.py to include all 14 Ollama node display names. Update comfy-manager-entry.json nodename array and description to register all 14 nodes with ComfyUI Manager. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * docs(006): T033 — add Ollama section to README and docs/index.md Add all 14 Ollama nodes to the node reference table and add a dedicated Ollama section covering minimal workflow, option nodes, and multi-turn conversation patterns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * test(006): T035-T/I — TestLoggingConsistency: no print(), correct log levels Add TestLoggingConsistency class to tests/test_logging.py: - AST scan: assert zero print() calls across all src/comfydv/*.py - circuit_breaker: ComfyUI-absent branch uses logger.warning() not debug - random_choice: exception path calls logger.error() and uses plain raise - ollama: absent-ComfyUI paths emit at least 2 logger.warning() calls All checks pass (fixes were already in Phase 2 broken windows commit). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * docs: add Quickstart section to README — satisfies beacon doctor readme-completeness Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * chore(006): mark all 55 tasks complete in tasks.md — spec fully implemented Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb * docs(006): T036/T037 — add Ollama screenshots and docker extra_hosts for host Ollama routing Captures 4 Ollama node screenshots (client, chat, workflow, options) via Playwright against the live dev ComfyUI instance. Adds extra_hosts to docker-compose.dev.yml so the container can reach host-machine Ollama. Updates README and docs/index.md to embed all 8 screenshots. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWysE6jYn4YjNorLBQ1cXb --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
150 lines
4.1 KiB
Python
150 lines
4.1 KiB
Python
"""
|
|
Pytest configuration and fixtures for comfydv tests.
|
|
|
|
This file sets up mocks for ComfyUI dependencies before any test imports.
|
|
"""
|
|
|
|
import os
|
|
import socket
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
# Add src directory to Python path so we can import modules
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
|
|
|
|
def pytest_configure(config):
|
|
"""Install ComfyUI mocks into sys.modules before any test collection."""
|
|
|
|
class MockInterruptProcessingException(Exception):
|
|
pass
|
|
|
|
class MockModelManagement:
|
|
InterruptProcessingException = MockInterruptProcessingException
|
|
|
|
comfy_module = type(sys)("comfy")
|
|
comfy_module.model_management = MockModelManagement
|
|
sys.modules["comfy"] = comfy_module
|
|
sys.modules["comfy.model_management"] = MockModelManagement
|
|
|
|
class MockRoutes:
|
|
@staticmethod
|
|
def post(path):
|
|
def decorator(func):
|
|
return func
|
|
|
|
return decorator
|
|
|
|
@staticmethod
|
|
def get(path):
|
|
def decorator(func):
|
|
return func
|
|
|
|
return decorator
|
|
|
|
class MockPromptServer:
|
|
def __init__(self):
|
|
self.routes = MockRoutes()
|
|
|
|
MockPromptServer.instance = MockPromptServer()
|
|
|
|
server_module = type(sys)("server")
|
|
server_module.PromptServer = MockPromptServer
|
|
sys.modules["server"] = server_module
|
|
|
|
class MockFolderPaths:
|
|
@staticmethod
|
|
def get_output_directory():
|
|
return "/tmp/comfydv_test"
|
|
|
|
sys.modules["folder_paths"] = MockFolderPaths
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Ollama fixtures (used by @pytest.mark.integration tests)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def ollama_host():
|
|
return "http://localhost:11434"
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def ollama_available():
|
|
try:
|
|
sock = socket.create_connection(("localhost", 11434), timeout=2.0)
|
|
sock.close()
|
|
return True
|
|
except OSError:
|
|
return False
|
|
|
|
|
|
@pytest.fixture
|
|
def skip_if_no_ollama(ollama_available):
|
|
if not ollama_available:
|
|
pytest.skip(
|
|
"Ollama not reachable at localhost:11434 — start Ollama to run integration tests"
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Existing ComfyUI node fixtures
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@pytest.fixture
|
|
def format_string_class():
|
|
"""Provide a fresh FormatString class for each test."""
|
|
import importlib.util
|
|
import os
|
|
|
|
spec = importlib.util.spec_from_file_location(
|
|
"format_string",
|
|
os.path.join(
|
|
os.path.dirname(__file__), "..", "src", "comfydv", "format_string.py"
|
|
),
|
|
)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
FormatString = module.FormatString
|
|
|
|
FormatString.node_configs = {}
|
|
FormatString.RETURN_TYPES = ("STRING", "STRING")
|
|
FormatString.RETURN_NAMES = ("formatted_string", "saved_file_path")
|
|
FormatString.OUTPUT_IS_LIST = (False, False)
|
|
|
|
return FormatString
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_templates():
|
|
"""Fixture providing sample templates for testing."""
|
|
return {
|
|
"simple_one_var": "Hello {name}",
|
|
"simple_two_vars": "Hello {name}, you are {age} years old",
|
|
"simple_three_vars": "{greeting} {name}, you are {age}",
|
|
"jinja2_simple": "Hello {{ name }}",
|
|
"jinja2_filter": "Hello {{ name | upper }}",
|
|
"jinja2_multiple_filters": "{{ first | upper }} {{ last | lower }}",
|
|
"jinja2_datetime": "Current time: {{ now() }}",
|
|
"jinja2_with_math": "Result: {{ value * 2 }}",
|
|
"mixed": "Hello {name}, today is {{ date }}",
|
|
"no_vars": "Hello World",
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_data():
|
|
"""Fixture providing sample data for template rendering."""
|
|
return {
|
|
"name": "Alice",
|
|
"age": "30",
|
|
"greeting": "Hi",
|
|
"first": "John",
|
|
"last": "Doe",
|
|
"date": "2025-11-05",
|
|
"value": 5,
|
|
}
|