comfy-env 0.0.30__py3-none-any.whl → 0.0.32__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/env/manager.py CHANGED
@@ -22,6 +22,7 @@ from .security import (
22
22
  )
23
23
  from ..registry import PACKAGE_REGISTRY, is_registered, get_cuda_short2
24
24
  from ..resolver import RuntimeEnv, parse_wheel_requirement
25
+ from ..index_resolver import resolve_wheel_from_index
25
26
 
26
27
 
27
28
  class IsolatedEnvManager:
@@ -388,6 +389,13 @@ class IsolatedEnvManager:
388
389
  # PEP 503 index - use --extra-index-url
389
390
  index_url = self._substitute_template(config["index_url"], vars_dict)
390
391
  pkg_spec = f"{package}=={version}" if version else package
392
+ # Try to resolve exact wheel URL from index
393
+ wheel_url = resolve_wheel_from_index(index_url, package, vars_dict, version)
394
+ if wheel_url:
395
+ self.log(f" Wheel: {wheel_url}")
396
+ else:
397
+ self.log(f" Index: {index_url}")
398
+ self.log(f" Package: {pkg_spec}")
391
399
  result = subprocess.run(
392
400
  pip_args + ["--extra-index-url", index_url, "--no-deps", pkg_spec],
393
401
  capture_output=True, text=True,
@@ -397,6 +405,13 @@ class IsolatedEnvManager:
397
405
  # GitHub Pages or generic find-links
398
406
  index_url = self._substitute_template(config["index_url"], vars_dict)
399
407
  pkg_spec = f"{package}=={version}" if version else package
408
+ # Try to resolve exact wheel URL from find-links page
409
+ wheel_url = resolve_wheel_from_index(index_url, package, vars_dict, version)
410
+ if wheel_url:
411
+ self.log(f" Wheel: {wheel_url}")
412
+ else:
413
+ self.log(f" Find-links: {index_url}")
414
+ self.log(f" Package: {pkg_spec}")
400
415
  result = subprocess.run(
401
416
  pip_args + ["--find-links", index_url, "--no-deps", pkg_spec],
402
417
  capture_output=True, text=True,
@@ -406,7 +421,7 @@ class IsolatedEnvManager:
406
421
  # Transform package name based on CUDA version
407
422
  actual_package = self._substitute_template(config["package_template"], vars_dict)
408
423
  pkg_spec = f"{actual_package}=={version}" if version else actual_package
409
- self.log(f" -> {actual_package}")
424
+ self.log(f" PyPI variant: {pkg_spec}")
410
425
  result = subprocess.run(
411
426
  pip_args + ["--no-deps", pkg_spec],
412
427
  capture_output=True, text=True,
@@ -0,0 +1,132 @@
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
comfy_env/install.py CHANGED
@@ -31,6 +31,7 @@ from .errors import CUDANotFoundError, DependencyError, InstallError, WheelNotFo
31
31
  from .pixi import pixi_install
32
32
  from .registry import PACKAGE_REGISTRY, get_cuda_short2
33
33
  from .resolver import RuntimeEnv, WheelResolver, parse_wheel_requirement
34
+ from .index_resolver import resolve_wheel_from_index
34
35
 
35
36
 
36
37
  def _install_system_packages(
@@ -482,21 +483,46 @@ def _install_cuda_package(
482
483
  pkg_spec = f"{package}=={resolved_version}"
483
484
  else:
484
485
  pkg_spec = f"{package}=={version}" if version else package
485
- log(f" Installing {package} from index...")
486
+ log(f" Installing {package} (index)...")
487
+ # Try to resolve exact wheel URL from index
488
+ actual_version = resolved_version if "version_template" in config else version
489
+ vars_dict = env.as_dict()
490
+ wheel_url = resolve_wheel_from_index(index_url, package, vars_dict, actual_version)
491
+ if wheel_url:
492
+ log(f" Wheel: {wheel_url}")
493
+ else:
494
+ log(f" Index: {index_url}")
495
+ log(f" Package: {pkg_spec}")
486
496
  _pip_install_with_index(pkg_spec, index_url, log)
487
497
 
488
498
  elif method == "github_index":
489
499
  # GitHub Pages index - use pip --find-links
490
500
  index_url = _substitute_template(config["index_url"], env)
491
501
  pkg_spec = f"{package}=={version}" if version else package
492
- log(f" Installing {package} from GitHub wheels...")
502
+ log(f" Installing {package} (github_index)...")
503
+ # Try to resolve exact wheel URL from find-links page
504
+ vars_dict = env.as_dict()
505
+ wheel_url = resolve_wheel_from_index(index_url, package, vars_dict, version)
506
+ if wheel_url:
507
+ log(f" Wheel: {wheel_url}")
508
+ else:
509
+ log(f" Find-links: {index_url}")
510
+ log(f" Package: {pkg_spec}")
493
511
  _pip_install_with_find_links(pkg_spec, index_url, log)
494
512
 
495
513
  elif method == "find_links":
496
514
  # Generic find-links (e.g., PyG) - use pip --find-links
497
515
  index_url = _substitute_template(config["index_url"], env)
498
516
  pkg_spec = f"{package}=={version}" if version else package
499
- log(f" Installing {package} from {index_url}...")
517
+ log(f" Installing {package} (find_links)...")
518
+ # Try to resolve exact wheel URL from find-links page
519
+ vars_dict = env.as_dict()
520
+ wheel_url = resolve_wheel_from_index(index_url, package, vars_dict, version)
521
+ if wheel_url:
522
+ log(f" Wheel: {wheel_url}")
523
+ else:
524
+ log(f" Find-links: {index_url}")
525
+ log(f" Package: {pkg_spec}")
500
526
  _pip_install_with_find_links(pkg_spec, index_url, log)
501
527
 
502
528
  elif method == "pypi_variant":
@@ -506,7 +532,8 @@ def _install_cuda_package(
506
532
  vars_dict["cuda_short2"] = get_cuda_short2(env.cuda_version)
507
533
  actual_package = _substitute_template(config["package_template"], vars_dict)
508
534
  pkg_spec = f"{actual_package}=={version}" if version else actual_package
509
- log(f" Installing {package} as {actual_package}...")
535
+ log(f" Installing {package} (pypi_variant)...")
536
+ log(f" PyPI variant: {pkg_spec}")
510
537
  _pip_install([pkg_spec], no_deps=False, log=log)
511
538
 
512
539
  elif method == "github_release":
@@ -60,50 +60,60 @@ packages:
60
60
  # ===========================================================================
61
61
  # PozzettiAndrea cuda-wheels (unified PEP 503 index)
62
62
  # https://pozzettiandrea.github.io/cuda-wheels
63
+ # Wheel naming: {package}-{version}+cu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl
63
64
  # ===========================================================================
64
65
  nvdiffrast:
65
66
  method: index
66
67
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
68
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/nvdiffrast/nvdiffrast-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
67
69
  description: NVIDIA differentiable rasterizer
68
70
 
69
71
  cumesh:
70
72
  method: index
71
73
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
74
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/cumesh/cumesh-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
72
75
  description: CUDA-accelerated mesh utilities
73
76
 
74
77
  o_voxel:
75
78
  method: index
76
79
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
80
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/o-voxel/o_voxel-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
77
81
  description: O-Voxel CUDA extension for TRELLIS
78
82
 
79
83
  flex_gemm:
80
84
  method: index
81
85
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
86
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/flex-gemm/flex_gemm-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
82
87
  description: Flexible GEMM operations
83
88
 
84
89
  nvdiffrec_render:
85
90
  method: index
86
91
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
92
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/nvdiffrec-render/nvdiffrec_render-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
87
93
  description: NVDiffRec rendering utilities
88
94
 
89
95
  gsplat:
90
96
  method: index
91
97
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
98
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/gsplat/gsplat-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
92
99
  description: Gaussian splatting rasterization
93
100
 
94
101
  cc_torch:
95
102
  method: index
96
103
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
104
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/cc-torch/cc_torch-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
97
105
  description: GPU-accelerated connected components
98
106
 
99
107
  torch_generic_nms:
100
108
  method: index
101
109
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
110
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/torch-generic-nms/torch_generic_nms-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
102
111
  description: GPU-accelerated Non-Maximum Suppression
103
112
 
104
113
  lietorch:
105
114
  method: index
106
115
  index_url: "https://pozzettiandrea.github.io/cuda-wheels"
116
+ wheel_template: "https://pozzettiandrea.github.io/cuda-wheels/lietorch/lietorch-{version}%2Bcu{cuda_short}torch{torch_mm}-{py_tag}-{py_tag}-{platform}.whl"
107
117
  description: Lie group operations for PyTorch (DPVO dependency)
108
118
 
109
119
  # ===========================================================================
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comfy-env
3
- Version: 0.0.30
3
+ Version: 0.0.32
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
@@ -2,7 +2,8 @@ comfy_env/__init__.py,sha256=u2uTyoysPQyNMcRp5U4VTMJF11FBW6Goqu0DN-BdUuY,3678
2
2
  comfy_env/cli.py,sha256=X-GCQMP0mtMcE3ZgkT-VLQ4Gq3UUvcb_Ux_NClEFhgI,15975
3
3
  comfy_env/decorator.py,sha256=6JCKwLHaZtOLVDexs_gh_-NtS2ZK0V7nGCPqkyeYEAA,16688
4
4
  comfy_env/errors.py,sha256=8hN8NDlo8oBUdapc-eT3ZluigI5VBzfqsSBvQdfWlz4,9943
5
- comfy_env/install.py,sha256=xgfQWH_dwhktkcuYFwn-iscYFhx9HzXToFZF-opUDqk,28400
5
+ comfy_env/index_resolver.py,sha256=D8BttTJ7BOiukUvmdT6_dGdzFV3CahGL2m28X-HwPeE,4650
6
+ comfy_env/install.py,sha256=zVrpo6bzWw2gSYTAzjp-6Ne75swLfOr-mhpROe6PhJY,29748
6
7
  comfy_env/nodes.py,sha256=CWUe35jU5SKk4ur-SddZePdqWgxJDlxGhpcJiu5pAK4,4354
7
8
  comfy_env/pixi.py,sha256=_p3h9iFPHwNaEAEL8SeMJLaUmoyrroH4HJcbfG1Nh8A,13383
8
9
  comfy_env/registry.py,sha256=uFCtGmWYvwGCqObXgzmArX7o5JsFNsHXxayofk3m6no,2569
@@ -11,7 +12,7 @@ comfy_env/env/__init__.py,sha256=imQdoQEQvrRT-QDtyNpFlkVbm2fBzgACdpQwRPd09fI,115
11
12
  comfy_env/env/config.py,sha256=5rK7r2uRItMXJnKAn8DmVQoadLo2njHTuaxrWybhppU,7469
12
13
  comfy_env/env/config_file.py,sha256=1UdcL1TwKceGaSunCnsHiuPyxpCSq1JpelScUEsCBn8,23669
13
14
  comfy_env/env/cuda_gpu_detection.py,sha256=YLuXUdWg6FeKdNyLlQAHPlveg4rTenXJ2VbeAaEi9QE,9755
14
- comfy_env/env/manager.py,sha256=bbV1MpURNGuBJ1sSWg_2oSU0J-dW-FhBCuHHHQxgrSM,24785
15
+ comfy_env/env/manager.py,sha256=zBBN5P0rOrXzPodoF2294xsk4F1Gg7CWZsn2MkxlWkw,25678
15
16
  comfy_env/env/security.py,sha256=dNSitAnfBNVdvxgBBntYw33AJaCs_S1MHb7KJhAVYzM,8171
16
17
  comfy_env/env/platform/__init__.py,sha256=Nb5MPZIEeanSMEWwqU4p4bnEKTJn1tWcwobnhq9x9IY,614
17
18
  comfy_env/env/platform/base.py,sha256=iS0ptTTVjXRwPU4qWUdvHI7jteuzxGSjWr5BUQ7hGiU,2453
@@ -33,9 +34,9 @@ comfy_env/workers/pool.py,sha256=MtjeOWfvHSCockq8j1gfnxIl-t01GSB79T5N4YB82Lg,695
33
34
  comfy_env/workers/tensor_utils.py,sha256=TCuOAjJymrSbkgfyvcKtQ_KbVWTqSwP9VH_bCaFLLq8,6409
34
35
  comfy_env/workers/torch_mp.py,sha256=4YSNPn7hALrvMVbkO4RkTeFTcc0lhfLMk5QTWjY4PHw,22134
35
36
  comfy_env/workers/venv.py,sha256=_ekHfZPqBIPY08DjqiXm6cTBQH4DrbxRWR3AAv3mit8,31589
36
- comfy_env/wheel_sources.yml,sha256=DAF-wGRAn_-um5_2_v72b4Z7KUph5SE3Zldw22-SXcU,7300
37
- comfy_env-0.0.30.dist-info/METADATA,sha256=wvvqao9-elGjRXxYmtAhV69CfONXZHvfCOBTipA_s98,5400
38
- comfy_env-0.0.30.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
39
- comfy_env-0.0.30.dist-info/entry_points.txt,sha256=J4fXeqgxU_YenuW_Zxn_pEL7J-3R0--b6MS5t0QmAr0,49
40
- comfy_env-0.0.30.dist-info/licenses/LICENSE,sha256=E68QZMMpW4P2YKstTZ3QU54HRQO8ecew09XZ4_Vn870,1093
41
- comfy_env-0.0.30.dist-info/RECORD,,
37
+ comfy_env/wheel_sources.yml,sha256=kZGK4-AJ0vvKmqDdxuiATLjGkaHHs-ansIckYION_nA,8871
38
+ comfy_env-0.0.32.dist-info/METADATA,sha256=1IkItwJJn7EIvUCVfSTT3iq0MSh5d8PKsYxkk2LCtVo,5400
39
+ comfy_env-0.0.32.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
40
+ comfy_env-0.0.32.dist-info/entry_points.txt,sha256=J4fXeqgxU_YenuW_Zxn_pEL7J-3R0--b6MS5t0QmAr0,49
41
+ comfy_env-0.0.32.dist-info/licenses/LICENSE,sha256=E68QZMMpW4P2YKstTZ3QU54HRQO8ecew09XZ4_Vn870,1093
42
+ comfy_env-0.0.32.dist-info/RECORD,,