comfy-env 0.0.55__tar.gz → 0.0.57__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.55 → comfy_env-0.0.57}/PKG-INFO +1 -1
- {comfy_env-0.0.55 → comfy_env-0.0.57}/pyproject.toml +1 -1
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/isolation.py +12 -5
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/pixi.py +129 -62
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/workers/venv.py +55 -31
- {comfy_env-0.0.55 → comfy_env-0.0.57}/.github/workflows/publish.yml +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/.gitignore +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/LICENSE +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/README.md +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/__init__.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/cli.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/decorator.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/__init__.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/config.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/config_file.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/cuda_gpu_detection.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/manager.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/platform/__init__.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/platform/base.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/platform/darwin.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/platform/linux.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/platform/windows.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/env/security.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/errors.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/install.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/ipc/__init__.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/ipc/bridge.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/ipc/protocol.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/ipc/tensor.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/ipc/torch_bridge.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/ipc/transport.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/ipc/worker.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/nodes.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/registry.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/resolver.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/stub_imports.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/stubs/__init__.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/stubs/comfy/__init__.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/stubs/comfy/model_management.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/stubs/comfy/utils.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/stubs/folder_paths.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/templates/comfy-env.toml +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/wheel_sources.yml +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/workers/__init__.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/workers/base.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/workers/pool.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/src/comfy_env/workers/tensor_utils.py +0 -0
- {comfy_env-0.0.55 → comfy_env-0.0.57}/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.
|
|
3
|
+
Version: 0.0.57
|
|
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
|
|
@@ -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
|
-
|
|
162
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
190
|
+
if _DEBUG:
|
|
191
|
+
print(f"[comfy-env] call_method returned", flush=True)
|
|
185
192
|
|
|
186
193
|
# Clone result tensors
|
|
187
194
|
try:
|
|
@@ -181,6 +181,97 @@ def _parse_pypi_requirement(dep: str) -> Tuple[str, Optional[str], List[str]]:
|
|
|
181
181
|
return name, version_spec, extras
|
|
182
182
|
|
|
183
183
|
|
|
184
|
+
def _build_cuda_vars(env_config: IsolatedEnv) -> dict:
|
|
185
|
+
"""
|
|
186
|
+
Build variable dict for CUDA wheel URL resolution.
|
|
187
|
+
|
|
188
|
+
Returns a dict with CUDA, PyTorch, Python, and platform variables
|
|
189
|
+
for template substitution.
|
|
190
|
+
"""
|
|
191
|
+
# Use fixed CUDA 12.8 / PyTorch 2.8 for pixi environments (modern GPU default)
|
|
192
|
+
vars_dict = {
|
|
193
|
+
"cuda_version": "12.8",
|
|
194
|
+
"cuda_short": "128",
|
|
195
|
+
"cuda_short2": "128",
|
|
196
|
+
"cuda_major": "12",
|
|
197
|
+
"torch_version": "2.8.0",
|
|
198
|
+
"torch_short": "280",
|
|
199
|
+
"torch_mm": "28",
|
|
200
|
+
"torch_dotted_mm": "2.8",
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
# Platform detection
|
|
204
|
+
if sys.platform == "linux":
|
|
205
|
+
vars_dict["platform"] = "linux_x86_64"
|
|
206
|
+
elif sys.platform == "darwin":
|
|
207
|
+
vars_dict["platform"] = "macosx_arm64" if platform.machine() == "arm64" else "macosx_x86_64"
|
|
208
|
+
elif sys.platform == "win32":
|
|
209
|
+
vars_dict["platform"] = "win_amd64"
|
|
210
|
+
|
|
211
|
+
# Python version from env config
|
|
212
|
+
if env_config.python:
|
|
213
|
+
py_parts = env_config.python.split(".")
|
|
214
|
+
py_major = py_parts[0]
|
|
215
|
+
py_minor = py_parts[1] if len(py_parts) > 1 else "0"
|
|
216
|
+
vars_dict["py_version"] = env_config.python
|
|
217
|
+
vars_dict["py_short"] = f"{py_major}{py_minor}"
|
|
218
|
+
vars_dict["py_minor"] = py_minor
|
|
219
|
+
vars_dict["py_tag"] = f"cp{py_major}{py_minor}"
|
|
220
|
+
|
|
221
|
+
return vars_dict
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _resolve_cuda_wheel_url(
|
|
225
|
+
req: str,
|
|
226
|
+
vars_dict: dict,
|
|
227
|
+
log: Callable[[str], None] = print,
|
|
228
|
+
) -> Optional[str]:
|
|
229
|
+
"""
|
|
230
|
+
Resolve a CUDA package requirement to a wheel URL.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
req: Package requirement (e.g., "cumesh" or "cumesh==0.0.1")
|
|
234
|
+
vars_dict: Variable dict for URL template substitution
|
|
235
|
+
log: Logging callback
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Resolved wheel URL, or None if package not in registry.
|
|
239
|
+
"""
|
|
240
|
+
from .registry import PACKAGE_REGISTRY
|
|
241
|
+
|
|
242
|
+
# Parse requirement (e.g., "cumesh" or "cumesh==0.0.1")
|
|
243
|
+
if "==" in req:
|
|
244
|
+
pkg_name, version = req.split("==", 1)
|
|
245
|
+
else:
|
|
246
|
+
pkg_name = req
|
|
247
|
+
version = None
|
|
248
|
+
|
|
249
|
+
pkg_lower = pkg_name.lower()
|
|
250
|
+
if pkg_lower not in PACKAGE_REGISTRY:
|
|
251
|
+
log(f" Warning: CUDA package {pkg_name} not in registry")
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
config = PACKAGE_REGISTRY[pkg_lower]
|
|
255
|
+
template = config.get("wheel_template")
|
|
256
|
+
if not template:
|
|
257
|
+
log(f" Warning: No wheel template for {pkg_name}")
|
|
258
|
+
return None
|
|
259
|
+
|
|
260
|
+
# Use version from requirement or default
|
|
261
|
+
v = version or config.get("default_version")
|
|
262
|
+
if v:
|
|
263
|
+
vars_dict = vars_dict.copy() # Don't mutate original
|
|
264
|
+
vars_dict["version"] = v
|
|
265
|
+
|
|
266
|
+
# Resolve URL template
|
|
267
|
+
url = template
|
|
268
|
+
for key, value in vars_dict.items():
|
|
269
|
+
if value:
|
|
270
|
+
url = url.replace(f"{{{key}}}", str(value))
|
|
271
|
+
|
|
272
|
+
return url
|
|
273
|
+
|
|
274
|
+
|
|
184
275
|
def create_pixi_toml(
|
|
185
276
|
env_config: IsolatedEnv,
|
|
186
277
|
node_dir: Path,
|
|
@@ -193,7 +284,11 @@ def create_pixi_toml(
|
|
|
193
284
|
- Project metadata
|
|
194
285
|
- Conda channels
|
|
195
286
|
- Conda dependencies
|
|
196
|
-
- PyPI dependencies (from requirements
|
|
287
|
+
- PyPI dependencies (from requirements)
|
|
288
|
+
|
|
289
|
+
Note: CUDA packages (no_deps_requirements) are NOT included in pixi.toml.
|
|
290
|
+
They are installed separately with pip --no-deps after pixi install
|
|
291
|
+
to avoid transitive dependency conflicts.
|
|
197
292
|
|
|
198
293
|
Args:
|
|
199
294
|
env_config: The isolated environment configuration.
|
|
@@ -312,67 +407,9 @@ def create_pixi_toml(
|
|
|
312
407
|
if env_config.requirements:
|
|
313
408
|
pypi_deps.extend(env_config.requirements)
|
|
314
409
|
|
|
315
|
-
#
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
# Use fixed CUDA 12.8 / PyTorch 2.8 for pixi environments (modern GPU default)
|
|
320
|
-
# This ensures wheels match what pixi will install, not what the host has
|
|
321
|
-
vars_dict = {
|
|
322
|
-
"cuda_version": "12.8",
|
|
323
|
-
"cuda_short": "128",
|
|
324
|
-
"cuda_short2": "128",
|
|
325
|
-
"cuda_major": "12",
|
|
326
|
-
"torch_version": "2.8.0",
|
|
327
|
-
"torch_short": "280",
|
|
328
|
-
"torch_mm": "28",
|
|
329
|
-
"torch_dotted_mm": "2.8",
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
# Platform detection
|
|
333
|
-
if sys.platform == "linux":
|
|
334
|
-
vars_dict["platform"] = "linux_x86_64"
|
|
335
|
-
elif sys.platform == "darwin":
|
|
336
|
-
vars_dict["platform"] = "macosx_arm64" if platform.machine() == "arm64" else "macosx_x86_64"
|
|
337
|
-
elif sys.platform == "win32":
|
|
338
|
-
vars_dict["platform"] = "win_amd64"
|
|
339
|
-
|
|
340
|
-
# Python version from pixi env config
|
|
341
|
-
if env_config.python:
|
|
342
|
-
py_parts = env_config.python.split(".")
|
|
343
|
-
py_major = py_parts[0]
|
|
344
|
-
py_minor = py_parts[1] if len(py_parts) > 1 else "0"
|
|
345
|
-
vars_dict["py_version"] = env_config.python
|
|
346
|
-
vars_dict["py_short"] = f"{py_major}{py_minor}"
|
|
347
|
-
vars_dict["py_minor"] = py_minor
|
|
348
|
-
vars_dict["py_tag"] = f"cp{py_major}{py_minor}"
|
|
349
|
-
|
|
350
|
-
for req in env_config.no_deps_requirements:
|
|
351
|
-
# Parse requirement (e.g., "cumesh" or "cumesh==0.0.1")
|
|
352
|
-
if "==" in req:
|
|
353
|
-
pkg_name, version = req.split("==", 1)
|
|
354
|
-
else:
|
|
355
|
-
pkg_name = req
|
|
356
|
-
version = None
|
|
357
|
-
|
|
358
|
-
pkg_lower = pkg_name.lower()
|
|
359
|
-
if pkg_lower in PACKAGE_REGISTRY:
|
|
360
|
-
config = PACKAGE_REGISTRY[pkg_lower]
|
|
361
|
-
template = config.get("wheel_template")
|
|
362
|
-
if template:
|
|
363
|
-
# Use version from requirement or default
|
|
364
|
-
v = version or config.get("default_version")
|
|
365
|
-
if v:
|
|
366
|
-
vars_dict["version"] = v
|
|
367
|
-
|
|
368
|
-
# Resolve URL
|
|
369
|
-
url = template
|
|
370
|
-
for key, value in vars_dict.items():
|
|
371
|
-
if value:
|
|
372
|
-
url = url.replace(f"{{{key}}}", str(value))
|
|
373
|
-
|
|
374
|
-
special_deps[pkg_name] = f'{{ url = "{url}" }}'
|
|
375
|
-
log(f" CUDA package {pkg_name}: resolved wheel URL")
|
|
410
|
+
# NOTE: CUDA packages (no_deps_requirements) are NOT added to pixi.toml.
|
|
411
|
+
# They are installed separately with pip --no-deps after pixi install
|
|
412
|
+
# to avoid transitive dependency conflicts. See pixi_install().
|
|
376
413
|
|
|
377
414
|
# Add platform-specific requirements
|
|
378
415
|
if sys.platform == "linux" and env_config.linux_requirements:
|
|
@@ -557,6 +594,36 @@ def pixi_install(
|
|
|
557
594
|
|
|
558
595
|
log("pixi install completed successfully!")
|
|
559
596
|
|
|
597
|
+
# Phase 2: Install CUDA packages with pip --no-deps
|
|
598
|
+
# These are kept out of pixi.toml to avoid transitive dependency conflicts
|
|
599
|
+
# Skip on macOS - CUDA is not supported
|
|
600
|
+
if env_config.no_deps_requirements:
|
|
601
|
+
if sys.platform == "darwin":
|
|
602
|
+
log("Skipping CUDA packages (not supported on macOS)")
|
|
603
|
+
else:
|
|
604
|
+
log("Installing CUDA packages with --no-deps...")
|
|
605
|
+
python_path = get_pixi_python(node_dir)
|
|
606
|
+
if not python_path:
|
|
607
|
+
raise RuntimeError("Failed to find Python in pixi environment")
|
|
608
|
+
|
|
609
|
+
vars_dict = _build_cuda_vars(env_config)
|
|
610
|
+
|
|
611
|
+
for req in env_config.no_deps_requirements:
|
|
612
|
+
url = _resolve_cuda_wheel_url(req, vars_dict, log)
|
|
613
|
+
if url:
|
|
614
|
+
log(f" Installing {req} (--no-deps)...")
|
|
615
|
+
result = subprocess.run(
|
|
616
|
+
[str(python_path), "-m", "pip", "install", "--no-deps", url],
|
|
617
|
+
capture_output=True,
|
|
618
|
+
text=True,
|
|
619
|
+
)
|
|
620
|
+
if result.returncode != 0:
|
|
621
|
+
log(f" Failed to install {req}:")
|
|
622
|
+
log(result.stderr)
|
|
623
|
+
raise RuntimeError(f"Failed to install {req} with --no-deps: {result.stderr}")
|
|
624
|
+
else:
|
|
625
|
+
log(f" Warning: Could not resolve wheel URL for {req}, skipping")
|
|
626
|
+
|
|
560
627
|
# Create _env_{name} link for compatibility with uv backend
|
|
561
628
|
# This ensures code that expects _env_envname/bin/python works with pixi
|
|
562
629
|
symlink_path = node_dir / f"_env_{env_config.name}"
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1412
|
+
if _DEBUG:
|
|
1413
|
+
print(f"[PersistentVenvWorker] acquired lock, ensuring started...", file=sys.stderr, flush=True)
|
|
1396
1414
|
self._ensure_started()
|
|
1397
|
-
|
|
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
|
-
|
|
1428
|
+
if _DEBUG:
|
|
1429
|
+
print(f"[PersistentVenvWorker] serializing kwargs...", file=sys.stderr, flush=True)
|
|
1410
1430
|
serialized_kwargs = _serialize_for_ipc(kwargs)
|
|
1411
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|