comfy-env 0.0.40__py3-none-any.whl → 0.0.42__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comfy-env
3
- Version: 0.0.40
3
+ Version: 0.0.42
4
4
  Summary: Environment management for ComfyUI custom nodes - CUDA wheel resolution and process isolation
5
5
  Project-URL: Homepage, https://github.com/PozzettiAndrea/comfy-env
6
6
  Project-URL: Repository, https://github.com/PozzettiAndrea/comfy-env
@@ -67,17 +67,12 @@ curl -LsSf https://astral.sh/uv/install.sh | sh
67
67
  Create a `comfy-env.toml` in your node directory:
68
68
 
69
69
  ```toml
70
- [env]
71
- name = "my-node"
72
- python = "3.10"
73
- cuda = "auto"
70
+ [cuda]
71
+ nvdiffrast = "0.4.0"
72
+ pytorch3d = "0.7.9"
74
73
 
75
74
  [packages]
76
75
  requirements = ["transformers>=4.56", "pillow"]
77
- no_deps = ["nvdiffrast==0.4.0", "pytorch3d>=0.7.8"]
78
-
79
- [sources]
80
- wheel_sources = ["https://github.com/PozzettiAndrea/nvdiffrast-full-wheels/releases/download/"]
81
76
  ```
82
77
 
83
78
  Then in your `__init__.py`:
@@ -122,56 +117,124 @@ comfy-env install --dry-run
122
117
  # Resolve wheel URLs without installing
123
118
  comfy-env resolve nvdiffrast==0.4.0
124
119
 
120
+ # List all packages in the built-in registry
121
+ comfy-env list-packages
122
+
125
123
  # Verify installation
126
124
  comfy-env doctor
127
125
  ```
128
126
 
129
- ## Configurations
127
+ ## Configuration
130
128
 
131
- ### comfy-env.toml
129
+ ### Simple Format (comfy-env.toml)
132
130
 
133
131
  ```toml
134
- [env]
135
- name = "my-node" # Unique name for caching
136
- python = "3.10" # Python version
137
- cuda = "auto" # "auto", "12.8", "12.4", or null
132
+ # CUDA packages (uses built-in registry)
133
+ [cuda]
134
+ nvdiffrast = "0.4.0"
135
+ pytorch3d = "0.7.9"
136
+ torch-scatter = "2.1.2"
138
137
 
138
+ # Regular pip packages
139
139
  [packages]
140
- requirements = [ # Regular pip packages
141
- "transformers>=4.56",
142
- "pillow",
143
- ]
144
- no_deps = [ # CUDA packages (installed with --no-deps)
145
- "nvdiffrast==0.4.0",
146
- "pytorch3d>=0.7.8",
147
- ]
148
-
149
- [sources]
150
- wheel_sources = [ # GitHub releases with pre-built wheels
151
- "https://github.com/.../releases/download/",
152
- ]
153
- index_urls = [ # Extra pip index URLs
154
- "https://pypi.org/simple/",
155
- ]
156
-
157
- [worker] # For isolation mode
158
- package = "worker" # worker/__main__.py
140
+ requirements = ["transformers>=4.56", "pillow"]
159
141
  ```
160
142
 
161
- ### Template Variables
143
+ ### Full Format
144
+
145
+ ```toml
146
+ [system]
147
+ linux = ["libgl1", "libopengl0"] # apt packages
148
+
149
+ [local.cuda]
150
+ nvdiffrast = "0.4.0"
151
+
152
+ [local.packages]
153
+ requirements = ["pillow", "numpy"]
154
+
155
+ # For isolated environments (creates separate venv)
156
+ [myenv]
157
+ python = "3.10"
158
+ cuda = "12.8"
159
+
160
+ [myenv.cuda]
161
+ torch-scatter = "2.1.2"
162
162
 
163
- Wheel URLs support these template variables:
163
+ [myenv.packages]
164
+ requirements = ["transformers>=4.56"]
165
+
166
+ # Custom wheel templates (override built-in registry)
167
+ [wheel_sources]
168
+ my-custom-pkg = "https://my-server.com/my-pkg-{version}+cu{cuda_short}-{py_tag}-{platform}.whl"
169
+ ```
170
+
171
+ ## Writing Wheel Templates
172
+
173
+ ### Template Variables
164
174
 
165
175
  | Variable | Example | Description |
166
176
  |----------|---------|-------------|
177
+ | `{version}` | `0.4.0` | Package version |
167
178
  | `{cuda_version}` | `12.8` | Full CUDA version |
168
179
  | `{cuda_short}` | `128` | CUDA without dot |
169
- | `{torch_version}` | `2.8.0` | PyTorch version |
170
- | `{torch_mm}` | `28` | PyTorch major.minor |
180
+ | `{cuda_major}` | `12` | CUDA major only |
181
+ | `{torch_version}` | `2.8.0` | Full PyTorch version |
182
+ | `{torch_mm}` | `28` | PyTorch major.minor no dot |
183
+ | `{torch_dotted_mm}` | `2.8` | PyTorch major.minor with dot |
171
184
  | `{py_version}` | `3.10` | Python version |
172
185
  | `{py_short}` | `310` | Python without dot |
186
+ | `{py_tag}` | `cp310` | Python wheel tag |
173
187
  | `{platform}` | `linux_x86_64` | Platform tag |
174
188
 
189
+ ### Common Wheel URL Patterns
190
+
191
+ **Pattern 1: Simple CUDA + Python**
192
+ ```
193
+ https://example.com/{package}-{version}+cu{cuda_short}-{py_tag}-{py_tag}-{platform}.whl
194
+ ```
195
+
196
+ **Pattern 2: CUDA + PyTorch**
197
+ ```
198
+ https://example.com/{package}-{version}+cu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl
199
+ ```
200
+
201
+ **Pattern 3: GitHub Releases**
202
+ ```
203
+ https://github.com/org/repo/releases/download/v{version}/{package}-{version}+cu{cuda_short}-{py_tag}-{platform}.whl
204
+ ```
205
+
206
+ ### How to Find the Right Template
207
+
208
+ 1. Download a wheel manually from the source
209
+ 2. Look at the filename pattern: `nvdiffrast-0.4.0+cu128torch28-cp310-cp310-linux_x86_64.whl`
210
+ 3. Replace values with variables: `nvdiffrast-{version}+cu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl`
211
+ 4. Prepend the base URL
212
+
213
+ ### Testing Your Template
214
+
215
+ ```bash
216
+ comfy-env resolve my-package==1.0.0
217
+ ```
218
+
219
+ This shows the resolved URL without installing.
220
+
221
+ ### Adding Custom Wheel Sources
222
+
223
+ If a package isn't in the built-in registry, add it to your `comfy-env.toml`:
224
+
225
+ ```toml
226
+ [cuda]
227
+ my-custom-pkg = "1.0.0"
228
+
229
+ [wheel_sources]
230
+ my-custom-pkg = "https://my-server.com/my-custom-pkg-{version}+cu{cuda_short}-{py_tag}-{platform}.whl"
231
+ ```
232
+
233
+ Resolution order:
234
+ 1. User's `[wheel_sources]` in comfy-env.toml (highest priority)
235
+ 2. Built-in `wheel_sources.yml` registry
236
+ 3. Error if not found
237
+
175
238
  ## API Reference
176
239
 
177
240
  ### install()
@@ -185,23 +248,22 @@ install()
185
248
  # Explicit config
186
249
  install(config="comfy-env.toml")
187
250
 
188
- # Isolated mode (creates separate venv)
189
- install(mode="isolated")
190
-
191
251
  # Dry run
192
252
  install(dry_run=True)
193
253
  ```
194
254
 
195
- ### WheelResolver
255
+ ### RuntimeEnv
196
256
 
197
257
  ```python
198
- from comfy_env import RuntimeEnv, WheelResolver
258
+ from comfy_env import RuntimeEnv
199
259
 
200
260
  env = RuntimeEnv.detect()
201
- resolver = WheelResolver()
261
+ print(env)
262
+ # Python 3.10, CUDA 12.8, PyTorch 2.8.0, GPU: NVIDIA GeForce RTX 4090
202
263
 
203
- url = resolver.resolve("nvdiffrast", "0.4.0", env)
204
- print(url) # https://github.com/.../nvdiffrast-0.4.0+cu128torch28-...whl
264
+ # Get template variables
265
+ vars_dict = env.as_dict()
266
+ # {'cuda_version': '12.8', 'cuda_short': '128', 'torch_mm': '28', ...}
205
267
  ```
