Skip to content

cuda.core: carry the cuda-bindings floors to pip/uv through minimal-sysctk12/13 extras, and yank 1.3.0 #3459

Description

@leofang

Since 1.3.0, cuda-core declares its cuda-bindings floors (>=12.9.8 for CUDA 12, >=13.5.0 for CUDA 13; #2783, #2920) only in the cu12/cu13 extras, and enforces them at import time. A package that depends on plain cuda-core therefore never passes the floor to the resolver. pip and uv install cuda-core 1.3.0 next to an older cuda-bindings, pip check passes (it ignores requirements gated on extras), and the import fails:

$ pip install "cuda-core==1.3.0" "cuda-bindings==12.9.3"   # exit 0
$ pip check
No broken requirements found.
$ python -c "import cuda.core"
ImportError: cuda.core 1.3.0 requires cuda-bindings >= 12.9.8 for CUDA 12, but cuda-bindings 12.9.3 is installed. Upgrade with: pip install -U "cuda-bindings>=12.9.8,<13"

This is how cuDF's oldest-deps CI broke: it pins cuda-bindings==12.9.3 and gets cuda-core only through numba-cuda-mlir, which depends on plain cuda-core (NVIDIA/cudf#25224, NVIDIA/numba-cuda-mlir#456).

The two floors cannot go into a single unconditional requirement: comma-separated specifiers are intersected, and a != list of the excluded minors would need an edit at every floor move.

Proposal

Add lean extras that carry only the floor (the names cuda-cccl already uses), and build cu12/cu13 on top of them:

dependencies = [
    "cuda-pathfinder >=1.4.2",
    "numpy",
]

[project.optional-dependencies]
minimal-sysctk12 = ["cuda-bindings>=12.9.8,<13"]
minimal-sysctk13 = ["cuda-bindings>=13.5.0,<14"]
cu12 = ["cuda-core[minimal-sysctk12]", "cuda-bindings[all]", "cuda-toolkit==12.*"]
cu13 = ["cuda-core[minimal-sysctk13]", "cuda-bindings[all]", "cuda-toolkit==13.*"]

Release this as 1.3.1, then yank 1.3.0 on PyPI. The yank is needed because pip and uv do not skip a release that lacks a requested extra: they warn (does not provide the extra / does not have an extra named) and use it. That is harmless for 1.2.x and older, which have no import-time floor, but 1.3.0 would fail at import.

Checked against a local index of empty wheels with this layout (pip 25.0.1 and 26.2.2, uv 0.13.8):

  • A package whose cu12 extra requests cuda-core[minimal-sysctk12], installed together with cuda-bindings==12.9.3, resolves to cuda-core 1.2.2 once 1.3.0 is yanked (to 1.3.0 while it is not). Installed into an environment that already has 12.9.3, it upgrades cuda-bindings to the newest 12.x.
  • cuda-core[cu12]==1.3.1 with cuda-bindings==12.9.3 has no solution, so the self-reference carries the floor.

1. Code changes in cuda-core

Everything below reads the floors through floors_from_extras, which accepts only cu<N> extras of the form cuda-bindings>=<floor>,<<next major>. With the layout above it raises ValueError: the 'cu12' extra must pin cuda-bindings as '>=<floor>,<<next major>' ... but it lists 'cuda-bindings[all]', so the build and pre-commit fail until it changes.

2. Docs

  • install.rst, "Installing from PyPI": add the minimal-sysctk12/minimal-sysctk13 extras; extend the advice for downstream packages: depend on cuda-core[minimal-sysctk12/13] (no toolkit wheels) or cuda-core[cu12/13] (with toolkit wheels) in CUDA-major-specific requirements, never on plain cuda-core, because plain cuda-core hides the floor from pip and uv and a mismatch shows up only at import.
  • support.rst, "cuda-bindings Version Requirements": the floors are declared by minimal-sysctk12/minimal-sysctk13, and reach pip and uv only through those extras or through cu12/cu13.
  • DESCRIPTION.rst (the PyPI page): mention the lean extras next to pip install cuda-core[cu12].
  • New docs/source/release/1.3.1-notes.rst: the new extras, and that 1.3.0 was yanked and why.

3. Downstream

Packages that depend on cuda-core should request one of these extras from their own CUDA-major-specific extras, and cut a release:

  • cuda-core[minimal-sysctk12] / [minimal-sysctk13] when the CUDA Toolkit comes from the system or from their own requirements;
  • cuda-core[cu12] / [cu13] when they also want the toolkit wheels.

Current PyPI metadata of known dependents:

  • numba-cuda-mlir 0.6.0 and numba-cuda 0.30.4 depend on plain cuda-core; their cu12/cu13 extras pin cuda-bindings but not cuda-core. Have cu12/cu13 extras depend on cuda-core extra numba-cuda-mlir#457 adds cuda-core[cu12]/[cu13]; minimal-sysctk12/minimal-sysctk13 would do the same without pulling cuda-bindings[all] and more toolkit wheels.
  • cuda-cccl 1.3.0 depends on plain cuda-core; its minimal-cu12/13 and minimal-sysctk12/13 extras pin only cuda-bindings.
  • nvmath-python 1.0.0: cu12/cu13 already use cuda-core[cu12]/[cu13]; sysctk12/sysctk13 pin only cuda-bindings.

A cuda-core lower bound is not required: older releases resolve with the warning above, which is harmless once 1.3.0 is yanked. Use cuda-core[...]>=1.3.1 to require the floor-carrying metadata.

CI that pins an old cuda-bindings (for example cuDF's oldest-deps jobs, cuda-bindings==12.9.3 / ==13.0.2) will then resolve to cuda-core 1.2.x instead of breaking at import. To test cuda-core 1.3.x there, raise those pins to the floors.

-- Leo's bot

Activity

  1. self-assigned this
    on Nov 13, 2026
  2. added
    packagingAnything related to wheels or Conda packages
    cuda.coreEverything related to the cuda.core module
    P0High priority - Must do!
    on Nov 13, 2026
  3. added this to the cuda.core 1.3.1 milestone on Nov 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P0High priority - Must do!cuda.coreEverything related to the cuda.core modulepackagingAnything related to wheels or Conda packages

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions