comfy-env 0.1.16__tar.gz → 0.1.17__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.17/PKG-INFO +225 -0
- comfy_env-0.1.17/README.md +196 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/pyproject.toml +1 -1
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/__init__.py +3 -1
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/cli.py +48 -9
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/config/__init__.py +5 -9
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/config/parser.py +11 -6
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/environment/setup.py +5 -2
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/install.py +11 -6
- comfy_env-0.1.16/PKG-INFO +0 -279
- comfy_env-0.1.16/README.md +0 -250
- {comfy_env-0.1.16 → comfy_env-0.1.17}/.github/workflows/ci.yml +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/.github/workflows/publish.yml +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/.gitignore +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/LICENSE +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/config/types.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/detection/__init__.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/detection/cuda.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/detection/gpu.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/detection/platform.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/detection/runtime.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/environment/__init__.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/environment/cache.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/environment/libomp.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/environment/paths.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/isolation/__init__.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/isolation/tensor_utils.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/isolation/workers/__init__.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/isolation/workers/base.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/isolation/workers/mp.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/isolation/workers/subprocess.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/isolation/wrap.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/packages/__init__.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/packages/apt.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/packages/cuda_wheels.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/packages/node_dependencies.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/packages/pixi.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/packages/toml_generator.py +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
- {comfy_env-0.1.16 → comfy_env-0.1.17}/src/comfy_env/templates/comfy-env.toml +0 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: comfy-env
|
|
3
|
+
Version: 0.1.17
|
|
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-root.toml` in your node directory:**
|
|
41
|
+
|
|
42
|
+
```toml
|
|
43
|
+
[cuda]
|
|
44
|
+
packages = ["nvdiffrast", "pytorch3d"]
|
|
45
|
+
|
|
46
|
+
[apt]
|
|
47
|
+
packages = ["libgl1-mesa-glx"]
|
|
48
|
+
|
|
49
|
+
[node_reqs]
|
|
50
|
+
ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
PyPI deps go in `requirements.txt` (standard ComfyUI pattern).
|
|
54
|
+
|
|
55
|
+
**2. In `install.py`:**
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from comfy_env import install
|
|
59
|
+
install()
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**3. In `prestartup_script.py`:**
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from comfy_env import setup_env
|
|
66
|
+
setup_env()
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Two Config Files
|
|
72
|
+
|
|
73
|
+
| File | Purpose |
|
|
74
|
+
|------|---------|
|
|
75
|
+
| `comfy-env-root.toml` | Main node config (root level) |
|
|
76
|
+
| `comfy-env.toml` | Isolated subfolder config |
|
|
77
|
+
|
|
78
|
+
### comfy-env-root.toml (main node)
|
|
79
|
+
|
|
80
|
+
```toml
|
|
81
|
+
[cuda]
|
|
82
|
+
packages = ["nvdiffrast", "pytorch3d"]
|
|
83
|
+
|
|
84
|
+
[apt]
|
|
85
|
+
packages = ["libgl1-mesa-glx"]
|
|
86
|
+
|
|
87
|
+
[dependencies]
|
|
88
|
+
cgal = "*"
|
|
89
|
+
|
|
90
|
+
[env_vars]
|
|
91
|
+
KMP_DUPLICATE_LIB_OK = "TRUE"
|
|
92
|
+
|
|
93
|
+
[node_reqs]
|
|
94
|
+
ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
PyPI deps → `requirements.txt`
|
|
98
|
+
|
|
99
|
+
### comfy-env.toml (isolated folder)
|
|
100
|
+
|
|
101
|
+
```toml
|
|
102
|
+
python = "3.11"
|
|
103
|
+
|
|
104
|
+
[dependencies]
|
|
105
|
+
cgal = "*"
|
|
106
|
+
|
|
107
|
+
[pypi-dependencies]
|
|
108
|
+
trimesh = { version = "*", extras = ["easy"] }
|
|
109
|
+
|
|
110
|
+
[env_vars]
|
|
111
|
+
SOME_VAR = "value"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### What goes where?
|
|
115
|
+
|
|
116
|
+
| Section | Root | Isolated |
|
|
117
|
+
|---------|------|----------|
|
|
118
|
+
| `[cuda]` | ✓ | ✓ |
|
|
119
|
+
| `[apt]` | ✓ | ✓ |
|
|
120
|
+
| `[dependencies]` | ✓ | ✓ |
|
|
121
|
+
| `[env_vars]` | ✓ | ✓ |
|
|
122
|
+
| `[node_reqs]` | ✓ | ✗ |
|
|
123
|
+
| `python = "X.Y"` | ✗ | ✓ |
|
|
124
|
+
| `[pypi-dependencies]` | ✗ | ✓ |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Process Isolation
|
|
129
|
+
|
|
130
|
+
For nodes with conflicting dependencies:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
# In nodes/__init__.py
|
|
134
|
+
from pathlib import Path
|
|
135
|
+
from comfy_env import wrap_isolated_nodes
|
|
136
|
+
|
|
137
|
+
from .cgal import NODE_CLASS_MAPPINGS as cgal_mappings
|
|
138
|
+
|
|
139
|
+
NODE_CLASS_MAPPINGS = wrap_isolated_nodes(
|
|
140
|
+
cgal_mappings,
|
|
141
|
+
Path(__file__).parent / "cgal" # Has comfy-env.toml
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Each wrapped node runs in a subprocess with its own Python environment.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## CLI
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
comfy-env init # Create comfy-env-root.toml
|
|
153
|
+
comfy-env init --isolated # Create comfy-env.toml (for subfolders)
|
|
154
|
+
comfy-env install # Install dependencies
|
|
155
|
+
comfy-env install --dry-run # Preview
|
|
156
|
+
comfy-env info # Show runtime info
|
|
157
|
+
comfy-env doctor # Verify packages
|
|
158
|
+
comfy-env apt-install # Install system packages
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## API
|
|
164
|
+
|
|
165
|
+
### install()
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from comfy_env import install
|
|
169
|
+
install()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### setup_env()
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from comfy_env import setup_env
|
|
176
|
+
setup_env() # Call in prestartup_script.py
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### wrap_isolated_nodes()
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from comfy_env import wrap_isolated_nodes
|
|
183
|
+
wrapped = wrap_isolated_nodes(NODE_CLASS_MAPPINGS, node_dir)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Detection
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from comfy_env import RuntimeEnv, detect_cuda_version, detect_gpu
|
|
190
|
+
|
|
191
|
+
env = RuntimeEnv.detect()
|
|
192
|
+
print(env) # Python 3.11, CUDA 12.8, PyTorch 2.8.0, GPU: RTX 4090
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Example
|
|
198
|
+
|
|
199
|
+
See [ComfyUI-GeometryPack](https://github.com/PozzettiAndrea/ComfyUI-GeometryPack):
|
|
200
|
+
|
|
201
|
+
- Multiple isolated environments (CGAL, Blender, GPU)
|
|
202
|
+
- Per-subdirectory `comfy-env.toml`
|
|
203
|
+
- Different Python versions
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Why?
|
|
208
|
+
|
|
209
|
+
**Why isolation?** ComfyUI nodes share one Python. Conflicts happen when:
|
|
210
|
+
- Node A needs torch 2.4, Node B needs torch 2.8
|
|
211
|
+
- Two packages bundle incompatible libomp
|
|
212
|
+
- Blender API requires Python 3.11
|
|
213
|
+
|
|
214
|
+
**Why CUDA wheels?** Installing nvdiffrast normally needs CUDA toolkit + C++ compiler + 30 min compilation. [cuda-wheels](https://pozzettiandrea.github.io/cuda-wheels/) provides pre-built wheels.
|
|
215
|
+
|
|
216
|
+
**How envs work:**
|
|
217
|
+
- Central cache: `~/.comfy-env/envs/`
|
|
218
|
+
- Marker files link nodes → cached envs
|
|
219
|
+
- Config hash in name → changes create new envs
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT
|
|
@@ -0,0 +1,196 @@
|
|
|
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-root.toml` in your node directory:**
|
|
12
|
+
|
|
13
|
+
```toml
|
|
14
|
+
[cuda]
|
|
15
|
+
packages = ["nvdiffrast", "pytorch3d"]
|
|
16
|
+
|
|
17
|
+
[apt]
|
|
18
|
+
packages = ["libgl1-mesa-glx"]
|
|
19
|
+
|
|
20
|
+
[node_reqs]
|
|
21
|
+
ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
PyPI deps go in `requirements.txt` (standard ComfyUI pattern).
|
|
25
|
+
|
|
26
|
+
**2. In `install.py`:**
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from comfy_env import install
|
|
30
|
+
install()
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**3. In `prestartup_script.py`:**
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from comfy_env import setup_env
|
|
37
|
+
setup_env()
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Two Config Files
|
|
43
|
+
|
|
44
|
+
| File | Purpose |
|
|
45
|
+
|------|---------|
|
|
46
|
+
| `comfy-env-root.toml` | Main node config (root level) |
|
|
47
|
+
| `comfy-env.toml` | Isolated subfolder config |
|
|
48
|
+
|
|
49
|
+
### comfy-env-root.toml (main node)
|
|
50
|
+
|
|
51
|
+
```toml
|
|
52
|
+
[cuda]
|
|
53
|
+
packages = ["nvdiffrast", "pytorch3d"]
|
|
54
|
+
|
|
55
|
+
[apt]
|
|
56
|
+
packages = ["libgl1-mesa-glx"]
|
|
57
|
+
|
|
58
|
+
[dependencies]
|
|
59
|
+
cgal = "*"
|
|
60
|
+
|
|
61
|
+
[env_vars]
|
|
62
|
+
KMP_DUPLICATE_LIB_OK = "TRUE"
|
|
63
|
+
|
|
64
|
+
[node_reqs]
|
|
65
|
+
ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
PyPI deps → `requirements.txt`
|
|
69
|
+
|
|
70
|
+
### comfy-env.toml (isolated folder)
|
|
71
|
+
|
|
72
|
+
```toml
|
|
73
|
+
python = "3.11"
|
|
74
|
+
|
|
75
|
+
[dependencies]
|
|
76
|
+
cgal = "*"
|
|
77
|
+
|
|
78
|
+
[pypi-dependencies]
|
|
79
|
+
trimesh = { version = "*", extras = ["easy"] }
|
|
80
|
+
|
|
81
|
+
[env_vars]
|
|
82
|
+
SOME_VAR = "value"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### What goes where?
|
|
86
|
+
|
|
87
|
+
| Section | Root | Isolated |
|
|
88
|
+
|---------|------|----------|
|
|
89
|
+
| `[cuda]` | ✓ | ✓ |
|
|
90
|
+
| `[apt]` | ✓ | ✓ |
|
|
91
|
+
| `[dependencies]` | ✓ | ✓ |
|
|
92
|
+
| `[env_vars]` | ✓ | ✓ |
|
|
93
|
+
| `[node_reqs]` | ✓ | ✗ |
|
|
94
|
+
| `python = "X.Y"` | ✗ | ✓ |
|
|
95
|
+
| `[pypi-dependencies]` | ✗ | ✓ |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Process Isolation
|
|
100
|
+
|
|
101
|
+
For nodes with conflicting dependencies:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# In nodes/__init__.py
|
|
105
|
+
from pathlib import Path
|
|
106
|
+
from comfy_env import wrap_isolated_nodes
|
|
107
|
+
|
|
108
|
+
from .cgal import NODE_CLASS_MAPPINGS as cgal_mappings
|
|
109
|
+
|
|
110
|
+
NODE_CLASS_MAPPINGS = wrap_isolated_nodes(
|
|
111
|
+
cgal_mappings,
|
|
112
|
+
Path(__file__).parent / "cgal" # Has comfy-env.toml
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Each wrapped node runs in a subprocess with its own Python environment.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## CLI
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
comfy-env init # Create comfy-env-root.toml
|
|
124
|
+
comfy-env init --isolated # Create comfy-env.toml (for subfolders)
|
|
125
|
+
comfy-env install # Install dependencies
|
|
126
|
+
comfy-env install --dry-run # Preview
|
|
127
|
+
comfy-env info # Show runtime info
|
|
128
|
+
comfy-env doctor # Verify packages
|
|
129
|
+
comfy-env apt-install # Install system packages
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## API
|
|
135
|
+
|
|
136
|
+
### install()
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from comfy_env import install
|
|
140
|
+
install()
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### setup_env()
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from comfy_env import setup_env
|
|
147
|
+
setup_env() # Call in prestartup_script.py
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### wrap_isolated_nodes()
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from comfy_env import wrap_isolated_nodes
|
|
154
|
+
wrapped = wrap_isolated_nodes(NODE_CLASS_MAPPINGS, node_dir)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Detection
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from comfy_env import RuntimeEnv, detect_cuda_version, detect_gpu
|
|
161
|
+
|
|
162
|
+
env = RuntimeEnv.detect()
|
|
163
|
+
print(env) # Python 3.11, CUDA 12.8, PyTorch 2.8.0, GPU: RTX 4090
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Example
|
|
169
|
+
|
|
170
|
+
See [ComfyUI-GeometryPack](https://github.com/PozzettiAndrea/ComfyUI-GeometryPack):
|
|
171
|
+
|
|
172
|
+
- Multiple isolated environments (CGAL, Blender, GPU)
|
|
173
|
+
- Per-subdirectory `comfy-env.toml`
|
|
174
|
+
- Different Python versions
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Why?
|
|
179
|
+
|
|
180
|
+
**Why isolation?** ComfyUI nodes share one Python. Conflicts happen when:
|
|
181
|
+
- Node A needs torch 2.4, Node B needs torch 2.8
|
|
182
|
+
- Two packages bundle incompatible libomp
|
|
183
|
+
- Blender API requires Python 3.11
|
|
184
|
+
|
|
185
|
+
**Why CUDA wheels?** Installing nvdiffrast normally needs CUDA toolkit + C++ compiler + 30 min compilation. [cuda-wheels](https://pozzettiandrea.github.io/cuda-wheels/) provides pre-built wheels.
|
|
186
|
+
|
|
187
|
+
**How envs work:**
|
|
188
|
+
- Central cache: `~/.comfy-env/envs/`
|
|
189
|
+
- Marker files link nodes → cached envs
|
|
190
|
+
- Config hash in name → changes create new envs
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
|
@@ -37,10 +37,11 @@ from .isolation import wrap_isolated_nodes, wrap_nodes
|
|
|
37
37
|
from .config import (
|
|
38
38
|
ComfyEnvConfig,
|
|
39
39
|
NodeDependency,
|
|
40
|
-
NodeReq,
|
|
40
|
+
NodeReq,
|
|
41
41
|
load_config,
|
|
42
42
|
discover_config,
|
|
43
43
|
CONFIG_FILE_NAME,
|
|
44
|
+
ROOT_CONFIG_FILE_NAME,
|
|
44
45
|
)
|
|
45
46
|
|
|
46
47
|
|
|
@@ -136,6 +137,7 @@ __all__ = [
|
|
|
136
137
|
"load_config",
|
|
137
138
|
"discover_config",
|
|
138
139
|
"CONFIG_FILE_NAME",
|
|
140
|
+
"ROOT_CONFIG_FILE_NAME",
|
|
139
141
|
# Detection
|
|
140
142
|
"detect_cuda_version",
|
|
141
143
|
"detect_cuda_environment",
|
|
@@ -6,6 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
from typing import List, Optional
|
|
7
7
|
|
|
8
8
|
from . import __version__
|
|
9
|
+
from .config import ROOT_CONFIG_FILE_NAME, CONFIG_FILE_NAME
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def main(args: Optional[List[str]] = None) -> int:
|
|
@@ -14,12 +15,13 @@ def main(args: Optional[List[str]] = None) -> int:
|
|
|
14
15
|
sub = parser.add_subparsers(dest="command", help="Commands")
|
|
15
16
|
|
|
16
17
|
# init
|
|
17
|
-
p = sub.add_parser("init", help="Create
|
|
18
|
+
p = sub.add_parser("init", help=f"Create {ROOT_CONFIG_FILE_NAME}")
|
|
18
19
|
p.add_argument("--force", "-f", action="store_true", help="Overwrite existing")
|
|
20
|
+
p.add_argument("--isolated", action="store_true", help=f"Create {CONFIG_FILE_NAME} instead (for isolated folders)")
|
|
19
21
|
|
|
20
22
|
# generate
|
|
21
|
-
p = sub.add_parser("generate", help="Generate pixi.toml from
|
|
22
|
-
p.add_argument("config", type=str, help="Path to
|
|
23
|
+
p = sub.add_parser("generate", help="Generate pixi.toml from config")
|
|
24
|
+
p.add_argument("config", type=str, help="Path to config file")
|
|
23
25
|
p.add_argument("--force", "-f", action="store_true", help="Overwrite existing")
|
|
24
26
|
|
|
25
27
|
# install
|
|
@@ -62,22 +64,53 @@ def main(args: Optional[List[str]] = None) -> int:
|
|
|
62
64
|
return 1
|
|
63
65
|
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
# comfy-env.toml
|
|
67
|
+
ROOT_DEFAULT_CONFIG = """\
|
|
68
|
+
# comfy-env-root.toml - Main node config
|
|
69
|
+
# PyPI deps go in requirements.txt
|
|
70
|
+
|
|
67
71
|
[cuda]
|
|
68
72
|
packages = []
|
|
69
73
|
|
|
74
|
+
[apt]
|
|
75
|
+
packages = []
|
|
76
|
+
|
|
77
|
+
[dependencies]
|
|
78
|
+
# cgal = "*"
|
|
79
|
+
|
|
80
|
+
[env_vars]
|
|
81
|
+
# KMP_DUPLICATE_LIB_OK = "TRUE"
|
|
82
|
+
|
|
83
|
+
[node_reqs]
|
|
84
|
+
# ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
ISOLATED_DEFAULT_CONFIG = """\
|
|
88
|
+
# comfy-env.toml - Isolated folder config
|
|
89
|
+
python = "3.11"
|
|
90
|
+
|
|
91
|
+
[dependencies]
|
|
92
|
+
# cgal = "*"
|
|
93
|
+
|
|
70
94
|
[pypi-dependencies]
|
|
71
|
-
#
|
|
95
|
+
# trimesh = { version = "*", extras = ["easy"] }
|
|
96
|
+
|
|
97
|
+
[env_vars]
|
|
98
|
+
# SOME_VAR = "value"
|
|
72
99
|
"""
|
|
73
100
|
|
|
74
101
|
|
|
75
102
|
def cmd_init(args) -> int:
|
|
76
|
-
|
|
103
|
+
if getattr(args, 'isolated', False):
|
|
104
|
+
config_path = Path.cwd() / CONFIG_FILE_NAME
|
|
105
|
+
content = ISOLATED_DEFAULT_CONFIG
|
|
106
|
+
else:
|
|
107
|
+
config_path = Path.cwd() / ROOT_CONFIG_FILE_NAME
|
|
108
|
+
content = ROOT_DEFAULT_CONFIG
|
|
109
|
+
|
|
77
110
|
if config_path.exists() and not args.force:
|
|
78
111
|
print(f"Already exists: {config_path}\nUse --force to overwrite", file=sys.stderr)
|
|
79
112
|
return 1
|
|
80
|
-
config_path.write_text(
|
|
113
|
+
config_path.write_text(content)
|
|
81
114
|
print(f"Created {config_path}")
|
|
82
115
|
return 0
|
|
83
116
|
|
|
@@ -170,7 +203,13 @@ def cmd_apt_install(args) -> int:
|
|
|
170
203
|
print("apt-install: Linux only", file=sys.stderr)
|
|
171
204
|
return 1
|
|
172
205
|
|
|
173
|
-
|
|
206
|
+
# Check root config first, then regular
|
|
207
|
+
if args.config:
|
|
208
|
+
config_path = Path(args.config).resolve()
|
|
209
|
+
else:
|
|
210
|
+
root_path = Path.cwd() / ROOT_CONFIG_FILE_NAME
|
|
211
|
+
config_path = root_path if root_path.exists() else Path.cwd() / CONFIG_FILE_NAME
|
|
212
|
+
|
|
174
213
|
if not config_path.exists():
|
|
175
214
|
print(f"Not found: {config_path}", file=sys.stderr)
|
|
176
215
|
return 1
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Config layer - Configuration parsing and types.
|
|
3
|
-
|
|
4
|
-
Pure parsing, no side effects.
|
|
5
|
-
"""
|
|
1
|
+
"""Config layer - Configuration parsing and types."""
|
|
6
2
|
|
|
7
3
|
from .types import (
|
|
8
4
|
ComfyEnvConfig,
|
|
9
5
|
NodeDependency,
|
|
10
|
-
NodeReq,
|
|
6
|
+
NodeReq,
|
|
11
7
|
)
|
|
12
8
|
from .parser import (
|
|
9
|
+
ROOT_CONFIG_FILE_NAME,
|
|
13
10
|
CONFIG_FILE_NAME,
|
|
14
11
|
load_config,
|
|
15
12
|
discover_config,
|
|
@@ -17,11 +14,10 @@ from .parser import (
|
|
|
17
14
|
)
|
|
18
15
|
|
|
19
16
|
__all__ = [
|
|
20
|
-
# Types
|
|
21
17
|
"ComfyEnvConfig",
|
|
22
18
|
"NodeDependency",
|
|
23
|
-
"NodeReq",
|
|
24
|
-
|
|
19
|
+
"NodeReq",
|
|
20
|
+
"ROOT_CONFIG_FILE_NAME",
|
|
25
21
|
"CONFIG_FILE_NAME",
|
|
26
22
|
"load_config",
|
|
27
23
|
"discover_config",
|
|
@@ -8,11 +8,12 @@ import tomli
|
|
|
8
8
|
|
|
9
9
|
from .types import ComfyEnvConfig, NodeDependency
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
ROOT_CONFIG_FILE_NAME = "comfy-env-root.toml" # Main node config
|
|
12
|
+
CONFIG_FILE_NAME = "comfy-env.toml" # Isolated folder config
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
def load_config(path: Path) -> ComfyEnvConfig:
|
|
15
|
-
"""Load and parse
|
|
16
|
+
"""Load and parse config file."""
|
|
16
17
|
path = Path(path)
|
|
17
18
|
if not path.exists():
|
|
18
19
|
raise FileNotFoundError(f"Config file not found: {path}")
|
|
@@ -20,9 +21,14 @@ def load_config(path: Path) -> ComfyEnvConfig:
|
|
|
20
21
|
return parse_config(tomli.load(f))
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
def discover_config(node_dir: Path) -> Optional[ComfyEnvConfig]:
|
|
24
|
-
"""Find and load
|
|
25
|
-
|
|
24
|
+
def discover_config(node_dir: Path, root: bool = True) -> Optional[ComfyEnvConfig]:
|
|
25
|
+
"""Find and load config from directory. Checks root config first if root=True."""
|
|
26
|
+
node_dir = Path(node_dir)
|
|
27
|
+
if root:
|
|
28
|
+
root_path = node_dir / ROOT_CONFIG_FILE_NAME
|
|
29
|
+
if root_path.exists():
|
|
30
|
+
return load_config(root_path)
|
|
31
|
+
config_path = node_dir / CONFIG_FILE_NAME
|
|
26
32
|
return load_config(config_path) if config_path.exists() else None
|
|
27
33
|
|
|
28
34
|
|
|
@@ -49,7 +55,6 @@ def parse_config(data: Dict[str, Any]) -> ComfyEnvConfig:
|
|
|
49
55
|
|
|
50
56
|
|
|
51
57
|
def _parse_node_reqs(data: Dict[str, Any]) -> List[NodeDependency]:
|
|
52
|
-
"""Parse [node_reqs] section."""
|
|
53
58
|
return [
|
|
54
59
|
NodeDependency(name=name, repo=value if isinstance(value, str) else value.get("repo", ""))
|
|
55
60
|
for name, value in data.items()
|
|
@@ -10,6 +10,7 @@ from .cache import MARKER_FILE, sanitize_name
|
|
|
10
10
|
from .libomp import dedupe_libomp
|
|
11
11
|
|
|
12
12
|
USE_COMFY_ENV_VAR = "USE_COMFY_ENV"
|
|
13
|
+
ROOT_CONFIG_FILE_NAME = "comfy-env-root.toml"
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def is_comfy_env_enabled() -> bool:
|
|
@@ -50,8 +51,10 @@ def setup_env(node_dir: Optional[str] = None) -> None:
|
|
|
50
51
|
import inspect
|
|
51
52
|
node_dir = str(Path(inspect.stack()[1].filename).parent)
|
|
52
53
|
|
|
53
|
-
# Apply env vars
|
|
54
|
-
|
|
54
|
+
# Apply env vars (check root config first, then regular)
|
|
55
|
+
root_config = os.path.join(node_dir, ROOT_CONFIG_FILE_NAME)
|
|
56
|
+
config = root_config if os.path.exists(root_config) else os.path.join(node_dir, "comfy-env.toml")
|
|
57
|
+
for k, v in load_env_vars(config).items():
|
|
55
58
|
os.environ[k] = v
|
|
56
59
|
|
|
57
60
|
# Find env: marker -> _env_<name> -> .pixi
|
|
@@ -5,7 +5,7 @@ import os
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Callable, List, Optional, Set, Union
|
|
7
7
|
|
|
8
|
-
from .config import ComfyEnvConfig, NodeDependency, load_config, discover_config, CONFIG_FILE_NAME
|
|
8
|
+
from .config import ComfyEnvConfig, NodeDependency, load_config, discover_config, CONFIG_FILE_NAME, ROOT_CONFIG_FILE_NAME
|
|
9
9
|
|
|
10
10
|
USE_COMFY_ENV_VAR = "USE_COMFY_ENV"
|
|
11
11
|
|
|
@@ -20,7 +20,7 @@ def install(
|
|
|
20
20
|
log_callback: Optional[Callable[[str], None]] = None,
|
|
21
21
|
dry_run: bool = False,
|
|
22
22
|
) -> bool:
|
|
23
|
-
"""Install dependencies from comfy-env.toml."""
|
|
23
|
+
"""Install dependencies from comfy-env-root.toml or comfy-env.toml."""
|
|
24
24
|
if node_dir is None:
|
|
25
25
|
node_dir = Path(inspect.stack()[1].filename).parent.resolve()
|
|
26
26
|
|
|
@@ -32,10 +32,10 @@ def install(
|
|
|
32
32
|
config_path = node_dir / config_path
|
|
33
33
|
cfg = load_config(config_path)
|
|
34
34
|
else:
|
|
35
|
-
cfg = discover_config(node_dir)
|
|
35
|
+
cfg = discover_config(node_dir, root=True)
|
|
36
36
|
|
|
37
37
|
if cfg is None:
|
|
38
|
-
raise FileNotFoundError(f"No
|
|
38
|
+
raise FileNotFoundError(f"No {ROOT_CONFIG_FILE_NAME} or {CONFIG_FILE_NAME} found in {node_dir}")
|
|
39
39
|
|
|
40
40
|
if cfg.apt_packages: _install_apt_packages(cfg.apt_packages, log, dry_run)
|
|
41
41
|
if cfg.env_vars: _set_persistent_env_vars(cfg.env_vars, log, dry_run)
|
|
@@ -168,8 +168,12 @@ def _install_via_pixi(cfg: ComfyEnvConfig, node_dir: Path, log: Callable[[str],
|
|
|
168
168
|
if result.returncode != 0:
|
|
169
169
|
raise RuntimeError(f"Failed: {result.stderr}")
|
|
170
170
|
|
|
171
|
+
# Find config file for marker
|
|
172
|
+
config_path = node_dir / CONFIG_FILE_NAME
|
|
173
|
+
if not config_path.exists():
|
|
174
|
+
config_path = node_dir / ROOT_CONFIG_FILE_NAME
|
|
175
|
+
|
|
171
176
|
old_env = node_dir / ".pixi" / "envs" / "default"
|
|
172
|
-
config_path = node_dir / "comfy-env.toml"
|
|
173
177
|
main_node_dir = node_dir
|
|
174
178
|
for parent in node_dir.parents:
|
|
175
179
|
if parent.parent.name == "custom_nodes":
|
|
@@ -229,8 +233,9 @@ def _install_to_host_python(cfg: ComfyEnvConfig, node_dir: Path, log: Callable[[
|
|
|
229
233
|
|
|
230
234
|
|
|
231
235
|
def _install_isolated_subdirs(node_dir: Path, log: Callable[[str], None], dry_run: bool) -> None:
|
|
236
|
+
"""Find and install comfy-env.toml in subdirectories (isolated folders only)."""
|
|
232
237
|
for config_file in node_dir.rglob(CONFIG_FILE_NAME):
|
|
233
|
-
if config_file.parent == node_dir: continue
|
|
238
|
+
if config_file.parent == node_dir: continue # Skip root
|
|
234
239
|
log(f"\n[isolated] {config_file.parent.relative_to(node_dir)}")
|
|
235
240
|
if not dry_run:
|
|
236
241
|
_install_via_pixi(load_config(config_file), config_file.parent, log, dry_run)
|
comfy_env-0.1.16/PKG-INFO
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
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
|
comfy_env-0.1.16/README.md
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
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
|
|
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
|