Skip to content

Commit f8cb7a5

Browse files
committed
Use _version.py import instead of importlib.metadata for cuda-bindings detection
Replace importlib.metadata.distribution() with direct import of cuda.bindings._version module. The former may incorrectly return the cuda-core distribution when queried for 'cuda-bindings' in isolated build environments (tested with Python 3.12 and pip 25.3). This may be due to cuda-core metadata being written during the build process before cuda-bindings is fully available, causing importlib.metadata to return the wrong distribution. Also ensure cuda-bindings is always required in build environment by returning ['cuda-bindings'] instead of [] when already installed. This ensures pip makes it available in isolated build environments even if installed elsewhere. Fix import sorting inconsistency for _version import in cuda_pathfinder by adding 'isort: skip' directive.
1 parent a573a72 commit f8cb7a5

2 files changed

Lines changed: 32 additions & 30 deletions

File tree

cuda_core/build_hooks.py

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
import functools
1111
import glob
12-
import importlib.metadata
13-
import json
1412
import os
1513
import re
1614
from pathlib import Path
@@ -197,33 +195,32 @@ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
197195
def _check_cuda_bindings_installed():
198196
"""Check if cuda-bindings is installed and validate its version.
199197
198+
Uses cuda.bindings._version module (generated by setuptools-scm) instead of
199+
importlib.metadata.distribution() because the latter may incorrectly return
200+
the cuda-core distribution when queried for "cuda-bindings" in isolated build
201+
environments (tested with Python 3.12 and pip 25.3). This may be due to
202+
cuda-core metadata being written during the build process before cuda-bindings
203+
is fully available, causing importlib.metadata to return the wrong distribution.
204+
200205
Returns:
201206
tuple: (is_installed: bool, is_editable: bool, major_version: str | None)
202207
If not installed, returns (False, False, None)
203208
"""
204209
try:
205-
bindings_dist = importlib.metadata.distribution("cuda-bindings")
206-
except importlib.metadata.PackageNotFoundError:
210+
import cuda.bindings._version as bv
211+
except ModuleNotFoundError:
207212
return (False, False, None)
208213

209-
bindings_version = bindings_dist.version
210-
bindings_major_version = bindings_version.split(".")[0]
214+
# Determine repo root (parent of cuda_core)
215+
repo_root = Path(__file__).resolve().parent.parent
211216

212-
# Check if it's an editable install using PEP 610 (direct_url.json)
213-
# This is the standard method for Python 3.10+ and pip 20.1+
214-
is_editable = False
215-
try:
216-
dist_location = Path(bindings_dist.locate_file(""))
217-
# dist-info or egg-info directory
218-
metadata_dir = dist_location.parent
219-
direct_url_path = metadata_dir / "direct_url.json"
220-
if direct_url_path.exists():
221-
with open(direct_url_path) as f:
222-
direct_url = json.load(f)
223-
if direct_url.get("dir_info", {}).get("editable"):
224-
is_editable = True
225-
except Exception: # noqa: S110
226-
pass
217+
# Check if _version.py is under repo root (editable install)
218+
version_file_path = Path(bv.__file__).resolve()
219+
is_editable = repo_root in version_file_path.parents
220+
221+
# Extract major version from version tuple
222+
bindings_version = bv.__version__
223+
bindings_major_version = bindings_version.split(".")[0]
227224

228225
return (True, is_editable, bindings_major_version)
229226

@@ -232,10 +229,15 @@ def _get_cuda_bindings_require():
232229
"""Determine cuda-bindings build requirement.
233230
234231
Strategy:
235-
1. If cuda-bindings is already installed (any version), don't require it (keep existing)
236-
2. If installed from sources (editable), definitely keep it
237-
3. Otherwise, if installed version major doesn't match CUDA major, raise error
238-
4. If not installed, require matching CUDA major version
232+
1. If not installed, require matching CUDA major version
233+
2. If installed from sources (editable), require it without version constraint
234+
(pip will keep the existing editable install)
235+
3. If installed but not editable and version major doesn't match CUDA major, raise error
236+
4. If installed and version matches, require it without version constraint
237+
(pip will keep the existing installation)
238+
239+
Note: We always return a requirement (never empty list) to ensure cuda-bindings
240+
is available in pip's isolated build environment, even if already installed elsewhere.
239241
"""
240242
bindings_installed, bindings_editable, bindings_major = _check_cuda_bindings_installed()
241243

@@ -244,9 +246,9 @@ def _get_cuda_bindings_require():
244246
cuda_major = _determine_cuda_major_version()
245247
return [f"cuda-bindings=={cuda_major}.*"]
246248

247-
# If installed from sources (editable), keep it (don't require anything)
249+
# If installed from sources (editable), keep it
248250
if bindings_editable:
249-
return []
251+
return ["cuda-bindings"]
250252

251253
# If installed but not editable, check version matches CUDA major
252254
cuda_major = _determine_cuda_major_version()
@@ -263,7 +265,7 @@ def _get_cuda_bindings_require():
263265
)
264266

265267
# Installed and version matches (or is editable), keep it
266-
return []
268+
return ["cuda-bindings"]
267269

268270

269271
def get_requires_for_build_editable(config_settings=None):

cuda_pathfinder/cuda/pathfinder/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
"""cuda.pathfinder public APIs"""
55

6-
from cuda.pathfinder._version import __version__ # noqa: F401
7-
86
from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError as DynamicLibNotFoundError
97
from cuda.pathfinder._dynamic_libs.load_dl_common import LoadedDL as LoadedDL
108
from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib
@@ -14,6 +12,8 @@
1412
from cuda.pathfinder._headers.find_nvidia_headers import find_nvidia_header_directory as find_nvidia_header_directory
1513
from cuda.pathfinder._headers.supported_nvidia_headers import SUPPORTED_HEADERS_CTK as _SUPPORTED_HEADERS_CTK
1614

15+
from cuda.pathfinder._version import __version__ # noqa: F401 # isort: skip
16+
1717
# Indirections to help Sphinx find the docstrings.
1818
#: Mapping from short CUDA Toolkit (CTK) library names to their canonical
1919
#: header basenames (used to validate a discovered include directory).

0 commit comments

Comments
 (0)