comfy-env 0.0.71__tar.gz → 0.0.72__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.71 → comfy_env-0.0.72}/PKG-INFO +1 -1
- {comfy_env-0.0.71 → comfy_env-0.0.72}/pyproject.toml +1 -1
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/cli.py +96 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/config/parser.py +6 -1
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/config/types.py +3 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/prestartup.py +38 -3
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/templates/comfy-env.toml +16 -1
- {comfy_env-0.0.71 → comfy_env-0.0.72}/.github/workflows/ci.yml +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/.github/workflows/publish.yml +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/.gitignore +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/LICENSE +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/README.md +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/__init__.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/config/__init__.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/errors.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/install.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/isolation/__init__.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/isolation/wrap.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/nodes.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/__init__.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/core.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/cuda_detection.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/platform/__init__.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/platform/base.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/platform/darwin.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/platform/linux.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/platform/windows.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/pixi/resolver.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/workers/__init__.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/workers/base.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/workers/mp.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/src/comfy_env/workers/subprocess.py +0 -0
- {comfy_env-0.0.71 → comfy_env-0.0.72}/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.72
|
|
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
|
|
@@ -119,6 +119,23 @@ def main(args: Optional[List[str]] = None) -> int:
|
|
|
119
119
|
help="Path to config file",
|
|
120
120
|
)
|
|
121
121
|
|
|
122
|
+
# apt-install command
|
|
123
|
+
apt_parser = subparsers.add_parser(
|
|
124
|
+
"apt-install",
|
|
125
|
+
help="Install system packages from [apt] section (Linux only)",
|
|
126
|
+
description="Read [apt] packages from comfy-env.toml and install via apt-get",
|
|
127
|
+
)
|
|
128
|
+
apt_parser.add_argument(
|
|
129
|
+
"--config", "-c",
|
|
130
|
+
type=str,
|
|
131
|
+
help="Path to comfy-env.toml (default: auto-discover)",
|
|
132
|
+
)
|
|
133
|
+
apt_parser.add_argument(
|
|
134
|
+
"--dry-run",
|
|
135
|
+
action="store_true",
|
|
136
|
+
help="Show what would be installed without installing",
|
|
137
|
+
)
|
|
138
|
+
|
|
122
139
|
parsed = parser.parse_args(args)
|
|
123
140
|
|
|
124
141
|
if parsed.command is None:
|
|
@@ -136,6 +153,8 @@ def main(args: Optional[List[str]] = None) -> int:
|
|
|
136
153
|
return cmd_info(parsed)
|
|
137
154
|
elif parsed.command == "doctor":
|
|
138
155
|
return cmd_doctor(parsed)
|
|
156
|
+
elif parsed.command == "apt-install":
|
|
157
|
+
return cmd_apt_install(parsed)
|
|
139
158
|
else:
|
|
140
159
|
parser.print_help()
|
|
141
160
|
return 1
|
|
@@ -332,5 +351,82 @@ def cmd_doctor(args) -> int:
|
|
|
332
351
|
return 0
|
|
333
352
|
|
|
334
353
|
|
|
354
|
+
def cmd_apt_install(args) -> int:
|
|
355
|
+
"""Handle apt-install command - install system packages from [apt] section."""
|
|
356
|
+
import os
|
|
357
|
+
import shutil
|
|
358
|
+
import subprocess
|
|
359
|
+
import platform
|
|
360
|
+
|
|
361
|
+
if platform.system() != "Linux":
|
|
362
|
+
print("apt-install is only supported on Linux", file=sys.stderr)
|
|
363
|
+
return 1
|
|
364
|
+
|
|
365
|
+
# Find config
|
|
366
|
+
if args.config:
|
|
367
|
+
config_path = Path(args.config).resolve()
|
|
368
|
+
else:
|
|
369
|
+
config_path = Path.cwd() / "comfy-env.toml"
|
|
370
|
+
|
|
371
|
+
if not config_path.exists():
|
|
372
|
+
print(f"Config file not found: {config_path}", file=sys.stderr)
|
|
373
|
+
return 1
|
|
374
|
+
|
|
375
|
+
# Parse config to get apt packages
|
|
376
|
+
from .config.parser import load_config
|
|
377
|
+
config = load_config(config_path)
|
|
378
|
+
|
|
379
|
+
if not config.apt_packages:
|
|
380
|
+
print("No [apt] packages specified in config")
|
|
381
|
+
return 0
|
|
382
|
+
|
|
383
|
+
packages = config.apt_packages
|
|
384
|
+
print(f"Found {len(packages)} apt package(s) to install:")
|
|
385
|
+
for pkg in packages:
|
|
386
|
+
print(f" - {pkg}")
|
|
387
|
+
|
|
388
|
+
# Determine if we need sudo
|
|
389
|
+
is_root = os.geteuid() == 0
|
|
390
|
+
has_sudo = shutil.which("sudo") is not None
|
|
391
|
+
use_sudo = not is_root and has_sudo
|
|
392
|
+
|
|
393
|
+
prefix = ["sudo"] if use_sudo else []
|
|
394
|
+
|
|
395
|
+
if args.dry_run:
|
|
396
|
+
print("\n[Dry run] Would run:")
|
|
397
|
+
prefix_str = "sudo " if use_sudo else ""
|
|
398
|
+
print(f" {prefix_str}apt-get update && {prefix_str}apt-get install -y {' '.join(packages)}")
|
|
399
|
+
return 0
|
|
400
|
+
|
|
401
|
+
if not is_root and not has_sudo:
|
|
402
|
+
print("\nError: Need root privileges to install apt packages.", file=sys.stderr)
|
|
403
|
+
print("Run manually with:", file=sys.stderr)
|
|
404
|
+
print(f" sudo apt-get update && sudo apt-get install -y {' '.join(packages)}", file=sys.stderr)
|
|
405
|
+
return 1
|
|
406
|
+
|
|
407
|
+
# Run apt-get update
|
|
408
|
+
print("\nUpdating package lists...")
|
|
409
|
+
result = subprocess.run(
|
|
410
|
+
prefix + ["apt-get", "update"],
|
|
411
|
+
capture_output=False,
|
|
412
|
+
)
|
|
413
|
+
if result.returncode != 0:
|
|
414
|
+
print("Warning: apt-get update failed, continuing anyway...")
|
|
415
|
+
|
|
416
|
+
# Run apt-get install
|
|
417
|
+
print(f"\nInstalling: {' '.join(packages)}")
|
|
418
|
+
result = subprocess.run(
|
|
419
|
+
prefix + ["apt-get", "install", "-y"] + packages,
|
|
420
|
+
capture_output=False,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
if result.returncode == 0:
|
|
424
|
+
print("\nSystem packages installed successfully!")
|
|
425
|
+
return 0
|
|
426
|
+
else:
|
|
427
|
+
print("\nFailed to install some packages", file=sys.stderr)
|
|
428
|
+
return result.returncode
|
|
429
|
+
|
|
430
|
+
|
|
335
431
|
if __name__ == "__main__":
|
|
336
432
|
sys.exit(main())
|
|
@@ -49,7 +49,7 @@ from .types import ComfyEnvConfig, NodeReq
|
|
|
49
49
|
CONFIG_FILE_NAME = "comfy-env.toml"
|
|
50
50
|
|
|
51
51
|
# Sections we handle specially (not passed through to pixi.toml)
|
|
52
|
-
CUSTOM_SECTIONS = {"python", "cuda", "node_reqs", "apt"}
|
|
52
|
+
CUSTOM_SECTIONS = {"python", "cuda", "node_reqs", "apt", "env_vars"}
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
def load_config(path: Path) -> ComfyEnvConfig:
|
|
@@ -120,6 +120,10 @@ def _parse_config(data: Dict[str, Any]) -> ComfyEnvConfig:
|
|
|
120
120
|
apt_data = data.pop("apt", {})
|
|
121
121
|
apt_packages = _ensure_list(apt_data.get("packages", []))
|
|
122
122
|
|
|
123
|
+
# Extract [env_vars] section
|
|
124
|
+
env_vars_data = data.pop("env_vars", {})
|
|
125
|
+
env_vars = {str(k): str(v) for k, v in env_vars_data.items()}
|
|
126
|
+
|
|
123
127
|
# Extract [node_reqs] section
|
|
124
128
|
node_reqs_data = data.pop("node_reqs", {})
|
|
125
129
|
node_reqs = _parse_node_reqs(node_reqs_data)
|
|
@@ -131,6 +135,7 @@ def _parse_config(data: Dict[str, Any]) -> ComfyEnvConfig:
|
|
|
131
135
|
python=python_version,
|
|
132
136
|
cuda_packages=cuda_packages,
|
|
133
137
|
apt_packages=apt_packages,
|
|
138
|
+
env_vars=env_vars,
|
|
134
139
|
node_reqs=node_reqs,
|
|
135
140
|
pixi_passthrough=pixi_passthrough,
|
|
136
141
|
)
|
|
@@ -56,6 +56,9 @@ class ComfyEnvConfig:
|
|
|
56
56
|
# [apt] - System packages to install via apt (Linux only)
|
|
57
57
|
apt_packages: List[str] = field(default_factory=list)
|
|
58
58
|
|
|
59
|
+
# [env_vars] - Environment variables to set early (in prestartup)
|
|
60
|
+
env_vars: Dict[str, str] = field(default_factory=dict)
|
|
61
|
+
|
|
59
62
|
# [node_reqs] - other ComfyUI nodes to clone
|
|
60
63
|
node_reqs: List[NodeReq] = field(default_factory=list)
|
|
61
64
|
|
|
@@ -8,7 +8,35 @@ import glob
|
|
|
8
8
|
import os
|
|
9
9
|
import sys
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Optional
|
|
11
|
+
from typing import Optional, Dict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _load_env_vars(config_path: str) -> Dict[str, str]:
|
|
15
|
+
"""
|
|
16
|
+
Load [env_vars] section from comfy-env.toml.
|
|
17
|
+
|
|
18
|
+
Uses tomllib (Python 3.11+) or tomli fallback.
|
|
19
|
+
Returns empty dict if file not found or parsing fails.
|
|
20
|
+
"""
|
|
21
|
+
if not os.path.exists(config_path):
|
|
22
|
+
return {}
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
if sys.version_info >= (3, 11):
|
|
26
|
+
import tomllib
|
|
27
|
+
else:
|
|
28
|
+
try:
|
|
29
|
+
import tomli as tomllib
|
|
30
|
+
except ImportError:
|
|
31
|
+
return {}
|
|
32
|
+
|
|
33
|
+
with open(config_path, "rb") as f:
|
|
34
|
+
data = tomllib.load(f)
|
|
35
|
+
|
|
36
|
+
env_vars_data = data.get("env_vars", {})
|
|
37
|
+
return {str(k): str(v) for k, v in env_vars_data.items()}
|
|
38
|
+
except Exception:
|
|
39
|
+
return {}
|
|
12
40
|
|
|
13
41
|
|
|
14
42
|
def setup_env(node_dir: Optional[str] = None) -> None:
|
|
@@ -16,8 +44,9 @@ def setup_env(node_dir: Optional[str] = None) -> None:
|
|
|
16
44
|
Set up environment for pixi conda libraries.
|
|
17
45
|
|
|
18
46
|
Call this in prestartup_script.py before any native library imports.
|
|
19
|
-
|
|
20
|
-
|
|
47
|
+
- Applies [env_vars] from comfy-env.toml first (for OpenMP settings, etc.)
|
|
48
|
+
- Sets LD_LIBRARY_PATH (Linux/Mac) or PATH (Windows) for conda libs
|
|
49
|
+
- Adds pixi site-packages to sys.path
|
|
21
50
|
|
|
22
51
|
Args:
|
|
23
52
|
node_dir: Path to the custom node directory. Auto-detected if not provided.
|
|
@@ -33,6 +62,12 @@ def setup_env(node_dir: Optional[str] = None) -> None:
|
|
|
33
62
|
frame = inspect.stack()[1]
|
|
34
63
|
node_dir = str(Path(frame.filename).parent)
|
|
35
64
|
|
|
65
|
+
# Apply [env_vars] from comfy-env.toml FIRST (before any library loading)
|
|
66
|
+
config_path = os.path.join(node_dir, "comfy-env.toml")
|
|
67
|
+
env_vars = _load_env_vars(config_path)
|
|
68
|
+
for key, value in env_vars.items():
|
|
69
|
+
os.environ[key] = value
|
|
70
|
+
|
|
36
71
|
pixi_env = os.path.join(node_dir, ".pixi", "envs", "default")
|
|
37
72
|
|
|
38
73
|
if not os.path.exists(pixi_env):
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# =============================================================================
|
|
4
4
|
#
|
|
5
5
|
# comfy-env.toml is a SUPERSET of pixi.toml. All pixi.toml syntax works here.
|
|
6
|
-
# We add custom sections: [cuda], [node_reqs], and top-level `python = "x.x"`.
|
|
6
|
+
# We add custom sections: [cuda], [node_reqs], [env_vars], and top-level `python = "x.x"`.
|
|
7
7
|
#
|
|
8
8
|
# GPU is auto-detected to select the right CUDA version.
|
|
9
9
|
#
|
|
@@ -22,6 +22,21 @@
|
|
|
22
22
|
# python = "3.11"
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
# =============================================================================
|
|
26
|
+
# ENVIRONMENT VARIABLES (custom section)
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# Environment variables applied early via setup_env() in prestartup_script.py.
|
|
29
|
+
# Useful for OpenMP settings, library configs, etc. that must be set before imports.
|
|
30
|
+
#
|
|
31
|
+
# Requires prestartup_script.py in your node directory:
|
|
32
|
+
# from comfy_env import setup_env
|
|
33
|
+
# setup_env()
|
|
34
|
+
|
|
35
|
+
[env_vars]
|
|
36
|
+
# KMP_DUPLICATE_LIB_OK = "TRUE" # Allow duplicate OpenMP libraries (macOS fix)
|
|
37
|
+
# OMP_NUM_THREADS = "4" # Limit OpenMP threads
|
|
38
|
+
|
|
39
|
+
|
|
25
40
|
# =============================================================================
|
|
26
41
|
# CUDA PACKAGES (custom section)
|
|
27
42
|
# =============================================================================
|
|
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
|