comfy-env 0.0.6__py3-none-any.whl → 0.0.9__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/__init__.py +1 -1
- comfy_env/env/config.py +4 -0
- comfy_env/env/config_file.py +27 -0
- comfy_env/env/manager.py +79 -12
- comfy_env/env/platform/windows.py +182 -0
- comfy_env/workers/venv.py +41 -7
- {comfy_env-0.0.6.dist-info → comfy_env-0.0.9.dist-info}/METADATA +1 -1
- {comfy_env-0.0.6.dist-info → comfy_env-0.0.9.dist-info}/RECORD +11 -11
- {comfy_env-0.0.6.dist-info → comfy_env-0.0.9.dist-info}/WHEEL +0 -0
- {comfy_env-0.0.6.dist-info → comfy_env-0.0.9.dist-info}/entry_points.txt +0 -0
- {comfy_env-0.0.6.dist-info → comfy_env-0.0.9.dist-info}/licenses/LICENSE +0 -0
comfy_env/__init__.py
CHANGED
|
@@ -40,7 +40,7 @@ This package provides:
|
|
|
40
40
|
The @isolated decorator and WorkerBridge are still available.
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
|
-
__version__ = "0.0.
|
|
43
|
+
__version__ = "0.0.8"
|
|
44
44
|
|
|
45
45
|
from .env.config import IsolatedEnv, EnvManagerConfig, LocalConfig, NodeReq
|
|
46
46
|
from .env.config_file import (
|
comfy_env/env/config.py
CHANGED
|
@@ -98,6 +98,10 @@ class IsolatedEnv:
|
|
|
98
98
|
cuda: Optional[str] = None
|
|
99
99
|
requirements: list[str] = field(default_factory=list)
|
|
100
100
|
no_deps_requirements: list[str] = field(default_factory=list) # Install with --no-deps
|
|
101
|
+
# Platform-specific requirements (merged at install time)
|
|
102
|
+
windows_requirements: list[str] = field(default_factory=list)
|
|
103
|
+
linux_requirements: list[str] = field(default_factory=list)
|
|
104
|
+
darwin_requirements: list[str] = field(default_factory=list)
|
|
101
105
|
requirements_file: Optional[Path] = None
|
|
102
106
|
wheel_sources: list[str] = field(default_factory=list)
|
|
103
107
|
index_urls: list[str] = field(default_factory=list)
|
comfy_env/env/config_file.py
CHANGED
|
@@ -529,6 +529,30 @@ def _parse_single_env(name: str, env_data: Dict[str, Any], base_dir: Path) -> Is
|
|
|
529
529
|
elif isinstance(packages_section, list):
|
|
530
530
|
requirements = packages_section
|
|
531
531
|
|
|
532
|
+
# Parse platform-specific packages [envname.packages.windows], etc.
|
|
533
|
+
windows_reqs = []
|
|
534
|
+
linux_reqs = []
|
|
535
|
+
darwin_reqs = []
|
|
536
|
+
|
|
537
|
+
if isinstance(packages_section, dict):
|
|
538
|
+
win_section = packages_section.get("windows", {})
|
|
539
|
+
if isinstance(win_section, dict):
|
|
540
|
+
windows_reqs = win_section.get("requirements", [])
|
|
541
|
+
elif isinstance(win_section, list):
|
|
542
|
+
windows_reqs = win_section
|
|
543
|
+
|
|
544
|
+
linux_section = packages_section.get("linux", {})
|
|
545
|
+
if isinstance(linux_section, dict):
|
|
546
|
+
linux_reqs = linux_section.get("requirements", [])
|
|
547
|
+
elif isinstance(linux_section, list):
|
|
548
|
+
linux_reqs = linux_section
|
|
549
|
+
|
|
550
|
+
darwin_section = packages_section.get("darwin", {})
|
|
551
|
+
if isinstance(darwin_section, dict):
|
|
552
|
+
darwin_reqs = darwin_section.get("requirements", [])
|
|
553
|
+
elif isinstance(darwin_section, list):
|
|
554
|
+
darwin_reqs = darwin_section
|
|
555
|
+
|
|
532
556
|
return IsolatedEnv(
|
|
533
557
|
name=name,
|
|
534
558
|
python=python,
|
|
@@ -536,6 +560,9 @@ def _parse_single_env(name: str, env_data: Dict[str, Any], base_dir: Path) -> Is
|
|
|
536
560
|
pytorch_version=pytorch,
|
|
537
561
|
requirements=requirements,
|
|
538
562
|
no_deps_requirements=no_deps_requirements,
|
|
563
|
+
windows_requirements=windows_reqs,
|
|
564
|
+
linux_requirements=linux_reqs,
|
|
565
|
+
darwin_requirements=darwin_reqs,
|
|
539
566
|
)
|
|
540
567
|
|
|
541
568
|
|
comfy_env/env/manager.py
CHANGED
|
@@ -263,13 +263,29 @@ class IsolatedEnvManager:
|
|
|
263
263
|
"""
|
|
264
264
|
python_exe = self.get_python(env)
|
|
265
265
|
|
|
266
|
-
|
|
266
|
+
# Merge platform-specific requirements
|
|
267
|
+
if sys.platform == 'win32':
|
|
268
|
+
platform_reqs = env.windows_requirements
|
|
269
|
+
platform_name = 'Windows'
|
|
270
|
+
elif sys.platform == 'darwin':
|
|
271
|
+
platform_reqs = env.darwin_requirements
|
|
272
|
+
platform_name = 'macOS'
|
|
273
|
+
else:
|
|
274
|
+
platform_reqs = env.linux_requirements
|
|
275
|
+
platform_name = 'Linux'
|
|
276
|
+
|
|
277
|
+
all_requirements = list(env.requirements) + list(platform_reqs)
|
|
278
|
+
|
|
279
|
+
if platform_reqs:
|
|
280
|
+
self.log(f"Including {len(platform_reqs)} {platform_name}-specific packages")
|
|
281
|
+
|
|
282
|
+
if not all_requirements and not env.requirements_file:
|
|
267
283
|
self.log("No requirements to install")
|
|
268
284
|
return
|
|
269
285
|
|
|
270
286
|
# Validate requirements for security
|
|
271
|
-
if
|
|
272
|
-
validate_dependencies(
|
|
287
|
+
if all_requirements:
|
|
288
|
+
validate_dependencies(all_requirements)
|
|
273
289
|
|
|
274
290
|
# Validate wheel sources
|
|
275
291
|
for wheel_source in env.wheel_sources:
|
|
@@ -311,11 +327,11 @@ class IsolatedEnvManager:
|
|
|
311
327
|
self.log(f"Installing {len(env.no_deps_requirements)} CUDA packages")
|
|
312
328
|
self._install_cuda_packages(env, pip_args)
|
|
313
329
|
|
|
314
|
-
# Install individual requirements
|
|
315
|
-
if
|
|
316
|
-
self.log(f"Installing {len(
|
|
330
|
+
# Install individual requirements (including platform-specific)
|
|
331
|
+
if all_requirements:
|
|
332
|
+
self.log(f"Installing {len(all_requirements)} packages")
|
|
317
333
|
result = subprocess.run(
|
|
318
|
-
pip_args +
|
|
334
|
+
pip_args + all_requirements,
|
|
319
335
|
capture_output=True,
|
|
320
336
|
text=True,
|
|
321
337
|
)
|
|
@@ -502,6 +518,57 @@ class IsolatedEnvManager:
|
|
|
502
518
|
else:
|
|
503
519
|
self.log("comfy-env installed")
|
|
504
520
|
|
|
521
|
+
def _setup_windows_deps(self, env: IsolatedEnv, env_dir: Path) -> None:
|
|
522
|
+
"""
|
|
523
|
+
Set up Windows-specific dependencies (VC++ runtime, DLL paths).
|
|
524
|
+
|
|
525
|
+
This:
|
|
526
|
+
1. Installs msvc-runtime package (provides VC++ DLLs)
|
|
527
|
+
2. Sets up the Lib/x64/vc17/bin directory structure for opencv
|
|
528
|
+
"""
|
|
529
|
+
python_exe = self.get_python(env)
|
|
530
|
+
uv = self._find_uv()
|
|
531
|
+
|
|
532
|
+
# Install msvc-runtime package to get VC++ DLLs
|
|
533
|
+
self.log("Installing VC++ runtime (msvc-runtime)...")
|
|
534
|
+
result = subprocess.run(
|
|
535
|
+
[str(uv), "pip", "install", "--python", str(python_exe), "msvc-runtime"],
|
|
536
|
+
capture_output=True,
|
|
537
|
+
text=True,
|
|
538
|
+
)
|
|
539
|
+
if result.returncode != 0:
|
|
540
|
+
self.log(f"Warning: Failed to install msvc-runtime: {result.stderr}")
|
|
541
|
+
else:
|
|
542
|
+
self.log("msvc-runtime installed")
|
|
543
|
+
|
|
544
|
+
# Set up opencv DLL paths (copies DLLs to Lib/x64/vc17/bin)
|
|
545
|
+
self.log("Setting up opencv DLL paths...")
|
|
546
|
+
success, msg = self.platform.setup_opencv_dll_paths(env_dir)
|
|
547
|
+
if success:
|
|
548
|
+
if msg:
|
|
549
|
+
self.log(f" {msg}")
|
|
550
|
+
else:
|
|
551
|
+
self.log(f"Warning: {msg}")
|
|
552
|
+
|
|
553
|
+
def ensure_system_deps(self) -> bool:
|
|
554
|
+
"""
|
|
555
|
+
Ensure system-level dependencies are installed (Windows only).
|
|
556
|
+
|
|
557
|
+
On Windows, this checks for Media Foundation and installs if missing.
|
|
558
|
+
Returns True if all deps are available, False otherwise.
|
|
559
|
+
"""
|
|
560
|
+
if self.platform.name != 'windows':
|
|
561
|
+
return True
|
|
562
|
+
|
|
563
|
+
# Check and install Media Foundation if needed
|
|
564
|
+
success, error = self.platform.ensure_media_foundation(self.log)
|
|
565
|
+
if not success:
|
|
566
|
+
self.log(f"WARNING: {error}")
|
|
567
|
+
self.log("Some packages (like opencv) may not work correctly.")
|
|
568
|
+
return False
|
|
569
|
+
|
|
570
|
+
return True
|
|
571
|
+
|
|
505
572
|
def setup(
|
|
506
573
|
self,
|
|
507
574
|
env: IsolatedEnv,
|
|
@@ -525,6 +592,9 @@ class IsolatedEnvManager:
|
|
|
525
592
|
self.log(f"Setting up isolated environment: {env.name}")
|
|
526
593
|
self.log("=" * 50)
|
|
527
594
|
|
|
595
|
+
# Ensure system-level deps (Media Foundation on Windows)
|
|
596
|
+
self.ensure_system_deps()
|
|
597
|
+
|
|
528
598
|
# Check if already ready
|
|
529
599
|
if self.is_ready(env, verify_packages):
|
|
530
600
|
self.log("Environment already ready, skipping setup")
|
|
@@ -543,12 +613,9 @@ class IsolatedEnvManager:
|
|
|
543
613
|
# Install other requirements
|
|
544
614
|
self.install_requirements(env)
|
|
545
615
|
|
|
546
|
-
# Windows:
|
|
616
|
+
# Windows: Install VC++ runtime and set up DLL paths
|
|
547
617
|
if self.platform.name == 'windows':
|
|
548
|
-
self.
|
|
549
|
-
success, error = self.platform.bundle_vc_dlls_to_env(env_dir)
|
|
550
|
-
if not success:
|
|
551
|
-
self.log(f"Warning: {error}")
|
|
618
|
+
self._setup_windows_deps(env, env_dir)
|
|
552
619
|
|
|
553
620
|
# Verify installation
|
|
554
621
|
if verify_packages:
|
|
@@ -5,6 +5,7 @@ Windows platform provider implementation.
|
|
|
5
5
|
import os
|
|
6
6
|
import stat
|
|
7
7
|
import shutil
|
|
8
|
+
import subprocess
|
|
8
9
|
import sys
|
|
9
10
|
import time
|
|
10
11
|
from pathlib import Path
|
|
@@ -193,3 +194,184 @@ class WindowsPlatformProvider(PlatformProvider):
|
|
|
193
194
|
raise
|
|
194
195
|
|
|
195
196
|
return False
|
|
197
|
+
|
|
198
|
+
# =========================================================================
|
|
199
|
+
# Media Foundation Detection and Installation
|
|
200
|
+
# =========================================================================
|
|
201
|
+
|
|
202
|
+
def check_media_foundation(self) -> bool:
|
|
203
|
+
"""
|
|
204
|
+
Check if Media Foundation DLLs exist on the system.
|
|
205
|
+
|
|
206
|
+
These are required by packages like opencv-python for video/media support.
|
|
207
|
+
Missing on Windows N/KN editions and some Windows Server installations.
|
|
208
|
+
"""
|
|
209
|
+
system_root = os.environ.get('SystemRoot', r'C:\Windows')
|
|
210
|
+
mf_dlls = ['MFPlat.dll', 'MF.dll', 'MFReadWrite.dll']
|
|
211
|
+
|
|
212
|
+
for dll in mf_dlls:
|
|
213
|
+
dll_path = Path(system_root) / 'System32' / dll
|
|
214
|
+
if not dll_path.exists():
|
|
215
|
+
return False
|
|
216
|
+
return True
|
|
217
|
+
|
|
218
|
+
def install_media_foundation(self, log_callback=None) -> Tuple[bool, Optional[str]]:
|
|
219
|
+
"""
|
|
220
|
+
Install Media Foundation via DISM.
|
|
221
|
+
|
|
222
|
+
Requires administrator privileges. Will trigger UAC prompt if needed.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
Tuple of (success, error_message)
|
|
226
|
+
"""
|
|
227
|
+
log = log_callback or print
|
|
228
|
+
|
|
229
|
+
if self.check_media_foundation():
|
|
230
|
+
return (True, None)
|
|
231
|
+
|
|
232
|
+
log("Media Foundation not found. Installing via DISM...")
|
|
233
|
+
log("(This requires administrator privileges - a UAC prompt may appear)")
|
|
234
|
+
|
|
235
|
+
# DISM command to install Media Feature Pack
|
|
236
|
+
dism_cmd = [
|
|
237
|
+
"DISM.exe", "/Online", "/Add-Capability",
|
|
238
|
+
"/CapabilityName:Media.MediaFeaturePack~~~~0.0.1.0"
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
# First try without elevation (in case already running as admin)
|
|
243
|
+
result = subprocess.run(
|
|
244
|
+
dism_cmd,
|
|
245
|
+
capture_output=True,
|
|
246
|
+
text=True,
|
|
247
|
+
timeout=300 # 5 minute timeout for installation
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
if result.returncode == 0:
|
|
251
|
+
log("Media Foundation installed successfully!")
|
|
252
|
+
return (True, None)
|
|
253
|
+
|
|
254
|
+
# Check if we need elevation
|
|
255
|
+
if "administrator" in result.stderr.lower() or result.returncode == 740:
|
|
256
|
+
log("Requesting administrator privileges...")
|
|
257
|
+
return self._install_media_foundation_elevated(log)
|
|
258
|
+
|
|
259
|
+
# Other error
|
|
260
|
+
return (False,
|
|
261
|
+
f"DISM failed with code {result.returncode}:\n{result.stderr}\n\n"
|
|
262
|
+
f"Please install Media Foundation manually:\n"
|
|
263
|
+
f" 1. Open Settings > Apps > Optional Features\n"
|
|
264
|
+
f" 2. Click 'Add a feature'\n"
|
|
265
|
+
f" 3. Search for 'Media Feature Pack' and install it\n"
|
|
266
|
+
f" 4. Restart your computer")
|
|
267
|
+
|
|
268
|
+
except subprocess.TimeoutExpired:
|
|
269
|
+
return (False, "DISM timed out. Please try installing manually via Settings.")
|
|
270
|
+
except FileNotFoundError:
|
|
271
|
+
return (False, "DISM.exe not found. Please install Media Feature Pack manually via Settings.")
|
|
272
|
+
except Exception as e:
|
|
273
|
+
return (False, f"Error running DISM: {e}")
|
|
274
|
+
|
|
275
|
+
def _install_media_foundation_elevated(self, log_callback=None) -> Tuple[bool, Optional[str]]:
|
|
276
|
+
"""
|
|
277
|
+
Install Media Foundation with UAC elevation.
|
|
278
|
+
|
|
279
|
+
Uses PowerShell Start-Process -Verb RunAs to trigger UAC prompt.
|
|
280
|
+
"""
|
|
281
|
+
log = log_callback or print
|
|
282
|
+
|
|
283
|
+
# Create a PowerShell script that runs DISM elevated
|
|
284
|
+
ps_script = '''
|
|
285
|
+
$result = Start-Process -FilePath "DISM.exe" -ArgumentList "/Online", "/Add-Capability", "/CapabilityName:Media.MediaFeaturePack~~~~0.0.1.0" -Verb RunAs -Wait -PassThru
|
|
286
|
+
exit $result.ExitCode
|
|
287
|
+
'''
|
|
288
|
+
|
|
289
|
+
try:
|
|
290
|
+
result = subprocess.run(
|
|
291
|
+
["powershell", "-ExecutionPolicy", "Bypass", "-Command", ps_script],
|
|
292
|
+
capture_output=True,
|
|
293
|
+
text=True,
|
|
294
|
+
timeout=300
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
if result.returncode == 0:
|
|
298
|
+
# Verify installation
|
|
299
|
+
if self.check_media_foundation():
|
|
300
|
+
log("Media Foundation installed successfully!")
|
|
301
|
+
return (True, None)
|
|
302
|
+
else:
|
|
303
|
+
return (False,
|
|
304
|
+
"Installation completed but Media Foundation DLLs not found.\n"
|
|
305
|
+
"A system restart may be required.")
|
|
306
|
+
else:
|
|
307
|
+
return (False,
|
|
308
|
+
f"Installation failed or was cancelled.\n"
|
|
309
|
+
f"Please install Media Feature Pack manually:\n"
|
|
310
|
+
f" Settings > Apps > Optional Features > Add a feature > Media Feature Pack")
|
|
311
|
+
|
|
312
|
+
except subprocess.TimeoutExpired:
|
|
313
|
+
return (False, "Installation timed out. Please try installing manually via Settings.")
|
|
314
|
+
except Exception as e:
|
|
315
|
+
return (False, f"Error during elevated installation: {e}")
|
|
316
|
+
|
|
317
|
+
def ensure_media_foundation(self, log_callback=None) -> Tuple[bool, Optional[str]]:
|
|
318
|
+
"""
|
|
319
|
+
Ensure Media Foundation is installed, installing if necessary.
|
|
320
|
+
|
|
321
|
+
This is the main entry point for MF dependency checking.
|
|
322
|
+
"""
|
|
323
|
+
if self.check_media_foundation():
|
|
324
|
+
return (True, None)
|
|
325
|
+
|
|
326
|
+
return self.install_media_foundation(log_callback)
|
|
327
|
+
|
|
328
|
+
# =========================================================================
|
|
329
|
+
# OpenCV DLL Directory Setup
|
|
330
|
+
# =========================================================================
|
|
331
|
+
|
|
332
|
+
def setup_opencv_dll_paths(self, env_dir: Path) -> Tuple[bool, Optional[str]]:
|
|
333
|
+
"""
|
|
334
|
+
Set up the DLL directory structure that opencv-python expects.
|
|
335
|
+
|
|
336
|
+
OpenCV's config.py expects VC++ DLLs at:
|
|
337
|
+
{site-packages}/cv2/../../x64/vc17/bin
|
|
338
|
+
Which resolves to:
|
|
339
|
+
{env_dir}/Lib/x64/vc17/bin
|
|
340
|
+
|
|
341
|
+
This copies the VC++ DLLs to that location.
|
|
342
|
+
"""
|
|
343
|
+
# Target directory that opencv expects
|
|
344
|
+
target_dir = env_dir / "Lib" / "x64" / "vc17" / "bin"
|
|
345
|
+
|
|
346
|
+
# Source: DLLs in Scripts or base env dir (from msvc-runtime package)
|
|
347
|
+
scripts_dir = env_dir / "Scripts"
|
|
348
|
+
|
|
349
|
+
vc_dlls = [
|
|
350
|
+
'vcruntime140.dll', 'vcruntime140_1.dll', 'vcruntime140_threads.dll',
|
|
351
|
+
'msvcp140.dll', 'msvcp140_1.dll', 'msvcp140_2.dll',
|
|
352
|
+
'msvcp140_atomic_wait.dll', 'msvcp140_codecvt_ids.dll',
|
|
353
|
+
'concrt140.dll', 'vcomp140.dll', 'vcamp140.dll', 'vccorlib140.dll'
|
|
354
|
+
]
|
|
355
|
+
|
|
356
|
+
try:
|
|
357
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
358
|
+
|
|
359
|
+
copied = 0
|
|
360
|
+
for dll_name in vc_dlls:
|
|
361
|
+
# Try Scripts first, then env root
|
|
362
|
+
for source_dir in [scripts_dir, env_dir]:
|
|
363
|
+
source = source_dir / dll_name
|
|
364
|
+
if source.exists():
|
|
365
|
+
target = target_dir / dll_name
|
|
366
|
+
if not target.exists():
|
|
367
|
+
shutil.copy2(source, target)
|
|
368
|
+
copied += 1
|
|
369
|
+
break
|
|
370
|
+
|
|
371
|
+
if copied > 0:
|
|
372
|
+
return (True, f"Copied {copied} VC++ DLLs to opencv path")
|
|
373
|
+
else:
|
|
374
|
+
return (True, "VC++ DLLs already in place or not found in venv")
|
|
375
|
+
|
|
376
|
+
except Exception as e:
|
|
377
|
+
return (False, f"Failed to set up opencv DLL paths: {e}")
|
comfy_env/workers/venv.py
CHANGED
|
@@ -421,6 +421,19 @@ import json
|
|
|
421
421
|
import traceback
|
|
422
422
|
from types import SimpleNamespace
|
|
423
423
|
|
|
424
|
+
# On Windows, add host Python's DLL directories so packages like opencv can find VC++ runtime
|
|
425
|
+
if sys.platform == "win32":
|
|
426
|
+
_host_python_dir = os.environ.get("COMFYUI_HOST_PYTHON_DIR")
|
|
427
|
+
if _host_python_dir and hasattr(os, "add_dll_directory"):
|
|
428
|
+
try:
|
|
429
|
+
os.add_dll_directory(_host_python_dir)
|
|
430
|
+
# Also add DLLs subdirectory if it exists
|
|
431
|
+
_dlls_dir = os.path.join(_host_python_dir, "DLLs")
|
|
432
|
+
if os.path.isdir(_dlls_dir):
|
|
433
|
+
os.add_dll_directory(_dlls_dir)
|
|
434
|
+
except Exception:
|
|
435
|
+
pass
|
|
436
|
+
|
|
424
437
|
def _deserialize_isolated_objects(obj):
|
|
425
438
|
"""Reconstruct objects serialized with __isolated_object__ marker."""
|
|
426
439
|
if isinstance(obj, dict):
|
|
@@ -437,6 +450,10 @@ def _deserialize_isolated_objects(obj):
|
|
|
437
450
|
return obj
|
|
438
451
|
|
|
439
452
|
def main():
|
|
453
|
+
# Save original stdout for JSON IPC - redirect stdout to stderr for module prints
|
|
454
|
+
_ipc_out = sys.stdout
|
|
455
|
+
sys.stdout = sys.stderr # All print() calls go to stderr now
|
|
456
|
+
|
|
440
457
|
# Read config from first line
|
|
441
458
|
config_line = sys.stdin.readline()
|
|
442
459
|
if not config_line:
|
|
@@ -451,9 +468,9 @@ def main():
|
|
|
451
468
|
# Import torch after path setup
|
|
452
469
|
import torch
|
|
453
470
|
|
|
454
|
-
# Signal ready
|
|
455
|
-
|
|
456
|
-
|
|
471
|
+
# Signal ready (use _ipc_out, not stdout)
|
|
472
|
+
_ipc_out.write(json.dumps({"status": "ready"}) + "\\n")
|
|
473
|
+
_ipc_out.flush()
|
|
457
474
|
|
|
458
475
|
# Process requests
|
|
459
476
|
while True:
|
|
@@ -504,16 +521,16 @@ def main():
|
|
|
504
521
|
if outputs_path:
|
|
505
522
|
torch.save(result, outputs_path)
|
|
506
523
|
|
|
507
|
-
|
|
508
|
-
|
|
524
|
+
_ipc_out.write(json.dumps({"status": "ok"}) + "\\n")
|
|
525
|
+
_ipc_out.flush()
|
|
509
526
|
|
|
510
527
|
except Exception as e:
|
|
511
|
-
|
|
528
|
+
_ipc_out.write(json.dumps({
|
|
512
529
|
"status": "error",
|
|
513
530
|
"error": str(e),
|
|
514
531
|
"traceback": traceback.format_exc(),
|
|
515
532
|
}) + "\\n")
|
|
516
|
-
|
|
533
|
+
_ipc_out.flush()
|
|
517
534
|
|
|
518
535
|
if __name__ == "__main__":
|
|
519
536
|
main()
|
|
@@ -598,6 +615,11 @@ class PersistentVenvWorker(Worker):
|
|
|
598
615
|
env.update(self.extra_env)
|
|
599
616
|
env["COMFYUI_ISOLATION_WORKER"] = "1"
|
|
600
617
|
|
|
618
|
+
# On Windows, pass host Python directory so worker can add it via os.add_dll_directory()
|
|
619
|
+
# This fixes "DLL load failed" errors for packages like opencv-python-headless
|
|
620
|
+
if sys.platform == "win32":
|
|
621
|
+
env["COMFYUI_HOST_PYTHON_DIR"] = str(Path(sys.executable).parent)
|
|
622
|
+
|
|
601
623
|
# Find ComfyUI base and set env var for folder_paths stub
|
|
602
624
|
comfyui_base = self._find_comfyui_base()
|
|
603
625
|
if comfyui_base:
|
|
@@ -620,6 +642,18 @@ class PersistentVenvWorker(Worker):
|
|
|
620
642
|
text=True, # Text mode for JSON
|
|
621
643
|
)
|
|
622
644
|
|
|
645
|
+
# Start stderr forwarding thread to show worker output in real-time
|
|
646
|
+
def forward_stderr():
|
|
647
|
+
try:
|
|
648
|
+
for line in self._process.stderr:
|
|
649
|
+
# Forward to main process stderr (visible in console)
|
|
650
|
+
sys.stderr.write(f" {line}")
|
|
651
|
+
sys.stderr.flush()
|
|
652
|
+
except:
|
|
653
|
+
pass
|
|
654
|
+
self._stderr_thread = threading.Thread(target=forward_stderr, daemon=True)
|
|
655
|
+
self._stderr_thread.start()
|
|
656
|
+
|
|
623
657
|
# Send config
|
|
624
658
|
config = {"sys_paths": all_sys_path}
|
|
625
659
|
self._process.stdin.write(json.dumps(config) + "\n")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: comfy-env
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
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,4 +1,4 @@
|
|
|
1
|
-
comfy_env/__init__.py,sha256=
|
|
1
|
+
comfy_env/__init__.py,sha256=U5XtB2UeXZi8JPBhlh0XjQprLsAuVslPoJNWOSvCFhs,4249
|
|
2
2
|
comfy_env/cli.py,sha256=9GvQYrXlJRl0ZaCuFHvRtVxWQ34Axd5Brgu5FWRONp4,11424
|
|
3
3
|
comfy_env/decorator.py,sha256=daFR5aLzshkmo5sRKhSGPcTUgIUWml7Gs6A1bfnDuyc,15718
|
|
4
4
|
comfy_env/errors.py,sha256=egeyXY-j7KpxyA0s67TcJLEfJX23LCAD3v1P4FgQIGE,10917
|
|
@@ -7,16 +7,16 @@ comfy_env/registry.py,sha256=iZprw2iIAJl-Vvotsf_B_PofzqE-6IiVfNPBHYUYg6g,11577
|
|
|
7
7
|
comfy_env/resolver.py,sha256=xz7GPlxy02iwwpocIzzbdGnrwnSpi-D5IzpL8SQSgvI,12893
|
|
8
8
|
comfy_env/runner.py,sha256=0YUqzK93u--7pKV6_yVC564AJE9rS3y81t5ZhQi2t4Y,9696
|
|
9
9
|
comfy_env/env/__init__.py,sha256=sybOBrxJCfL4Xry9NNd5xwn9hXIHudXlXDa7SpJkPCE,811
|
|
10
|
-
comfy_env/env/config.py,sha256=
|
|
11
|
-
comfy_env/env/config_file.py,sha256=
|
|
10
|
+
comfy_env/env/config.py,sha256=R8JyE5iQLHKgnxXOGA8SAI7iu2eYSfXn-MsaqHoU2_A,5667
|
|
11
|
+
comfy_env/env/config_file.py,sha256=2sTeBUqdDYPwQfUO-3Mu2zTsgxQ4IhllRxEd2a4pgPg,20593
|
|
12
12
|
comfy_env/env/detection.py,sha256=Co8BJmTRCq1ZHDsm6832jF87za0GRAhH7zF04-5QwcE,4949
|
|
13
|
-
comfy_env/env/manager.py,sha256=
|
|
13
|
+
comfy_env/env/manager.py,sha256=hGaK9C_nRwfHthowgFv2rPhhpfAMDJhxPEdQFFv6BbI,24770
|
|
14
14
|
comfy_env/env/security.py,sha256=dNSitAnfBNVdvxgBBntYw33AJaCs_S1MHb7KJhAVYzM,8171
|
|
15
15
|
comfy_env/env/platform/__init__.py,sha256=Nb5MPZIEeanSMEWwqU4p4bnEKTJn1tWcwobnhq9x9IY,614
|
|
16
16
|
comfy_env/env/platform/base.py,sha256=iS0ptTTVjXRwPU4qWUdvHI7jteuzxGSjWr5BUQ7hGiU,2453
|
|
17
17
|
comfy_env/env/platform/darwin.py,sha256=HK3VkLT6DfesAnIXwx2IaUFHTBclF0xTQnC7azWY6Kc,1552
|
|
18
18
|
comfy_env/env/platform/linux.py,sha256=xLp8FEbFqZLQrzIZBI9z3C4g23Ab1ASTHLsXDzsdCoA,2062
|
|
19
|
-
comfy_env/env/platform/windows.py,sha256=
|
|
19
|
+
comfy_env/env/platform/windows.py,sha256=nD1-bKU2rGmEJlS-cc5yWXMSA51YQtVupn-lQEO5UYA,14840
|
|
20
20
|
comfy_env/ipc/__init__.py,sha256=pTjgJn5YJxLXmEvuKh3lkCEJQs-6W6_F01jfkFMUi0c,1375
|
|
21
21
|
comfy_env/ipc/bridge.py,sha256=kEy__kco8FVQNj5MyadF5k00YEivcGmifAJAOfr643U,17645
|
|
22
22
|
comfy_env/ipc/protocol.py,sha256=gfWe5yEDUn4QWhcdWFcxn40GqxlW1Uf23j0edOzPPng,7951
|
|
@@ -31,9 +31,9 @@ comfy_env/workers/base.py,sha256=ZILYXlvGCWuCZXmjKqfG8VeD19ihdYaASdlbasl2BMo,231
|
|
|
31
31
|
comfy_env/workers/pool.py,sha256=MtjeOWfvHSCockq8j1gfnxIl-t01GSB79T5N4YB82Lg,6956
|
|
32
32
|
comfy_env/workers/tensor_utils.py,sha256=TCuOAjJymrSbkgfyvcKtQ_KbVWTqSwP9VH_bCaFLLq8,6409
|
|
33
33
|
comfy_env/workers/torch_mp.py,sha256=DsfxE3LBAWEuGtk-p-YL0UhVQ7VDh73KT_TFRxYN4-Q,12563
|
|
34
|
-
comfy_env/workers/venv.py,sha256=
|
|
35
|
-
comfy_env-0.0.
|
|
36
|
-
comfy_env-0.0.
|
|
37
|
-
comfy_env-0.0.
|
|
38
|
-
comfy_env-0.0.
|
|
39
|
-
comfy_env-0.0.
|
|
34
|
+
comfy_env/workers/venv.py,sha256=_ekHfZPqBIPY08DjqiXm6cTBQH4DrbxRWR3AAv3mit8,31589
|
|
35
|
+
comfy_env-0.0.9.dist-info/METADATA,sha256=HwKjPaZyiGGsJ47w8nempK8MokAu1YbWS1ZqwSCXS_4,5371
|
|
36
|
+
comfy_env-0.0.9.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
37
|
+
comfy_env-0.0.9.dist-info/entry_points.txt,sha256=J4fXeqgxU_YenuW_Zxn_pEL7J-3R0--b6MS5t0QmAr0,49
|
|
38
|
+
comfy_env-0.0.9.dist-info/licenses/LICENSE,sha256=E68QZMMpW4P2YKstTZ3QU54HRQO8ecew09XZ4_Vn870,1093
|
|
39
|
+
comfy_env-0.0.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|