comfy-env 0.0.62__tar.gz → 0.0.65__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {comfy_env-0.0.62 → comfy_env-0.0.65}/PKG-INFO +1 -1
- {comfy_env-0.0.62 → comfy_env-0.0.65}/pyproject.toml +1 -1
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/__init__.py +1 -2
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/config.py +0 -10
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/config_file.py +4 -38
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/pixi.py +20 -22
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/templates/comfy-env.toml +0 -9
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/venv.py +12 -2
- {comfy_env-0.0.62 → comfy_env-0.0.65}/.github/workflows/publish.yml +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/.gitignore +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/LICENSE +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/README.md +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/__init__.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/cli.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/decorator.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/cuda_gpu_detection.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/manager.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/__init__.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/base.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/darwin.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/linux.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/windows.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/security.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/errors.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/install.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/__init__.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/bridge.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/protocol.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/tensor.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/torch_bridge.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/transport.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/worker.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/isolation.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/nodes.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/registry.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/resolver.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stub_imports.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/__init__.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/comfy/__init__.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/comfy/model_management.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/comfy/utils.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/folder_paths.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/wheel_sources.yml +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/__init__.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/base.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/pool.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/tensor_utils.py +0 -0
- {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/torch_mp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: comfy-env
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.65
|
|
4
4
|
Summary: Environment management for ComfyUI custom nodes - CUDA wheel resolution and process isolation
|
|
5
5
|
Project-URL: Homepage, https://github.com/PozzettiAndrea/comfy-env
|
|
6
6
|
Project-URL: Repository, https://github.com/PozzettiAndrea/comfy-env
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Environment management for comfyui-isolation."""
|
|
2
2
|
|
|
3
|
-
from .config import IsolatedEnv
|
|
3
|
+
from .config import IsolatedEnv
|
|
4
4
|
from .manager import IsolatedEnvManager
|
|
5
5
|
from .cuda_gpu_detection import (
|
|
6
6
|
GPUInfo,
|
|
@@ -24,7 +24,6 @@ from .security import (
|
|
|
24
24
|
__all__ = [
|
|
25
25
|
"IsolatedEnv",
|
|
26
26
|
"IsolatedEnvManager",
|
|
27
|
-
"ToolConfig",
|
|
28
27
|
# GPU Detection
|
|
29
28
|
"GPUInfo",
|
|
30
29
|
"CUDAEnvironment",
|
|
@@ -46,14 +46,6 @@ class NodeReq:
|
|
|
46
46
|
repo: str # GitHub repo path, e.g., "Kosinkadink/ComfyUI-VideoHelperSuite"
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
@dataclass
|
|
50
|
-
class ToolConfig:
|
|
51
|
-
"""Configuration for an external tool like Blender."""
|
|
52
|
-
name: str
|
|
53
|
-
version: str = "latest"
|
|
54
|
-
install_dir: Optional[Path] = None
|
|
55
|
-
|
|
56
|
-
|
|
57
49
|
@dataclass
|
|
58
50
|
class EnvManagerConfig:
|
|
59
51
|
"""
|
|
@@ -67,14 +59,12 @@ class EnvManagerConfig:
|
|
|
67
59
|
[envname.cuda] - CUDA packages for isolated env
|
|
68
60
|
[envname.packages] - Regular packages for isolated env
|
|
69
61
|
[node_reqs] - Node dependencies
|
|
70
|
-
[tools] - External tools (e.g., blender = "4.2")
|
|
71
62
|
[wheel_sources] - Custom wheel URL templates (override registry)
|
|
72
63
|
"""
|
|
73
64
|
system: SystemConfig = field(default_factory=SystemConfig)
|
|
74
65
|
local: LocalConfig = field(default_factory=LocalConfig)
|
|
75
66
|
envs: Dict[str, "IsolatedEnv"] = field(default_factory=dict)
|
|
76
67
|
node_reqs: List[NodeReq] = field(default_factory=list)
|
|
77
|
-
tools: Dict[str, ToolConfig] = field(default_factory=dict)
|
|
78
68
|
wheel_sources: Dict[str, str] = field(default_factory=dict) # package -> wheel_template URL
|
|
79
69
|
|
|
80
70
|
@property
|
|
@@ -63,7 +63,7 @@ else:
|
|
|
63
63
|
except ImportError:
|
|
64
64
|
tomllib = None # type: ignore
|
|
65
65
|
|
|
66
|
-
from .config import IsolatedEnv, EnvManagerConfig, LocalConfig, NodeReq, SystemConfig,
|
|
66
|
+
from .config import IsolatedEnv, EnvManagerConfig, LocalConfig, NodeReq, SystemConfig, CondaConfig
|
|
67
67
|
from .cuda_gpu_detection import detect_cuda_version
|
|
68
68
|
|
|
69
69
|
|
|
@@ -168,7 +168,7 @@ def _get_default_pytorch_version(cuda_version: Optional[str]) -> str:
|
|
|
168
168
|
- CUDA 12.8 (Turing+): PyTorch 2.8.0
|
|
169
169
|
"""
|
|
170
170
|
if cuda_version == "12.4":
|
|
171
|
-
return "2.
|
|
171
|
+
return "2.4.0" # Pascal GPUs (last PyTorch with sm_60/61 support)
|
|
172
172
|
return "2.8.0" # Modern: Turing through Blackwell
|
|
173
173
|
|
|
174
174
|
|
|
@@ -332,7 +332,7 @@ def _substitute_vars(s: str, variables: Dict[str, str]) -> str:
|
|
|
332
332
|
# =============================================================================
|
|
333
333
|
|
|
334
334
|
# Reserved table names that are NOT isolated environments
|
|
335
|
-
RESERVED_TABLES = {"local", "node_reqs", "env", "packages", "sources", "cuda", "variables", "worker", "
|
|
335
|
+
RESERVED_TABLES = {"local", "node_reqs", "env", "packages", "sources", "cuda", "variables", "worker", "system", "wheel_sources"}
|
|
336
336
|
|
|
337
337
|
|
|
338
338
|
def load_config(
|
|
@@ -431,7 +431,6 @@ def _parse_full_config(data: Dict[str, Any], base_dir: Path) -> EnvManagerConfig
|
|
|
431
431
|
local = _parse_local_section(data.get("local", {}))
|
|
432
432
|
envs = _parse_env_sections(data, base_dir)
|
|
433
433
|
node_reqs = _parse_node_reqs(data.get("node_reqs", {}))
|
|
434
|
-
tools = _parse_tools_section(data.get("tools", {}))
|
|
435
434
|
wheel_sources = _parse_wheel_sources_section(data.get("wheel_sources", {}))
|
|
436
435
|
|
|
437
436
|
return EnvManagerConfig(
|
|
@@ -439,7 +438,6 @@ def _parse_full_config(data: Dict[str, Any], base_dir: Path) -> EnvManagerConfig
|
|
|
439
438
|
local=local,
|
|
440
439
|
envs=envs,
|
|
441
440
|
node_reqs=node_reqs,
|
|
442
|
-
tools=tools,
|
|
443
441
|
wheel_sources=wheel_sources,
|
|
444
442
|
)
|
|
445
443
|
|
|
@@ -614,35 +612,6 @@ def _parse_node_reqs(node_reqs_data: Dict[str, Any]) -> List[NodeReq]:
|
|
|
614
612
|
return reqs
|
|
615
613
|
|
|
616
614
|
|
|
617
|
-
def _parse_tools_section(tools_data: Dict[str, Any]) -> Dict[str, ToolConfig]:
|
|
618
|
-
"""Parse [tools] section.
|
|
619
|
-
|
|
620
|
-
Supports:
|
|
621
|
-
[tools]
|
|
622
|
-
blender = "4.2"
|
|
623
|
-
|
|
624
|
-
Or extended:
|
|
625
|
-
[tools.blender]
|
|
626
|
-
version = "4.2"
|
|
627
|
-
install_dir = "/custom/path"
|
|
628
|
-
"""
|
|
629
|
-
tools = {}
|
|
630
|
-
|
|
631
|
-
for name, value in tools_data.items():
|
|
632
|
-
if isinstance(value, str):
|
|
633
|
-
# Simple format: blender = "4.2"
|
|
634
|
-
tools[name] = ToolConfig(name=name, version=value)
|
|
635
|
-
elif isinstance(value, dict):
|
|
636
|
-
# Extended format: [tools.blender] with version, install_dir
|
|
637
|
-
version = value.get("version", "latest")
|
|
638
|
-
install_dir = value.get("install_dir")
|
|
639
|
-
if install_dir:
|
|
640
|
-
install_dir = Path(install_dir)
|
|
641
|
-
tools[name] = ToolConfig(name=name, version=version, install_dir=install_dir)
|
|
642
|
-
|
|
643
|
-
return tools
|
|
644
|
-
|
|
645
|
-
|
|
646
615
|
def _parse_system_section(system_data: Dict[str, Any]) -> SystemConfig:
|
|
647
616
|
"""Parse [system] section.
|
|
648
617
|
|
|
@@ -698,8 +667,7 @@ def _convert_simple_to_full(data: Dict[str, Any], base_dir: Path) -> EnvManagerC
|
|
|
698
667
|
# Parse using simple parser to get IsolatedEnv
|
|
699
668
|
simple_env = _parse_config(data, base_dir)
|
|
700
669
|
|
|
701
|
-
# Parse
|
|
702
|
-
tools = _parse_tools_section(data.get("tools", {}))
|
|
670
|
+
# Parse system and wheel_sources sections (shared between simple and full format)
|
|
703
671
|
system = _parse_system_section(data.get("system", {}))
|
|
704
672
|
wheel_sources = _parse_wheel_sources_section(data.get("wheel_sources", {}))
|
|
705
673
|
|
|
@@ -714,7 +682,6 @@ def _convert_simple_to_full(data: Dict[str, Any], base_dir: Path) -> EnvManagerC
|
|
|
714
682
|
local=LocalConfig(),
|
|
715
683
|
envs={simple_env.name: simple_env},
|
|
716
684
|
node_reqs=[],
|
|
717
|
-
tools=tools,
|
|
718
685
|
wheel_sources=wheel_sources,
|
|
719
686
|
)
|
|
720
687
|
else:
|
|
@@ -735,6 +702,5 @@ def _convert_simple_to_full(data: Dict[str, Any], base_dir: Path) -> EnvManagerC
|
|
|
735
702
|
),
|
|
736
703
|
envs={},
|
|
737
704
|
node_reqs=[],
|
|
738
|
-
tools=tools,
|
|
739
705
|
wheel_sources=wheel_sources,
|
|
740
706
|
)
|
|
@@ -329,15 +329,10 @@ def create_pixi_toml(
|
|
|
329
329
|
lines.append(f'name = "{env_config.name}"')
|
|
330
330
|
lines.append('version = "0.1.0"')
|
|
331
331
|
|
|
332
|
-
# Channels -
|
|
332
|
+
# Channels - use conda-forge only (pytorch channel is deprecated)
|
|
333
|
+
# PyTorch is installed via PyPI with extra-index-urls for proper CUDA version support
|
|
333
334
|
base_channels = conda.channels or ["conda-forge"]
|
|
334
|
-
|
|
335
|
-
# GPU detected - add pytorch and nvidia channels for CUDA support
|
|
336
|
-
channels = ["pytorch", "nvidia"] + [ch for ch in base_channels if ch not in ["pytorch", "nvidia"]]
|
|
337
|
-
else:
|
|
338
|
-
# No GPU - just add pytorch channel for CPU-only pytorch
|
|
339
|
-
channels = ["pytorch"] + [ch for ch in base_channels if ch != "pytorch"]
|
|
340
|
-
channels_str = ", ".join(f'"{ch}"' for ch in channels)
|
|
335
|
+
channels_str = ", ".join(f'"{ch}"' for ch in base_channels)
|
|
341
336
|
lines.append(f"channels = [{channels_str}]")
|
|
342
337
|
|
|
343
338
|
# Platforms
|
|
@@ -365,20 +360,6 @@ def create_pixi_toml(
|
|
|
365
360
|
lines.append(f'python = "{env_config.python}.*"')
|
|
366
361
|
lines.append('pip = "*"') # Required for installing CUDA packages with --no-deps
|
|
367
362
|
|
|
368
|
-
# Add PyTorch via conda
|
|
369
|
-
# - With GPU: pytorch + pytorch-cuda for CUDA support
|
|
370
|
-
# - No GPU: pytorch 2.8.0 CPU-only (default)
|
|
371
|
-
torch_version = env_config.pytorch_version or "2.8.0"
|
|
372
|
-
torch_parts = torch_version.split(".")
|
|
373
|
-
torch_mm = ".".join(torch_parts[:2]) # "2.8.0" -> "2.8"
|
|
374
|
-
lines.append(f'pytorch = "{torch_mm}.*"')
|
|
375
|
-
|
|
376
|
-
if env_config.cuda:
|
|
377
|
-
# GPU detected - add pytorch-cuda for CUDA runtime
|
|
378
|
-
cuda_parts = env_config.cuda.split(".")
|
|
379
|
-
cuda_mm = ".".join(cuda_parts[:2]) # "12.8" -> "12.8"
|
|
380
|
-
lines.append(f'pytorch-cuda = "{cuda_mm}"')
|
|
381
|
-
|
|
382
363
|
# On Windows, use MKL BLAS to avoid OpenBLAS crashes (numpy blas_fpe_check issue)
|
|
383
364
|
if sys.platform == "win32":
|
|
384
365
|
lines.append('libblas = { version = "*", build = "*mkl" }')
|
|
@@ -455,6 +436,23 @@ def create_pixi_toml(
|
|
|
455
436
|
elif sys.platform == "win32" and env_config.windows_requirements:
|
|
456
437
|
pypi_deps.extend(env_config.windows_requirements)
|
|
457
438
|
|
|
439
|
+
# PyPI options for PyTorch - use CUDA index for GPU, plain PyPI for CPU
|
|
440
|
+
# The pytorch conda channel is deprecated, so we use PyPI wheels
|
|
441
|
+
if env_config.cuda:
|
|
442
|
+
# GPU detected - use CUDA-enabled PyTorch wheels
|
|
443
|
+
cuda_parts = env_config.cuda.split(".")
|
|
444
|
+
cuda_short = "".join(cuda_parts[:2]) # "12.8" -> "128"
|
|
445
|
+
lines.append("[pypi-options]")
|
|
446
|
+
lines.append(f'extra-index-urls = ["https://download.pytorch.org/whl/cu{cuda_short}"]')
|
|
447
|
+
lines.append("")
|
|
448
|
+
# For CPU-only, no extra index needed - plain torch from PyPI works
|
|
449
|
+
|
|
450
|
+
# Add torch to pypi dependencies
|
|
451
|
+
torch_version = env_config.pytorch_version or "2.8.0"
|
|
452
|
+
torch_parts = torch_version.split(".")
|
|
453
|
+
torch_mm = ".".join(torch_parts[:2]) # "2.8.0" -> "2.8"
|
|
454
|
+
pypi_deps.insert(0, f"torch>={torch_mm},<{torch_parts[0]}.{int(torch_parts[1])+1}")
|
|
455
|
+
|
|
458
456
|
if pypi_deps or special_deps:
|
|
459
457
|
lines.append("[pypi-dependencies]")
|
|
460
458
|
|
|
@@ -85,15 +85,6 @@ requirements = []
|
|
|
85
85
|
# ComfyUI-Impact-Pack = "ltdrdata/ComfyUI-Impact-Pack"
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
# =============================================================================
|
|
89
|
-
# EXTERNAL TOOLS (optional)
|
|
90
|
-
# =============================================================================
|
|
91
|
-
# External applications required by the node.
|
|
92
|
-
|
|
93
|
-
[tools]
|
|
94
|
-
# blender = "4.2"
|
|
95
|
-
|
|
96
|
-
|
|
97
88
|
# #############################################################################
|
|
98
89
|
#
|
|
99
90
|
# PROCESS ISOLATION (ADVANCED)
|
|
@@ -204,6 +204,11 @@ def _serialize_for_ipc(obj, visited=None):
|
|
|
204
204
|
if obj_id in visited:
|
|
205
205
|
return visited[obj_id] # Return cached serialized result
|
|
206
206
|
|
|
207
|
+
# Handle Path objects - convert to string for JSON serialization
|
|
208
|
+
from pathlib import PurePath
|
|
209
|
+
if isinstance(obj, PurePath):
|
|
210
|
+
return str(obj)
|
|
211
|
+
|
|
207
212
|
# Check if this is a custom object with broken module path
|
|
208
213
|
if (hasattr(obj, '__dict__') and
|
|
209
214
|
hasattr(obj, '__class__') and
|
|
@@ -762,7 +767,10 @@ def _should_use_reference(obj):
|
|
|
762
767
|
# Dicts, lists, tuples - recurse into contents (don't ref the container)
|
|
763
768
|
if isinstance(obj, (dict, list, tuple)):
|
|
764
769
|
return False
|
|
765
|
-
#
|
|
770
|
+
# Trimesh - pass by value (pickle handles it well across Python versions)
|
|
771
|
+
if obj_type == 'Trimesh':
|
|
772
|
+
return False
|
|
773
|
+
# Everything else (custom classes) - pass by reference
|
|
766
774
|
return True
|
|
767
775
|
|
|
768
776
|
def _serialize_result(obj, visited=None):
|
|
@@ -1435,12 +1443,14 @@ class PersistentVenvWorker(Worker):
|
|
|
1435
1443
|
print(f"[PersistentVenvWorker] saved inputs", file=sys.stderr, flush=True)
|
|
1436
1444
|
|
|
1437
1445
|
# Send request with class info
|
|
1446
|
+
# Serialize self_state to handle Path objects and other non-JSON types
|
|
1447
|
+
serialized_self_state = _serialize_for_ipc(self_state) if self_state else None
|
|
1438
1448
|
request = {
|
|
1439
1449
|
"type": "call_method",
|
|
1440
1450
|
"module": module_name,
|
|
1441
1451
|
"class_name": class_name,
|
|
1442
1452
|
"method_name": method_name,
|
|
1443
|
-
"self_state":
|
|
1453
|
+
"self_state": serialized_self_state,
|
|
1444
1454
|
"inputs_path": str(inputs_path) if kwargs else None,
|
|
1445
1455
|
"outputs_path": str(outputs_path),
|
|
1446
1456
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|