Skip to content

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

Merged
mdboom merged 2 commits into
NVIDIA:mainfrom
LeSingh1:core-tab-completion-env-parse
Aug 13, 2026
Merged

fix(core): don't crash import cuda.core when CUDA_CORE_DONT_FIX_TAB_COMPLETION is not an integer#2535
mdboom merged 2 commits 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.

@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
Comment thread cuda_core/cuda/core/__init__.py Outdated
Comment on lines +44 to +49
# Parsed leniently on purpose: this runs during ``import cuda.core``, so a
# bare ``int()`` turns any non-integer value -- including the empty string
# left by ``export CUDA_CORE_DONT_FIX_TAB_COMPLETION=`` -- into a
# ValueError that makes the whole package unimportable. Integer values keep
# their previous meaning (non-zero opts out); anything else non-empty is
# honored as an opt-out rather than silently ignored.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary comment.

Suggested change
# Parsed leniently on purpose: this runs during ``import cuda.core``, so a
# bare ``int()`` turns any non-integer value -- including the empty string
# left by ``export CUDA_CORE_DONT_FIX_TAB_COMPLETION=`` -- into a
# ValueError that makes the whole package unimportable. Integer values keep
# their previous meaning (non-zero opts out); anything else non-empty is
# honored as an opt-out rather than silently ignored.

Comment on lines +76 to +84
- ``import cuda.core`` no longer fails when
``CUDA_CORE_DONT_FIX_TAB_COMPLETION`` is set to a value that is not a
base-10 integer. The opt-out was read with a bare ``int()`` at import time,
so an empty value (``export CUDA_CORE_DONT_FIX_TAB_COMPLETION=``) or a value
such as ``true`` raised ``ValueError`` out of the package's ``__init__``.
Unset, empty, and ``0`` leave the ``rlcompleter`` patch enabled; any other
value disables it. The variable is now listed under
:doc:`Environment Variables <../environment_variables>`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too obscure for the release notes.

Suggested change
- ``import cuda.core`` no longer fails when
``CUDA_CORE_DONT_FIX_TAB_COMPLETION`` is set to a value that is not a
base-10 integer. The opt-out was read with a bare ``int()`` at import time,
so an empty value (``export CUDA_CORE_DONT_FIX_TAB_COMPLETION=``) or a value
such as ``true`` raised ``ValueError`` out of the package's ``__init__``.
Unset, empty, and ``0`` leave the ``rlcompleter`` patch enabled; any other
value disables it. The variable is now listed under
:doc:`Environment Variables <../environment_variables>`.

`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.
@LeSingh1
LeSingh1 force-pushed the core-tab-completion-env-parse branch from 9e1c223 to 0a94476 Compare August 12, 2026 23:19
@LeSingh1

Copy link
Copy Markdown
Contributor Author

Both applied in 0a94476 — comment gone, and the release-note entry dropped. The variable is still documented under Environment Variables, which seemed like the right place for it.

@mdboom mdboom self-assigned this Aug 13, 2026
@mdboom mdboom added bug Something isn't working P1 Medium priority - Should do labels Aug 13, 2026
@mdboom mdboom added this to the cuda.core 1.2.0 milestone Aug 13, 2026
@mdboom

mdboom commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

/ok to test a6f910f

@mdboom
mdboom enabled auto-merge (squash) August 13, 2026 13:40
@github-actions

This comment has been minimized.

@mdboom
mdboom merged commit 21c4b70 into NVIDIA:main Aug 13, 2026
114 of 116 checks passed
@github-actions

Copy link
Copy Markdown
Doc Preview CI
Preview removed because the pull request was closed or merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working cuda.core Everything related to the cuda.core module P1 Medium priority - Should do

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants