From 39f0f9d6bc736d4b9c287893ccabc42033e1cf0a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 24 Feb 2026 15:13:52 -0800 Subject: [PATCH 1/4] fix(pathfinder): restore backward-compatible dynamic lib errors Replace the short-lived ValueError validation path from 1.3.5 with DynamicLibNotFoundError subclasses so downstream exception handling remains compatible while exposing more precise failure reasons. Co-authored-by: Cursor --- cuda_pathfinder/cuda/pathfinder/__init__.py | 6 ++++++ .../_dynamic_libs/load_dl_common.py | 8 +++++++ .../_dynamic_libs/load_nvidia_dynamic_lib.py | 21 ++++++++++++++++--- cuda_pathfinder/docs/source/api.rst | 2 ++ .../tests/test_load_nvidia_dynamic_lib.py | 19 ++++++++++++++--- 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/__init__.py b/cuda_pathfinder/cuda/pathfinder/__init__.py index a0ba8e4f21..b598829cc7 100644 --- a/cuda_pathfinder/cuda/pathfinder/__init__.py +++ b/cuda_pathfinder/cuda/pathfinder/__init__.py @@ -7,7 +7,13 @@ find_nvidia_binary_utility as find_nvidia_binary_utility, ) from cuda.pathfinder._binaries.supported_nvidia_binaries import SUPPORTED_BINARIES as _SUPPORTED_BINARIES +from cuda.pathfinder._dynamic_libs.load_dl_common import ( + DynamicLibNotAvailableError as DynamicLibNotAvailableError, +) from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError as DynamicLibNotFoundError +from cuda.pathfinder._dynamic_libs.load_dl_common import ( + DynamicLibUnknownError as DynamicLibUnknownError, +) from cuda.pathfinder._dynamic_libs.load_dl_common import LoadedDL as LoadedDL from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import ( diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_common.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_common.py index 91e6284a00..1204a23c15 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_common.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_dl_common.py @@ -11,6 +11,14 @@ class DynamicLibNotFoundError(RuntimeError): pass +class DynamicLibNotAvailableError(DynamicLibNotFoundError): + pass + + +class DynamicLibUnknownError(DynamicLibNotFoundError): + pass + + @dataclass class LoadedDL: abs_path: str | None diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py index 3e22d62b30..9df1c5de23 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py @@ -11,7 +11,13 @@ _FindNvidiaDynamicLib, derive_ctk_root, ) -from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError, LoadedDL, load_dependencies +from cuda.pathfinder._dynamic_libs.load_dl_common import ( + DynamicLibNotAvailableError, + DynamicLibNotFoundError, + DynamicLibUnknownError, + LoadedDL, + load_dependencies, +) from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import ( _CTK_ROOT_CANARY_ANCHOR_LIBNAMES, _CTK_ROOT_CANARY_DISCOVERABLE_LIBNAMES, @@ -41,6 +47,8 @@ _ALL_SUPPORTED_LIBNAMES: frozenset[str] = frozenset( (SUPPORTED_WINDOWS_DLLS if IS_WINDOWS else SUPPORTED_LINUX_SONAMES).keys() ) +_ALL_KNOWN_LIBNAMES: frozenset[str] = frozenset(SUPPORTED_LINUX_SONAMES) | frozenset(SUPPORTED_WINDOWS_DLLS) +_PLATFORM_NAME = "Windows" if IS_WINDOWS else "Linux" # Driver libraries: shipped with the NVIDIA display driver, always on the # system linker path. These skip all CTK search steps (site-packages, @@ -205,7 +213,9 @@ def load_nvidia_dynamic_lib(libname: str) -> LoadedDL: https://github.com/NVIDIA/cuda-python/issues/1011 Raises: - ValueError: If ``libname`` is not a recognized library name. + DynamicLibUnknownError: If ``libname`` is not a recognized library name. + DynamicLibNotAvailableError: If ``libname`` is recognized but not + supported on this platform. DynamicLibNotFoundError: If the library cannot be found or loaded. RuntimeError: If Python is not 64-bit. @@ -278,6 +288,11 @@ def load_nvidia_dynamic_lib(libname: str) -> LoadedDL: f" Currently running: {pointer_size_bits}-bit Python" f" {sys.version_info.major}.{sys.version_info.minor}" ) + if libname not in _ALL_KNOWN_LIBNAMES: + raise DynamicLibUnknownError(f"Unknown library name: {libname!r}. Known names: {sorted(_ALL_KNOWN_LIBNAMES)}") if libname not in _ALL_SUPPORTED_LIBNAMES: - raise ValueError(f"Unsupported library name: {libname!r}. Supported names: {sorted(_ALL_SUPPORTED_LIBNAMES)}") + raise DynamicLibNotAvailableError( + f"Library name {libname!r} is known but not available on {_PLATFORM_NAME}. " + f"Supported names on {_PLATFORM_NAME}: {sorted(_ALL_SUPPORTED_LIBNAMES)}" + ) return _load_lib_no_cache(libname) diff --git a/cuda_pathfinder/docs/source/api.rst b/cuda_pathfinder/docs/source/api.rst index 19ade040b4..52a4ff5010 100644 --- a/cuda_pathfinder/docs/source/api.rst +++ b/cuda_pathfinder/docs/source/api.rst @@ -16,6 +16,8 @@ locating NVIDIA C/C++ header directories, and finding CUDA binary utilities. load_nvidia_dynamic_lib LoadedDL DynamicLibNotFoundError + DynamicLibUnknownError + DynamicLibNotAvailableError SUPPORTED_HEADERS_CTK SUPPORTED_HEADERS_NON_CTK diff --git a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py index 05c00f81ed..6de2bff097 100644 --- a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py @@ -9,7 +9,8 @@ from child_load_nvidia_dynamic_lib_helper import build_child_process_failed_for_libname_message, child_process_func from local_helpers import have_distribution -from cuda.pathfinder import load_nvidia_dynamic_lib +from cuda.pathfinder import DynamicLibNotAvailableError, DynamicLibUnknownError, load_nvidia_dynamic_lib +from cuda.pathfinder._dynamic_libs import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib_module from cuda.pathfinder._dynamic_libs import supported_nvidia_libs from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, quote_for_shell from cuda.pathfinder._utils.spawned_process_runner import run_in_spawned_child_process @@ -69,11 +70,23 @@ def test_runtime_error_on_non_64bit_python(mocker): load_nvidia_dynamic_lib("cudart") -def test_unsupported_libname_raises_value_error(): - with pytest.raises(ValueError, match=r"Unsupported library name: 'not_a_real_lib'.*cudart"): +def test_unknown_libname_raises_dynamic_lib_unknown_error(): + with pytest.raises(DynamicLibUnknownError, match=r"Unknown library name: 'not_a_real_lib'.*cudart"): load_nvidia_dynamic_lib("not_a_real_lib") +def test_known_but_platform_unavailable_libname_raises_dynamic_lib_not_available_error(monkeypatch): + load_nvidia_dynamic_lib.cache_clear() + monkeypatch.setattr(load_nvidia_dynamic_lib_module, "_ALL_KNOWN_LIBNAMES", frozenset(("known_but_unavailable",))) + monkeypatch.setattr(load_nvidia_dynamic_lib_module, "_ALL_SUPPORTED_LIBNAMES", frozenset()) + monkeypatch.setattr(load_nvidia_dynamic_lib_module, "_PLATFORM_NAME", "TestOS") + with pytest.raises( + DynamicLibNotAvailableError, + match=r"known_but_unavailable.*not available on TestOS", + ): + load_nvidia_dynamic_lib("known_but_unavailable") + + IMPORTLIB_METADATA_DISTRIBUTIONS_NAMES = { "cufftMp": r"^nvidia-cufftmp-.*$", "mathdx": r"^nvidia-libmathdx-.*$", From 9ce8030b8d0ee7eba6e27a9389cb0e680aa5647f Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 24 Feb 2026 15:28:14 -0800 Subject: [PATCH 2/4] docs(pathfinder): prepare 1.4.0 release notes Add the 1.4.0 pathfinder release notes entry and publish the 1.4.0 docs version link in nv-versions.json for the upcoming release. Co-authored-by: Cursor --- cuda_pathfinder/docs/nv-versions.json | 4 ++++ .../docs/source/release/1.4.0-notes.rst | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 cuda_pathfinder/docs/source/release/1.4.0-notes.rst diff --git a/cuda_pathfinder/docs/nv-versions.json b/cuda_pathfinder/docs/nv-versions.json index 69f16c3c40..a8498094b5 100644 --- a/cuda_pathfinder/docs/nv-versions.json +++ b/cuda_pathfinder/docs/nv-versions.json @@ -3,6 +3,10 @@ "version": "latest", "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/latest/" }, + { + "version": "1.4.0", + "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/1.4.0/" + }, { "version": "1.3.5", "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/1.3.5/" diff --git a/cuda_pathfinder/docs/source/release/1.4.0-notes.rst b/cuda_pathfinder/docs/source/release/1.4.0-notes.rst new file mode 100644 index 0000000000..8a402c36d0 --- /dev/null +++ b/cuda_pathfinder/docs/source/release/1.4.0-notes.rst @@ -0,0 +1,23 @@ +.. SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +.. SPDX-License-Identifier: Apache-2.0 + +.. py:currentmodule:: cuda.pathfinder + +``cuda-pathfinder`` 1.4.0 Release notes +======================================= + +Released on Feb 25, 2026 + +Highlights +---------- + +* Add CTK root canary probing for non-standard-path libraries in + ``load_nvidia_dynamic_lib()`` (notably ``nvvm``), including spawned child + process isolation for the canary probe. + (`PR #1595 `_) + +* Restore backward-compatible exception behavior for + ``load_nvidia_dynamic_lib()`` argument validation by replacing the short-lived + 1.3.5 ``ValueError`` behavior with ``DynamicLibNotFoundError`` subclasses: + ``DynamicLibUnknownError`` and ``DynamicLibNotAvailableError``. + (`PR #1688 `_) From 0022ea32553b491575794c377b375b4160cffb90 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 24 Feb 2026 15:48:50 -0800 Subject: [PATCH 3/4] docs(pathfinder): add 1.3.5 yank notice Document the planned PyPI yank for cuda-pathfinder 1.3.5 in the release notes, including upgrade guidance to 1.4.0 and links to the tracking issue and PR. Co-authored-by: Cursor --- .../docs/source/release/1.3.5-notes.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cuda_pathfinder/docs/source/release/1.3.5-notes.rst b/cuda_pathfinder/docs/source/release/1.3.5-notes.rst index acf66adf04..7aa9de519c 100644 --- a/cuda_pathfinder/docs/source/release/1.3.5-notes.rst +++ b/cuda_pathfinder/docs/source/release/1.3.5-notes.rst @@ -8,6 +8,20 @@ Released on Feb 23, 2026 +.. warning:: + + **YANK NOTICE (PyPI):** ``cuda-pathfinder==1.3.5`` is planned to be yanked + because it introduced a short-lived backward-incompatible exception behavior + in ``load_nvidia_dynamic_lib()`` (unsupported library names raising + ``ValueError``). + + Please use ``cuda-pathfinder>=1.4.0``, which restores backward-compatible + ``DynamicLibNotFoundError`` subclass behavior while preserving more specific + error signaling. + + See `Issue #1684 `_ and + `PR #1688 `_. + Highlights ---------- From 99ad65060836e3d5ce48c3ce73cf94515654287c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 24 Feb 2026 21:06:54 -0800 Subject: [PATCH 4/4] docs(pathfinder): clarify 1.3.5 exception regression notes Update the 1.3.5 and 1.4.0 release notes to remove the YANK NOTICE and document that the ValueError behavior in 1.3.5 was a regression that is fixed in 1.4.0. Co-authored-by: Cursor --- cuda_pathfinder/docs/source/release/1.3.5-notes.rst | 13 +++++++------ cuda_pathfinder/docs/source/release/1.4.0-notes.rst | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cuda_pathfinder/docs/source/release/1.3.5-notes.rst b/cuda_pathfinder/docs/source/release/1.3.5-notes.rst index 7aa9de519c..9db2dbf4fe 100644 --- a/cuda_pathfinder/docs/source/release/1.3.5-notes.rst +++ b/cuda_pathfinder/docs/source/release/1.3.5-notes.rst @@ -10,12 +10,11 @@ Released on Feb 23, 2026 .. warning:: - **YANK NOTICE (PyPI):** ``cuda-pathfinder==1.3.5`` is planned to be yanked - because it introduced a short-lived backward-incompatible exception behavior - in ``load_nvidia_dynamic_lib()`` (unsupported library names raising - ``ValueError``). + ``cuda-pathfinder==1.3.5`` introduced a short-lived backward-incompatible + exception regression in ``load_nvidia_dynamic_lib()`` (unsupported + library names incorrectly raising ``ValueError``). - Please use ``cuda-pathfinder>=1.4.0``, which restores backward-compatible + This bug was corrected in ``cuda-pathfinder>=1.4.0``, restoring backward-compatible ``DynamicLibNotFoundError`` subclass behavior while preserving more specific error signaling. @@ -27,7 +26,9 @@ Highlights * Add support for loading NVIDIA driver libraries (``"cuda"``, ``"nvml"``) via ``load_nvidia_dynamic_lib()``, and reject unsupported library names - with ``ValueError``. + with ``ValueError`` (**EDIT:** this behavior was + `a regression `_ + and was corrected in ``cuda-pathfinder>=1.4.0``). (`PR #1602 `_) * Add bitcode library discovery helpers and public API support, including diff --git a/cuda_pathfinder/docs/source/release/1.4.0-notes.rst b/cuda_pathfinder/docs/source/release/1.4.0-notes.rst index 8a402c36d0..bcfd202b7d 100644 --- a/cuda_pathfinder/docs/source/release/1.4.0-notes.rst +++ b/cuda_pathfinder/docs/source/release/1.4.0-notes.rst @@ -18,6 +18,6 @@ Highlights * Restore backward-compatible exception behavior for ``load_nvidia_dynamic_lib()`` argument validation by replacing the short-lived - 1.3.5 ``ValueError`` behavior with ``DynamicLibNotFoundError`` subclasses: - ``DynamicLibUnknownError`` and ``DynamicLibNotAvailableError``. + ``ValueError`` introduced in ``1.3.5`` with ``DynamicLibNotFoundError`` + subclasses: ``DynamicLibUnknownError`` and ``DynamicLibNotAvailableError``. (`PR #1688 `_)