comfy-env 0.1.14__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.
Files changed (63) hide show
  1. comfy_env-0.1.16/PKG-INFO +279 -0
  2. comfy_env-0.1.16/README.md +250 -0
  3. {comfy_env-0.1.14 → comfy_env-0.1.16}/pyproject.toml +5 -5
  4. comfy_env-0.1.16/src/comfy_env/__init__.py +186 -0
  5. comfy_env-0.1.16/src/comfy_env/cli.py +202 -0
  6. comfy_env-0.1.16/src/comfy_env/config/__init__.py +29 -0
  7. comfy_env-0.1.16/src/comfy_env/config/parser.py +60 -0
  8. comfy_env-0.1.16/src/comfy_env/config/types.py +37 -0
  9. comfy_env-0.1.16/src/comfy_env/detection/__init__.py +77 -0
  10. comfy_env-0.1.16/src/comfy_env/detection/cuda.py +61 -0
  11. comfy_env-0.1.16/src/comfy_env/detection/gpu.py +230 -0
  12. comfy_env-0.1.16/src/comfy_env/detection/platform.py +70 -0
  13. comfy_env-0.1.16/src/comfy_env/detection/runtime.py +103 -0
  14. comfy_env-0.1.16/src/comfy_env/environment/__init__.py +53 -0
  15. comfy_env-0.1.16/src/comfy_env/environment/cache.py +141 -0
  16. comfy_env-0.1.16/src/comfy_env/environment/libomp.py +41 -0
  17. comfy_env-0.1.16/src/comfy_env/environment/paths.py +38 -0
  18. comfy_env-0.1.16/src/comfy_env/environment/setup.py +88 -0
  19. comfy_env-0.1.16/src/comfy_env/install.py +249 -0
  20. comfy_env-0.1.16/src/comfy_env/isolation/__init__.py +40 -0
  21. comfy_env-0.1.16/src/comfy_env/isolation/tensor_utils.py +83 -0
  22. comfy_env-0.1.16/src/comfy_env/isolation/workers/__init__.py +16 -0
  23. {comfy_env-0.1.14/src/comfy_env → comfy_env-0.1.16/src/comfy_env/isolation}/workers/mp.py +1 -1
  24. {comfy_env-0.1.14/src/comfy_env → comfy_env-0.1.16/src/comfy_env/isolation}/workers/subprocess.py +2 -2
  25. comfy_env-0.1.16/src/comfy_env/isolation/wrap.py +235 -0
  26. comfy_env-0.1.16/src/comfy_env/packages/__init__.py +60 -0
  27. comfy_env-0.1.16/src/comfy_env/packages/apt.py +36 -0
  28. comfy_env-0.1.16/src/comfy_env/packages/cuda_wheels.py +97 -0
  29. comfy_env-0.1.16/src/comfy_env/packages/node_dependencies.py +77 -0
  30. comfy_env-0.1.16/src/comfy_env/packages/pixi.py +85 -0
  31. comfy_env-0.1.16/src/comfy_env/packages/toml_generator.py +88 -0
  32. comfy_env-0.1.14/PKG-INFO +0 -291
  33. comfy_env-0.1.14/README.md +0 -262
  34. comfy_env-0.1.14/src/comfy_env/__init__.py +0 -133
  35. comfy_env-0.1.14/src/comfy_env/cache.py +0 -331
  36. comfy_env-0.1.14/src/comfy_env/cli.py +0 -432
  37. comfy_env-0.1.14/src/comfy_env/config/__init__.py +0 -19
  38. comfy_env-0.1.14/src/comfy_env/config/parser.py +0 -161
  39. comfy_env-0.1.14/src/comfy_env/config/types.py +0 -70
  40. comfy_env-0.1.14/src/comfy_env/errors.py +0 -293
  41. comfy_env-0.1.14/src/comfy_env/install.py +0 -335
  42. comfy_env-0.1.14/src/comfy_env/isolation/__init__.py +0 -9
  43. comfy_env-0.1.14/src/comfy_env/isolation/wrap.py +0 -495
  44. comfy_env-0.1.14/src/comfy_env/nodes.py +0 -187
  45. comfy_env-0.1.14/src/comfy_env/pixi/__init__.py +0 -48
  46. comfy_env-0.1.14/src/comfy_env/pixi/core.py +0 -588
  47. comfy_env-0.1.14/src/comfy_env/pixi/cuda_detection.py +0 -303
  48. comfy_env-0.1.14/src/comfy_env/pixi/platform/__init__.py +0 -21
  49. comfy_env-0.1.14/src/comfy_env/pixi/platform/base.py +0 -96
  50. comfy_env-0.1.14/src/comfy_env/pixi/platform/darwin.py +0 -53
  51. comfy_env-0.1.14/src/comfy_env/pixi/platform/linux.py +0 -68
  52. comfy_env-0.1.14/src/comfy_env/pixi/platform/windows.py +0 -284
  53. comfy_env-0.1.14/src/comfy_env/pixi/resolver.py +0 -198
  54. comfy_env-0.1.14/src/comfy_env/prestartup.py +0 -192
  55. comfy_env-0.1.14/src/comfy_env/workers/__init__.py +0 -38
  56. comfy_env-0.1.14/src/comfy_env/workers/tensor_utils.py +0 -188
  57. {comfy_env-0.1.14 → comfy_env-0.1.16}/.github/workflows/ci.yml +0 -0
  58. {comfy_env-0.1.14 → comfy_env-0.1.16}/.github/workflows/publish.yml +0 -0
  59. {comfy_env-0.1.14 → comfy_env-0.1.16}/.gitignore +0 -0
  60. {comfy_env-0.1.14 → comfy_env-0.1.16}/LICENSE +0 -0
  61. {comfy_env-0.1.14/src/comfy_env → comfy_env-0.1.16/src/comfy_env/isolation}/workers/base.py +0 -0
  62. {comfy_env-0.1.14 → comfy_env-0.1.16}/src/comfy_env/templates/comfy-env-instructions.txt +0 -0
  63. {comfy_env-0.1.14 → 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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "comfy-env"
3
- version = "0.1.14"
3
+ version = "0.1.16"
4
4
  description = "Environment management for ComfyUI custom nodes - CUDA wheel resolution and process isolation"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -19,10 +19,10 @@ classifiers = [
19
19
  "Programming Language :: Python :: 3.13",
20
20
  ]
21
21
  dependencies = [
22
- "tomli>=2.0.0; python_version < '3.11'", # TOML parsing (built-in tomllib for 3.11+)
23
- "tomli-w>=1.0.0", # TOML writing (no stdlib equivalent)
24
- "uv>=0.4.0", # Fast Python package installer and venv creator
25
- "pip>=21.0", # Fallback package installer
22
+ "tomli>=2.0.0",
23
+ "tomli-w>=1.0.0",
24
+ "uv>=0.4.0",
25
+ "pip>=21.0",
26
26
  ]
27
27
 
28
28
  [project.optional-dependencies]