comfy-env 0.1.10__py3-none-any.whl → 0.1.11__py3-none-any.whl
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/isolation/wrap.py +31 -1
- comfy_env/pixi/core.py +15 -4
- comfy_env/workers/subprocess.py +37 -68
- {comfy_env-0.1.10.dist-info → comfy_env-0.1.11.dist-info}/METADATA +1 -1
- {comfy_env-0.1.10.dist-info → comfy_env-0.1.11.dist-info}/RECORD +8 -8
- {comfy_env-0.1.10.dist-info → comfy_env-0.1.11.dist-info}/WHEEL +0 -0
- {comfy_env-0.1.10.dist-info → comfy_env-0.1.11.dist-info}/entry_points.txt +0 -0
- {comfy_env-0.1.10.dist-info → comfy_env-0.1.11.dist-info}/licenses/LICENSE +0 -0
comfy_env/isolation/wrap.py
CHANGED
|
@@ -211,6 +211,34 @@ def _find_env_dir(node_dir: Path) -> Optional[Path]:
|
|
|
211
211
|
return None
|
|
212
212
|
|
|
213
213
|
|
|
214
|
+
def _find_custom_node_root(nodes_dir: Path) -> Optional[Path]:
|
|
215
|
+
"""
|
|
216
|
+
Find the custom node root (direct child of custom_nodes/).
|
|
217
|
+
|
|
218
|
+
Uses folder_paths to find custom_nodes directories, then finds
|
|
219
|
+
which one is an ancestor of nodes_dir.
|
|
220
|
+
|
|
221
|
+
Example: /path/custom_nodes/ComfyUI-UniRig/nodes/nodes_gpu
|
|
222
|
+
-> returns /path/custom_nodes/ComfyUI-UniRig
|
|
223
|
+
"""
|
|
224
|
+
try:
|
|
225
|
+
import folder_paths
|
|
226
|
+
custom_nodes_dirs = folder_paths.get_folder_paths("custom_nodes")
|
|
227
|
+
except (ImportError, KeyError):
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
for cn_dir in custom_nodes_dirs:
|
|
231
|
+
cn_path = Path(cn_dir)
|
|
232
|
+
try:
|
|
233
|
+
rel = nodes_dir.relative_to(cn_path)
|
|
234
|
+
if rel.parts:
|
|
235
|
+
return cn_path / rel.parts[0]
|
|
236
|
+
except ValueError:
|
|
237
|
+
continue
|
|
238
|
+
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
|
|
214
242
|
def _wrap_node_class(
|
|
215
243
|
cls: type,
|
|
216
244
|
env_dir: Path,
|
|
@@ -388,7 +416,9 @@ def wrap_isolated_nodes(
|
|
|
388
416
|
print(f"[comfy-env] Run 'comfy-env install' in {nodes_dir}")
|
|
389
417
|
return node_class_mappings
|
|
390
418
|
|
|
391
|
-
# Build sys.path
|
|
419
|
+
# Build sys.path - site-packages first, then nodes_dir
|
|
420
|
+
# Note: isolated modules should use absolute imports (their dir is in sys.path)
|
|
421
|
+
# Relative imports would require importing parent package which may have host-only deps
|
|
392
422
|
sys_path = [str(site_packages), str(nodes_dir)]
|
|
393
423
|
|
|
394
424
|
# lib_dir for LD_LIBRARY_PATH (conda libraries)
|
comfy_env/pixi/core.py
CHANGED
|
@@ -457,11 +457,14 @@ def pixi_install(
|
|
|
457
457
|
# Build pypi-dependencies section (CUDA packages excluded - installed separately)
|
|
458
458
|
pypi_deps = pixi_data.get("pypi-dependencies", {})
|
|
459
459
|
|
|
460
|
-
#
|
|
460
|
+
# Enforce torch version if we have CUDA packages (must match cuda_packages wheels)
|
|
461
461
|
if cfg.has_cuda and torch_version:
|
|
462
462
|
torch_major = torch_version.split(".")[0]
|
|
463
463
|
torch_minor = int(torch_version.split(".")[1])
|
|
464
|
-
|
|
464
|
+
required_torch = f">={torch_version},<{torch_major}.{torch_minor + 1}"
|
|
465
|
+
if "torch" in pypi_deps and pypi_deps["torch"] != required_torch:
|
|
466
|
+
log(f"Overriding torch={pypi_deps['torch']} with {required_torch} (required for cuda_packages)")
|
|
467
|
+
pypi_deps["torch"] = required_torch
|
|
465
468
|
|
|
466
469
|
# NOTE: CUDA packages are NOT added here - they're installed with --no-deps after pixi
|
|
467
470
|
|
|
@@ -494,8 +497,16 @@ def pixi_install(
|
|
|
494
497
|
if not python_path:
|
|
495
498
|
raise RuntimeError("Could not find Python in pixi environment")
|
|
496
499
|
|
|
497
|
-
# Get Python version from the pixi environment
|
|
498
|
-
|
|
500
|
+
# Get Python version from the pixi environment (not host Python)
|
|
501
|
+
result = subprocess.run(
|
|
502
|
+
[str(python_path), "-c", "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"],
|
|
503
|
+
capture_output=True, text=True
|
|
504
|
+
)
|
|
505
|
+
if result.returncode == 0:
|
|
506
|
+
py_version = result.stdout.strip()
|
|
507
|
+
else:
|
|
508
|
+
py_version = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
509
|
+
log(f"Warning: Could not detect pixi Python version, using host: {py_version}")
|
|
499
510
|
|
|
500
511
|
for package in cfg.cuda_packages:
|
|
501
512
|
# Find direct wheel URL (bypasses metadata validation)
|
comfy_env/workers/subprocess.py
CHANGED
|
@@ -228,23 +228,19 @@ def _to_shm(obj, registry, visited=None):
|
|
|
228
228
|
result["__was_tensor__"] = True
|
|
229
229
|
return result
|
|
230
230
|
|
|
231
|
-
# trimesh.Trimesh →
|
|
231
|
+
# trimesh.Trimesh → pickle → shared memory (preserves visual, metadata, normals)
|
|
232
232
|
if t == 'Trimesh':
|
|
233
|
-
|
|
234
|
-
|
|
233
|
+
import pickle
|
|
234
|
+
mesh_bytes = pickle.dumps(obj)
|
|
235
235
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
registry.append(
|
|
239
|
-
|
|
240
|
-
f_block = shm.SharedMemory(create=True, size=faces.nbytes)
|
|
241
|
-
np.ndarray(faces.shape, faces.dtype, buffer=f_block.buf)[:] = faces
|
|
242
|
-
registry.append(f_block)
|
|
236
|
+
block = shm.SharedMemory(create=True, size=len(mesh_bytes))
|
|
237
|
+
block.buf[:len(mesh_bytes)] = mesh_bytes
|
|
238
|
+
registry.append(block)
|
|
243
239
|
|
|
244
240
|
result = {
|
|
245
241
|
"__shm_trimesh__": True,
|
|
246
|
-
"
|
|
247
|
-
"
|
|
242
|
+
"name": block.name,
|
|
243
|
+
"size": len(mesh_bytes),
|
|
248
244
|
}
|
|
249
245
|
visited[obj_id] = result
|
|
250
246
|
return result
|
|
@@ -294,22 +290,15 @@ def _from_shm(obj, unlink=True):
|
|
|
294
290
|
return torch.from_numpy(arr)
|
|
295
291
|
return arr
|
|
296
292
|
|
|
297
|
-
# trimesh
|
|
293
|
+
# trimesh (pickled to preserve visual, metadata, normals)
|
|
298
294
|
if "__shm_trimesh__" in obj:
|
|
299
|
-
import
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if unlink:
|
|
304
|
-
v_block.unlink()
|
|
305
|
-
|
|
306
|
-
f_block = shm.SharedMemory(name=obj["f_name"])
|
|
307
|
-
faces = np.ndarray(tuple(obj["f_shape"]), dtype=np.int64, buffer=f_block.buf).copy()
|
|
308
|
-
f_block.close()
|
|
295
|
+
import pickle
|
|
296
|
+
block = shm.SharedMemory(name=obj["name"])
|
|
297
|
+
mesh_bytes = bytes(block.buf[:obj["size"]])
|
|
298
|
+
block.close()
|
|
309
299
|
if unlink:
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return trimesh.Trimesh(vertices=verts, faces=faces, process=False)
|
|
300
|
+
block.unlink()
|
|
301
|
+
return pickle.loads(mesh_bytes)
|
|
313
302
|
|
|
314
303
|
# regular dict - recurse
|
|
315
304
|
return {k: _from_shm(v, unlink) for k, v in obj.items()}
|
|
@@ -426,42 +415,29 @@ faulthandler.enable(file=sys.stderr, all_threads=True)
|
|
|
426
415
|
# Debug logging (set COMFY_ENV_DEBUG=1 to enable)
|
|
427
416
|
_DEBUG = os.environ.get("COMFY_ENV_DEBUG", "").lower() in ("1", "true", "yes")
|
|
428
417
|
|
|
429
|
-
# Pre-import bpy FIRST to avoid DLL conflicts with numpy/torch/MKL
|
|
430
|
-
# bpy's DLLs must be loaded before other packages load conflicting versions
|
|
431
|
-
try:
|
|
432
|
-
import bpy
|
|
433
|
-
if _DEBUG:
|
|
434
|
-
print("[worker] Pre-imported bpy successfully", file=sys.stderr, flush=True)
|
|
435
|
-
except ImportError as e:
|
|
436
|
-
# bpy not available in this environment - that's fine
|
|
437
|
-
pass
|
|
438
|
-
except Exception as e:
|
|
439
|
-
if _DEBUG:
|
|
440
|
-
print(f"[worker] bpy pre-import warning: {e}", file=sys.stderr, flush=True)
|
|
441
|
-
|
|
442
418
|
# Watchdog: dump all thread stacks every 60 seconds to catch hangs
|
|
443
419
|
import threading
|
|
444
420
|
import tempfile as _tempfile
|
|
445
421
|
_watchdog_log = os.path.join(_tempfile.gettempdir(), "comfy_worker_watchdog.log")
|
|
446
422
|
def _watchdog():
|
|
447
423
|
import time
|
|
448
|
-
import io
|
|
449
424
|
tick = 0
|
|
450
425
|
while True:
|
|
451
426
|
time.sleep(60)
|
|
452
427
|
tick += 1
|
|
453
|
-
#
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
428
|
+
# Dump to temp file first (faulthandler needs real file descriptor)
|
|
429
|
+
tmp_path = _watchdog_log + ".tmp"
|
|
430
|
+
with open(tmp_path, "w", encoding="utf-8") as tmp:
|
|
431
|
+
faulthandler.dump_traceback(file=tmp, all_threads=True)
|
|
432
|
+
with open(tmp_path, "r", encoding="utf-8") as tmp:
|
|
433
|
+
dump = tmp.read()
|
|
434
|
+
|
|
435
|
+
# Write to persistent log
|
|
459
436
|
with open(_watchdog_log, "a", encoding="utf-8") as f:
|
|
460
437
|
f.write(f"\\n=== WATCHDOG TICK {tick} ({time.strftime('%H:%M:%S')}) ===\\n")
|
|
461
438
|
f.write(dump)
|
|
462
439
|
f.write("=== END ===\\n")
|
|
463
440
|
f.flush()
|
|
464
|
-
os.fsync(f.fileno())
|
|
465
441
|
|
|
466
442
|
# Also print
|
|
467
443
|
print(f"\\n=== WATCHDOG TICK {tick} ===", flush=True)
|
|
@@ -554,22 +530,19 @@ def _to_shm(obj, registry, visited=None):
|
|
|
554
530
|
result["__was_tensor__"] = True
|
|
555
531
|
return result
|
|
556
532
|
|
|
533
|
+
# trimesh.Trimesh → pickle → shared memory (preserves visual, metadata, normals)
|
|
557
534
|
if t == 'Trimesh':
|
|
558
|
-
|
|
559
|
-
|
|
535
|
+
import pickle
|
|
536
|
+
mesh_bytes = pickle.dumps(obj)
|
|
560
537
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
registry.append(
|
|
564
|
-
|
|
565
|
-
f_block = shm.SharedMemory(create=True, size=faces.nbytes)
|
|
566
|
-
np.ndarray(faces.shape, faces.dtype, buffer=f_block.buf)[:] = faces
|
|
567
|
-
registry.append(f_block)
|
|
538
|
+
block = shm.SharedMemory(create=True, size=len(mesh_bytes))
|
|
539
|
+
block.buf[:len(mesh_bytes)] = mesh_bytes
|
|
540
|
+
registry.append(block)
|
|
568
541
|
|
|
569
542
|
result = {
|
|
570
543
|
"__shm_trimesh__": True,
|
|
571
|
-
"
|
|
572
|
-
"
|
|
544
|
+
"name": block.name,
|
|
545
|
+
"size": len(mesh_bytes),
|
|
573
546
|
}
|
|
574
547
|
visited[obj_id] = result
|
|
575
548
|
return result
|
|
@@ -600,17 +573,13 @@ def _from_shm(obj):
|
|
|
600
573
|
import torch
|
|
601
574
|
return torch.from_numpy(arr)
|
|
602
575
|
return arr
|
|
576
|
+
# trimesh (pickled to preserve visual, metadata, normals)
|
|
603
577
|
if "__shm_trimesh__" in obj:
|
|
604
|
-
import
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
f_block = shm.SharedMemory(name=obj["f_name"])
|
|
610
|
-
faces = np.ndarray(tuple(obj["f_shape"]), dtype=np.int64, buffer=f_block.buf).copy()
|
|
611
|
-
f_block.close()
|
|
612
|
-
|
|
613
|
-
return trimesh.Trimesh(vertices=verts, faces=faces, process=False)
|
|
578
|
+
import pickle
|
|
579
|
+
block = shm.SharedMemory(name=obj["name"])
|
|
580
|
+
mesh_bytes = bytes(block.buf[:obj["size"]])
|
|
581
|
+
block.close()
|
|
582
|
+
return pickle.loads(mesh_bytes)
|
|
614
583
|
return {k: _from_shm(v) for k, v in obj.items()}
|
|
615
584
|
|
|
616
585
|
def _cleanup_shm(registry):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: comfy-env
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
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
|
|
@@ -8,9 +8,9 @@ comfy_env/config/__init__.py,sha256=4Guylkb-FV8QxhFwschzpzbr2eu8y-KNgNT3_JOm9jc,
|
|
|
8
8
|
comfy_env/config/parser.py,sha256=dA1lX5ExBEfCqUJwe4V5i_jn2NJ69bMq3c3ji3lMSV8,4295
|
|
9
9
|
comfy_env/config/types.py,sha256=Sb8HO34xsSZu5YAc2K4M7Gb3QNevJlngf12hHiwuU0w,2140
|
|
10
10
|
comfy_env/isolation/__init__.py,sha256=vw9a4mpJ2CFjy-PLe_A3zQ6umBQklgqWNxwn9beNw3g,175
|
|
11
|
-
comfy_env/isolation/wrap.py,sha256=
|
|
11
|
+
comfy_env/isolation/wrap.py,sha256=cTRzbdHJncmg4yUAyH5n9TPBu88grv6D1XezZwXKpok,14638
|
|
12
12
|
comfy_env/pixi/__init__.py,sha256=BUrq7AQf3WDm0cHWh72B2xZbURNnDu2dCuELWiQCUiM,997
|
|
13
|
-
comfy_env/pixi/core.py,sha256=
|
|
13
|
+
comfy_env/pixi/core.py,sha256=fqozZZEoub8dAQaE6v6gyqw1mMiAYiCcdzH0gjCANBo,20637
|
|
14
14
|
comfy_env/pixi/cuda_detection.py,sha256=sqB3LjvGNdV4eFqiARQGfyecBM3ZiUmeh6nG0YCRYQw,9751
|
|
15
15
|
comfy_env/pixi/resolver.py,sha256=U_A8rBDxCj4gUlJt2YJQniP4cCKqxJEiVFgXOoH7vM8,6339
|
|
16
16
|
comfy_env/pixi/platform/__init__.py,sha256=Nb5MPZIEeanSMEWwqU4p4bnEKTJn1tWcwobnhq9x9IY,614
|
|
@@ -23,10 +23,10 @@ comfy_env/templates/comfy-env.toml,sha256=ROIqi4BlPL1MEdL1VgebfTHpdwPNYGHwWeigI9
|
|
|
23
23
|
comfy_env/workers/__init__.py,sha256=TMVG55d2XLP1mJ3x1d16H0SBDJZtk2kMC5P4HLk9TrA,1073
|
|
24
24
|
comfy_env/workers/base.py,sha256=4ZYTaQ4J0kBHCoO_OfZnsowm4rJCoqinZUaOtgkOPbw,2307
|
|
25
25
|
comfy_env/workers/mp.py,sha256=vsxDGWepmSNgfqBhZPW7h8yOiKEyQcDFYP09masLTV4,32337
|
|
26
|
-
comfy_env/workers/subprocess.py,sha256=
|
|
26
|
+
comfy_env/workers/subprocess.py,sha256=bNwHpgz_EIIwZVRlgsx_ZEowYRrWbp-8uUIboacc-7M,57136
|
|
27
27
|
comfy_env/workers/tensor_utils.py,sha256=TCuOAjJymrSbkgfyvcKtQ_KbVWTqSwP9VH_bCaFLLq8,6409
|
|
28
|
-
comfy_env-0.1.
|
|
29
|
-
comfy_env-0.1.
|
|
30
|
-
comfy_env-0.1.
|
|
31
|
-
comfy_env-0.1.
|
|
32
|
-
comfy_env-0.1.
|
|
28
|
+
comfy_env-0.1.11.dist-info/METADATA,sha256=lqJAy8ibQELhvALr-YajG4e2NG2y-ApYXW5X58PWqXY,6971
|
|
29
|
+
comfy_env-0.1.11.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
30
|
+
comfy_env-0.1.11.dist-info/entry_points.txt,sha256=J4fXeqgxU_YenuW_Zxn_pEL7J-3R0--b6MS5t0QmAr0,49
|
|
31
|
+
comfy_env-0.1.11.dist-info/licenses/LICENSE,sha256=E68QZMMpW4P2YKstTZ3QU54HRQO8ecew09XZ4_Vn870,1093
|
|
32
|
+
comfy_env-0.1.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|