mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-03-13 17:20:01 +00:00
Adds opt-in process isolation for custom nodes using pyisolate's bwrap sandbox and JSON-RPC bridge. Each isolated node pack runs in its own child process with zero-copy tensor transfer via shared memory. Core infrastructure: - CLI flag --use-process-isolation to enable isolation - Host/child startup fencing via PYISOLATE_CHILD env var - Manifest-driven node discovery and extension loading - JSON-RPC bridge between host and child processes - Shared memory forensics for leak detection Proxy layer: - ModelPatcher, CLIP, VAE, and ModelSampling proxies - Host service proxies (folder_paths, model_management, progress, etc.) - Proxy base with automatic method forwarding Execution integration: - Extension wrapper with V3 hidden param mapping - Runtime helpers for isolated node execution - Host policy for node isolation decisions - Fenced sampler device handling and model ejection parity Serializers for cross-process data transfer: - File3D (GLB), PLY (structured + gaussian), NPZ (streaming frames), VIDEO (VideoFromFile + VideoFromComponents) serializers - data_type flag in SerializerRegistry for type-aware dispatch - Isolated get_temp_directory() fence New core save nodes: - SavePLY and SaveNPZ with comfytype registrations (Ply, Npz) DynamicVRAM compatibility: - comfy-aimdo early init gated by isolation fence Tests: - Integration and policy tests for isolation lifecycle - Manifest loader, host policy, proxy, and adapter unit tests Depends on: pyisolate >= 0.9.2
52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
repo_root = Path(__file__).resolve().parents[1]
|
|
pyisolate_root = repo_root.parent / "pyisolate"
|
|
if pyisolate_root.exists():
|
|
sys.path.insert(0, str(pyisolate_root))
|
|
|
|
from comfy.isolation.adapter import ComfyUIAdapter
|
|
from pyisolate._internal.serialization_registry import SerializerRegistry
|
|
|
|
|
|
def test_identifier():
|
|
adapter = ComfyUIAdapter()
|
|
assert adapter.identifier == "comfyui"
|
|
|
|
|
|
def test_get_path_config_valid():
|
|
adapter = ComfyUIAdapter()
|
|
path = os.path.join("/opt", "ComfyUI", "custom_nodes", "demo")
|
|
cfg = adapter.get_path_config(path)
|
|
assert cfg is not None
|
|
assert cfg["preferred_root"].endswith("ComfyUI")
|
|
assert "custom_nodes" in cfg["additional_paths"][0]
|
|
|
|
|
|
def test_get_path_config_invalid():
|
|
adapter = ComfyUIAdapter()
|
|
assert adapter.get_path_config("/random/path") is None
|
|
|
|
|
|
def test_provide_rpc_services():
|
|
adapter = ComfyUIAdapter()
|
|
services = adapter.provide_rpc_services()
|
|
names = {s.__name__ for s in services}
|
|
assert "PromptServerService" in names
|
|
assert "FolderPathsProxy" in names
|
|
|
|
|
|
def test_register_serializers():
|
|
adapter = ComfyUIAdapter()
|
|
registry = SerializerRegistry.get_instance()
|
|
registry.clear()
|
|
|
|
adapter.register_serializers(registry)
|
|
assert registry.has_handler("ModelPatcher")
|
|
assert registry.has_handler("CLIP")
|
|
assert registry.has_handler("VAE")
|
|
|
|
registry.clear()
|