comfy-env 0.1.13__py3-none-any.whl → 0.1.15__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.
- comfy_env/__init__.py +30 -27
- comfy_env/cache.py +203 -0
- comfy_env/cli.py +9 -11
- comfy_env/config/__init__.py +8 -10
- comfy_env/config/parser.py +28 -75
- comfy_env/install.py +141 -25
- comfy_env/isolation/__init__.py +2 -1
- comfy_env/isolation/wrap.py +202 -25
- comfy_env/nodes.py +1 -1
- comfy_env/pixi/core.py +44 -10
- comfy_env/prestartup.py +63 -19
- comfy_env/workers/subprocess.py +1 -1
- {comfy_env-0.1.13.dist-info → comfy_env-0.1.15.dist-info}/METADATA +2 -2
- comfy_env-0.1.15.dist-info/RECORD +31 -0
- comfy_env/config/types.py +0 -70
- comfy_env/errors.py +0 -293
- comfy_env-0.1.13.dist-info/RECORD +0 -32
- {comfy_env-0.1.13.dist-info → comfy_env-0.1.15.dist-info}/WHEEL +0 -0
- {comfy_env-0.1.13.dist-info → comfy_env-0.1.15.dist-info}/entry_points.txt +0 -0
- {comfy_env-0.1.13.dist-info → comfy_env-0.1.15.dist-info}/licenses/LICENSE +0 -0
comfy_env/errors.py
DELETED
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Rich error messages for comfy-env.
|
|
3
|
-
|
|
4
|
-
This module provides error classes with actionable, user-friendly messages.
|
|
5
|
-
Instead of cryptic pip errors, users see exactly what went wrong and what
|
|
6
|
-
they can do to fix it.
|
|
7
|
-
|
|
8
|
-
Example output:
|
|
9
|
-
|
|
10
|
-
+------------------------------------------------------------------+
|
|
11
|
-
| CUDA Wheel Not Found |
|
|
12
|
-
+------------------------------------------------------------------+
|
|
13
|
-
| Package: nvdiffrast==0.4.0 |
|
|
14
|
-
| Requested: cu130-torch291-cp312-linux_x86_64 |
|
|
15
|
-
| |
|
|
16
|
-
| Suggestions: |
|
|
17
|
-
| 1. Use Python 3.10 instead of 3.12 |
|
|
18
|
-
| 2. Use CUDA 12.8 (set cuda = "12.8" in config) |
|
|
19
|
-
| 3. Build wheel locally: comfy-env build nvdiffrast |
|
|
20
|
-
+------------------------------------------------------------------+
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
from dataclasses import dataclass, field
|
|
24
|
-
from typing import List, Optional, TYPE_CHECKING
|
|
25
|
-
|
|
26
|
-
if TYPE_CHECKING:
|
|
27
|
-
from .resolver import RuntimeEnv
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class EnvManagerError(Exception):
|
|
31
|
-
"""Base exception for comfy-env errors."""
|
|
32
|
-
|
|
33
|
-
def __init__(self, message: str, details: Optional[str] = None):
|
|
34
|
-
self.message = message
|
|
35
|
-
self.details = details
|
|
36
|
-
super().__init__(self.format())
|
|
37
|
-
|
|
38
|
-
def format(self) -> str:
|
|
39
|
-
"""Format error message for display."""
|
|
40
|
-
if self.details:
|
|
41
|
-
return f"{self.message}\n\n{self.details}"
|
|
42
|
-
return self.message
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class ConfigError(EnvManagerError):
|
|
46
|
-
"""Error in configuration file."""
|
|
47
|
-
|
|
48
|
-
def __init__(self, message: str, file_path: Optional[str] = None, line: Optional[int] = None):
|
|
49
|
-
self.file_path = file_path
|
|
50
|
-
self.line = line
|
|
51
|
-
|
|
52
|
-
details = None
|
|
53
|
-
if file_path:
|
|
54
|
-
location = f"in {file_path}"
|
|
55
|
-
if line:
|
|
56
|
-
location += f" at line {line}"
|
|
57
|
-
details = location
|
|
58
|
-
|
|
59
|
-
super().__init__(message, details)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
@dataclass
|
|
63
|
-
class WheelNotFoundError(EnvManagerError):
|
|
64
|
-
"""
|
|
65
|
-
Raised when a CUDA wheel cannot be found or resolved.
|
|
66
|
-
|
|
67
|
-
Provides actionable suggestions based on the environment and what
|
|
68
|
-
wheels are typically available.
|
|
69
|
-
"""
|
|
70
|
-
package: str
|
|
71
|
-
version: Optional[str] = None
|
|
72
|
-
env: Optional["RuntimeEnv"] = None
|
|
73
|
-
tried_urls: List[str] = field(default_factory=list)
|
|
74
|
-
reason: Optional[str] = None
|
|
75
|
-
available_combos: List[str] = field(default_factory=list)
|
|
76
|
-
|
|
77
|
-
def __post_init__(self):
|
|
78
|
-
# Build the formatted message
|
|
79
|
-
self.message = self._build_message()
|
|
80
|
-
self.details = self._build_details()
|
|
81
|
-
Exception.__init__(self, self.format())
|
|
82
|
-
|
|
83
|
-
def _build_message(self) -> str:
|
|
84
|
-
"""Build the main error message."""
|
|
85
|
-
pkg = self.package
|
|
86
|
-
if self.version:
|
|
87
|
-
pkg = f"{self.package}=={self.version}"
|
|
88
|
-
return f"CUDA wheel not found: {pkg}"
|
|
89
|
-
|
|
90
|
-
def _build_details(self) -> str:
|
|
91
|
-
"""Build detailed error with suggestions."""
|
|
92
|
-
lines = []
|
|
93
|
-
|
|
94
|
-
# Box header
|
|
95
|
-
lines.append("+" + "-" * 66 + "+")
|
|
96
|
-
lines.append("| CUDA Wheel Not Found" + " " * 44 + "|")
|
|
97
|
-
lines.append("+" + "-" * 66 + "+")
|
|
98
|
-
|
|
99
|
-
# Package info
|
|
100
|
-
pkg_line = f" Package: {self.package}"
|
|
101
|
-
if self.version:
|
|
102
|
-
pkg_line += f"=={self.version}"
|
|
103
|
-
lines.append(f"|{pkg_line:<66}|")
|
|
104
|
-
|
|
105
|
-
# Requested configuration
|
|
106
|
-
if self.env:
|
|
107
|
-
requested = self._format_requested()
|
|
108
|
-
lines.append(f"| Requested: {requested:<54}|")
|
|
109
|
-
|
|
110
|
-
lines.append("|" + " " * 66 + "|")
|
|
111
|
-
|
|
112
|
-
# Reason if provided
|
|
113
|
-
if self.reason:
|
|
114
|
-
lines.append(f"| Reason: {self.reason:<57}|")
|
|
115
|
-
lines.append("|" + " " * 66 + "|")
|
|
116
|
-
|
|
117
|
-
# Tried URLs
|
|
118
|
-
if self.tried_urls:
|
|
119
|
-
lines.append("| Tried URLs:" + " " * 53 + "|")
|
|
120
|
-
for url in self.tried_urls[:3]: # Limit to first 3
|
|
121
|
-
# Truncate long URLs
|
|
122
|
-
if len(url) > 60:
|
|
123
|
-
url = "..." + url[-57:]
|
|
124
|
-
lines.append(f"| {url:<62}|")
|
|
125
|
-
lines.append("|" + " " * 66 + "|")
|
|
126
|
-
|
|
127
|
-
# Suggestions
|
|
128
|
-
suggestions = self._generate_suggestions()
|
|
129
|
-
if suggestions:
|
|
130
|
-
lines.append("| Suggestions:" + " " * 52 + "|")
|
|
131
|
-
for i, suggestion in enumerate(suggestions, 1):
|
|
132
|
-
lines.append(f"| {i}. {suggestion:<60}|")
|
|
133
|
-
lines.append("|" + " " * 66 + "|")
|
|
134
|
-
|
|
135
|
-
# Footer
|
|
136
|
-
lines.append("+" + "-" * 66 + "+")
|
|
137
|
-
|
|
138
|
-
return "\n".join(lines)
|
|
139
|
-
|
|
140
|
-
def _format_requested(self) -> str:
|
|
141
|
-
"""Format the requested configuration."""
|
|
142
|
-
if not self.env:
|
|
143
|
-
return "unknown"
|
|
144
|
-
|
|
145
|
-
parts = []
|
|
146
|
-
if self.env.cuda_short:
|
|
147
|
-
parts.append(f"cu{self.env.cuda_short}")
|
|
148
|
-
else:
|
|
149
|
-
parts.append("cpu")
|
|
150
|
-
|
|
151
|
-
if self.env.torch_mm:
|
|
152
|
-
parts.append(f"torch{self.env.torch_mm}")
|
|
153
|
-
|
|
154
|
-
parts.append(f"cp{self.env.python_short}")
|
|
155
|
-
parts.append(self.env.platform_tag)
|
|
156
|
-
|
|
157
|
-
return "-".join(parts)
|
|
158
|
-
|
|
159
|
-
def _generate_suggestions(self) -> List[str]:
|
|
160
|
-
"""Generate actionable suggestions based on the error context."""
|
|
161
|
-
suggestions = []
|
|
162
|
-
|
|
163
|
-
if not self.env:
|
|
164
|
-
suggestions.append("Run 'comfy-env info' to see your environment")
|
|
165
|
-
return suggestions
|
|
166
|
-
|
|
167
|
-
# Python version suggestion
|
|
168
|
-
if self.env.python_short not in ("310", "311"):
|
|
169
|
-
suggestions.append(
|
|
170
|
-
f"Use Python 3.10 or 3.11 (you have {self.env.python_version})"
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
# CUDA version suggestion
|
|
174
|
-
if self.env.cuda_version and self.env.cuda_version not in ("12.4", "12.8"):
|
|
175
|
-
suggestions.append(
|
|
176
|
-
f"Use CUDA 12.4 or 12.8 (you have {self.env.cuda_version})"
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
# PyTorch version suggestion
|
|
180
|
-
if self.env.torch_version:
|
|
181
|
-
torch_major_minor = ".".join(self.env.torch_version.split(".")[:2])
|
|
182
|
-
if torch_major_minor not in ("2.5", "2.8"):
|
|
183
|
-
suggestions.append(
|
|
184
|
-
f"Use PyTorch 2.5 or 2.8 (you have {self.env.torch_version})"
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
# General suggestions
|
|
188
|
-
suggestions.append(
|
|
189
|
-
f"Check if wheel exists: comfy-env resolve {self.package}"
|
|
190
|
-
)
|
|
191
|
-
suggestions.append(
|
|
192
|
-
f"Build wheel locally: comfy-env build {self.package}"
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
return suggestions[:4] # Limit to 4 suggestions
|
|
196
|
-
|
|
197
|
-
def format(self) -> str:
|
|
198
|
-
"""Format the complete error message."""
|
|
199
|
-
return f"{self.message}\n\n{self.details}"
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
class DependencyError(EnvManagerError):
|
|
203
|
-
"""Error resolving or installing dependencies."""
|
|
204
|
-
|
|
205
|
-
def __init__(
|
|
206
|
-
self,
|
|
207
|
-
message: str,
|
|
208
|
-
package: Optional[str] = None,
|
|
209
|
-
pip_error: Optional[str] = None,
|
|
210
|
-
):
|
|
211
|
-
self.package = package
|
|
212
|
-
self.pip_error = pip_error
|
|
213
|
-
|
|
214
|
-
details = None
|
|
215
|
-
if pip_error:
|
|
216
|
-
# Extract relevant lines from pip error
|
|
217
|
-
relevant_lines = self._extract_pip_error(pip_error)
|
|
218
|
-
if relevant_lines:
|
|
219
|
-
details = "pip error:\n" + "\n".join(relevant_lines)
|
|
220
|
-
|
|
221
|
-
super().__init__(message, details)
|
|
222
|
-
|
|
223
|
-
def _extract_pip_error(self, pip_error: str) -> List[str]:
|
|
224
|
-
"""Extract the most relevant lines from pip error output."""
|
|
225
|
-
lines = pip_error.strip().split("\n")
|
|
226
|
-
relevant = []
|
|
227
|
-
|
|
228
|
-
for line in lines:
|
|
229
|
-
# Skip empty lines and progress bars
|
|
230
|
-
if not line.strip():
|
|
231
|
-
continue
|
|
232
|
-
if line.startswith(" ") and "%" in line:
|
|
233
|
-
continue
|
|
234
|
-
|
|
235
|
-
# Keep error lines and important info
|
|
236
|
-
lower = line.lower()
|
|
237
|
-
if any(keyword in lower for keyword in [
|
|
238
|
-
"error", "failed", "could not", "no matching",
|
|
239
|
-
"requirement", "conflict", "incompatible"
|
|
240
|
-
]):
|
|
241
|
-
relevant.append(line)
|
|
242
|
-
|
|
243
|
-
return relevant[:10] # Limit to 10 lines
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
class CUDANotFoundError(EnvManagerError):
|
|
247
|
-
"""Raised when CUDA is required but not available."""
|
|
248
|
-
|
|
249
|
-
def __init__(self, package: Optional[str] = None):
|
|
250
|
-
message = "CUDA is required but not detected"
|
|
251
|
-
details_lines = [
|
|
252
|
-
"This package requires a CUDA-capable GPU.",
|
|
253
|
-
"",
|
|
254
|
-
"To fix this:",
|
|
255
|
-
" 1. Ensure you have an NVIDIA GPU",
|
|
256
|
-
" 2. Install NVIDIA drivers",
|
|
257
|
-
" 3. Install CUDA Toolkit",
|
|
258
|
-
"",
|
|
259
|
-
"Or if you want to run on CPU:",
|
|
260
|
-
" Set 'fallback_to_cpu = true' in your config",
|
|
261
|
-
]
|
|
262
|
-
|
|
263
|
-
if package:
|
|
264
|
-
message = f"CUDA is required for {package} but not detected"
|
|
265
|
-
|
|
266
|
-
super().__init__(message, "\n".join(details_lines))
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
class InstallError(EnvManagerError):
|
|
270
|
-
"""Error during package installation."""
|
|
271
|
-
|
|
272
|
-
def __init__(
|
|
273
|
-
self,
|
|
274
|
-
message: str,
|
|
275
|
-
package: Optional[str] = None,
|
|
276
|
-
exit_code: Optional[int] = None,
|
|
277
|
-
stderr: Optional[str] = None,
|
|
278
|
-
):
|
|
279
|
-
self.package = package
|
|
280
|
-
self.exit_code = exit_code
|
|
281
|
-
self.stderr = stderr
|
|
282
|
-
|
|
283
|
-
details_parts = []
|
|
284
|
-
if exit_code is not None:
|
|
285
|
-
details_parts.append(f"Exit code: {exit_code}")
|
|
286
|
-
if stderr:
|
|
287
|
-
# Truncate long stderr
|
|
288
|
-
if len(stderr) > 500:
|
|
289
|
-
stderr = stderr[:500] + "\n... (truncated)"
|
|
290
|
-
details_parts.append(f"Output:\n{stderr}")
|
|
291
|
-
|
|
292
|
-
details = "\n".join(details_parts) if details_parts else None
|
|
293
|
-
super().__init__(message, details)
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
comfy_env/__init__.py,sha256=s0RkyKsBlDiSI4ZSwivtWLvYhc8DS0CUEWgFLVJbtLA,2176
|
|
2
|
-
comfy_env/cli.py,sha256=ty4HYlzollCUCS0o6Sha6eczPAsW_gHRVgvck3IfA2w,12723
|
|
3
|
-
comfy_env/errors.py,sha256=q-C3vyrPa_kk_Ao8l17mIGfJiG2IR0hCFV0GFcNLmcI,9924
|
|
4
|
-
comfy_env/install.py,sha256=N7eBj8wB2DrGepVYk-Hks2mSf6UuGzj34pfVLNYJgQ4,10357
|
|
5
|
-
comfy_env/nodes.py,sha256=tUbsUdjnJCUUoxM7NpsdUuawuIz1exfOmWdsLGILXiY,5391
|
|
6
|
-
comfy_env/prestartup.py,sha256=aNiTgkDeTdez7bsX0Ew3AoPoUKiTM3fmjjhCGWzZbLY,5812
|
|
7
|
-
comfy_env/config/__init__.py,sha256=4Guylkb-FV8QxhFwschzpzbr2eu8y-KNgNT3_JOm9jc,403
|
|
8
|
-
comfy_env/config/parser.py,sha256=dA1lX5ExBEfCqUJwe4V5i_jn2NJ69bMq3c3ji3lMSV8,4295
|
|
9
|
-
comfy_env/config/types.py,sha256=Sb8HO34xsSZu5YAc2K4M7Gb3QNevJlngf12hHiwuU0w,2140
|
|
10
|
-
comfy_env/isolation/__init__.py,sha256=vw9a4mpJ2CFjy-PLe_A3zQ6umBQklgqWNxwn9beNw3g,175
|
|
11
|
-
comfy_env/isolation/wrap.py,sha256=A6kv4p4xBxx9-1yCNDKuKJi6esnT3hF2Y5wqLQZB_ig,14637
|
|
12
|
-
comfy_env/pixi/__init__.py,sha256=BUrq7AQf3WDm0cHWh72B2xZbURNnDu2dCuELWiQCUiM,997
|
|
13
|
-
comfy_env/pixi/core.py,sha256=ZpjAmwh7EE1jqBK1Q41GJEEXIsAtyqdNsr_ygoPQdUY,20636
|
|
14
|
-
comfy_env/pixi/cuda_detection.py,sha256=sqB3LjvGNdV4eFqiARQGfyecBM3ZiUmeh6nG0YCRYQw,9751
|
|
15
|
-
comfy_env/pixi/resolver.py,sha256=U_A8rBDxCj4gUlJt2YJQniP4cCKqxJEiVFgXOoH7vM8,6339
|
|
16
|
-
comfy_env/pixi/platform/__init__.py,sha256=Nb5MPZIEeanSMEWwqU4p4bnEKTJn1tWcwobnhq9x9IY,614
|
|
17
|
-
comfy_env/pixi/platform/base.py,sha256=iS0ptTTVjXRwPU4qWUdvHI7jteuzxGSjWr5BUQ7hGiU,2453
|
|
18
|
-
comfy_env/pixi/platform/darwin.py,sha256=HK3VkLT6DfesAnIXwx2IaUFHTBclF0xTQnC7azWY6Kc,1552
|
|
19
|
-
comfy_env/pixi/platform/linux.py,sha256=xLp8FEbFqZLQrzIZBI9z3C4g23Ab1ASTHLsXDzsdCoA,2062
|
|
20
|
-
comfy_env/pixi/platform/windows.py,sha256=FCOCgpzGzorY9-HueMlJUR8DxM2eH-cj9iZk6K026Is,10891
|
|
21
|
-
comfy_env/templates/comfy-env-instructions.txt,sha256=ve1RAthW7ouumU9h6DM7mIRX1MS8_Tyonq2U4tcrFu8,1031
|
|
22
|
-
comfy_env/templates/comfy-env.toml,sha256=ROIqi4BlPL1MEdL1VgebfTHpdwPNYGHwWeigI9Kw-1I,4831
|
|
23
|
-
comfy_env/workers/__init__.py,sha256=TMVG55d2XLP1mJ3x1d16H0SBDJZtk2kMC5P4HLk9TrA,1073
|
|
24
|
-
comfy_env/workers/base.py,sha256=4ZYTaQ4J0kBHCoO_OfZnsowm4rJCoqinZUaOtgkOPbw,2307
|
|
25
|
-
comfy_env/workers/mp.py,sha256=R0XWsiHv8gswxa_-iNHU14o_9Og0RFG0QnY9DRZzn2c,34060
|
|
26
|
-
comfy_env/workers/subprocess.py,sha256=B0PsHLuywPIJSRpuA4E8Dg6tGzuro6wqIr8czqMqtPE,57128
|
|
27
|
-
comfy_env/workers/tensor_utils.py,sha256=TCuOAjJymrSbkgfyvcKtQ_KbVWTqSwP9VH_bCaFLLq8,6409
|
|
28
|
-
comfy_env-0.1.13.dist-info/METADATA,sha256=xBivq9U8DeIzi-fwdAHZ1GjSyG-p724kEg42FqMdSlc,6971
|
|
29
|
-
comfy_env-0.1.13.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
30
|
-
comfy_env-0.1.13.dist-info/entry_points.txt,sha256=J4fXeqgxU_YenuW_Zxn_pEL7J-3R0--b6MS5t0QmAr0,49
|
|
31
|
-
comfy_env-0.1.13.dist-info/licenses/LICENSE,sha256=E68QZMMpW4P2YKstTZ3QU54HRQO8ecew09XZ4_Vn870,1093
|
|
32
|
-
comfy_env-0.1.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|