comfy-env 0.1.15__tar.gz → 0.1.16__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.1.16/PKG-INFO +279 -0
- comfy_env-0.1.16/README.md +250 -0
- {comfy_env-0.1.15 → comfy_env-0.1.16}/pyproject.toml +1 -1
- comfy_env-0.1.16/src/comfy_env/__init__.py +186 -0
- comfy_env-0.1.16/src/comfy_env/cli.py +202 -0
- comfy_env-0.1.16/src/comfy_env/config/__init__.py +29 -0
- comfy_env-0.1.16/src/comfy_env/config/parser.py +60 -0
- comfy_env-0.1.16/src/comfy_env/config/types.py +37 -0
- comfy_env-0.1.16/src/comfy_env/detection/__init__.py +77 -0
- comfy_env-0.1.16/src/comfy_env/detection/cuda.py +61 -0
- comfy_env-0.1.16/src/comfy_env/detection/gpu.py +230 -0
- comfy_env-0.1.16/src/comfy_env/detection/platform.py +70 -0
- comfy_env-0.1.16/src/comfy_env/detection/runtime.py +103 -0
- comfy_env-0.1.16/src/comfy_env/environment/__init__.py +53 -0
- comfy_env-0.1.16/src/comfy_env/environment/cache.py +141 -0
- comfy_env-0.1.16/src/comfy_env/environment/libomp.py +41 -0
- comfy_env-0.1.16/src/comfy_env/environment/paths.py +38 -0
- comfy_env-0.1.16/src/comfy_env/environment/setup.py +88 -0
- comfy_env-0.1.16/src/comfy_env/install.py +249 -0
- comfy_env-0.1.16/src/comfy_env/isolation/__init__.py +40 -0
- comfy_env-0.1.16/src/comfy_env/isolation/tensor_utils.py +83 -0
- comfy_env-0.1.16/src/comfy_env/isolation/workers/__init__.py +16 -0
- {comfy_env-0.1.15/src/comfy_env → comfy_env-0.1.16/src/comfy_env/isolation}/workers/mp.py +1 -1
- {comfy_env-0.1.15/src/comfy_env → comfy_env-0.1.16/src/comfy_env/isolation}/workers/subprocess.py +1 -1
- comfy_env-0.1.16/src/comfy_env/isolation/wrap.py +235 -0
- comfy_env-0.1.16/src/comfy_env/packages/__init__.py +60 -0
- comfy_env-0.1.16/src/comfy_env/packages/apt.py +36 -0
- comfy_env-0.1.16/src/comfy_env/packages/cuda_wheels.py +97 -0
- comfy_env-0.1.16/src/comfy_env/packages/node_dependencies.py +77 -0
- comfy_env-0.1.16/src/comfy_env/packages/pixi.py +85 -0
- comfy_env-0.1.16/src/comfy_env/packages/toml_generator.py +88 -0
- comfy_env-0.1.15/PKG-INFO +0 -291
- comfy_env-0.1.15/README.md +0 -262
- comfy_env-0.1.15/src/comfy_env/__init__.py +0 -111
- comfy_env-0.1.15/src/comfy_env/cache.py +0 -203
- comfy_env-0.1.15/src/comfy_env/cli.py +0 -430
- comfy_env-0.1.15/src/comfy_env/config/__init__.py +0 -17
- comfy_env-0.1.15/src/comfy_env/config/parser.py +0 -114
- comfy_env-0.1.15/src/comfy_env/install.py +0 -451
- comfy_env-0.1.15/src/comfy_env/isolation/__init__.py +0 -10
- comfy_env-0.1.15/src/comfy_env/isolation/wrap.py +0 -616
- comfy_env-0.1.15/src/comfy_env/nodes.py +0 -187
- comfy_env-0.1.15/src/comfy_env/pixi/__init__.py +0 -48
- comfy_env-0.1.15/src/comfy_env/pixi/core.py +0 -587
- comfy_env-0.1.15/src/comfy_env/pixi/cuda_detection.py +0 -303
- comfy_env-0.1.15/src/comfy_env/pixi/platform/__init__.py +0 -21
- comfy_env-0.1.15/src/comfy_env/pixi/platform/base.py +0 -96
- comfy_env-0.1.15/src/comfy_env/pixi/platform/darwin.py +0 -53
- comfy_env-0.1.15/src/comfy_env/pixi/platform/linux.py +0 -68
- comfy_env-0.1.15/src/comfy_env/pixi/platform/windows.py +0 -284
- comfy_env-0.1.15/src/comfy_env/pixi/resolver.py +0 -198
- comfy_env-0.1.15/src/comfy_env/prestartup.py +0 -208
- comfy_env-0.1.15/src/comfy_env/workers/__init__.py +0 -38
- comfy_env-0.1.15/src/comfy_env/workers/tensor_utils.py +0 -188
- {comfy_env-0.1.15 → comfy_env-0.1.16}/.github/workflows/ci.yml +0 -0
- {comfy_env-0.1.15 → comfy_env-0.1.16}/.github/workflows/publish.yml +0 -0
- {comfy_env-0.1.15 → comfy_env-0.1.16}/.gitignore +0 -0
- {comfy_env-0.1.15 → comfy_env-0.1.16}/LICENSE +0 -0
- {comfy_env-0.1.15/src/comfy_env → comfy_env-0.1.16/src/comfy_env/isolation}/workers/base.py +0 -0
- {comfy_env-0.1.15 → comfy_env-0.1.16}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
- {comfy_env-0.1.15 → comfy_env-0.1.16}/src/comfy_env/templates/comfy-env.toml +0 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: comfy-env
|
|
3
|
+
Version: 0.1.16
|
|
4
|
+
Summary: Environment management for ComfyUI custom nodes - CUDA wheel resolution and process isolation
|
|
5
|
+
Project-URL: Homepage, https://github.com/PozzettiAndrea/comfy-env
|
|
6
|
+
Project-URL: Repository, https://github.com/PozzettiAndrea/comfy-env
|
|
7
|
+
Project-URL: Issues, https://github.com/PozzettiAndrea/comfy-env/issues
|
|
8
|
+
Author: Andrea Pozzetti
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: comfyui,cuda,environment,isolation,process,venv,wheels
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: pip>=21.0
|
|
21
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
22
|
+
Requires-Dist: tomli>=2.0.0
|
|
23
|
+
Requires-Dist: uv>=0.4.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# comfy-env
|
|
31
|
+
|
|
32
|
+
Environment management for ComfyUI custom nodes.
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install comfy-env
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**1. Create `comfy-env.toml` in your node directory:**
|
|
41
|
+
|
|
42
|
+
```toml
|
|
43
|
+
[cuda]
|
|
44
|
+
packages = ["nvdiffrast", "pytorch3d"]
|
|
45
|
+
|
|
46
|
+
[pypi-dependencies]
|
|
47
|
+
trimesh = { version = "*", extras = ["easy"] }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**2. In `install.py`:**
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from comfy_env import install
|
|
54
|
+
install()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**3. In `prestartup_script.py`:**
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from comfy_env import setup_env
|
|
61
|
+
setup_env()
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
That's it. CUDA wheels install without compilation, and the environment is ready.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
Create `comfy-env.toml` in your node directory:
|
|
71
|
+
|
|
72
|
+
```toml
|
|
73
|
+
# Python version for isolated environment (optional)
|
|
74
|
+
python = "3.11"
|
|
75
|
+
|
|
76
|
+
# CUDA packages from cuda-wheels index (no compilation needed)
|
|
77
|
+
[cuda]
|
|
78
|
+
packages = ["nvdiffrast", "pytorch3d", "flash-attn"]
|
|
79
|
+
|
|
80
|
+
# System packages (Linux only)
|
|
81
|
+
[apt]
|
|
82
|
+
packages = ["libgl1-mesa-glx", "libglu1-mesa"]
|
|
83
|
+
|
|
84
|
+
# Environment variables
|
|
85
|
+
[env_vars]
|
|
86
|
+
KMP_DUPLICATE_LIB_OK = "TRUE"
|
|
87
|
+
OMP_NUM_THREADS = "1"
|
|
88
|
+
|
|
89
|
+
# Dependent custom nodes to auto-install
|
|
90
|
+
[node_reqs]
|
|
91
|
+
ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
92
|
+
|
|
93
|
+
# Conda packages (via pixi)
|
|
94
|
+
[dependencies]
|
|
95
|
+
cgal = "*"
|
|
96
|
+
|
|
97
|
+
# PyPI packages
|
|
98
|
+
[pypi-dependencies]
|
|
99
|
+
trimesh = { version = "*", extras = ["easy"] }
|
|
100
|
+
numpy = "*"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Process Isolation
|
|
106
|
+
|
|
107
|
+
For nodes with conflicting dependencies, use isolated execution:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
# In nodes/__init__.py
|
|
111
|
+
from pathlib import Path
|
|
112
|
+
from comfy_env import wrap_isolated_nodes
|
|
113
|
+
|
|
114
|
+
# Import your isolated nodes
|
|
115
|
+
from .cgal import NODE_CLASS_MAPPINGS as cgal_mappings
|
|
116
|
+
|
|
117
|
+
# Wrap them for isolated execution
|
|
118
|
+
NODE_CLASS_MAPPINGS = wrap_isolated_nodes(
|
|
119
|
+
cgal_mappings,
|
|
120
|
+
Path(__file__).parent / "cgal" # Directory with comfy-env.toml
|
|
121
|
+
)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Each wrapped node runs in a subprocess with its own Python environment.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## CLI Commands
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Show detected environment
|
|
132
|
+
comfy-env info
|
|
133
|
+
|
|
134
|
+
# Install dependencies
|
|
135
|
+
comfy-env install
|
|
136
|
+
|
|
137
|
+
# Preview without installing
|
|
138
|
+
comfy-env install --dry-run
|
|
139
|
+
|
|
140
|
+
# Verify packages
|
|
141
|
+
comfy-env doctor
|
|
142
|
+
|
|
143
|
+
# Install system packages
|
|
144
|
+
comfy-env apt-install
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## API Reference
|
|
150
|
+
|
|
151
|
+
### install()
|
|
152
|
+
|
|
153
|
+
Install dependencies from comfy-env.toml:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from comfy_env import install
|
|
157
|
+
|
|
158
|
+
install() # Auto-detect config
|
|
159
|
+
install(dry_run=True) # Preview only
|
|
160
|
+
install(config="path.toml") # Explicit config
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### setup_env()
|
|
164
|
+
|
|
165
|
+
Set up environment at ComfyUI startup:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from comfy_env import setup_env
|
|
169
|
+
|
|
170
|
+
setup_env() # Auto-detects node directory from caller
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Sets library paths, environment variables, and injects site-packages.
|
|
174
|
+
|
|
175
|
+
### wrap_isolated_nodes()
|
|
176
|
+
|
|
177
|
+
Wrap nodes for subprocess isolation:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from comfy_env import wrap_isolated_nodes
|
|
181
|
+
|
|
182
|
+
wrapped = wrap_isolated_nodes(NODE_CLASS_MAPPINGS, node_dir)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Detection
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from comfy_env import (
|
|
189
|
+
detect_cuda_version, # Returns "12.8", "12.4", or None
|
|
190
|
+
detect_gpu, # Returns GPUInfo or None
|
|
191
|
+
get_gpu_summary, # Human-readable string
|
|
192
|
+
RuntimeEnv, # Combined runtime info
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
env = RuntimeEnv.detect()
|
|
196
|
+
print(env) # Python 3.11, CUDA 12.8, PyTorch 2.8.0, GPU: RTX 4090
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Workers
|
|
200
|
+
|
|
201
|
+
Low-level process isolation:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from comfy_env import MPWorker, SubprocessWorker
|
|
205
|
+
|
|
206
|
+
# Same Python version (multiprocessing)
|
|
207
|
+
worker = MPWorker()
|
|
208
|
+
result = worker.call(my_function, arg1, arg2)
|
|
209
|
+
|
|
210
|
+
# Different Python version (subprocess)
|
|
211
|
+
worker = SubprocessWorker(python="/path/to/python")
|
|
212
|
+
result = worker.call(my_function, arg1, arg2)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Real Example
|
|
218
|
+
|
|
219
|
+
See [ComfyUI-GeometryPack](https://github.com/PozzettiAndrea/ComfyUI-GeometryPack) for a production example with:
|
|
220
|
+
|
|
221
|
+
- Multiple isolated environments (CGAL, Blender, GPU)
|
|
222
|
+
- Per-subdirectory comfy-env.toml
|
|
223
|
+
- Prestartup asset copying
|
|
224
|
+
- Different Python versions (3.11 for Blender API)
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Architecture
|
|
229
|
+
|
|
230
|
+
### Layers
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
comfy_env/
|
|
234
|
+
├── detection/ # Pure functions - CUDA, GPU, platform detection
|
|
235
|
+
├── config/ # Pure parsing - comfy-env.toml → typed config
|
|
236
|
+
├── environment/ # Side effects - cache, paths, setup
|
|
237
|
+
├── packages/ # Side effects - pixi, cuda-wheels, apt
|
|
238
|
+
├── isolation/ # Side effects - subprocess workers, node wrapping
|
|
239
|
+
└── install.py # Orchestration
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Why Isolation?
|
|
243
|
+
|
|
244
|
+
ComfyUI nodes share a single Python environment. This breaks when:
|
|
245
|
+
|
|
246
|
+
1. **Dependency conflicts**: Node A needs `torch==2.4`, Node B needs `torch==2.8`
|
|
247
|
+
2. **Native library conflicts**: Two packages bundle incompatible libomp
|
|
248
|
+
3. **Python version requirements**: Blender API requires Python 3.11
|
|
249
|
+
|
|
250
|
+
Solution: Run each node group in its own subprocess with isolated dependencies.
|
|
251
|
+
|
|
252
|
+
### Why CUDA Wheels?
|
|
253
|
+
|
|
254
|
+
Installing packages like `nvdiffrast` normally requires:
|
|
255
|
+
- CUDA toolkit
|
|
256
|
+
- C++ compiler
|
|
257
|
+
- 30+ minutes of compilation
|
|
258
|
+
|
|
259
|
+
CUDA wheels from [cuda-wheels](https://pozzettiandrea.github.io/cuda-wheels/) are pre-built for common configurations:
|
|
260
|
+
|
|
261
|
+
| GPU | CUDA | PyTorch |
|
|
262
|
+
|-----|------|---------|
|
|
263
|
+
| Blackwell (sm_100+) | 12.8 | 2.8 |
|
|
264
|
+
| Ada/Hopper/Ampere | 12.8 | 2.8 |
|
|
265
|
+
| Turing | 12.8 | 2.8 |
|
|
266
|
+
| Pascal | 12.4 | 2.4 |
|
|
267
|
+
|
|
268
|
+
### How Environments Work
|
|
269
|
+
|
|
270
|
+
1. **Central cache**: Environments stored at `~/.comfy-env/envs/`
|
|
271
|
+
2. **Marker files**: `.comfy-env-marker.toml` links node → env
|
|
272
|
+
3. **Orphan cleanup**: Envs deleted when their node is removed
|
|
273
|
+
4. **Hash-based naming**: Config changes create new envs
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
MIT
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# comfy-env
|
|
2
|
+
|
|
3
|
+
Environment management for ComfyUI custom nodes.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install comfy-env
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**1. Create `comfy-env.toml` in your node directory:**
|
|
12
|
+
|
|
13
|
+
```toml
|
|
14
|
+
[cuda]
|
|
15
|
+
packages = ["nvdiffrast", "pytorch3d"]
|
|
16
|
+
|
|
17
|
+
[pypi-dependencies]
|
|
18
|
+
trimesh = { version = "*", extras = ["easy"] }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**2. In `install.py`:**
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from comfy_env import install
|
|
25
|
+
install()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**3. In `prestartup_script.py`:**
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from comfy_env import setup_env
|
|
32
|
+
setup_env()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
That's it. CUDA wheels install without compilation, and the environment is ready.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Configuration
|
|
40
|
+
|
|
41
|
+
Create `comfy-env.toml` in your node directory:
|
|
42
|
+
|
|
43
|
+
```toml
|
|
44
|
+
# Python version for isolated environment (optional)
|
|
45
|
+
python = "3.11"
|
|
46
|
+
|
|
47
|
+
# CUDA packages from cuda-wheels index (no compilation needed)
|
|
48
|
+
[cuda]
|
|
49
|
+
packages = ["nvdiffrast", "pytorch3d", "flash-attn"]
|
|
50
|
+
|
|
51
|
+
# System packages (Linux only)
|
|
52
|
+
[apt]
|
|
53
|
+
packages = ["libgl1-mesa-glx", "libglu1-mesa"]
|
|
54
|
+
|
|
55
|
+
# Environment variables
|
|
56
|
+
[env_vars]
|
|
57
|
+
KMP_DUPLICATE_LIB_OK = "TRUE"
|
|
58
|
+
OMP_NUM_THREADS = "1"
|
|
59
|
+
|
|
60
|
+
# Dependent custom nodes to auto-install
|
|
61
|
+
[node_reqs]
|
|
62
|
+
ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
63
|
+
|
|
64
|
+
# Conda packages (via pixi)
|
|
65
|
+
[dependencies]
|
|
66
|
+
cgal = "*"
|
|
67
|
+
|
|
68
|
+
# PyPI packages
|
|
69
|
+
[pypi-dependencies]
|
|
70
|
+
trimesh = { version = "*", extras = ["easy"] }
|
|
71
|
+
numpy = "*"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Process Isolation
|
|
77
|
+
|
|
78
|
+
For nodes with conflicting dependencies, use isolated execution:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# In nodes/__init__.py
|
|
82
|
+
from pathlib import Path
|
|
83
|
+
from comfy_env import wrap_isolated_nodes
|
|
84
|
+
|
|
85
|
+
# Import your isolated nodes
|
|
86
|
+
from .cgal import NODE_CLASS_MAPPINGS as cgal_mappings
|
|
87
|
+
|
|
88
|
+
# Wrap them for isolated execution
|
|
89
|
+
NODE_CLASS_MAPPINGS = wrap_isolated_nodes(
|
|
90
|
+
cgal_mappings,
|
|
91
|
+
Path(__file__).parent / "cgal" # Directory with comfy-env.toml
|
|
92
|
+
)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Each wrapped node runs in a subprocess with its own Python environment.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## CLI Commands
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Show detected environment
|
|
103
|
+
comfy-env info
|
|
104
|
+
|
|
105
|
+
# Install dependencies
|
|
106
|
+
comfy-env install
|
|
107
|
+
|
|
108
|
+
# Preview without installing
|
|
109
|
+
comfy-env install --dry-run
|
|
110
|
+
|
|
111
|
+
# Verify packages
|
|
112
|
+
comfy-env doctor
|
|
113
|
+
|
|
114
|
+
# Install system packages
|
|
115
|
+
comfy-env apt-install
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## API Reference
|
|
121
|
+
|
|
122
|
+
### install()
|
|
123
|
+
|
|
124
|
+
Install dependencies from comfy-env.toml:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from comfy_env import install
|
|
128
|
+
|
|
129
|
+
install() # Auto-detect config
|
|
130
|
+
install(dry_run=True) # Preview only
|
|
131
|
+
install(config="path.toml") # Explicit config
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### setup_env()
|
|
135
|
+
|
|
136
|
+
Set up environment at ComfyUI startup:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from comfy_env import setup_env
|
|
140
|
+
|
|
141
|
+
setup_env() # Auto-detects node directory from caller
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Sets library paths, environment variables, and injects site-packages.
|
|
145
|
+
|
|
146
|
+
### wrap_isolated_nodes()
|
|
147
|
+
|
|
148
|
+
Wrap nodes for subprocess isolation:
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from comfy_env import wrap_isolated_nodes
|
|
152
|
+
|
|
153
|
+
wrapped = wrap_isolated_nodes(NODE_CLASS_MAPPINGS, node_dir)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Detection
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from comfy_env import (
|
|
160
|
+
detect_cuda_version, # Returns "12.8", "12.4", or None
|
|
161
|
+
detect_gpu, # Returns GPUInfo or None
|
|
162
|
+
get_gpu_summary, # Human-readable string
|
|
163
|
+
RuntimeEnv, # Combined runtime info
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
env = RuntimeEnv.detect()
|
|
167
|
+
print(env) # Python 3.11, CUDA 12.8, PyTorch 2.8.0, GPU: RTX 4090
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Workers
|
|
171
|
+
|
|
172
|
+
Low-level process isolation:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from comfy_env import MPWorker, SubprocessWorker
|
|
176
|
+
|
|
177
|
+
# Same Python version (multiprocessing)
|
|
178
|
+
worker = MPWorker()
|
|
179
|
+
result = worker.call(my_function, arg1, arg2)
|
|
180
|
+
|
|
181
|
+
# Different Python version (subprocess)
|
|
182
|
+
worker = SubprocessWorker(python="/path/to/python")
|
|
183
|
+
result = worker.call(my_function, arg1, arg2)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Real Example
|
|
189
|
+
|
|
190
|
+
See [ComfyUI-GeometryPack](https://github.com/PozzettiAndrea/ComfyUI-GeometryPack) for a production example with:
|
|
191
|
+
|
|
192
|
+
- Multiple isolated environments (CGAL, Blender, GPU)
|
|
193
|
+
- Per-subdirectory comfy-env.toml
|
|
194
|
+
- Prestartup asset copying
|
|
195
|
+
- Different Python versions (3.11 for Blender API)
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Architecture
|
|
200
|
+
|
|
201
|
+
### Layers
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
comfy_env/
|
|
205
|
+
├── detection/ # Pure functions - CUDA, GPU, platform detection
|
|
206
|
+
├── config/ # Pure parsing - comfy-env.toml → typed config
|
|
207
|
+
├── environment/ # Side effects - cache, paths, setup
|
|
208
|
+
├── packages/ # Side effects - pixi, cuda-wheels, apt
|
|
209
|
+
├── isolation/ # Side effects - subprocess workers, node wrapping
|
|
210
|
+
└── install.py # Orchestration
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Why Isolation?
|
|
214
|
+
|
|
215
|
+
ComfyUI nodes share a single Python environment. This breaks when:
|
|
216
|
+
|
|
217
|
+
1. **Dependency conflicts**: Node A needs `torch==2.4`, Node B needs `torch==2.8`
|
|
218
|
+
2. **Native library conflicts**: Two packages bundle incompatible libomp
|
|
219
|
+
3. **Python version requirements**: Blender API requires Python 3.11
|
|
220
|
+
|
|
221
|
+
Solution: Run each node group in its own subprocess with isolated dependencies.
|
|
222
|
+
|
|
223
|
+
### Why CUDA Wheels?
|
|
224
|
+
|
|
225
|
+
Installing packages like `nvdiffrast` normally requires:
|
|
226
|
+
- CUDA toolkit
|
|
227
|
+
- C++ compiler
|
|
228
|
+
- 30+ minutes of compilation
|
|
229
|
+
|
|
230
|
+
CUDA wheels from [cuda-wheels](https://pozzettiandrea.github.io/cuda-wheels/) are pre-built for common configurations:
|
|
231
|
+
|
|
232
|
+
| GPU | CUDA | PyTorch |
|
|
233
|
+
|-----|------|---------|
|
|
234
|
+
| Blackwell (sm_100+) | 12.8 | 2.8 |
|
|
235
|
+
| Ada/Hopper/Ampere | 12.8 | 2.8 |
|
|
236
|
+
| Turing | 12.8 | 2.8 |
|
|
237
|
+
| Pascal | 12.4 | 2.4 |
|
|
238
|
+
|
|
239
|
+
### How Environments Work
|
|
240
|
+
|
|
241
|
+
1. **Central cache**: Environments stored at `~/.comfy-env/envs/`
|
|
242
|
+
2. **Marker files**: `.comfy-env-marker.toml` links node → env
|
|
243
|
+
3. **Orphan cleanup**: Envs deleted when their node is removed
|
|
244
|
+
4. **Hash-based naming**: Config changes create new envs
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""
|
|
2
|
+
comfy-env - Environment management for ComfyUI custom nodes.
|
|
3
|
+
|
|
4
|
+
Features:
|
|
5
|
+
- CUDA wheel resolution (pre-built wheels without compilation)
|
|
6
|
+
- Process isolation (run nodes in separate Python environments)
|
|
7
|
+
- Central environment cache (~/.comfy-env/envs/)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
__version__ = version("comfy-env")
|
|
14
|
+
except PackageNotFoundError:
|
|
15
|
+
__version__ = "0.0.0-dev"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# =============================================================================
|
|
19
|
+
# Primary API (what most users need)
|
|
20
|
+
# =============================================================================
|
|
21
|
+
|
|
22
|
+
# Install API
|
|
23
|
+
from .install import install, verify_installation, USE_COMFY_ENV_VAR
|
|
24
|
+
|
|
25
|
+
# Prestartup helpers
|
|
26
|
+
from .environment.setup import setup_env
|
|
27
|
+
from .environment.paths import copy_files
|
|
28
|
+
|
|
29
|
+
# Isolation
|
|
30
|
+
from .isolation import wrap_isolated_nodes, wrap_nodes
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# =============================================================================
|
|
34
|
+
# Config Layer
|
|
35
|
+
# =============================================================================
|
|
36
|
+
|
|
37
|
+
from .config import (
|
|
38
|
+
ComfyEnvConfig,
|
|
39
|
+
NodeDependency,
|
|
40
|
+
NodeReq, # Backwards compatibility alias
|
|
41
|
+
load_config,
|
|
42
|
+
discover_config,
|
|
43
|
+
CONFIG_FILE_NAME,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# =============================================================================
|
|
48
|
+
# Detection Layer
|
|
49
|
+
# =============================================================================
|
|
50
|
+
|
|
51
|
+
from .detection import (
|
|
52
|
+
# CUDA detection
|
|
53
|
+
detect_cuda_version,
|
|
54
|
+
detect_cuda_environment,
|
|
55
|
+
get_recommended_cuda_version,
|
|
56
|
+
# GPU detection
|
|
57
|
+
GPUInfo,
|
|
58
|
+
CUDAEnvironment,
|
|
59
|
+
detect_gpu,
|
|
60
|
+
get_gpu_summary,
|
|
61
|
+
# Platform detection
|
|
62
|
+
detect_platform,
|
|
63
|
+
get_platform_tag,
|
|
64
|
+
# Runtime detection
|
|
65
|
+
RuntimeEnv,
|
|
66
|
+
detect_runtime,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# =============================================================================
|
|
71
|
+
# Packages Layer
|
|
72
|
+
# =============================================================================
|
|
73
|
+
|
|
74
|
+
from .packages import (
|
|
75
|
+
# Pixi
|
|
76
|
+
ensure_pixi,
|
|
77
|
+
get_pixi_path,
|
|
78
|
+
get_pixi_python,
|
|
79
|
+
pixi_run,
|
|
80
|
+
pixi_clean,
|
|
81
|
+
# CUDA wheels
|
|
82
|
+
CUDA_WHEELS_INDEX,
|
|
83
|
+
get_wheel_url,
|
|
84
|
+
get_cuda_torch_mapping,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# =============================================================================
|
|
89
|
+
# Environment Layer
|
|
90
|
+
# =============================================================================
|
|
91
|
+
|
|
92
|
+
from .environment import (
|
|
93
|
+
# Cache management
|
|
94
|
+
get_cache_dir,
|
|
95
|
+
cleanup_orphaned_envs,
|
|
96
|
+
resolve_env_path,
|
|
97
|
+
CACHE_DIR,
|
|
98
|
+
MARKER_FILE,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# =============================================================================
|
|
103
|
+
# Isolation Layer
|
|
104
|
+
# =============================================================================
|
|
105
|
+
|
|
106
|
+
from .isolation import (
|
|
107
|
+
# Workers
|
|
108
|
+
Worker,
|
|
109
|
+
WorkerError,
|
|
110
|
+
MPWorker,
|
|
111
|
+
SubprocessWorker,
|
|
112
|
+
# Tensor utilities
|
|
113
|
+
TensorKeeper,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# =============================================================================
|
|
118
|
+
# Exports
|
|
119
|
+
# =============================================================================
|
|
120
|
+
|
|
121
|
+
__all__ = [
|
|
122
|
+
# Install API
|
|
123
|
+
"install",
|
|
124
|
+
"verify_installation",
|
|
125
|
+
"USE_COMFY_ENV_VAR",
|
|
126
|
+
# Prestartup
|
|
127
|
+
"setup_env",
|
|
128
|
+
"copy_files",
|
|
129
|
+
# Isolation
|
|
130
|
+
"wrap_isolated_nodes",
|
|
131
|
+
"wrap_nodes",
|
|
132
|
+
# Config
|
|
133
|
+
"ComfyEnvConfig",
|
|
134
|
+
"NodeDependency",
|
|
135
|
+
"NodeReq",
|
|
136
|
+
"load_config",
|
|
137
|
+
"discover_config",
|
|
138
|
+
"CONFIG_FILE_NAME",
|
|
139
|
+
# Detection
|
|
140
|
+
"detect_cuda_version",
|
|
141
|
+
"detect_cuda_environment",
|
|
142
|
+
"get_recommended_cuda_version",
|
|
143
|
+
"GPUInfo",
|
|
144
|
+
"CUDAEnvironment",
|
|
145
|
+
"detect_gpu",
|
|
146
|
+
"get_gpu_summary",
|
|
147
|
+
"detect_platform",
|
|
148
|
+
"get_platform_tag",
|
|
149
|
+
"RuntimeEnv",
|
|
150
|
+
"detect_runtime",
|
|
151
|
+
# Packages
|
|
152
|
+
"ensure_pixi",
|
|
153
|
+
"get_pixi_path",
|
|
154
|
+
"get_pixi_python",
|
|
155
|
+
"pixi_run",
|
|
156
|
+
"pixi_clean",
|
|
157
|
+
"CUDA_WHEELS_INDEX",
|
|
158
|
+
"get_wheel_url",
|
|
159
|
+
"get_cuda_torch_mapping",
|
|
160
|
+
# Environment
|
|
161
|
+
"get_cache_dir",
|
|
162
|
+
"cleanup_orphaned_envs",
|
|
163
|
+
"resolve_env_path",
|
|
164
|
+
"CACHE_DIR",
|
|
165
|
+
"MARKER_FILE",
|
|
166
|
+
# Workers
|
|
167
|
+
"Worker",
|
|
168
|
+
"WorkerError",
|
|
169
|
+
"MPWorker",
|
|
170
|
+
"SubprocessWorker",
|
|
171
|
+
"TensorKeeper",
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# =============================================================================
|
|
176
|
+
# Startup cleanup
|
|
177
|
+
# =============================================================================
|
|
178
|
+
|
|
179
|
+
def _run_startup_cleanup():
|
|
180
|
+
"""Clean orphaned envs on startup."""
|
|
181
|
+
try:
|
|
182
|
+
cleanup_orphaned_envs(log=lambda x: None) # Silent
|
|
183
|
+
except Exception:
|
|
184
|
+
pass # Never fail startup due to cleanup
|
|
185
|
+
|
|
186
|
+
_run_startup_cleanup()
|