206
268
 
207
269
  ### Workers (for isolation)
@@ -224,6 +286,16 @@ print(get_gpu_summary())
224
286
  # GPU 0: NVIDIA GeForce RTX 5090 (sm_120) [Blackwell - CUDA 12.8]
225
287
  ```
226
288
 
289
+ ## Built-in Package Registry
290
+
291
+ Run `comfy-env list-packages` to see all packages in the built-in registry.
292
+
293
+ The registry includes:
294
+ - PyTorch Geometric packages (torch-scatter, torch-cluster, torch-sparse)
295
+ - NVIDIA packages (nvdiffrast, pytorch3d, gsplat)
296
+ - Flash Attention (flash-attn)
297
+ - And more
298
+
227
299
  ## License
228
300
 
229
301
  MIT - see LICENSE file.
@@ -1,18 +1,17 @@
1
- comfy_env/__init__.py,sha256=PCx-J6DaolN2TEQ90YfhKMV_Kdd2BK2rxlnhVa7SQFc,3685
2
- comfy_env/cli.py,sha256=X-GCQMP0mtMcE3ZgkT-VLQ4Gq3UUvcb_Ux_NClEFhgI,15975
1
+ comfy_env/__init__.py,sha256=OQJFNjmArjLcgrfHAFxgDJQFH_IhxibqMXbU5bu_j9Q,3822
2
+ comfy_env/cli.py,sha256=hZv_oJsmaMoG62Fr2Fjp778P_32BHr4fzS7G4lULSwU,13153
3
3
  comfy_env/decorator.py,sha256=6JCKwLHaZtOLVDexs_gh_-NtS2ZK0V7nGCPqkyeYEAA,16688
4
4
  comfy_env/errors.py,sha256=8hN8NDlo8oBUdapc-eT3ZluigI5VBzfqsSBvQdfWlz4,9943
5
- comfy_env/index_resolver.py,sha256=D8BttTJ7BOiukUvmdT6_dGdzFV3CahGL2m28X-HwPeE,4650
6
- comfy_env/install.py,sha256=Az72DmrDpyD9KZ8KUK1nna7v19jjPVQXGSncSeAkNSY,32320
5
+ comfy_env/install.py,sha256=0wz4i19BbNAhfK-bK77LPabheOYhpfBgZFOLWsqKPPY,16329
7
6
  comfy_env/nodes.py,sha256=CWUe35jU5SKk4ur-SddZePdqWgxJDlxGhpcJiu5pAK4,4354
8
7
  comfy_env/pixi.py,sha256=y25mUDhB3bCqhPMGF0h23Tf8ZHykK4gLJrkvOhsPWmE,14398
9
- comfy_env/registry.py,sha256=uFCtGmWYvwGCqObXgzmArX7o5JsFNsHXxayofk3m6no,2569
10
- comfy_env/resolver.py,sha256=l-AnmCE1puG6CvdpDB-KrsfG_cn_3uO2DryYizUnG_4,12474
8
+ comfy_env/registry.py,sha256=w-QwvAPFlCrBYRAv4cXkp2zujQPZn8Fk5DUxKCtox8o,3430
9
+ comfy_env/resolver.py,sha256=WoNIo2IfTR2RlEf_HQl66eAeMa2R2pmLof_UdK-0RNE,6714
11
10
  comfy_env/env/__init__.py,sha256=imQdoQEQvrRT-QDtyNpFlkVbm2fBzgACdpQwRPd09fI,1157
12
- comfy_env/env/config.py,sha256=5rK7r2uRItMXJnKAn8DmVQoadLo2njHTuaxrWybhppU,7469
13
- comfy_env/env/config_file.py,sha256=1UdcL1TwKceGaSunCnsHiuPyxpCSq1JpelScUEsCBn8,23669
11
+ comfy_env/env/config.py,sha256=Ila-5Yal3bj6jENbBeYJlZtkbgdwnzJzImVZK3ZF1lg,7645
12
+ comfy_env/env/config_file.py,sha256=HzFKeQh9zQ--K1V-XuvgE6DiE_bYrXrChL1ZT8Tzlq4,24684
14
13
  comfy_env/env/cuda_gpu_detection.py,sha256=YLuXUdWg6FeKdNyLlQAHPlveg4rTenXJ2VbeAaEi9QE,9755
15
- comfy_env/env/manager.py,sha256=wv_od7Rxa-qMlToUGzOhAsDvZY6C0P7y9ayqYiKKLPg,26460
14
+ comfy_env/env/manager.py,sha256=eDcrtJeNrW3jYb0q0R_DmUfAYjGo5Cs4BMuZUxWEzeg,21789
16
15
  comfy_env/env/security.py,sha256=dNSitAnfBNVdvxgBBntYw33AJaCs_S1MHb7KJhAVYzM,8171
17
16
  comfy_env/env/platform/__init__.py,sha256=Nb5MPZIEeanSMEWwqU4p4bnEKTJn1tWcwobnhq9x9IY,614
18
17
  comfy_env/env/platform/base.py,sha256=iS0ptTTVjXRwPU4qWUdvHI7jteuzxGSjWr5BUQ7hGiU,2453
@@ -37,9 +36,9 @@ comfy_env/workers/pool.py,sha256=MtjeOWfvHSCockq8j1gfnxIl-t01GSB79T5N4YB82Lg,695
37
36
  comfy_env/workers/tensor_utils.py,sha256=TCuOAjJymrSbkgfyvcKtQ_KbVWTqSwP9VH_bCaFLLq8,6409
38
37
  comfy_env/workers/torch_mp.py,sha256=4YSNPn7hALrvMVbkO4RkTeFTcc0lhfLMk5QTWjY4PHw,22134
39
38
  comfy_env/workers/venv.py,sha256=PmsVOu5i89tBYkGRupo2bjOLPBmk06q4GNUwDWsd9F8,32088
40
- comfy_env/wheel_sources.yml,sha256=IEyi3JnySo4sXTRkYR0VjtCdXaCsF5Q5c0nU0S9LC8I,9143
41
- comfy_env-0.0.40.dist-info/METADATA,sha256=eJYprZ_ULUXc7vWu10nqRaMntOuerWRSJpBYf4zXUwc,5400
42
- comfy_env-0.0.40.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
43
- comfy_env-0.0.40.dist-info/entry_points.txt,sha256=J4fXeqgxU_YenuW_Zxn_pEL7J-3R0--b6MS5t0QmAr0,49
44
- comfy_env-0.0.40.dist-info/licenses/LICENSE,sha256=E68QZMMpW4P2YKstTZ3QU54HRQO8ecew09XZ4_Vn870,1093
45
- comfy_env-0.0.40.dist-info/RECORD,,
39
+ comfy_env/wheel_sources.yml,sha256=B8HIRuakB68oD3bcGBJPnrCnAFkP5FMPaDotUX4-2TY,7278
40
+ comfy_env-0.0.42.dist-info/METADATA,sha256=KLuQlF5nxK_DSEoVWlBU7kfaGtiXr26-8jokF_8FmSA,7138
41
+ comfy_env-0.0.42.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
42
+ comfy_env-0.0.42.dist-info/entry_points.txt,sha256=J4fXeqgxU_YenuW_Zxn_pEL7J-3R0--b6MS5t0QmAr0,49
43
+ comfy_env-0.0.42.dist-info/licenses/LICENSE,sha256=E68QZMMpW4P2YKstTZ3QU54HRQO8ecew09XZ4_Vn870,1093
44
+ comfy_env-0.0.42.dist-info/RECORD,,
@@ -1,132 +0,0 @@
1
- """
2
- Simple index resolver for finding wheel URLs from PEP 503 indexes.
3
-
4
- This module fetches and parses simple index HTML to find the exact wheel URL
5
- for a package given the runtime environment (CUDA, torch, python versions).
6
- """
7
-
8
- import re
9
- import urllib.request
10
- from typing import Optional, Dict
11
- from urllib.parse import urljoin
12
-
13
-
14
- def resolve_wheel_from_index(
15
- index_url: str,
16
- package: str,
17
- vars_dict: Dict[str, str],
18
- version: Optional[str] = None,
19
- ) -> Optional[str]:
20
- """
21
- Resolve the exact wheel URL from a PEP 503 simple index or find-links page.
22
-
23
- Args:
24
- index_url: Base URL of the simple index (e.g., https://pozzettiandrea.github.io/cuda-wheels)
25
- or find-links page (e.g., https://data.pyg.org/whl/torch-2.8.0+cu128.html)
26
- package: Package name (e.g., "cumesh")
27
- vars_dict: Environment variables dict with cuda_short, torch_mm, py_tag, platform
28
- version: Specific version to match, or None for latest
29
-
30
- Returns:
31
- Full wheel URL if found, None otherwise
32
- """
33
- # PEP 503: normalize package name (lowercase, replace _ with -)
34
- normalized = package.lower().replace("_", "-")
35
-
36
- # Try two URL patterns:
37
- # 1. PEP 503 index: {index_url}/{package}/
38
- # 2. Find-links page: {index_url} directly (e.g., .html file)
39
- urls_to_try = []
40
-
41
- if index_url.endswith('.html'):
42
- # Direct HTML page (find-links style)
43
- urls_to_try = [index_url]
44
- else:
45
- # PEP 503 style - try package subdirectory first, then root
46
- urls_to_try = [
47
- f"{index_url.rstrip('/')}/{normalized}/",
48
- index_url,
49
- ]
50
-
51
- html = None
52
- base_url = None
53
- for url in urls_to_try:
54
- try:
55
- with urllib.request.urlopen(url, timeout=10) as response:
56
- html = response.read().decode('utf-8')
57
- base_url = url
58
- break
59
- except Exception:
60
- continue
61
-
62
- if not html:
63
- return None
64
-
65
- # Extract wheel links from HTML
66
- # Simple index format: <a href="...">wheel_filename</a>
67
- wheel_pattern = re.compile(r'<a[^>]+href="([^"]+\.whl)"[^>]*>([^<]+)</a>', re.IGNORECASE)
68
- wheels = wheel_pattern.findall(html)
69
-
70
- if not wheels:
71
- return None
72
-
73
- # Build matching criteria from vars_dict
74
- cuda_short = vars_dict.get("cuda_short", "")
75
- torch_mm = vars_dict.get("torch_mm", "")
76
- py_tag = vars_dict.get("py_tag", "")
77
- platform = vars_dict.get("platform", "")
78
-
79
- # Find matching wheel
80
- # Wheel filename format: {package}-{version}+cu{cuda}torch{torch}-{pytag}-{pytag}-{platform}.whl
81
- best_match = None
82
- best_version = None
83
-
84
- for href, filename in wheels:
85
- # Check if wheel matches our environment
86
- if cuda_short and f"cu{cuda_short}" not in filename.lower():
87
- continue
88
- if torch_mm and f"torch{torch_mm}" not in filename.lower():
89
- continue
90
- if py_tag and py_tag not in filename:
91
- continue
92
- if platform and platform not in filename:
93
- continue
94
-
95
- # Extract version from filename
96
- # Format: package-version+... or package-version-...
97
- # Package name in wheel can use underscore or hyphen interchangeably
98
- pkg_pattern = re.escape(package).replace(r'\_', '[-_]').replace(r'\-', '[-_]')
99
- norm_pattern = re.escape(normalized).replace(r'\_', '[-_]').replace(r'\-', '[-_]')
100
- match = re.match(rf'{pkg_pattern}[-_]([^+\-]+)', filename, re.IGNORECASE)
101
- if not match:
102
- # Try with normalized name
103
- match = re.match(rf'{norm_pattern}[-_]([^+\-]+)', filename, re.IGNORECASE)
104
-
105
- if match:
106
- wheel_version = match.group(1)
107
-
108
- # If specific version requested, must match
109
- if version and version != "*" and wheel_version != version:
110
- continue
111
-
112
- # Track best (highest) version
113
- if best_version is None or _version_gt(wheel_version, best_version):
114
- best_version = wheel_version
115
- # Resolve relative URL
116
- if href.startswith('http'):
117
- best_match = href
118
- else:
119
- best_match = urljoin(base_url, href)
120
-
121
- return best_match
122
-
123
-
124
- def _version_gt(v1: str, v2: str) -> bool:
125
- """Compare version strings (simple comparison)."""
126
- try:
127
- # Split into parts and compare numerically
128
- parts1 = [int(x) for x in re.split(r'[.\-+]', v1) if x.isdigit()]
129
- parts2 = [int(x) for x in re.split(r'[.\-+]', v2) if x.isdigit()]
130
- return parts1 > parts2
131
- except (ValueError, AttributeError):
132
- return v1 > v2