comfy-env 0.0.67__tar.gz → 0.0.69__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.67 → comfy_env-0.0.69}/PKG-INFO +1 -1
- {comfy_env-0.0.67 → comfy_env-0.0.69}/pyproject.toml +1 -1
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/install.py +1 -1
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/core.py +43 -51
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/workers/mp.py +60 -12
- {comfy_env-0.0.67 → comfy_env-0.0.69}/.github/workflows/publish.yml +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/.gitignore +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/LICENSE +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/README.md +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/__init__.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/cli.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/config/__init__.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/config/parser.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/config/types.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/errors.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/isolation/__init__.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/isolation/wrap.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/nodes.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/__init__.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/cuda_detection.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/platform/__init__.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/platform/base.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/platform/darwin.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/platform/linux.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/platform/windows.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/pixi/resolver.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/prestartup.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/templates/comfy-env.toml +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/workers/__init__.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/workers/base.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/workers/subprocess.py +0 -0
- {comfy_env-0.0.67 → comfy_env-0.0.69}/src/comfy_env/workers/tensor_utils.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.69
|
|
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
|
|
@@ -172,7 +172,6 @@ def pixi_install(
|
|
|
172
172
|
cfg: ComfyEnvConfig,
|
|
173
173
|
node_dir: Path,
|
|
174
174
|
log: Callable[[str], None] = print,
|
|
175
|
-
create_env_link: bool = False,
|
|
176
175
|
) -> bool:
|
|
177
176
|
"""
|
|
178
177
|
Install all packages via pixi.
|
|
@@ -188,7 +187,6 @@ def pixi_install(
|
|
|
188
187
|
cfg: ComfyEnvConfig with packages to install.
|
|
189
188
|
node_dir: Directory to install in.
|
|
190
189
|
log: Logging callback.
|
|
191
|
-
create_env_link: If True, create _env_<name> symlink for isolation.
|
|
192
190
|
|
|
193
191
|
Returns:
|
|
194
192
|
True if installation succeeded.
|
|
@@ -217,9 +215,31 @@ def pixi_install(
|
|
|
217
215
|
else:
|
|
218
216
|
log("Warning: CUDA packages requested but no GPU detected")
|
|
219
217
|
|
|
218
|
+
# Install system dependencies on Linux (OpenGL, build tools)
|
|
219
|
+
if sys.platform == "linux":
|
|
220
|
+
log("Installing system dependencies...")
|
|
221
|
+
subprocess.run(
|
|
222
|
+
["sudo", "apt-get", "update"],
|
|
223
|
+
capture_output=True,
|
|
224
|
+
)
|
|
225
|
+
subprocess.run(
|
|
226
|
+
["sudo", "apt-get", "install", "-y",
|
|
227
|
+
"python3-dev", # Build deps for C extensions
|
|
228
|
+
"libgl1-mesa-glx", # OpenGL
|
|
229
|
+
"libglu1-mesa", # GLU
|
|
230
|
+
],
|
|
231
|
+
capture_output=True,
|
|
232
|
+
)
|
|
233
|
+
|
|
220
234
|
# Clean previous artifacts
|
|
221
235
|
clean_pixi_artifacts(node_dir, log)
|
|
222
236
|
|
|
237
|
+
# Create .pixi/config.toml to ensure inline (non-detached) environments
|
|
238
|
+
pixi_config_dir = node_dir / ".pixi"
|
|
239
|
+
pixi_config_dir.mkdir(parents=True, exist_ok=True)
|
|
240
|
+
pixi_config_file = pixi_config_dir / "config.toml"
|
|
241
|
+
pixi_config_file.write_text("detached-environments = false\n")
|
|
242
|
+
|
|
223
243
|
# Ensure pixi is installed
|
|
224
244
|
pixi_path = ensure_pixi(log=log)
|
|
225
245
|
|
|
@@ -252,24 +272,10 @@ def pixi_install(
|
|
|
252
272
|
dependencies.setdefault("pip", "*") # Always include pip
|
|
253
273
|
pixi_data["dependencies"] = dependencies
|
|
254
274
|
|
|
255
|
-
# Add pypi-options for CUDA
|
|
275
|
+
# Add pypi-options for PyTorch index (CUDA packages installed separately via pip)
|
|
256
276
|
if cfg.has_cuda and cuda_version:
|
|
257
277
|
pypi_options = pixi_data.get("pypi-options", {})
|
|
258
|
-
#
|
|
259
|
-
find_links = pypi_options.get("find-links", [])
|
|
260
|
-
existing_urls = {
|
|
261
|
-
entry.get("url") if isinstance(entry, dict) else entry
|
|
262
|
-
for entry in find_links
|
|
263
|
-
}
|
|
264
|
-
if CUDA_WHEELS_INDEX not in existing_urls:
|
|
265
|
-
find_links.append({"url": CUDA_WHEELS_INDEX})
|
|
266
|
-
# Normalize any plain strings to {url: ...} format
|
|
267
|
-
find_links = [
|
|
268
|
-
{"url": entry} if isinstance(entry, str) else entry
|
|
269
|
-
for entry in find_links
|
|
270
|
-
]
|
|
271
|
-
pypi_options["find-links"] = find_links
|
|
272
|
-
# Merge extra-index-urls
|
|
278
|
+
# Add PyTorch CUDA index for torch installation
|
|
273
279
|
cuda_short = cuda_version.replace(".", "")[:3]
|
|
274
280
|
pytorch_index = f"https://download.pytorch.org/whl/cu{cuda_short}"
|
|
275
281
|
extra_urls = pypi_options.get("extra-index-urls", [])
|
|
@@ -311,46 +317,32 @@ def pixi_install(
|
|
|
311
317
|
log(f"pixi install failed:\n{result.stderr}")
|
|
312
318
|
raise RuntimeError(f"pixi install failed: {result.stderr}")
|
|
313
319
|
|
|
314
|
-
# Install CUDA packages with --no-
|
|
320
|
+
# Install CUDA packages with --no-index --find-links (bypasses PyPI completely)
|
|
315
321
|
if cfg.cuda_packages and cuda_version:
|
|
316
|
-
log(f"Installing CUDA packages
|
|
322
|
+
log(f"Installing CUDA packages: {cfg.cuda_packages}")
|
|
317
323
|
python_path = get_pixi_python(node_dir)
|
|
318
324
|
if not python_path:
|
|
319
325
|
raise RuntimeError("Could not find Python in pixi environment")
|
|
320
326
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
"
|
|
324
|
-
"
|
|
325
|
-
|
|
327
|
+
for package in cfg.cuda_packages:
|
|
328
|
+
# Each package has its own find-links page at CUDA_WHEELS_INDEX/<package>/
|
|
329
|
+
find_links_url = f"{CUDA_WHEELS_INDEX}{package}/"
|
|
330
|
+
log(f" Installing {package} from {find_links_url}")
|
|
331
|
+
|
|
332
|
+
pip_cmd = [
|
|
333
|
+
str(python_path), "-m", "pip", "install",
|
|
334
|
+
"--no-index",
|
|
335
|
+
"--no-deps",
|
|
336
|
+
"--no-cache-dir",
|
|
337
|
+
"--find-links", find_links_url,
|
|
338
|
+
package,
|
|
339
|
+
]
|
|
340
|
+
result = subprocess.run(pip_cmd, capture_output=True, text=True)
|
|
341
|
+
if result.returncode != 0:
|
|
342
|
+
log(f"CUDA package install failed for {package}:\n{result.stderr}")
|
|
343
|
+
raise RuntimeError(f"CUDA package install failed: {result.stderr}")
|
|
326
344
|
|
|
327
|
-
result = subprocess.run(pip_cmd, capture_output=True, text=True)
|
|
328
|
-
if result.returncode != 0:
|
|
329
|
-
log(f"CUDA package install failed:\n{result.stderr}")
|
|
330
|
-
raise RuntimeError(f"CUDA package install failed: {result.stderr}")
|
|
331
345
|
log("CUDA packages installed")
|
|
332
346
|
|
|
333
|
-
# Create symlink/junction to _env_<name> for discovery (only for isolated subdirs)
|
|
334
|
-
if create_env_link:
|
|
335
|
-
env_dir = node_dir / ".pixi" / "envs" / "default"
|
|
336
|
-
env_link = node_dir / f"_env_{node_dir.name}"
|
|
337
|
-
if env_dir.exists():
|
|
338
|
-
# Remove existing link/dir if present
|
|
339
|
-
if env_link.is_symlink() or env_link.exists():
|
|
340
|
-
if env_link.is_symlink():
|
|
341
|
-
env_link.unlink()
|
|
342
|
-
else:
|
|
343
|
-
shutil.rmtree(env_link)
|
|
344
|
-
# Create symlink (Linux/Mac) or junction (Windows)
|
|
345
|
-
if sys.platform == "win32":
|
|
346
|
-
# Use junction on Windows
|
|
347
|
-
subprocess.run(
|
|
348
|
-
["cmd", "/c", "mklink", "/J", str(env_link), str(env_dir)],
|
|
349
|
-
capture_output=True,
|
|
350
|
-
)
|
|
351
|
-
else:
|
|
352
|
-
env_link.symlink_to(env_dir)
|
|
353
|
-
log(f"Linked: {env_link.name} -> .pixi/envs/default")
|
|
354
|
-
|
|
355
347
|
log("Installation complete!")
|
|
356
348
|
return True
|
|
@@ -430,20 +430,68 @@ class MPWorker(Worker):
|
|
|
430
430
|
return
|
|
431
431
|
|
|
432
432
|
# Import torch here to avoid import at module level
|
|
433
|
+
import os
|
|
434
|
+
import sys
|
|
435
|
+
|
|
436
|
+
# Clear conda/pixi environment variables FIRST, before importing multiprocessing
|
|
437
|
+
# These can cause the child process to pick up the wrong Python interpreter
|
|
438
|
+
# or stdlib, leading to sys.version mismatch errors in platform module
|
|
439
|
+
conda_env_vars = [
|
|
440
|
+
'CONDA_PREFIX',
|
|
441
|
+
'CONDA_DEFAULT_ENV',
|
|
442
|
+
'CONDA_PYTHON_EXE',
|
|
443
|
+
'CONDA_EXE',
|
|
444
|
+
'CONDA_SHLVL',
|
|
445
|
+
'PYTHONHOME',
|
|
446
|
+
'PYTHONPATH', # Also clear PYTHONPATH to prevent pixi paths
|
|
447
|
+
'_CE_CONDA',
|
|
448
|
+
'_CE_M',
|
|
449
|
+
]
|
|
450
|
+
saved_env = {}
|
|
451
|
+
for var in conda_env_vars:
|
|
452
|
+
if var in os.environ:
|
|
453
|
+
saved_env[var] = os.environ.pop(var)
|
|
454
|
+
|
|
455
|
+
# Also remove pixi paths from LD_LIBRARY_PATH
|
|
456
|
+
ld_lib = os.environ.get('LD_LIBRARY_PATH', '')
|
|
457
|
+
if '.pixi' in ld_lib:
|
|
458
|
+
saved_env['LD_LIBRARY_PATH'] = ld_lib
|
|
459
|
+
# Filter out pixi paths
|
|
460
|
+
new_ld_lib = ':'.join(p for p in ld_lib.split(':') if '.pixi' not in p)
|
|
461
|
+
if new_ld_lib:
|
|
462
|
+
os.environ['LD_LIBRARY_PATH'] = new_ld_lib
|
|
463
|
+
else:
|
|
464
|
+
os.environ.pop('LD_LIBRARY_PATH', None)
|
|
465
|
+
|
|
433
466
|
import torch.multiprocessing as mp
|
|
434
467
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
468
|
+
try:
|
|
469
|
+
# Use spawn to get clean subprocess (no inherited CUDA context)
|
|
470
|
+
ctx = mp.get_context('spawn')
|
|
471
|
+
|
|
472
|
+
# Explicitly set the spawn executable to the current Python
|
|
473
|
+
# This prevents pixi/conda from hijacking the spawn process
|
|
474
|
+
import multiprocessing.spawn as mp_spawn
|
|
475
|
+
original_exe = mp_spawn.get_executable()
|
|
476
|
+
if original_exe != sys.executable.encode() and original_exe != sys.executable:
|
|
477
|
+
print(f"[comfy-env] Warning: spawn executable was {original_exe}, forcing to {sys.executable}")
|
|
478
|
+
mp_spawn.set_executable(sys.executable)
|
|
479
|
+
|
|
480
|
+
self._queue_in = ctx.Queue()
|
|
481
|
+
self._queue_out = ctx.Queue()
|
|
482
|
+
self._process = ctx.Process(
|
|
483
|
+
target=_worker_loop,
|
|
484
|
+
args=(self._queue_in, self._queue_out, self._sys_path, self._lib_path),
|
|
485
|
+
daemon=True,
|
|
486
|
+
)
|
|
487
|
+
self._process.start()
|
|
488
|
+
self._started = True
|
|
489
|
+
|
|
490
|
+
# Restore original executable setting
|
|
491
|
+
mp_spawn.set_executable(original_exe)
|
|
492
|
+
finally:
|
|
493
|
+
# Restore env vars in parent process
|
|
494
|
+
os.environ.update(saved_env)
|
|
447
495
|
|
|
448
496
|
def call(
|
|
449
497
|
self,
|
|
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
|