From e4dd1dd2aaa245f56c8ea09640465e381a4d839f Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 13 Jan 2026 10:56:32 -0800 Subject: [PATCH] Add version validation to prevent silent setuptools-scm fallback versions Add import-time version validation to cuda.bindings, cuda.core, and cuda.pathfinder to detect and fail fast when setuptools-scm produces fallback versions (e.g., 0.1.dev...) due to missing git tags. This prevents silent failures that can invalidate QA test runs and waste developer time debugging version-related issues. Features: - User-friendly error messages explaining the problem and how to fix it - Opt-out mechanism via CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 - Consistent implementation across all three packages with sync reminder comments The validation checks that major.minor > 0.1, which catches common fallback versions while allowing legitimate early development versions. --- cuda_bindings/cuda/bindings/__init__.py | 33 +++++++++++++++++++++ cuda_core/cuda/core/__init__.py | 33 +++++++++++++++++++++ cuda_pathfinder/cuda/pathfinder/__init__.py | 33 +++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/cuda_bindings/cuda/bindings/__init__.py b/cuda_bindings/cuda/bindings/__init__.py index 38d71fcfde..29219091ef 100644 --- a/cuda_bindings/cuda/bindings/__init__.py +++ b/cuda_bindings/cuda/bindings/__init__.py @@ -1,5 +1,38 @@ # SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +import os + from cuda.bindings import utils from cuda.bindings._version import __version__ + +# Version validation: detect setuptools-scm fallback versions (e.g., 0.1.dev...) +# This check must be kept in sync with similar checks in cuda.core and cuda.pathfinder +if not os.environ.get("CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING"): + version_parts = __version__.split(".") + if len(version_parts) < 2: + raise RuntimeError( + f"Invalid version format: '{__version__}'. " + f"The version detection system failed. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) + try: + major, minor = int(version_parts[0]), int(version_parts[1]) + except ValueError: + raise RuntimeError( + f"Invalid version format: '{__version__}'. " + f"The version detection system failed. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) from None + if major == 0 and minor <= 1: + raise RuntimeError( + f"Invalid version detected: '{__version__}'. " + f"The version detection system failed silently and produced a fallback version. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) diff --git a/cuda_core/cuda/core/__init__.py b/cuda_core/cuda/core/__init__.py index 67a815d1de..a33637ee17 100644 --- a/cuda_core/cuda/core/__init__.py +++ b/cuda_core/cuda/core/__init__.py @@ -2,8 +2,41 @@ # # SPDX-License-Identifier: Apache-2.0 +import os + from cuda.core._version import __version__ +# Version validation: detect setuptools-scm fallback versions (e.g., 0.1.dev...) +# This check must be kept in sync with similar checks in cuda.bindings and cuda.pathfinder +if not os.environ.get("CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING"): + version_parts = __version__.split(".") + if len(version_parts) < 2: + raise RuntimeError( + f"Invalid version format: '{__version__}'. " + f"The version detection system failed. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) + try: + major, minor = int(version_parts[0]), int(version_parts[1]) + except ValueError: + raise RuntimeError( + f"Invalid version format: '{__version__}'. " + f"The version detection system failed. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) from None + if major == 0 and minor <= 1: + raise RuntimeError( + f"Invalid version detected: '{__version__}'. " + f"The version detection system failed silently and produced a fallback version. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) + try: from cuda import bindings except ImportError: diff --git a/cuda_pathfinder/cuda/pathfinder/__init__.py b/cuda_pathfinder/cuda/pathfinder/__init__.py index 8da4020116..60bf11fadb 100644 --- a/cuda_pathfinder/cuda/pathfinder/__init__.py +++ b/cuda_pathfinder/cuda/pathfinder/__init__.py @@ -3,6 +3,8 @@ """cuda.pathfinder public APIs""" +import os + from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError as DynamicLibNotFoundError 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 @@ -14,6 +16,37 @@ from cuda.pathfinder._version import __version__ # isort: skip # noqa: F401 +# Version validation: detect setuptools-scm fallback versions (e.g., 0.1.dev...) +# This check must be kept in sync with similar checks in cuda.bindings and cuda.core +if not os.environ.get("CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING"): + version_parts = __version__.split(".") + if len(version_parts) < 2: + raise RuntimeError( + f"Invalid version format: '{__version__}'. " + f"The version detection system failed. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) + try: + major, minor = int(version_parts[0]), int(version_parts[1]) + except ValueError: + raise RuntimeError( + f"Invalid version format: '{__version__}'. " + f"The version detection system failed. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) from None + if major == 0 and minor <= 1: + raise RuntimeError( + f"Invalid version detected: '{__version__}'. " + f"The version detection system failed silently and produced a fallback version. " + f"This usually means git tags are not available (e.g., shallow clone or zip archive). " + f"To fix: ensure you have a full git checkout with tags, or set " + f"CUDA_PYTHON_ALLOW_FALLBACK_VERSIONING=1 to disable this check." + ) + # Indirections to help Sphinx find the docstrings. #: Mapping from short CUDA Toolkit (CTK) library names to their canonical #: header basenames (used to validate a discovered include directory).