Skip to content

fix(core): don't abort the build when an integer build knob is set but empty - #2547

Open
LeSingh1 wants to merge 1 commit into
NVIDIA:mainfrom
LeSingh1:core-build-env-int
Open

fix(core): don't abort the build when an integer build knob is set but empty#2547
LeSingh1 wants to merge 1 commit into
NVIDIA:mainfrom
LeSingh1:core-build-env-int

Conversation

@LeSingh1

@LeSingh1 LeSingh1 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Stacking note: cuda_core/build_hooks.py is also touched by #2500 (the os.pathpathlib migration, part 5 of #2410). The hunks are disjoint — #2500 rewrites the os.path call sites, this one changes the two environment reads — so they merge in either order.

Problem

cuda_core/build_hooks.py reads two integer build knobs with a bare int():

COMPILE_FOR_COVERAGE = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))
...
nthreads = int(os.environ.get("CUDA_PYTHON_PARALLEL_LEVEL", os.cpu_count() // 2))

os.environ.get(name, default) returns the empty string, not the default, when a variable is set but empty — and VAR= pip install ., an empty ENV in a Dockerfile, or an unfilled CI job variable is exactly how these get neutralised.

The first line runs at module scope, so the failure lands while pip is still importing the PEP 517 backend, before any build output:

$ CUDA_PYTHON_COVERAGE= pip install ./cuda_core
  File ".../cuda_core/build_hooks.py", line 29, in <module>
    COMPILE_FOR_COVERAGE = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))
ValueError: invalid literal for int() with base 10: ''

cuda_core/setup.py carries the same two expressions verbatim (lines 13–14), so the second build entry point fails the same way.

Measured against the module as it stands on main:

CUDA_PYTHON_COVERAGE backend import on main
unset / 0 / 1 ok
"" ValueError: invalid literal for int() with base 10: ''
" " ValueError
"yes" ValueError (correct to reject, but the message names nothing)

Separately, os.cpu_count() is documented to return None when the count cannot be determined, which makes the nthreads default None // 2TypeError.

Fix

Add build_hooks.env_int(name, default) and route all four call sites through it:

  • unset and empty/whitespace-only both fall back to the default;
  • a value that is set to something non-integer still raises — silently ignoring CUDA_PYTHON_COVERAGE=yes would hand back a build with no coverage instrumentation, which is worse than stopping — but names the variable:
    environment variable CUDA_PYTHON_COVERAGE='yes' must be an integer;
  • os.cpu_count() or 1 so an undetermined CPU count falls back to a serial build instead of a TypeError.

setup.py already does import build_hooks, so both entry points now share one helper instead of duplicating the expression.

Integer values keep their exact current meaning: 0 → off, non-zero → on, and CUDA_PYTHON_PARALLEL_LEVEL=4 still yields 4.

Tests

Added TestEnvInt to the existing cuda_core/tests/test_build_hooks.py (which already loads build_hooks.py by path via _load_build_hooks() and needs no built cuda.core):

  • env_int over unset / "" / " " / "0" / "4" / " 4 ";
  • the error message names the variable for a non-integer;
  • test_backend_imports_with_an_empty_coverage_flag reloads the backend module with CUDA_PYTHON_COVERAGE="" and " " and asserts it imports with COMPILE_FOR_COVERAGE is False — this is the regression test for the crash above.

Verification I could and could not do

  • Loaded both the upstream/main and the fixed build_hooks.py by path and ran the new test bodies against each. On main, importing the backend with CUDA_PYTHON_COVERAGE="" and " " raises ValueError (both new cases fail); with the fix both import cleanly with COMPILE_FOR_COVERAGE is False. The env_int table above was produced the same way.
  • ruff check / ruff format --check and python -m py_compile clean on all three changed files.
  • Not run: pytest cuda_core/tests/test_build_hooks.py itself. The module does from cuda.pathfinder import get_cuda_path_or_home at import, and cuda.pathfinder cannot be imported on macOS (it resolves dlinfo, which does not exist there), so collection fails locally for reasons unrelated to this change. Cython and setuptools are present, and build_hooks.py itself loads fine — that is what the verification above exercises. Please treat CI as the first real run of the test file.

cuda_core/build_hooks.py reads two integer knobs from the environment with
a bare int():

    COMPILE_FOR_COVERAGE = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))
    nthreads = int(os.environ.get("CUDA_PYTHON_PARALLEL_LEVEL", os.cpu_count() // 2))

os.environ.get returns the empty string, not the default, when a variable is
set but empty -- and `VAR= pip install .` (or an empty Dockerfile ENV, or an
unfilled CI job variable) is exactly how these get neutralised. The first
line runs at module scope, so the failure lands while pip is still importing
the PEP 517 backend:

    $ CUDA_PYTHON_COVERAGE= pip install ./cuda_core
    ValueError: invalid literal for int() with base 10: ''

cuda_core/setup.py carries the same two expressions verbatim.

Add build_hooks.env_int and route all four call sites through it. Unset and
empty/whitespace-only both fall back to the default; a value that is set to
something non-integer still raises, but names the variable
(`environment variable CUDA_PYTHON_COVERAGE='yes' must be an integer`)
instead of an anonymous int() failure. Silently ignoring `=yes` would be
worse than stopping here -- it would hand back a build with no coverage
instrumentation.

Also stop assuming os.cpu_count() returns a number. It is documented to
return None when the count cannot be determined, which made the nthreads
default a TypeError. Fall back to a serial build instead.

setup.py already imports build_hooks, so both build entry points now parse
these knobs through the same helper rather than duplicating the expression.
@copy-pr-bot

copy-pr-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added the cuda.core Everything related to the cuda.core module label Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cuda.core Everything related to the cuda.core module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant