comfy-env 0.0.55__tar.gz → 0.0.56__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.55 → comfy_env-0.0.56}/PKG-INFO +1 -1
  2. {comfy_env-0.0.55 → comfy_env-0.0.56}/pyproject.toml +1 -1
  3. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/isolation.py +12 -5
  4. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/workers/venv.py +55 -31
  5. {comfy_env-0.0.55 → comfy_env-0.0.56}/.github/workflows/publish.yml +0 -0
  6. {comfy_env-0.0.55 → comfy_env-0.0.56}/.gitignore +0 -0
  7. {comfy_env-0.0.55 → comfy_env-0.0.56}/LICENSE +0 -0
  8. {comfy_env-0.0.55 → comfy_env-0.0.56}/README.md +0 -0
  9. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/__init__.py +0 -0
  10. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/cli.py +0 -0
  11. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/decorator.py +0 -0
  12. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/__init__.py +0 -0
  13. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/config.py +0 -0
  14. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/config_file.py +0 -0
  15. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/cuda_gpu_detection.py +0 -0
  16. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/manager.py +0 -0
  17. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/platform/__init__.py +0 -0
  18. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/platform/base.py +0 -0
  19. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/platform/darwin.py +0 -0
  20. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/platform/linux.py +0 -0
  21. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/platform/windows.py +0 -0
  22. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/env/security.py +0 -0
  23. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/errors.py +0 -0
  24. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/install.py +0 -0
  25. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/ipc/__init__.py +0 -0
  26. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/ipc/bridge.py +0 -0
  27. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/ipc/protocol.py +0 -0
  28. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/ipc/tensor.py +0 -0
  29. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/ipc/torch_bridge.py +0 -0
  30. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/ipc/transport.py +0 -0
  31. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/ipc/worker.py +0 -0
  32. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/nodes.py +0 -0
  33. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/pixi.py +0 -0
  34. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/registry.py +0 -0
  35. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/resolver.py +0 -0
  36. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/stub_imports.py +0 -0
  37. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/stubs/__init__.py +0 -0
  38. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/stubs/comfy/__init__.py +0 -0
  39. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/stubs/comfy/model_management.py +0 -0
  40. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/stubs/comfy/utils.py +0 -0
  41. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/stubs/folder_paths.py +0 -0
  42. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
  43. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/templates/comfy-env.toml +0 -0
  44. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/wheel_sources.yml +0 -0
  45. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/workers/__init__.py +0 -0
  46. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/workers/base.py +0 -0
  47. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/workers/pool.py +0 -0
  48. {comfy_env-0.0.55 → comfy_env-0.0.56}/src/comfy_env/workers/tensor_utils.py +0 -0
  49. {comfy_env-0.0.55 → comfy_env-0.0.56}/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.55
3
+ Version: 0.0.56
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.55"
3
+ version = "0.0.56"
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"}
@@ -30,6 +30,9 @@ from functools import wraps
30
30
  from pathlib import Path
31
31
  from typing import Any, Dict, Optional
32
32
 
33
+ # Debug logging (set COMFY_ENV_DEBUG=1 to enable)
34
+ _DEBUG = os.environ.get("COMFY_ENV_DEBUG", "").lower() in ("1", "true", "yes")
35
+
33
36
  # Global worker cache (one per isolated environment)
34
37
  _workers: Dict[str, Any] = {}
35
38
  _workers_lock = threading.Lock()
@@ -158,11 +161,13 @@ def _wrap_node_class(
158
161
 
159
162
  @wraps(original_method)
160
163
  def proxy(self, **kwargs):
161
- print(f"[comfy-env] PROXY CALLED: {cls.__name__}.{func_name}", flush=True)
162
- print(f"[comfy-env] kwargs keys: {list(kwargs.keys())}", flush=True)
164
+ if _DEBUG:
165
+ print(f"[comfy-env] PROXY CALLED: {cls.__name__}.{func_name}", flush=True)
166
+ print(f"[comfy-env] kwargs keys: {list(kwargs.keys())}", flush=True)
163
167
 
164
168
  worker = _get_worker(env_name, python_path, working_dir, sys_path)
165
- print(f"[comfy-env] worker alive: {worker.is_alive()}", flush=True)
169
+ if _DEBUG:
170
+ print(f"[comfy-env] worker alive: {worker.is_alive()}", flush=True)
166
171
 
167
172
  # Clone tensors for IPC if needed
168
173
  try:
@@ -172,7 +177,8 @@ def _wrap_node_class(
172
177
  except ImportError:
173
178
  pass # No torch available, skip cloning
174
179
 
175
- print(f"[comfy-env] calling worker.call_method...", flush=True)
180
+ if _DEBUG:
181
+ print(f"[comfy-env] calling worker.call_method...", flush=True)
176
182
  result = worker.call_method(
177
183
  module_name=module_name,
178
184
  class_name=cls.__name__,
@@ -181,7 +187,8 @@ def _wrap_node_class(
181
187
  kwargs=kwargs,
182
188
  timeout=600.0,
183
189
  )
184
- print(f"[comfy-env] call_method returned", flush=True)
190
+ if _DEBUG:
191
+ print(f"[comfy-env] call_method returned", flush=True)
185
192
 
186
193
  # Clone result tensors
187
194
  try:
@@ -41,7 +41,10 @@ from pathlib import Path
41
41
  from typing import Any, Callable, Dict, List, Optional, Tuple, Union
42
42
 
43
43
  from .base import Worker, WorkerError
44
+ from ..pixi import get_pixi_path
44
45
 
46
+ # Debug logging (set COMFY_ENV_DEBUG=1 to enable)
47
+ _DEBUG = os.environ.get("COMFY_ENV_DEBUG", "").lower() in ("1", "true", "yes")
45
48
 
46
49
  # =============================================================================
47
50
  # Socket IPC utilities - cross-platform with TCP fallback
@@ -614,16 +617,21 @@ from types import SimpleNamespace
614
617
  # Enable faulthandler to dump traceback on SIGSEGV/SIGABRT/etc
615
618
  faulthandler.enable(file=sys.stderr, all_threads=True)
616
619
 
620
+ # Debug logging (set COMFY_ENV_DEBUG=1 to enable)
621
+ _DEBUG = os.environ.get("COMFY_ENV_DEBUG", "").lower() in ("1", "true", "yes")
622
+
617
623
  # Pre-import bpy FIRST to avoid DLL conflicts with numpy/torch/MKL
618
624
  # bpy's DLLs must be loaded before other packages load conflicting versions
619
625
  try:
620
626
  import bpy
621
- print("[worker] Pre-imported bpy successfully", file=sys.stderr, flush=True)
627
+ if _DEBUG:
628
+ print("[worker] Pre-imported bpy successfully", file=sys.stderr, flush=True)
622
629
  except ImportError as e:
623
630
  # bpy not available in this environment - that's fine
624
631
  pass
625
632
  except Exception as e:
626
- print(f"[worker] bpy pre-import warning: {e}", file=sys.stderr, flush=True)
633
+ if _DEBUG:
634
+ print(f"[worker] bpy pre-import warning: {e}", file=sys.stderr, flush=True)
627
635
 
628
636
  # Watchdog: dump all thread stacks every 60 seconds to catch hangs
629
637
  import threading
@@ -656,7 +664,8 @@ def _watchdog():
656
664
 
657
665
  _watchdog_thread = threading.Thread(target=_watchdog, daemon=True)
658
666
  _watchdog_thread.start()
659
- print(f"[worker] Watchdog started, logging to: {_watchdog_log}", flush=True)
667
+ if _DEBUG:
668
+ print(f"[worker] Watchdog started, logging to: {_watchdog_log}", flush=True)
660
669
 
661
670
  # File-based logging for debugging (persists even if stdout/stderr are swallowed)
662
671
  import tempfile
@@ -676,14 +685,15 @@ def wlog(msg):
676
685
 
677
686
  wlog(f"[worker] === Worker starting, log file: {_worker_log_file} ===")
678
687
 
679
- # Debug: print PATH at startup
680
- _path_sep = ";" if sys.platform == "win32" else ":"
681
- _path_parts = os.environ.get("PATH", "").split(_path_sep)
682
- print(f"[worker] PATH has {len(_path_parts)} entries:", file=sys.stderr, flush=True)
683
- for _i, _p in enumerate(_path_parts[:15]):
684
- print(f"[worker] [{_i}] {_p}", file=sys.stderr, flush=True)
685
- if len(_path_parts) > 15:
686
- print(f"[worker] ... and {len(_path_parts) - 15} more", file=sys.stderr, flush=True)
688
+ # Debug: print PATH at startup (only if debug enabled)
689
+ if _DEBUG:
690
+ _path_sep = ";" if sys.platform == "win32" else ":"
691
+ _path_parts = os.environ.get("PATH", "").split(_path_sep)
692
+ print(f"[worker] PATH has {len(_path_parts)} entries:", file=sys.stderr, flush=True)
693
+ for _i, _p in enumerate(_path_parts[:15]):
694
+ print(f"[worker] [{_i}] {_p}", file=sys.stderr, flush=True)
695
+ if len(_path_parts) > 15:
696
+ print(f"[worker] ... and {len(_path_parts) - 15} more", file=sys.stderr, flush=True)
687
697
 
688
698
  # On Windows, add host Python's DLL directories so packages like opencv can find VC++ runtime
689
699
  if sys.platform == "win32":
@@ -1199,7 +1209,8 @@ class PersistentVenvWorker(Worker):
1199
1209
  # For pixi environments, use "pixi run python" to get proper environment activation
1200
1210
  # (CONDA_PREFIX, Library paths, etc.) which fixes DLL loading issues with bpy
1201
1211
  is_pixi = '.pixi' in str(self.python)
1202
- print(f"[PersistentVenvWorker] is_pixi={is_pixi}, python={self.python}", flush=True)
1212
+ if _DEBUG:
1213
+ print(f"[PersistentVenvWorker] is_pixi={is_pixi}, python={self.python}", flush=True)
1203
1214
  if is_pixi:
1204
1215
  # Find pixi project root (parent of .pixi directory)
1205
1216
  pixi_project = self.python
@@ -1207,10 +1218,14 @@ class PersistentVenvWorker(Worker):
1207
1218
  pixi_project = pixi_project.parent
1208
1219
  pixi_project = pixi_project.parent # Go up from .pixi to project root
1209
1220
  pixi_toml = pixi_project / "pixi.toml"
1210
- print(f"[PersistentVenvWorker] pixi_toml={pixi_toml}, exists={pixi_toml.exists()}", flush=True)
1221
+ if _DEBUG:
1222
+ print(f"[PersistentVenvWorker] pixi_toml={pixi_toml}, exists={pixi_toml.exists()}", flush=True)
1211
1223
 
1212
1224
  if pixi_toml.exists():
1213
- cmd = ["pixi", "run", "--manifest-path", str(pixi_toml),
1225
+ pixi_exe = get_pixi_path()
1226
+ if pixi_exe is None:
1227
+ raise WorkerError("pixi not found - required for isolated environment execution")
1228
+ cmd = [str(pixi_exe), "run", "--manifest-path", str(pixi_toml),
1214
1229
  "python", str(self._worker_script), self._socket_addr]
1215
1230
  # Clean PATH to remove ct-env entries that have conflicting DLLs
1216
1231
  # Pixi will add its own environment paths
@@ -1230,15 +1245,16 @@ class PersistentVenvWorker(Worker):
1230
1245
  cmd = [str(self.python), str(self._worker_script), self._socket_addr]
1231
1246
  launch_env = env
1232
1247
 
1233
- print(f"[PersistentVenvWorker] launching cmd={cmd[:3]}...", flush=True)
1234
- if launch_env:
1235
- path_sep = ";" if sys.platform == "win32" else ":"
1236
- path_parts = launch_env.get("PATH", "").split(path_sep)
1237
- print(f"[PersistentVenvWorker] PATH has {len(path_parts)} entries:", flush=True)
1238
- for i, p in enumerate(path_parts[:10]): # Show first 10
1239
- print(f"[PersistentVenvWorker] [{i}] {p}", flush=True)
1240
- if len(path_parts) > 10:
1241
- print(f"[PersistentVenvWorker] ... and {len(path_parts) - 10} more", flush=True)
1248
+ if _DEBUG:
1249
+ print(f"[PersistentVenvWorker] launching cmd={cmd[:3]}...", flush=True)
1250
+ if launch_env:
1251
+ path_sep = ";" if sys.platform == "win32" else ":"
1252
+ path_parts = launch_env.get("PATH", "").split(path_sep)
1253
+ print(f"[PersistentVenvWorker] PATH has {len(path_parts)} entries:", flush=True)
1254
+ for i, p in enumerate(path_parts[:10]): # Show first 10
1255
+ print(f"[PersistentVenvWorker] [{i}] {p}", flush=True)
1256
+ if len(path_parts) > 10:
1257
+ print(f"[PersistentVenvWorker] ... and {len(path_parts) - 10} more", flush=True)
1242
1258
  self._process = subprocess.Popen(
1243
1259
  cmd,
1244
1260
  stdin=subprocess.DEVNULL,
@@ -1389,12 +1405,15 @@ class PersistentVenvWorker(Worker):
1389
1405
  Return value of the method.
1390
1406
  """
1391
1407
  import sys
1392
- print(f"[PersistentVenvWorker] call_method: {module_name}.{class_name}.{method_name}", file=sys.stderr, flush=True)
1408
+ if _DEBUG:
1409
+ print(f"[PersistentVenvWorker] call_method: {module_name}.{class_name}.{method_name}", file=sys.stderr, flush=True)
1393
1410
 
1394
1411
  with self._lock:
1395
- print(f"[PersistentVenvWorker] acquired lock, ensuring started...", file=sys.stderr, flush=True)
1412
+ if _DEBUG:
1413
+ print(f"[PersistentVenvWorker] acquired lock, ensuring started...", file=sys.stderr, flush=True)
1396
1414
  self._ensure_started()
1397
- print(f"[PersistentVenvWorker] worker started/confirmed", file=sys.stderr, flush=True)
1415
+ if _DEBUG:
1416
+ print(f"[PersistentVenvWorker] worker started/confirmed", file=sys.stderr, flush=True)
1398
1417
 
1399
1418
  timeout = timeout or 600.0
1400
1419
  call_id = str(uuid.uuid4())[:8]
@@ -1406,11 +1425,14 @@ class PersistentVenvWorker(Worker):
1406
1425
  try:
1407
1426
  # Serialize kwargs
1408
1427
  if kwargs:
1409
- print(f"[PersistentVenvWorker] serializing kwargs...", file=sys.stderr, flush=True)
1428
+ if _DEBUG:
1429
+ print(f"[PersistentVenvWorker] serializing kwargs...", file=sys.stderr, flush=True)
1410
1430
  serialized_kwargs = _serialize_for_ipc(kwargs)
1411
- print(f"[PersistentVenvWorker] saving to {inputs_path}...", file=sys.stderr, flush=True)
1431
+ if _DEBUG:
1432
+ print(f"[PersistentVenvWorker] saving to {inputs_path}...", file=sys.stderr, flush=True)
1412
1433
  torch.save(serialized_kwargs, str(inputs_path))
1413
- print(f"[PersistentVenvWorker] saved inputs", file=sys.stderr, flush=True)
1434
+ if _DEBUG:
1435
+ print(f"[PersistentVenvWorker] saved inputs", file=sys.stderr, flush=True)
1414
1436
 
1415
1437
  # Send request with class info
1416
1438
  request = {
@@ -1422,9 +1444,11 @@ class PersistentVenvWorker(Worker):
1422
1444
  "inputs_path": str(inputs_path) if kwargs else None,
1423
1445
  "outputs_path": str(outputs_path),
1424
1446
  }
1425
- print(f"[PersistentVenvWorker] sending request via socket...", file=sys.stderr, flush=True)
1447
+ if _DEBUG:
1448
+ print(f"[PersistentVenvWorker] sending request via socket...", file=sys.stderr, flush=True)
1426
1449
  response = self._send_request(request, timeout)
1427
- print(f"[PersistentVenvWorker] got response: {response.get('status')}", file=sys.stderr, flush=True)
1450
+ if _DEBUG:
1451
+ print(f"[PersistentVenvWorker] got response: {response.get('status')}", file=sys.stderr, flush=True)
1428
1452
 
1429
1453
  if response.get("status") == "error":
1430
1454
  raise WorkerError(
File without changes
File without changes
File without changes