Phase 3 of the modernization plan: move the framework-free math out of the comfy-coupled modules so Tier-0 tests can run on plain Linux without ComfyUI, coremltools, or python_coreml_stable_diffusion. New pure-core package (no comfy / coreml / mps imports): - coreml_suite.core.latents: chunk_batch, merge_chunks - coreml_suite.core.controlnet: expand_inputs, no_control, extract_residual_kwargs, chunk_control - coreml_suite.core.inputs: CoreMLInputs (chunks + coreml_kwargs) - coreml_suite.core.sdxl: is_sdxl / is_sdxl_base / is_sdxl_refiner, build_sdxl_time_ids (base len 6, refiner len 5), build_sdxl_text_embeds, sdxl_model_function_wrapper - coreml_suite.core.naming: compose_out_name, lora_names_from_params Thin adapters keep the public import paths: - coreml_suite.latents / coreml_suite.controlnet: re-export from core - coreml_suite.models: CoreMLModelWrapper, CoreMLModelWrapperLCM, add_sdxl_model_options (now uses the pure builders from core.sdxl), get_latent_image, get_model_patcher remain framework-coupled - coreml_suite.nodes: CoreMLConverter.convert now delegates the out_name composition to core.naming.compose_out_name Test infra: - tests/unit/* re-pointed at coreml_suite.core.* - test_chunks.py dropped `from comfy.model_management import ...` and the dead `model_config` fixture (Phase 1 left it broken; Phase 3 removes it entirely) - test_characterization_sdxl_options now targets the pure builders directly via inspect.getclosurevars on the wrapper closure - test_characterization_out_name now calls compose_out_name without the heavy CoreMLConverter monkey-patching that Phase 2 needed - tests/unit/test_tier0_purity.py: new gate that fails if comfy / coremltools / etc leak into sys.modules during a pure `-m unit` run (skipped in mixed runs where m2 / integration legitimately import them) - tests/__init__.py + top-level conftest.py + pyproject addopts `--import-mode=importlib --confcutdir=tests` together stop pytest from importing the repo-root `__init__.py` (the ComfyUI custom-node entry pulls in comfy) - tests/conftest.py adds tier-aware collect_ignore so `-m unit` skips tests/m2 + tests/integration at collection time Verification: - `pytest -m unit tests/` → 88 passed in ~2s; deterministic across runs - Tier-0 purity gate confirms no comfy/coreml/etc in sys.modules - m2 golden image (Phase 2 anchor) still hashes identical → refactor produced bit-for-bit unchanged output - `git diff main -- __init__.py coreml_suite/nodes.py` shows zero churn to NODE_CLASS_MAPPINGS keys or INPUT_TYPES field names (public workflow contract intact)
76 lines
2.3 KiB
Python
76 lines
2.3 KiB
Python
"""Pytest bootstrap for ComfyUI-CoreMLSuite tests.
|
|
|
|
- Adds the ComfyUI checkout to sys.path so production modules that
|
|
transitively import `comfy.*` resolve when pytest is invoked from this
|
|
package's root. Phase 3 will split pure logic into a comfy-free core and
|
|
this hack can go.
|
|
- Auto-applies tier markers based on the directory a test lives in, so
|
|
individual files don't have to repeat @pytest.mark.unit / .m2.
|
|
- Skips the maintainer's in-progress test scaffolds so they don't break
|
|
collection (they reference modules / venv layouts that aren't part of
|
|
Phase 2 scope).
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
COMFY_DIR = REPO_ROOT.parents[1]
|
|
|
|
for p in (str(COMFY_DIR), str(REPO_ROOT)):
|
|
if p not in sys.path:
|
|
sys.path.insert(0, p)
|
|
|
|
|
|
# Skip WIP test scaffolds left in the tree by the maintainer; they import
|
|
# modules (coreml_suite.experiments, convert_apple) that are not part of
|
|
# Phase 2 scope.
|
|
collect_ignore_glob = [
|
|
"unit/test_experiments.py",
|
|
"unit/test_unet_conversion.py",
|
|
"unit/standalone_test.py",
|
|
]
|
|
|
|
|
|
_TIER_BY_DIR = {
|
|
"tests/unit": "unit",
|
|
"tests/m2": "m2",
|
|
"tests/integration": "m2",
|
|
"tests/smoke": "smoke",
|
|
}
|
|
|
|
# When the user asks for a single tier (-m unit / -m m2), skip the other
|
|
# directories at collection time. Tier-0 cannot afford to import tests/m2
|
|
# files because they pull in PIL + ComfyUI runtime which Linux CI won't have.
|
|
_TIER_DIRS = {
|
|
"unit": ("/tests/unit/",),
|
|
"m2": ("/tests/m2/", "/tests/integration/"),
|
|
"smoke": ("/tests/smoke/",),
|
|
}
|
|
|
|
|
|
def pytest_ignore_collect(collection_path, config):
|
|
expr = config.option.markexpr
|
|
if expr not in _TIER_DIRS:
|
|
return None
|
|
allowed = _TIER_DIRS[expr]
|
|
rel = str(collection_path).replace("\\", "/")
|
|
if "/tests/" not in rel:
|
|
return None
|
|
# Always allow tests/ root + the tier's own dirs.
|
|
if rel.endswith("/tests"):
|
|
return None
|
|
if any(frag in rel + "/" for frag in allowed):
|
|
return None
|
|
return True
|
|
|
|
|
|
def pytest_collection_modifyitems(config, items):
|
|
for item in items:
|
|
path = str(item.fspath).replace("\\", "/")
|
|
for fragment, marker in _TIER_BY_DIR.items():
|
|
if f"/{fragment}/" in path:
|
|
item.add_marker(getattr(pytest.mark, marker))
|
|
break
|