comfy-env 0.0.64__py3-none-any.whl → 0.0.66__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.
Files changed (55) hide show
  1. comfy_env/__init__.py +70 -122
  2. comfy_env/cli.py +78 -7
  3. comfy_env/config/__init__.py +19 -0
  4. comfy_env/config/parser.py +151 -0
  5. comfy_env/config/types.py +64 -0
  6. comfy_env/install.py +83 -361
  7. comfy_env/isolation/__init__.py +9 -0
  8. comfy_env/isolation/wrap.py +351 -0
  9. comfy_env/nodes.py +2 -2
  10. comfy_env/pixi/__init__.py +48 -0
  11. comfy_env/pixi/core.py +356 -0
  12. comfy_env/{resolver.py → pixi/resolver.py} +1 -14
  13. comfy_env/prestartup.py +60 -0
  14. comfy_env/templates/comfy-env-instructions.txt +30 -87
  15. comfy_env/templates/comfy-env.toml +68 -136
  16. comfy_env/workers/__init__.py +21 -32
  17. comfy_env/workers/base.py +1 -1
  18. comfy_env/workers/{torch_mp.py → mp.py} +47 -14
  19. comfy_env/workers/{venv.py → subprocess.py} +405 -441
  20. {comfy_env-0.0.64.dist-info → comfy_env-0.0.66.dist-info}/METADATA +2 -1
  21. comfy_env-0.0.66.dist-info/RECORD +34 -0
  22. comfy_env/decorator.py +0 -700
  23. comfy_env/env/__init__.py +0 -47
  24. comfy_env/env/config.py +0 -201
  25. comfy_env/env/config_file.py +0 -740
  26. comfy_env/env/manager.py +0 -636
  27. comfy_env/env/security.py +0 -267
  28. comfy_env/ipc/__init__.py +0 -55
  29. comfy_env/ipc/bridge.py +0 -476
  30. comfy_env/ipc/protocol.py +0 -265
  31. comfy_env/ipc/tensor.py +0 -371
  32. comfy_env/ipc/torch_bridge.py +0 -401
  33. comfy_env/ipc/transport.py +0 -318
  34. comfy_env/ipc/worker.py +0 -221
  35. comfy_env/isolation.py +0 -310
  36. comfy_env/pixi.py +0 -760
  37. comfy_env/stub_imports.py +0 -270
  38. comfy_env/stubs/__init__.py +0 -1
  39. comfy_env/stubs/comfy/__init__.py +0 -6
  40. comfy_env/stubs/comfy/model_management.py +0 -58
  41. comfy_env/stubs/comfy/utils.py +0 -29
  42. comfy_env/stubs/folder_paths.py +0 -71
  43. comfy_env/workers/pool.py +0 -241
  44. comfy_env-0.0.64.dist-info/RECORD +0 -48
  45. /comfy_env/{env/cuda_gpu_detection.py → pixi/cuda_detection.py} +0 -0
  46. /comfy_env/{env → pixi}/platform/__init__.py +0 -0
  47. /comfy_env/{env → pixi}/platform/base.py +0 -0
  48. /comfy_env/{env → pixi}/platform/darwin.py +0 -0
  49. /comfy_env/{env → pixi}/platform/linux.py +0 -0
  50. /comfy_env/{env → pixi}/platform/windows.py +0 -0
  51. /comfy_env/{registry.py → pixi/registry.py} +0 -0
  52. /comfy_env/{wheel_sources.yml → pixi/wheel_sources.yml} +0 -0
  53. {comfy_env-0.0.64.dist-info → comfy_env-0.0.66.dist-info}/WHEEL +0 -0
  54. {comfy_env-0.0.64.dist-info → comfy_env-0.0.66.dist-info}/entry_points.txt +0 -0
  55. {comfy_env-0.0.64.dist-info → comfy_env-0.0.66.dist-info}/licenses/LICENSE +0 -0
comfy_env/__init__.py CHANGED
@@ -1,55 +1,63 @@
1
+ """
2
+ comfy-env: Environment management for ComfyUI custom nodes.
3
+
4
+ All dependencies go through pixi for unified management.
5
+
6
+ Main APIs:
7
+ - install(): Install dependencies from comfy-env.toml
8
+ - wrap_isolated_nodes(): Wrap nodes for subprocess isolation
9
+ """
10
+
1
11
  from importlib.metadata import version, PackageNotFoundError
