comfy-env 0.0.24__tar.gz → 0.0.25__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.0.24 → comfy_env-0.0.25}/PKG-INFO +1 -1
- {comfy_env-0.0.24 → comfy_env-0.0.25}/pyproject.toml +1 -1
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/install.py +49 -3
- comfy_env-0.0.25/src/comfy_env/nodes.py +154 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/.github/workflows/publish.yml +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/.gitignore +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/LICENSE +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/README.md +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/__init__.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/cli.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/decorator.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/__init__.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/config.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/config_file.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/cuda_gpu_detection.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/manager.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/platform/__init__.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/platform/base.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/platform/darwin.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/platform/linux.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/platform/windows.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/env/security.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/errors.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/ipc/__init__.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/ipc/bridge.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/ipc/protocol.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/ipc/tensor.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/ipc/torch_bridge.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/ipc/transport.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/ipc/worker.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/pixi.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/registry.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/resolver.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/stubs/__init__.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/stubs/folder_paths.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/wheel_sources.yml +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/workers/__init__.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/workers/base.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/workers/pool.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/workers/tensor_utils.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/workers/torch_mp.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/src/comfy_env/workers/venv.py +0 -0
- {comfy_env-0.0.24 → comfy_env-0.0.25}/untitled.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: comfy-env
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.25
|
|
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
|
|
@@ -22,9 +22,9 @@ import shutil
|
|
|
22
22
|
import subprocess
|
|
23
23
|
import sys
|
|
24
24
|
from pathlib import Path
|
|
25
|
-
from typing import Any, Callable, Dict, List, Optional, Union
|
|
25
|
+
from typing import Any, Callable, Dict, List, Optional, Set, Union
|
|
26
26
|
|
|
27
|
-
from .env.config import IsolatedEnv, SystemConfig
|
|
27
|
+
from .env.config import IsolatedEnv, NodeReq, SystemConfig
|
|
28
28
|
from .env.config_file import load_config, discover_config
|
|
29
29
|
from .env.manager import IsolatedEnvManager
|
|
30
30
|
from .errors import CUDANotFoundError, DependencyError, InstallError, WheelNotFoundError
|
|
@@ -132,6 +132,47 @@ def _install_system_packages(
|
|
|
132
132
|
return True
|
|
133
133
|
|
|
134
134
|
|
|
135
|
+
def _install_node_dependencies(
|
|
136
|
+
node_reqs: List[NodeReq],
|
|
137
|
+
node_dir: Path,
|
|
138
|
+
log: Callable[[str], None],
|
|
139
|
+
dry_run: bool = False,
|
|
140
|
+
) -> bool:
|
|
141
|
+
"""
|
|
142
|
+
Install node dependencies (other ComfyUI custom nodes).
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
node_reqs: List of NodeReq objects from [node_reqs] config section.
|
|
146
|
+
node_dir: Directory of the current node (used to find custom_nodes/).
|
|
147
|
+
log: Logging callback.
|
|
148
|
+
dry_run: If True, show what would be installed without installing.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
True if installation succeeded or no dependencies needed.
|
|
152
|
+
"""
|
|
153
|
+
from .nodes import install_node_deps
|
|
154
|
+
|
|
155
|
+
# Detect custom_nodes directory (parent of current node)
|
|
156
|
+
custom_nodes_dir = node_dir.parent
|
|
157
|
+
|
|
158
|
+
log(f"\nInstalling {len(node_reqs)} node dependencies...")
|
|
159
|
+
|
|
160
|
+
if dry_run:
|
|
161
|
+
for req in node_reqs:
|
|
162
|
+
node_path = custom_nodes_dir / req.name
|
|
163
|
+
status = "exists" if node_path.exists() else "would clone"
|
|
164
|
+
log(f" {req.name}: {status}")
|
|
165
|
+
return True
|
|
166
|
+
|
|
167
|
+
# Track visited nodes to prevent cycles
|
|
168
|
+
# Start with current node's directory name
|
|
169
|
+
visited: Set[str] = {node_dir.name}
|
|
170
|
+
|
|
171
|
+
install_node_deps(node_reqs, custom_nodes_dir, log, visited)
|
|
172
|
+
|
|
173
|
+
return True
|
|
174
|
+
|
|
175
|
+
|
|
135
176
|
def install(
|
|
136
177
|
config: Optional[Union[str, Path]] = None,
|
|
137
178
|
mode: str = "inplace",
|
|
@@ -185,7 +226,12 @@ def install(
|
|
|
185
226
|
"Create comfy-env.toml or specify path explicitly."
|
|
186
227
|
)
|
|
187
228
|
|
|
188
|
-
# Install
|
|
229
|
+
# Install node dependencies first (other ComfyUI custom nodes)
|
|
230
|
+
# These may have their own system packages and Python packages
|
|
231
|
+
if full_config.node_reqs:
|
|
232
|
+
_install_node_dependencies(full_config.node_reqs, node_dir, log, dry_run)
|
|
233
|
+
|
|
234
|
+
# Install system packages (apt, brew, etc.)
|
|
189
235
|
# These need to be installed before Python packages that depend on them
|
|
190
236
|
if full_config.has_system:
|
|
191
237
|
_install_system_packages(full_config.system, log, dry_run)
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Node dependency installation for comfy-env.
|
|
3
|
+
|
|
4
|
+
This module handles installation of dependent ComfyUI custom nodes
|
|
5
|
+
specified in the [node_reqs] section of comfy-env.toml.
|
|
6
|
+
|
|
7
|
+
Example configuration:
|
|
8
|
+
[node_reqs]
|
|
9
|
+
ComfyUI_essentials = "cubiq/ComfyUI_essentials"
|
|
10
|
+
ComfyUI-DepthAnythingV2 = "kijai/ComfyUI-DepthAnythingV2"
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import TYPE_CHECKING, Callable, List, Set
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from .env.config import NodeReq
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def normalize_repo_url(repo: str) -> str:
|
|
23
|
+
"""
|
|
24
|
+
Convert GitHub shorthand to full URL.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
repo: Either 'owner/repo' or full URL like 'https://github.com/owner/repo'
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Full GitHub URL
|
|
31
|
+
"""
|
|
32
|
+
if repo.startswith("http://") or repo.startswith("https://"):
|
|
33
|
+
return repo
|
|
34
|
+
return f"https://github.com/{repo}"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def clone_node(
|
|
38
|
+
repo: str,
|
|
39
|
+
name: str,
|
|
40
|
+
target_dir: Path,
|
|
41
|
+
log: Callable[[str], None],
|
|
42
|
+
) -> Path:
|
|
43
|
+
"""
|
|
44
|
+
Clone a node repository to target_dir/name.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
repo: GitHub repo path (e.g., 'owner/repo') or full URL
|
|
48
|
+
name: Directory name for the cloned repo
|
|
49
|
+
target_dir: Parent directory (usually custom_nodes/)
|
|
50
|
+
log: Logging callback
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Path to the cloned node directory
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
RuntimeError: If git clone fails
|
|
57
|
+
"""
|
|
58
|
+
node_path = target_dir / name
|
|
59
|
+
url = normalize_repo_url(repo)
|
|
60
|
+
|
|
61
|
+
log(f" Cloning {name} from {url}...")
|
|
62
|
+
result = subprocess.run(
|
|
63
|
+
["git", "clone", "--depth", "1", url, str(node_path)],
|
|
64
|
+
capture_output=True,
|
|
65
|
+
text=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if result.returncode != 0:
|
|
69
|
+
raise RuntimeError(f"Failed to clone {url}: {result.stderr.strip()}")
|
|
70
|
+
|
|
71
|
+
return node_path
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def run_install_script(
|
|
75
|
+
node_dir: Path,
|
|
76
|
+
log: Callable[[str], None],
|
|
77
|
+
) -> None:
|
|
78
|
+
"""
|
|
79
|
+
Run install.py in a node directory if it exists.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
node_dir: Path to the node directory
|
|
83
|
+
log: Logging callback
|
|
84
|
+
"""
|
|
85
|
+
install_script = node_dir / "install.py"
|
|
86
|
+
|
|
87
|
+
if install_script.exists():
|
|
88
|
+
log(f" Running install.py for {node_dir.name}...")
|
|
89
|
+
result = subprocess.run(
|
|
90
|
+
[sys.executable, str(install_script)],
|
|
91
|
+
cwd=node_dir,
|
|
92
|
+
capture_output=True,
|
|
93
|
+
text=True,
|
|
94
|
+
)
|
|
95
|
+
if result.returncode != 0:
|
|
96
|
+
log(f" Warning: install.py failed for {node_dir.name}: {result.stderr.strip()[:200]}")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def install_node_deps(
|
|
100
|
+
node_reqs: "List[NodeReq]",
|
|
101
|
+
custom_nodes_dir: Path,
|
|
102
|
+
log: Callable[[str], None],
|
|
103
|
+
visited: Set[str],
|
|
104
|
+
) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Install node dependencies recursively.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
node_reqs: List of NodeReq objects to install
|
|
110
|
+
custom_nodes_dir: Path to custom_nodes directory
|
|
111
|
+
log: Logging callback
|
|
112
|
+
visited: Set of already-processed node names (for cycle detection)
|
|
113
|
+
"""
|
|
114
|
+
from .env.config_file import discover_config
|
|
115
|
+
|
|
116
|
+
for req in node_reqs:
|
|
117
|
+
# Skip if already visited (cycle detection)
|
|
118
|
+
if req.name in visited:
|
|
119
|
+
log(f" {req.name}: already in dependency chain, skipping")
|
|
120
|
+
continue
|
|
121
|
+
|
|
122
|
+
visited.add(req.name)
|
|
123
|
+
|
|
124
|
+
node_path = custom_nodes_dir / req.name
|
|
125
|
+
|
|
126
|
+
# Skip if already installed (directory exists)
|
|
127
|
+
if node_path.exists():
|
|
128
|
+
log(f" {req.name}: already installed, skipping")
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
# Clone the repository
|
|
133
|
+
clone_node(req.repo, req.name, custom_nodes_dir, log)
|
|
134
|
+
|
|
135
|
+
# Run install.py if present
|
|
136
|
+
run_install_script(node_path, log)
|
|
137
|
+
|
|
138
|
+
# Recursively process nested node_reqs
|
|
139
|
+
try:
|
|
140
|
+
nested_config = discover_config(node_path)
|
|
141
|
+
if nested_config and nested_config.node_reqs:
|
|
142
|
+
log(f" {req.name}: found {len(nested_config.node_reqs)} nested dependencies")
|
|
143
|
+
install_node_deps(
|
|
144
|
+
nested_config.node_reqs,
|
|
145
|
+
custom_nodes_dir,
|
|
146
|
+
log,
|
|
147
|
+
visited,
|
|
148
|
+
)
|
|
149
|
+
except Exception as e:
|
|
150
|
+
# Don't fail if we can't parse nested config
|
|
151
|
+
log(f" {req.name}: could not check for nested deps: {e}")
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
log(f" Warning: Failed to install {req.name}: {e}")
|
|
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
|
|
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
|