Skip to content

fix(core): don't crash import cuda.core when CUDA_CORE_DONT_FIX_TAB_COMPLETION is not an integer - #2535

Open
LeSingh1 wants to merge 1 commit into
NVIDIA:mainfrom
LeSingh1:core-tab-completion-env-parse
Open

fix(core): don't crash import cuda.core when CUDA_CORE_DONT_FIX_TAB_COMPLETION is not an integer#2535
LeSingh1 wants to merge 1 commit into
NVIDIA:mainfrom
LeSingh1:core-tab-completion-env-parse

Conversation

@LeSingh1

@LeSingh1 LeSingh1 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Problem

cuda_core/cuda/core/__init__.py reads the tab-completion opt-out with a bare int() at import time:

if int(os.environ.get("CUDA_CORE_DONT_FIX_TAB_COMPLETION", "0")):
    return

os.environ.get(name, "0") returns the empty string, not the "0" default, when the variable is set but empty — and int("") raises. Because _patch_rlcompleter_for_cython_properties() is called unconditionally at module scope, the exception escapes import cuda.core:

$ export CUDA_CORE_DONT_FIX_TAB_COMPLETION=
$ python -c "import cuda.core"
Traceback (most recent call last):
  ...
  File ".../cuda/core/__init__.py", line 44, in _patch_rlcompleter_for_cython_properties
    if int(os.environ.get("CUDA_CORE_DONT_FIX_TAB_COMPLETION", "0")):
ValueError: invalid literal for int() with base 10: ''

The same happens for =true, =yes, =on, or any other non-integer value.

Clearing a variable with export VAR= is the standard way to neutralize it in a shell profile, a Dockerfile ENV, or a CI job spec, and boolean-looking spellings are the obvious guess for a knob named DONT_FIX_.... Every one of them makes the whole package unimportable — a hard, confusing failure for a variable whose only job is to skip an optional rlcompleter patch.

Fix

Parse the value leniently. Integer values keep exactly their previous meaning (non-zero opts out, so 0 and 00 still install the patch); a non-integer, non-empty value is honored as an opt-out rather than silently ignored; unset and empty/whitespace-only both mean "not set".

cuda.core already takes the tolerant approach for its other integer environment variable — default_stream() in _stream.pyx parses CUDA_PYTHON_CUDA_PER_THREAD_DEFAULT_STREAM with strtol, with an explicit comment that weird values are handled rather than fatal. This brings the opt-out in line with that.

Resulting behavior:

CUDA_CORE_DONT_FIX_TAB_COMPLETION before after
unset patch installed patch installed
"" / " " ValueError at import patch installed
"0" / "00" patch installed patch installed
"1" / "2" patch skipped patch skipped
"true" / "yes" ValueError at import patch skipped

Also in this PR

  • Documented the variable. cuda_core/docs/source/environment_variables.rst lists the runtime environment variables that affect cuda.core, but CUDA_CORE_DONT_FIX_TAB_COMPLETION was missing from it even though the code describes it as an "explicit opt-out for users".
  • Dropped a stale comment. The comment above the check said the patch is "Only installed in interactive mode so library users running scripts see no global rlcompleter side effect". There is no interactivity check in the code — Fix tab completion #2055 landed with an explicit "Always install the monkeypatch" step, so the patch has been unconditional since it was introduced.
  • Release note under 1.2.0-notes.rst.

Test

test_opt_out_env_var_values in cuda_core/tests/test_rlcompleter_patch.py runs import cuda.core in a subprocess for eight values of the variable and asserts both that the import succeeds and whether the rlcompleter patch was installed (the stdlib rlcompleter module has no property attribute of its own, so its presence is exactly the patch signal).

Four of the eight cases — "", " ", "true", "yes" — fail on main: the subprocess exits non-zero with the ValueError above.

The test needs no CUDA device; the opt-out is evaluated at import time.

Verification I could and could not do

  • Verified the parsing table above (old expression vs. new) case-by-case in isolation: the previous expression raises ValueError on 4 of the 8 values and agrees with the new one on the other 4.
  • ruff check / ruff format --check on both changed Python files: no new findings versus an upstream/main baseline of the same files (the pre-existing UP038 in __init__.py and ARG001 in the test file are untouched).
  • python -m py_compile on both changed Python files.
  • Not run: the new subprocess test itself, and the rest of the cuda_core suite. I do not have an environment where cuda.core is importable (no CUDA driver / no built extension modules), so the test was written against the existing helpers in that module but not executed. Please treat CI as the first real run.

`cuda/core/__init__.py` reads `CUDA_CORE_DONT_FIX_TAB_COMPLETION` with a
bare `int(os.environ.get(..., "0"))` at import time. `int()` raises for any
value that is not a base-10 integer, and `os.environ.get` returns the empty
string (not the `"0"` default) when the variable is set but empty, so:

    export CUDA_CORE_DONT_FIX_TAB_COMPLETION=
    python -c "import cuda.core"
    ValueError: invalid literal for int() with base 10: ''

Clearing a variable with `export VAR=` is the usual way to neutralize it in
a shell profile, a Dockerfile, or a CI job spec, and `=true` / `=yes` are
the obvious guesses for a boolean-looking opt-out. All of them make the
whole package unimportable, which is a hard failure for a knob whose only
purpose is to skip an optional `rlcompleter` patch.

Parse the value leniently instead. Integer values keep their existing
meaning (non-zero opts out, so `0` and `00` still install the patch), while
a non-integer, non-empty value is honored as an opt-out rather than being
silently ignored. Unset and empty/whitespace-only both mean "not set".

Also document the variable, which was not listed on the environment
variables page, and drop the stale "only installed in interactive mode"
comment: the interactivity gate was intentionally removed in NVIDIA#2055 ("Always
install the monkeypatch"), so the patch has been unconditional since then.

The new parametrized test asserts the resulting behavior for eight values;
four of them ("", "   ", "true", "yes") fail on main because the subprocess
exits non-zero with the ValueError above.
@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