Skip to content

fix(ci): fail cleanly on a malformed cuda.build.version instead of tracebacking - #2544

Open
LeSingh1 wants to merge 1 commit into
NVIDIA:mainfrom
LeSingh1:ci-pixi-version-parse
Open

fix(ci): fail cleanly on a malformed cuda.build.version instead of tracebacking#2544
LeSingh1 wants to merge 1 commit into
NVIDIA:mainfrom
LeSingh1:ci-pixi-version-parse

Conversation

@LeSingh1

@LeSingh1 LeSingh1 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Problem

ci/tools/check_pixi_cuda_version.py returns a deliberate diagnostic exit code for every problem it anticipates — missing versions.yml, missing cuda.build.version, missing pixi.toml, missing feature key — and then unpacks the version with no checking at all:

try:
    build_version = yaml.safe_load(...)["cuda"]["build"]["version"]
except (KeyError, TypeError):
    print(f"error: cuda.build.version not found in {VERSIONS_FILE_PATH}", file=sys.stderr)
    return 2

major, minor, *_ = build_version.split(".")

YAML makes that easy to break. ci/versions.yml quotes the value today:

cuda:
  build:
    version: "13.3.0"

Drop the quotes and a two-component value loads as a float, a bare number as an int — neither has .split. And a quoted-but-single-component value survives to the tuple unpacking and dies there instead.

Driving main() against the real pixi.toml files with only ci/versions.yml varied:

version: value loaded as result on main
"13.3.0" str exit 0 (correct)
13.3 float AttributeError: 'float' object has no attribute 'split'
13 int AttributeError: 'int' object has no attribute 'split'
(empty) None AttributeError: 'NoneType' object has no attribute 'split'
[13, 3] list AttributeError: 'list' object has no attribute 'split'
"13" str ValueError: not enough values to unpack (expected at least 2, got 1)

All five escape as an uncaught traceback out of a pre-commit hook, pointing the contributor at this script rather than at the line they edited. The except (KeyError, TypeError) above shows the intent was already to fail cleanly here.

Fix

Add parse_build_version, which returns (major, minor) only for a <major>.<minor>[.<patch>] string of digits and None otherwise, and have main report the bad value with the same return 2 shape as its neighbours:

error: cuda.build.version=13.3 in .../ci/versions.yml is not a '<major>.<minor>[.<patch>]'
version string. Quote the value in YAML so it is not loaded as a number (13.3 becomes a
float, 13 becomes an int).

The message names the quoting trap because that is how the value actually goes wrong.

No behavior change for well-formed input: the current "13.3.0" still yields expected="13.3.*" and cuda_feature="cu13", and running the tool against the real repo still exits 0.

Tests

This script had no tests. Added ci/tools/tests/test_check_pixi_cuda_version.py:

  • parse_build_version over the accepted shapes (13.3.0, 12.9.1, 13.3, 13.3.0.1) and every rejected one (float, int, None, list, "13", "", "13.", ".3", "cuda.13").
  • End-to-end tests that build a temporary repo layout (ci/versions.yml + both pixi.toml files), monkeypatch the module's path constants, and assert main() returns 2 with the diagnostic — and returns 0 for a well-formed version.

The module imports PyYAML at module scope (the pre-commit hook supplies it via additional_dependencies), so the test module opens with pytest.importorskip("yaml") rather than failing collection where PyYAML is absent.

Verification

Executed in full (pure Python, no GPU):

  • The six-row table above was produced by driving the upstream/main main() directly with monkeypatched path constants; five of the six raise uncaught.
  • With the fix, all of those return exit 2 with the new message, and pytest ci/tools/tests is 73 passed.
  • Running the tool against the real repo checkout still prints OK: ... and exits 0.
  • Note on the usual "restore the file from upstream/main and watch the tests fail" check: because the fix introduces a new function, the test module cannot even import against main (ImportError: cannot import name 'parse_build_version'). The evidence that matters is the table above, taken against unmodified upstream/main code.
  • ruff check / ruff format --check clean on both files; toolshed/check_spdx.py clean on the new file; python -m py_compile clean. Index verified clean before committing.

Related

Independent of #2538, #2543 (both check_mempool_hygiene.py) and #2496 (check_release_notes.py) — different files, no overlap.

check_pixi_cuda_version.py returns a diagnostic exit code for every problem
it anticipates -- missing versions.yml, missing cuda.build.version, missing
pixi.toml, missing feature key -- and then unpacks the version with no
checking at all:

    major, minor, *_ = build_version.split(".")

YAML makes that easy to break. `version: "13.3.0"` is quoted today, but drop
the quotes and a two-component value loads as a float and a bare number as an
int, neither of which has `.split`. Against the real pixi.toml files:

    version: 13.3     -> AttributeError: 'float' object has no attribute 'split'
    version: 13       -> AttributeError: 'int' object has no attribute 'split'
    version:          -> AttributeError: 'NoneType' object has no attribute 'split'
    version: [13, 3]  -> AttributeError: 'list' object has no attribute 'split'
    version: "13"     -> ValueError: not enough values to unpack (expected at least 2, got 1)

All five escape as an uncaught traceback from a pre-commit hook, pointing at
this script rather than at the line the contributor edited.

Add `parse_build_version`, which returns `(major, minor)` only for a
`<major>.<minor>[.<patch>]` string of digits, and have `main` report the bad
value with the same `return 2` shape as its neighbours. The message names the
YAML quoting trap, since that is how the value goes wrong in practice.

Adds the first tests for this script. The parse tests cover the accepted
shapes and every rejected one; the end-to-end tests drive `main()` against a
temporary repo layout and assert exit 2 plus the diagnostic.
@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 CI/CD CI/CD infrastructure label Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/CD CI/CD infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant