Files
malkuthro-ComfyUI-Koolook/tests/scripts/test_sync_to_dev.py
T
malkuthroandClaude Opus 4.8 447465ecd8 refactor(nodes): remove superseded LTX Director extra nodes + harden registry (#198) (#199)
* refactor(nodes): remove superseded LTX Director extra nodes + harden registry (#198)

Remove the two experimental nodes layered on the WhatDreamsCost fork — KoolookAudioTranscriptTimeline (k_audio_timeline.py) and KoolookTimelineEditor (k_timeline_editor.py) — plus the transcribe_audio_timeline.py CLI and its test. The audio-transcript to Director-timing job now lives inside the fork via the Director's audio_transcript_json input, so the standalone nodes are redundant. Also drops the orphaned [audio]/faster-whisper extra and updates packaging, dev-sync, web, and docs references.

Harden the node registry against the #183 failure: __init__.py now imports each node group independently and installs the /koolook/presets/* routes regardless of node-import results, so one missing or broken module degrades to 'that node absent' instead of zeroing every node and 404'ing the sidebar disk routes. A new test keeps every root k_*.py listed in dev-sync's RUNTIME_PATHS.

Closes #198.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(nodes): ship loader gates via dev-sync-audio; generalize RUNTIME_PATHS guard (#198)

Address the K-Flame review on #199:

MEDIUM — the #198 refactor made koolook_versioning.py a single registration gate, but dev-sync-audio shipped the new __init__.py without it (and the k_*.py-glob guard test couldn't see it). Add koolook_versioning.py AND koolook_install_guard.py (whose absolute-import fallback raises uncaught) to AUDIO_PATHS so a scoped sync can never leave the loader pointing at a module the target lacks.

Generalize the guard test: parse __init__.py's actual load-time import targets (relative imports + _merge_node_group calls) and assert each is in RUNTIME_PATHS, instead of globbing k_*.py which missed the non-k_ gates. Add an AUDIO_PATHS gate-coverage test.

LOW — CHANGELOG now records the [audio]/faster-whisper + transcribe_audio_timeline.py removal as an external-contract break.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 19:47:25 +02:00

79 lines
3.5 KiB
Python

"""Guards on which modules ``dev-sync`` ships, so the loader can never point
at a file the install lacks.
The #183 incident (root cause behind #198): a module that ``__init__.py``
imported but ``scripts/sync_to_dev.py``'s ``RUNTIME_PATHS`` never copied raised
``ImportError`` at startup. After the #198 refactor the blast radius of such a
gap depends on *where* the import sits — a per-group node import degrades to
"that node absent", but the context probe (``koolook_versioning``) and the
install guard gate *all* registration. So the real invariant is: every module
``__init__.py`` imports at load must be shipped by ``RUNTIME_PATHS``. This test
derives those imports from ``__init__.py`` itself (rather than a ``k_*.py``
glob, which misses the non-``k_`` gates) so it can't drift.
"""
from __future__ import annotations
import ast
import importlib.util
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
_SCRIPT = REPO_ROOT / "scripts" / "sync_to_dev.py"
_spec = importlib.util.spec_from_file_location("koolook_sync_to_dev_under_test", _SCRIPT)
assert _spec is not None and _spec.loader is not None
sync_to_dev = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(sync_to_dev)
def _init_load_time_module_deps() -> set[str]:
"""Top-level package modules/packages ``__init__.py`` imports at load.
Covers relative ``from .X import ...`` / ``from . import X`` statements and
the ``_merge_node_group(label, ".X")`` node-group imports. Returns the
first path segment of each (e.g. ``forks.radiance_koolook`` -> ``forks``),
the granularity ``RUNTIME_PATHS`` ships at. Absolute imports (the install
guard's out-of-package fallback) are level 0 and intentionally ignored.
"""
tree = ast.parse((REPO_ROOT / "__init__.py").read_text(encoding="utf-8"))
deps: set[str] = set()
for node in ast.walk(tree):
if isinstance(node, ast.ImportFrom) and (node.level or 0) >= 1:
if node.module: # from .pkg import ...
deps.add(node.module.split(".")[0])
else: # from . import a, b
deps.update(alias.name.split(".")[0] for alias in node.names)
elif (
isinstance(node, ast.Call)
and getattr(node.func, "id", None) == "_merge_node_group"
):
for arg in node.args:
if (
isinstance(arg, ast.Constant)
and isinstance(arg.value, str)
and arg.value.startswith(".")
):
deps.add(arg.value.lstrip(".").split(".")[0])
return deps
def test_init_load_deps_are_shipped_by_runtime_paths():
runtime_paths = set(sync_to_dev.RUNTIME_PATHS)
deps = _init_load_time_module_deps()
# Sanity: the parse actually found the imports (guards against a refactor
# that renames _merge_node_group and silently makes this test vacuous).
assert "koolook_versioning" in deps and "k_ai_pipeline" in deps, (
f"__init__.py import parse looks broken — only found: {sorted(deps)}"
)
# A single-file module ships as "<dep>.py"; a package (e.g. forks) ships as
# its top-level dir entry.
missing = sorted(
dep
for dep in deps
if f"{dep}.py" not in runtime_paths and dep not in runtime_paths
)
assert not missing, (
"__init__.py imports these at load but dev-sync RUNTIME_PATHS does not "
f"ship them: {missing}. Add them to RUNTIME_PATHS in "
"scripts/sync_to_dev.py so a plain dev-sync can't 404 the loader."
)