- Async node execution: on ComfyUI with native async support (detected via comfy_execution.utils, added in the same commit as async nodes), all dynamic nodes and Fal Any Endpoint run as coroutines — independent graph branches execute fal calls concurrently with no Submit/Collect required. Uploads/downloads/preflight run off-loop; older ComfyUI versions keep byte-identical sync behavior. Live-verified: two concurrent generations in 2.5s total. - Typed builder nodes (FAL/Utils/Builders): 8 chainable builders (LoRA, embedding, ControlNet, IP-Adapter, reference image/element, multi-prompt shot, key-value, JSON merge) replacing JSON-by-hand for the 467 object-typed inputs across the catalog; shapes validated against live OpenAPI schemas. - Discovery: FAL/Featured tier (data/featured_models.json, 26 flagship endpoints with display-name overrides), 434 models flagged as superseded within their family in node help, thumbnails in the endpoint picker. - Registry freshness: startup delta check against the live catalog (logs how many models are newer than the snapshot), sidebar Registry section with one-click refresh (atomic registry write; restart note). - Docs: README 1,946 → 327 lines; model tables moved to MODELS.md (generator retargeted; weekly refresh workflow now regenerates it); CONTRIBUTING.md redirects hand-written-node PRs to the registry and featured-list workflow. Review fixes: spend-guard preflight moved off the event loop in the async path; registry writes atomically via temp+rename; freshness daemon gated off in tests; non-finite numbers rejected in FalKeyValue; sidebar poll budget aligned with the server timeout.
73 lines
1.7 KiB
Python
73 lines
1.7 KiB
Python
"""Shared fixtures: load the pack exactly like ComfyUI does (hyphenated dir)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import importlib.util
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
PKG = "ComfyUI_fal_API"
|
|
|
|
# never let the freshness daemon make live network calls during tests
|
|
os.environ.setdefault("FAL_DISABLE_STARTUP_CHECK", "1")
|
|
|
|
# keep the persistent result cache out of the user's real cache dir during tests
|
|
os.environ.setdefault(
|
|
"COMFYUI_FAL_API_CACHE_DB",
|
|
str(Path(tempfile.mkdtemp(prefix="fal-api-test-cache-")) / "cache.db"),
|
|
)
|
|
|
|
|
|
def _load_package():
|
|
if PKG in sys.modules:
|
|
return sys.modules[PKG]
|
|
spec = importlib.util.spec_from_file_location(
|
|
PKG, ROOT / "__init__.py", submodule_search_locations=[str(ROOT)]
|
|
)
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[PKG] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def pack():
|
|
"""The fully loaded node pack (static + dynamic mappings)."""
|
|
return _load_package()
|
|
|
|
|
|
def _submodule(name: str):
|
|
_load_package()
|
|
return importlib.import_module(f"{PKG}.{name}")
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def schema_to_inputs():
|
|
return _submodule("nodes.dynamic.schema_to_inputs")
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def arguments_mod():
|
|
return _submodule("nodes.dynamic.arguments")
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def outputs_mod():
|
|
return _submodule("nodes.dynamic.outputs")
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def factory_mod():
|
|
return _submodule("nodes.dynamic.factory")
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def errors_mod():
|
|
return _submodule("nodes.utils.errors")
|