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.
Files changed (49) hide show
  1. {comfy_env-0.0.62 → comfy_env-0.0.65}/PKG-INFO +1 -1
  2. {comfy_env-0.0.62 → comfy_env-0.0.65}/pyproject.toml +1 -1
  3. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/__init__.py +1 -2
  4. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/config.py +0 -10
  5. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/config_file.py +4 -38
  6. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/pixi.py +20 -22
  7. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/templates/comfy-env.toml +0 -9
  8. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/venv.py +12 -2
  9. {comfy_env-0.0.62 → comfy_env-0.0.65}/.github/workflows/publish.yml +0 -0
  10. {comfy_env-0.0.62 → comfy_env-0.0.65}/.gitignore +0 -0
  11. {comfy_env-0.0.62 → comfy_env-0.0.65}/LICENSE +0 -0
  12. {comfy_env-0.0.62 → comfy_env-0.0.65}/README.md +0 -0
  13. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/__init__.py +0 -0
  14. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/cli.py +0 -0
  15. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/decorator.py +0 -0
  16. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/cuda_gpu_detection.py +0 -0
  17. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/manager.py +0 -0
  18. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/__init__.py +0 -0
  19. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/base.py +0 -0
  20. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/darwin.py +0 -0
  21. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/linux.py +0 -0
  22. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/platform/windows.py +0 -0
  23. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/env/security.py +0 -0
  24. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/errors.py +0 -0
  25. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/install.py +0 -0
  26. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/__init__.py +0 -0
  27. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/bridge.py +0 -0
  28. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/protocol.py +0 -0
  29. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/tensor.py +0 -0
  30. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/torch_bridge.py +0 -0
  31. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/transport.py +0 -0
  32. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/ipc/worker.py +0 -0
  33. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/isolation.py +0 -0
  34. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/nodes.py +0 -0
  35. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/registry.py +0 -0
  36. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/resolver.py +0 -0
  37. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stub_imports.py +0 -0
  38. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/__init__.py +0 -0
  39. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/comfy/__init__.py +0 -0
  40. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/comfy/model_management.py +0 -0
  41. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/comfy/utils.py +0 -0
  42. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/stubs/folder_paths.py +0 -0
  43. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
  44. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/wheel_sources.yml +0 -0
  45. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/__init__.py +0 -0
  46. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/base.py +0 -0
  47. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/pool.py +0 -0
  48. {comfy_env-0.0.62 → comfy_env-0.0.65}/src/comfy_env/workers/tensor_utils.py +0 -0
  49. {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.62
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
  [project]
2
2
  name = "comfy-env"
3
- version = "0.0.62"
3
+ version = "0.0.65"
4
4
  description = "Environment management for ComfyUI custom nodes - CUDA wheel resolution and process isolation"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -1,6 +1,6 @@
1
1
  """Environment management for comfyui-isolation."""
2
2
 
3
- from .config import IsolatedEnv, ToolConfig
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, ToolConfig, CondaConfig
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.5.1" # Full: Pascal GPUs
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", "tools", "system", "wheel_sources"}
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 tools, system, and wheel_sources sections (shared between simple and full format)
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 - add pytorch channel, and nvidia if CUDA GPU detected
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
- if env_config.cuda:
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
- # Everything else (trimesh, custom classes) - pass by reference
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": 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