2
12
 
3
13
  try:
4
14
  __version__ = version("comfy-env")
5
15
  except PackageNotFoundError:
6
- __version__ = "0.0.0-dev" # Fallback for editable installs
16
+ __version__ = "0.0.0-dev"
7
17
 
8
- from .env.config import IsolatedEnv, EnvManagerConfig, LocalConfig, NodeReq, CondaConfig
9
- from .env.config_file import (
10
- load_env_from_file,
11
- discover_env_config,
18
+ # Config types and parsing
19
+ from .config import (
20
+ ComfyEnvConfig,
21
+ NodeReq,
12
22
  load_config,
13
23
  discover_config,
14
- CONFIG_FILE_NAMES,
24
+ CONFIG_FILE_NAME,
15
25
  )
16
- from .env.manager import IsolatedEnvManager
17
- from .env.cuda_gpu_detection import (
18
- GPUInfo,
19
- CUDAEnvironment,
20
- detect_cuda_environment,
21
- detect_cuda_version,
22
- detect_gpu_info,
23
- detect_gpus,
24
- get_gpu_summary,
25
- get_recommended_cuda_version,
26
- )
27
- from .env.security import (
28
- normalize_env_name,
29
- validate_dependency,
30
- validate_dependencies,
31
- validate_path_within_root,
32
- validate_wheel_url,
33
- )
34
- from .ipc.bridge import WorkerBridge
35
- from .ipc.worker import BaseWorker, register
36
- from .decorator import isolated, shutdown_all_processes
37
- from .isolation import enable_isolation
38
- from .stub_imports import setup_isolated_imports, cleanup_stubs
39
-
40
- # New in-place installation API
41
- from .install import install, verify_installation
42
- from .resolver import RuntimeEnv
43
26
 
44
- # Pixi integration (for conda packages)
27
+ # Pixi integration
45
28
  from .pixi import (
46
29
  ensure_pixi,
47
30
  get_pixi_path,
48
- pixi_install,
49
- create_pixi_toml,
50
31
  get_pixi_python,
51
32
  pixi_run,
33
+ pixi_install,
34
+ CUDA_WHEELS_INDEX,
35
+ PACKAGE_REGISTRY,
36
+ detect_cuda_version,
37
+ detect_cuda_environment,
38
+ get_recommended_cuda_version,
39
+ GPUInfo,
40
+ CUDAEnvironment,
41
+ )
42
+
43
+ # Workers
44
+ from .workers import (
45
+ Worker,
46
+ WorkerError,
47
+ MPWorker,
48
+ SubprocessWorker,
52
49
  )
50
+
51
+ # Isolation
52
+ from .isolation import wrap_isolated_nodes
53
+
54
+ # Install API
55
+ from .install import install, verify_installation
56
+
57
+ # Prestartup helpers
58
+ from .prestartup import setup_env
59
+
60
+ # Errors
53
61
  from .errors import (
54
62
  EnvManagerError,
55
63
  ConfigError,
@@ -59,43 +67,39 @@ from .errors import (
59
67
  InstallError,
60
68
  )
61
69
 
62
- # New workers module (recommended API)
63
- from .workers import (
64
- Worker,
65
- TorchMPWorker,
66
- VenvWorker,
67
- WorkerPool,
68
- get_worker,
69
- register_worker,
70
- shutdown_workers,
71
- )
72
-
73
- # TorchBridge is optional (requires PyTorch)
74
- try:
75
- from .ipc.torch_bridge import TorchBridge, TorchWorker
76
- _TORCH_AVAILABLE = True
77
- except ImportError:
78
- _TORCH_AVAILABLE = False
79
-
80
- # PersistentVenvWorker requires the ipc.transport module
81
- try:
82
- from .workers.venv import PersistentVenvWorker
83
- _PERSISTENT_AVAILABLE = True
84
- except ImportError:
85
- _PERSISTENT_AVAILABLE = False
86
-
87
70
  __all__ = [
88
- # NEW: In-place installation API
71
+ # Install API
89
72
  "install",
90
73
  "verify_installation",
91
- "RuntimeEnv",
92
- # Pixi integration (for conda packages)
74
+ # Prestartup
75
+ "setup_env",
76
+ # Isolation
77
+ "wrap_isolated_nodes",
78
+ # Config
79
+ "ComfyEnvConfig",
80
+ "NodeReq",
81
+ "load_config",
82
+ "discover_config",
83
+ "CONFIG_FILE_NAME",
84
+ # Pixi
93
85
  "ensure_pixi",
94
86
  "get_pixi_path",
95
- "pixi_install",
96
- "create_pixi_toml",
97
87
  "get_pixi_python",
98
88
  "pixi_run",
89
+ "pixi_install",
90
+ "CUDA_WHEELS_INDEX",
91
+ "PACKAGE_REGISTRY",
92
+ # CUDA detection
93
+ "detect_cuda_version",
94
+ "detect_cuda_environment",
95
+ "get_recommended_cuda_version",
96
+ "GPUInfo",
97
+ "CUDAEnvironment",
98
+ # Workers
99
+ "Worker",
100
+ "WorkerError",
101
+ "MPWorker",
102
+ "SubprocessWorker",
99
103
  # Errors
100
104
  "EnvManagerError",
101
105
  "ConfigError",
@@ -103,60 +107,4 @@ __all__ = [
103
107
  "DependencyError",
104
108
  "CUDANotFoundError",
105
109
  "InstallError",
106
- # Workers API (recommended for isolation)
107
- "Worker",
108
- "TorchMPWorker",
109
- "VenvWorker",
110
- "WorkerPool",
111
- "get_worker",
112
- "register_worker",
113
- "shutdown_workers",
114
- # Environment & Config
115
- "IsolatedEnv",
116
- "EnvManagerConfig",
117
- "LocalConfig",
118
- "NodeReq",
119
- "CondaConfig",
120
- "IsolatedEnvManager",
121
- # Config file loading
122
- "load_env_from_file",
123
- "discover_env_config",
124
- "load_config",
125
- "discover_config",
126
- "CONFIG_FILE_NAMES",
127
- # Detection
128
- "GPUInfo",
129
- "CUDAEnvironment",
130
- "detect_cuda_environment",
131
- "detect_cuda_version",
132
- "detect_gpu_info",
133
- "detect_gpus",
134
- "get_gpu_summary",
135
- "get_recommended_cuda_version",
136
- # Security validation
137
- "normalize_env_name",
138
- "validate_dependency",
139
- "validate_dependencies",
140
- "validate_path_within_root",
141
- "validate_wheel_url",
142
- # Legacy IPC (subprocess-based)
143
- "WorkerBridge",
144
- "BaseWorker",
145
- "register",
146
- # Legacy Decorator API
147
- "isolated",
148
- "shutdown_all_processes",
149
- # New: Enable isolation for entire node pack
150
- "enable_isolation",
151
- # Import stubbing for isolated packages
152
- "setup_isolated_imports",
153
- "cleanup_stubs",
154
110
  ]
155
-
156
- # Add torch-based IPC if available
157
- if _TORCH_AVAILABLE:
158
- __all__ += ["TorchBridge", "TorchWorker"]
159
-
160
- # Add PersistentVenvWorker if available
161
- if _PERSISTENT_AVAILABLE:
162
- __all__ += ["PersistentVenvWorker"]
comfy_env/cli.py CHANGED
@@ -2,6 +2,8 @@
2
2
  CLI for comfy-env.
3
3
 
4
4
  Provides the `comfy-env` command with subcommands:
5
+ - init: Create a default comfy-env.toml
6
+ - generate: Generate pixi.toml from comfy-env.toml
5
7
  - install: Install dependencies from config
6
8
  - info: Show runtime environment information
7
9
  - resolve: Show resolved wheel URLs
@@ -9,7 +11,9 @@ Provides the `comfy-env` command with subcommands:
9
11
  - list-packages: Show all packages in the built-in registry
10
12
 
11
13
  Usage:
12
- comfy-env install
14
+ comfy-env init ---> creates template comfy-env.toml
15
+ comfy-env generate nodes/cgal/comfy-env.toml ---> nodes/cgal/pixi.toml
16
+ comfy-env install ---> installs from comfy
13
17
  comfy-env install --dry-run
14
18
 
15
19
  comfy-env info
@@ -54,6 +58,23 @@ def main(args: Optional[List[str]] = None) -> int:
54
58
  help="Overwrite existing config file",
55
59
  )
56
60
 
61
+ # generate command
62
+ generate_parser = subparsers.add_parser(
63
+ "generate",
64
+ help="Generate pixi.toml from comfy-env.toml",
65
+ description="Parse comfy-env.toml and generate a pixi.toml in the same directory",
66
+ )
67
+ generate_parser.add_argument(
68
+ "config",
69
+ type=str,
70
+ help="Path to comfy-env.toml",
71
+ )
72
+ generate_parser.add_argument(
73
+ "--force", "-f",
74
+ action="store_true",
75
+ help="Overwrite existing pixi.toml",
76
+ )
77
+
57
78
  # install command
58
79
  install_parser = subparsers.add_parser(
59
80
  "install",
@@ -148,6 +169,8 @@ def main(args: Optional[List[str]] = None) -> int:
148
169
  try:
149
170
  if parsed.command == "init":
150
171
  return cmd_init(parsed)
172
+ elif parsed.command == "generate":
173
+ return cmd_generate(parsed)
151
174
  elif parsed.command == "install":
152
175
  return cmd_install(parsed)
153
176
  elif parsed.command == "info":
@@ -205,6 +228,53 @@ def cmd_init(args) -> int:
205
228
  return 0
206
229
 
207
230
 
231
+ def cmd_generate(args) -> int:
232
+ """Handle generate command - create pixi.toml from comfy-env.toml."""
233
+ from .config.parser import load_config
234
+ from .pixi import create_pixi_toml
235
+
236
+ config_path = Path(args.config).resolve()
237
+
238
+ if not config_path.exists():
239
+ print(f"Config file not found: {config_path}", file=sys.stderr)
240
+ return 1
241
+
242
+ if config_path.name != "comfy-env.toml":
243
+ print(f"Warning: Expected comfy-env.toml, got {config_path.name}", file=sys.stderr)
244
+
245
+ node_dir = config_path.parent
246
+ pixi_path = node_dir / "pixi.toml"
247
+
248
+ if pixi_path.exists() and not args.force:
249
+ print(f"pixi.toml already exists: {pixi_path}", file=sys.stderr)
250
+ print("Use --force to overwrite", file=sys.stderr)
251
+ return 1
252
+
253
+ # Load the config
254
+ config = load_config(config_path)
255
+ if not config or not config.envs:
256
+ print(f"No environments found in {config_path}", file=sys.stderr)
257
+ return 1
258
+
259
+ # Use the first environment
260
+ env_name = next(iter(config.envs.keys()))
261
+ env_config = config.envs[env_name]
262
+
263
+ print(f"Generating pixi.toml from {config_path}")
264
+ print(f" Environment: {env_name}")
265
+ print(f" Python: {env_config.python}")
266
+
267
+ # Generate pixi.toml
268
+ result_path = create_pixi_toml(env_config, node_dir)
269
+
270
+ print(f"Created {result_path}")
271
+ print()
272
+ print("Next steps:")
273
+ print(f" cd {node_dir}")
274
+ print(" pixi install")
275
+ return 0
276
+
277
+
208
278
  def cmd_install(args) -> int:
209
279
  """Handle install command."""
210
280
  from .install import install
@@ -228,7 +298,7 @@ def cmd_install(args) -> int:
228
298
 
229
299
  def cmd_info(args) -> int:
230
300
  """Handle info command."""
231
- from .resolver import RuntimeEnv
301
+ from .pixi import RuntimeEnv
232
302
 
233
303
  env = RuntimeEnv.detect()
234
304
 
@@ -264,9 +334,10 @@ def cmd_info(args) -> int:
264
334
 
265
335
  def cmd_resolve(args) -> int:
266
336
  """Handle resolve command."""
267
- from .resolver import RuntimeEnv, parse_wheel_requirement
268
- from .registry import PACKAGE_REGISTRY, get_cuda_short2
269
- from .env.config_file import discover_env_config, load_env_from_file
337
+ from .pixi import RuntimeEnv, parse_wheel_requirement
338
+ from .pixi import PACKAGE_REGISTRY
339
+ from .pixi.registry import get_cuda_short2
340
+ from .config.parser import discover_env_config, load_env_from_file
270
341
 
271
342
  env = RuntimeEnv.detect()
272
343
  packages = []
@@ -353,7 +424,7 @@ def _substitute_template(template: str, vars_dict: dict) -> str:
353
424
  def cmd_doctor(args) -> int:
354
425
  """Handle doctor command."""
355
426
  from .install import verify_installation
356
- from .env.config_file import discover_env_config, load_env_from_file
427
+ from .config.parser import discover_env_config, load_env_from_file
357
428
 
358
429
  print("Running diagnostics...")
359
430
  print("=" * 40)
@@ -397,7 +468,7 @@ def cmd_doctor(args) -> int:
397
468
 
398
469
  def cmd_list_packages(args) -> int:
399
470
  """Handle list-packages command."""
400
- from .registry import PACKAGE_REGISTRY
471
+ from .pixi import PACKAGE_REGISTRY
401
472
 
402
473
  if args.json:
403
474
  import json
@@ -0,0 +1,19 @@
1
+ """
2
+ Config parsing for comfy-env.
3
+
4
+ This module handles parsing comfy-env.toml files and provides
5
+ typed configuration objects.
6
+ """
7
+
8
+ from .types import ComfyEnvConfig, NodeReq
9
+ from .parser import load_config, discover_config, CONFIG_FILE_NAME
10
+
11
+ __all__ = [
12
+ # Types
13
+ "ComfyEnvConfig",
14
+ "NodeReq",
15
+ # Parser
16
+ "load_config",
17
+ "discover_config",
18
+ "CONFIG_FILE_NAME",
19
+ ]
@@ -0,0 +1,151 @@
1
+ """Load configuration from comfy-env.toml.
2
+
3
+ comfy-env.toml is a superset of pixi.toml. Custom sections we handle:
4
+ - python = "3.11" - Python version for isolated envs
5
+ - [cuda] packages = [...] - CUDA packages (triggers find-links + PyTorch detection)
6
+ - [node_reqs] - Other ComfyUI nodes to clone
7
+
8
+ Everything else passes through to pixi.toml directly.
9
+
10
+ Example config:
11
+
12
+ python = "3.11"
13
+
14
+ [cuda]
15
+ packages = ["cumesh"]
16
+
17
+ [dependencies]
18
+ mesalib = "*"
19
+ cgal = "*"
20
+
21
+ [pypi-dependencies]
22
+ numpy = ">=1.21.0,<2"
23
+ trimesh = { version = ">=4.0.0", extras = ["easy"] }
24
+
25
+ [target.linux-64.pypi-dependencies]
26
+ embreex = "*"
27
+
28
+ [node_reqs]
29
+ SomeNode = "owner/repo"
30
+ """
31
+
32
+ import copy
33
+ import sys
34
+ from pathlib import Path
35
+ from typing import Optional, Dict, Any, List
36
+
37
+ # Use built-in tomllib (Python 3.11+) or tomli fallback
38
+ if sys.version_info >= (3, 11):
39
+ import tomllib
40
+ else:
41
+ try:
42
+ import tomli as tomllib
43
+ except ImportError:
44
+ tomllib = None # type: ignore
45
+
46
+ from .types import ComfyEnvConfig, NodeReq
47
+
48
+
49
+ CONFIG_FILE_NAME = "comfy-env.toml"
50
+
51
+ # Sections we handle specially (not passed through to pixi.toml)
52
+ CUSTOM_SECTIONS = {"python", "cuda", "node_reqs"}
53
+
54
+
55
+ def load_config(path: Path) -> ComfyEnvConfig:
56
+ """
57
+ Load configuration from a TOML file.
58
+
59
+ Args:
60
+ path: Path to comfy-env.toml
61
+
62
+ Returns:
63
+ ComfyEnvConfig instance
64
+
65
+ Raises:
66
+ FileNotFoundError: If config file doesn't exist
67
+ ImportError: If tomli not installed (Python < 3.11)
68
+ """
69
+ if tomllib is None:
70
+ raise ImportError(
71
+ "TOML parsing requires tomli for Python < 3.11. "
72
+ "Install with: pip install tomli"
73
+ )
74
+
75
+ path = Path(path)
76
+ if not path.exists():
77
+ raise FileNotFoundError(f"Config file not found: {path}")
78
+
79
+ with open(path, "rb") as f:
80
+ data = tomllib.load(f)
81
+
82
+ return _parse_config(data)
83
+
84
+
85
+ def discover_config(node_dir: Path) -> Optional[ComfyEnvConfig]:
86
+ """
87
+ Find and load comfy-env.toml from a directory.
88
+
89
+ Args:
90
+ node_dir: Directory to search
91
+
92
+ Returns:
93
+ ComfyEnvConfig if found, None otherwise
94
+ """
95
+ if tomllib is None:
96
+ return None
97
+
98
+ config_path = Path(node_dir) / CONFIG_FILE_NAME
99
+ if config_path.exists():
100
+ return load_config(config_path)
101
+
102
+ return None
103
+
104
+
105
+ def _parse_config(data: Dict[str, Any]) -> ComfyEnvConfig:
106
+ """Parse TOML data into ComfyEnvConfig."""
107
+ # Make a copy so we can pop our custom sections
108
+ data = copy.deepcopy(data)
109
+
110
+ # Extract python version (top-level key)
111
+ python_version = data.pop("python", None)
112
+ if python_version is not None:
113
+ python_version = str(python_version)
114
+
115
+ # Extract [cuda] section
116
+ cuda_data = data.pop("cuda", {})
117
+ cuda_packages = _ensure_list(cuda_data.get("packages", []))
118
+
119
+ # Extract [node_reqs] section
120
+ node_reqs_data = data.pop("node_reqs", {})
121
+ node_reqs = _parse_node_reqs(node_reqs_data)
122
+
123
+ # Everything else passes through to pixi.toml
124
+ pixi_passthrough = data
125
+
126
+ return ComfyEnvConfig(
127
+ python=python_version,
128
+ cuda_packages=cuda_packages,
129
+ node_reqs=node_reqs,
130
+ pixi_passthrough=pixi_passthrough,
131
+ )
132
+
133
+
134
+ def _parse_node_reqs(data: Dict[str, Any]) -> List[NodeReq]:
135
+ """Parse [node_reqs] section."""
136
+ node_reqs = []
137
+ for name, value in data.items():
138
+ if isinstance(value, str):
139
+ node_reqs.append(NodeReq(name=name, repo=value))
140
+ elif isinstance(value, dict):
141
+ node_reqs.append(NodeReq(name=name, repo=value.get("repo", "")))
142
+ return node_reqs
143
+
144
+
145
+ def _ensure_list(value) -> List:
146
+ """Ensure value is a list."""
147
+ if isinstance(value, list):
148
+ return value
149
+ if value:
150
+ return [value]
151
+ return []
@@ -0,0 +1,64 @@
1
+ """Configuration types for comfy-env."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Any, Dict, List, Optional
5
+
6
+
7
+ @dataclass
8
+ class NodeReq:
9
+ """A node dependency (another ComfyUI custom node)."""
10
+ name: str
11
+ repo: str # GitHub repo, e.g., "owner/repo"
12
+
13
+
14
+ @dataclass
15
+ class ComfyEnvConfig:
16
+ """
17
+ Configuration from comfy-env.toml.
18
+
19
+ comfy-env.toml is a superset of pixi.toml. Custom sections we handle:
20
+ - python = "3.11" - Python version for isolated envs
21
+ - [cuda] packages = [...] - CUDA packages (triggers find-links + PyTorch detection)
22
+ - [node_reqs] - Other ComfyUI nodes to clone
23
+
24
+ Everything else passes through to pixi.toml directly:
25
+ - [dependencies] - conda packages
26
+ - [pypi-dependencies] - pip packages
27
+ - [target.linux-64.pypi-dependencies] - platform-specific deps
28
+ - Any other pixi.toml syntax
29
+
30
+ Example config:
31
+ python = "3.11"
32
+
33
+ [cuda]
34
+ packages = ["cumesh"]
35
+
36
+ [dependencies]
37
+ mesalib = "*"
38
+ cgal = "*"
39
+
40
+ [pypi-dependencies]
41
+ numpy = ">=1.21.0,<2"
42
+ trimesh = { version = ">=4.0.0", extras = ["easy"] }
43
+
44
+ [target.linux-64.pypi-dependencies]
45
+ embreex = "*"
46
+
47
+ [node_reqs]
48
+ SomeNode = "owner/repo"
49
+ """
50
+ # python = "3.11" - Python version (for isolated envs)
51
+ python: Optional[str] = None
52
+
53
+ # [cuda] - CUDA packages (installed via find-links index)
54
+ cuda_packages: List[str] = field(default_factory=list)
55
+
56
+ # [node_reqs] - other ComfyUI nodes to clone
57
+ node_reqs: List[NodeReq] = field(default_factory=list)
58
+
59
+ # Everything else from comfy-env.toml passes through to pixi.toml
60
+ pixi_passthrough: Dict[str, Any] = field(default_factory=dict)
61
+
62
+ @property
63
+ def has_cuda(self) -> bool:
64
+ return bool(self.cuda_packages)