feat: add support for Python 3.14#933
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
/ok to test |
|
/ok to test |
|
/ok to test |
1 similar comment
|
/ok to test |
|
/ok to test |
2 similar comments
|
/ok to test |
|
/ok to test |
|
/ok to test |
|
/ok to test |
|
/ok to test |
|
/ok to test |
| host: | ||
| - pip | ||
| - python =${{ py_version }} | ||
| - python-gil =${{ py_version }} |
There was a problem hiding this comment.
We're in the era of free-threaded Python, so we specify python-gil to get the GIL version
| ctx = get_context("fork") | ||
| complete = ctx.Event() | ||
|
|
||
| from cuopt_server.utils import solver | ||
|
|
||
| s = Process( | ||
| s = ctx.Process( |
There was a problem hiding this comment.
In Python 3.14, the default method for multiprocessing changed from fork to forkserver -- forkserver is easier to reason about, but requires, in this case, pickling things that cannot be pickled.
For now, explicitly enabling a fork process to match the existing behavior with Python 3.11-3.13
| ) | ||
| parser.add_argument( | ||
| "--compare", action="store_true", help="Compare 1% vs 0.1% gap" | ||
| "--compare", action="store_true", help="Compare 1%% vs 0.1%% gap" |
There was a problem hiding this comment.
% need to be escaped with a second % - this is now an error from argparse in Python 3.14
There was a problem hiding this comment.
Oh wow, I didn't realize that argparse had format specifiers like this. Just read about them at https://docs.python.org/3/library/argparse.html
Ok yeah makes sense.
📝 WalkthroughWalkthroughMultiple repositories across CI/CD workflows, documentation, and Python packages are updated to support Python 3.14, including version bumps for dependencies (msgpack, numba), conda recipe changes from python to python-gil, and multiprocessing context adjustments using fork-safety primitives. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
conda/recipes/cuopt/recipe.yaml (1)
72-79:⚠️ Potential issue | 🔴 CriticalKeep
pythoninrequirements.hostand addpython-gilas an additional constraint.Line 78 replaces
pythonwithpython-gil, butpython-gilis a selector metapackage that does not provide the standard Python ABI/version runtime pinning. The built artifact will lack correct runtime Python version/ABI constraints, risking installability on incompatible Python variants.Use the recommended pattern instead:
- Retain
python =${{ py_version }}inrequirements.host(andrunfor extension packages) to emit standard runtime constraints.- Add
python-gilas an additional constraint inrun_constrainedor as a directrundependency to enforce the GIL variant selection.Apply this fix to all recipes switched to
python-gilin this PR.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@conda/recipes/cuopt/recipe.yaml` around lines 72 - 79, The host requirements replaced the standard python pin with the selector metapackage python-gil; restore the proper Python ABI pin by adding back "python =${{ py_version }}" under requirements.host (keep cython, pip, etc.), and add "python-gil" as an additional constraint — either in run_constrained or as a run dependency for the extension package so the GIL variant is enforced without losing the standard runtime Python ABI/version pinning; update any other recipes in this PR that switched to python-gil the same way.
🧹 Nitpick comments (4)
python/cuopt_server/cuopt_server/utils/process_handler.py (1)
73-78: Extract the context selection to a shared location to avoid duplication.
cuopt_service.pyandprocess_handler.pyboth independently hardcodeget_context("fork")for the multiprocessing context. This creates two sources of truth and makes it easy to accidentally mix contexts acrossProcess/Event/Queueobjects if one location is changed without updating the other. Extract this to a shared constant or helper function, or pass the chosen context tocreate_abort_list_and_process()as a parameter.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@python/cuopt_server/cuopt_server/utils/process_handler.py` around lines 73 - 78, Both cuopt_service.py and process_handler.py call get_context("fork") independently; extract the multiprocessing context to a single shared symbol (e.g., a module-level constant or helper like DEFAULT_MP_CONTEXT = get_context("fork") or get_default_context()) and update create_abort_list_and_process() to accept the context as a parameter (or import the shared symbol) so ctx, ctx.Event(), ctx.Process(...) in process_handler.py use that single source; update cuopt_service.py to use the same shared constant/helper instead of calling get_context("fork") directly to avoid mismatched contexts.docs/cuopt/source/system-requirements.rst (1)
28-29: Use one Python range format throughout the page.The main requirements block uses
>= 3.11.* and <= 3.14.*, but the thin-client section switches to>= 3.11.x <= 3.14.x. Unifying the notation will make the supported range easier to scan and less ambiguous.As per coding guidelines: "Consistency: Version numbers, parameter types, and terminology match code".
Also applies to: 101-101
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/cuopt/source/system-requirements.rst` around lines 28 - 29, Replace inconsistent Python version range formats so the page uses a single notation; locate occurrences of ">= 3.11.* and <= 3.14.*" and ">= 3.11.x <= 3.14.x" (including the thin-client section) and standardize them to one format (pick the project's preferred style, e.g., ">= 3.11.* and <= 3.14.*") across the document; ensure both the main requirements block and the thin-client section use the exact same string to maintain consistency..github/workflows/build.yaml (1)
48-48: Replace mutable branch refs with immutable commit SHAs for reproducibility and stability.All
rapidsai/shared-workflowsreferences in this file use the@python-3.14branch, which is mutable. Future changes to that branch will silently alter build behavior, and branch deletion or cleanup upstream would break these jobs entirely. Pin these workflow refs to specific commit SHAs instead to ensure reproducible and stable builds.Also applies to: 58, 68, 76, 91, 102, 115, 126, 138, 148, 163, 174, 188, 204
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/build.yaml at line 48, The workflow references use mutable branch refs (e.g., the line "uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-build.yaml@python-3.14") which makes builds non‑reproducible; replace each "@python-3.14" ref (and the other occurrences mentioned) with the corresponding immutable commit SHA from the rapidsai/shared-workflows repo so the "uses:" entries point to a specific commit SHA instead of the branch name, updating all listed occurrences (lines referencing rapidsai/shared-workflows at the noted positions) to the matching commit SHAs.dependencies.yaml (1)
349-350: Encode the Python 3.14 Numba floor directly in the dependency matrix.Numba 0.61 adds Python 3.13 support, and Python 3.14 support arrives in 0.63.0. Keeping the floor at
numba>=0.60.0means the newpy: "3.14"environments rely on the resolver to filter out older Numba releases instead of expressing the compatibility floor here. Consider apy: "3.14"-specificnumba>=0.63,<0.65constraint, or raise the shared floor if older Python jobs no longer need 0.60–0.62. (numba.readthedocs.io)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dependencies.yaml` around lines 349 - 350, The dependency matrix currently pins numba as "numba>=0.60.0,<0.65.0" which does not express that Python 3.14 requires numba>=0.63; update the matrix so that the Python 3.14 job (py: "3.14") explicitly uses a stricter constraint (e.g., numba>=0.63,<0.65) or raise the shared floor to >=0.63 if older Python jobs no longer need 0.60–0.62; adjust the numba entry in dependencies.yaml and any matrix/job entries that reference numba so the resolver does not have to implicitly filter incompatible releases.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/pr.yaml:
- Line 37: The workflow uses mutable branch refs (e.g. the string "uses:
rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@python-3.14");
replace every instance of the branch ref "@python-3.14" (and any other
branch-style refs) with the corresponding immutable commit SHA for the target
repository/workflow so each "uses: rapidsai/shared-workflows/...@<commit-sha>"
invocation is pinned (apply the same change for all other occurrences of the
same pattern in this file).
In `@README.md`:
- Line 139: Replace the reStructuredText link syntax with Markdown by changing
"`cuOpt dockerhub page <https://hub.docker.com/r/nvidia/cuopt/tags>`_" to
"[cuOpt dockerhub page](https://hub.docker.com/r/nvidia/cuopt/tags)" and fix the
Python tag mismatch in the example by updating "25.10.0-cuda12.9-py3.13" and
"25.10.0-cuda13.0-py3.13" to use "py3.14" (e.g., "25.10.0-cuda12.9-py3.14" or
"25.10.0-cuda13.0-py3.14") so the note about `py3.14` matches the example.
---
Outside diff comments:
In `@conda/recipes/cuopt/recipe.yaml`:
- Around line 72-79: The host requirements replaced the standard python pin with
the selector metapackage python-gil; restore the proper Python ABI pin by adding
back "python =${{ py_version }}" under requirements.host (keep cython, pip,
etc.), and add "python-gil" as an additional constraint — either in
run_constrained or as a run dependency for the extension package so the GIL
variant is enforced without losing the standard runtime Python ABI/version
pinning; update any other recipes in this PR that switched to python-gil the
same way.
---
Nitpick comments:
In @.github/workflows/build.yaml:
- Line 48: The workflow references use mutable branch refs (e.g., the line
"uses:
rapidsai/shared-workflows/.github/workflows/conda-cpp-build.yaml@python-3.14")
which makes builds non‑reproducible; replace each "@python-3.14" ref (and the
other occurrences mentioned) with the corresponding immutable commit SHA from
the rapidsai/shared-workflows repo so the "uses:" entries point to a specific
commit SHA instead of the branch name, updating all listed occurrences (lines
referencing rapidsai/shared-workflows at the noted positions) to the matching
commit SHAs.
In `@dependencies.yaml`:
- Around line 349-350: The dependency matrix currently pins numba as
"numba>=0.60.0,<0.65.0" which does not express that Python 3.14 requires
numba>=0.63; update the matrix so that the Python 3.14 job (py: "3.14")
explicitly uses a stricter constraint (e.g., numba>=0.63,<0.65) or raise the
shared floor to >=0.63 if older Python jobs no longer need 0.60–0.62; adjust the
numba entry in dependencies.yaml and any matrix/job entries that reference numba
so the resolver does not have to implicitly filter incompatible releases.
In `@docs/cuopt/source/system-requirements.rst`:
- Around line 28-29: Replace inconsistent Python version range formats so the
page uses a single notation; locate occurrences of ">= 3.11.* and <= 3.14.*" and
">= 3.11.x <= 3.14.x" (including the thin-client section) and standardize them
to one format (pick the project's preferred style, e.g., ">= 3.11.* and <=
3.14.*") across the document; ensure both the main requirements block and the
thin-client section use the exact same string to maintain consistency.
In `@python/cuopt_server/cuopt_server/utils/process_handler.py`:
- Around line 73-78: Both cuopt_service.py and process_handler.py call
get_context("fork") independently; extract the multiprocessing context to a
single shared symbol (e.g., a module-level constant or helper like
DEFAULT_MP_CONTEXT = get_context("fork") or get_default_context()) and update
create_abort_list_and_process() to accept the context as a parameter (or import
the shared symbol) so ctx, ctx.Event(), ctx.Process(...) in process_handler.py
use that single source; update cuopt_service.py to use the same shared
constant/helper instead of calling get_context("fork") directly to avoid
mismatched contexts.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ae66a88a-3353-4e36-a1a8-6f91cd8309be
📒 Files selected for processing (22)
.github/workflows/build.yaml.github/workflows/pr.yamlCONTRIBUTING.mdREADME.mdconda/environments/all_cuda-129_arch-aarch64.yamlconda/environments/all_cuda-129_arch-x86_64.yamlconda/environments/all_cuda-131_arch-aarch64.yamlconda/environments/all_cuda-131_arch-x86_64.yamlconda/recipes/cuopt-server/recipe.yamlconda/recipes/cuopt-sh-client/recipe.yamlconda/recipes/cuopt/recipe.yamlconda/recipes/mps-parser/recipe.yamldependencies.yamldocs/cuopt/source/system-requirements.rstpython/cuopt/cuopt/linear_programming/pyproject.tomlpython/cuopt/pyproject.tomlpython/cuopt_self_hosted/pyproject.tomlpython/cuopt_server/cuopt_server/cuopt_service.pypython/cuopt_server/cuopt_server/utils/process_handler.pypython/cuopt_server/pyproject.tomlpython/libcuopt/pyproject.tomlskills/cuopt-lp-milp-api-python/assets/mps_solver/model.py
| - test-self-hosted-server | ||
| secrets: inherit | ||
| uses: rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@main | ||
| uses: rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@python-3.14 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Resolve the current head SHA for the temporary shared-workflows branch.
# Use the returned SHA in place of `python-3.14` for the refs in this file.
gh api repos/rapidsai/shared-workflows/git/ref/heads/python-3.14 --jq '.object.sha'Repository: NVIDIA/cuopt
Length of output: 216
🏁 Script executed:
# First, check the file structure and size
wc -l .github/workflows/pr.yaml
# Read the entire file to see all the references
cat -n .github/workflows/pr.yamlRepository: NVIDIA/cuopt
Length of output: 21773
Pin all shared-workflows refs to immutable commit SHAs.
This PR uses mutable branch references (@python-3.14) for 15 reusable workflow invocations across the file. Branch refs make CI non-reproducible and leave this workflow brittle if the branch is force-pushed or deleted before a follow-up PR switches to a stable reference. Replace each @python-3.14 ref with a commit SHA.
Also applies to: 114, 282, 288, 295, 311, 318, 335, 348, 360, 371, 380, 396, 408, 420
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/pr.yaml at line 37, The workflow uses mutable branch refs
(e.g. the string "uses:
rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@python-3.14");
replace every instance of the branch ref "@python-3.14" (and any other
branch-style refs) with the corresponding immutable commit SHA for the target
repository/workflow so each "uses: rapidsai/shared-workflows/...@<commit-sha>"
invocation is pinned (apply the same change for all other occurrences of the
same pattern in this file).
There was a problem hiding this comment.
No, we control this reference and it's only temporary anyway.
There was a problem hiding this comment.
@gforsyth, understood! Since you control the upstream rapidsai/shared-workflows repository and the @python-3.14 reference is intentionally temporary (to be reverted to @main once all RAPIDS repos add Python 3.14 support), the mutable branch ref is perfectly reasonable here. I'll take note of this for future reviews.
✏️ Learnings added
Learnt from: gforsyth
Repo: NVIDIA/cuopt PR: 933
File: .github/workflows/pr.yaml:37-37
Timestamp: 2026-03-11T17:18:07.089Z
Learning: In NVIDIA/cuopt PRs that add support for a new Python version (e.g. Python 3.14), the `.github/workflows/pr.yaml` and `.github/workflows/build.yaml` files intentionally use mutable branch references (e.g. `python-3.14`) for `rapidsai/shared-workflows` reusable workflows. This is a temporary, controlled reference as part of a RAPIDS-wide rollout pattern. Do not flag these as needing to be pinned to immutable commit SHAs — they will be reverted to `main` in a follow-up PR once all RAPIDS repositories add support.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
| ``` | ||
|
|
||
| Note: The ``latest`` tag is the latest stable release of cuOpt. If you want to use a specific version, you can use the ``<version>-cuda12.9-py3.13`` or ``<version>-cuda13.0-py3.13`` tag. For example, to use cuOpt 25.10.0, you can use the ``25.10.0-cuda12.9-py3.13`` or ``25.10.0-cuda13.0-py3.13`` tag. Please refer to `cuOpt dockerhub page <https://hub.docker.com/r/nvidia/cuopt/tags>`_ for the list of available tags. | ||
| Note: The ``latest`` tag is the latest stable release of cuOpt. If you want to use a specific version, you can use the ``<version>-cuda12.9-py3.14`` or ``<version>-cuda13.0-py3.14`` tag. For example, to use cuOpt 25.10.0, you can use the ``25.10.0-cuda12.9-py3.13`` or ``25.10.0-cuda13.0-py3.13`` tag. Please refer to `cuOpt dockerhub page <https://hub.docker.com/r/nvidia/cuopt/tags>`_ for the list of available tags. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check the README.md file around line 139 to see the exact content
head -n 145 README.md | tail -n 20Repository: NVIDIA/cuopt
Length of output: 1875
🏁 Script executed:
# Also check the context around line 133-136 to see the full picture of version changes
head -n 145 README.md | tail -n 30Repository: NVIDIA/cuopt
Length of output: 1875
🏁 Script executed:
# Check line 60 as well to understand the Python version support range
sed -n '55,65p' README.mdRepository: NVIDIA/cuopt
Length of output: 1875
Fix link syntax and Python version inconsistency.
Line 139 uses reStructuredText link syntax (`text <url>`_) which renders as literal text in Markdown instead of a hyperlink. Change to [cuOpt dockerhub page](https://hub.docker.com/r/nvidia/cuopt/tags).
Additionally, the note introduces py3.14 tags but the example uses py3.13—update the example to 25.10.0-cuda12.9-py3.14 or 25.10.0-cuda13.0-py3.14 for consistency, or clarify if 25.10.0 is intentionally a pre-3.14 release.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@README.md` at line 139, Replace the reStructuredText link syntax with
Markdown by changing "`cuOpt dockerhub page
<https://hub.docker.com/r/nvidia/cuopt/tags>`_" to "[cuOpt dockerhub
page](https://hub.docker.com/r/nvidia/cuopt/tags)" and fix the Python tag
mismatch in the example by updating "25.10.0-cuda12.9-py3.13" and
"25.10.0-cuda13.0-py3.13" to use "py3.14" (e.g., "25.10.0-cuda12.9-py3.14" or
"25.10.0-cuda13.0-py3.14") so the note about `py3.14` matches the example.
There was a problem hiding this comment.
There is no 25.10 release with Python 3.14 support and there never will be
There was a problem hiding this comment.
@gforsyth, that makes perfect sense — 25.10.0 predates Python 3.14 support, so using py3.13 in that example is entirely correct. I was wrong to flag it as inconsistent. My apologies for the noise!
The only remaining point from my comment would be the reStructuredText link syntax (`cuOpt dockerhub page <https://hub.docker.com/r/nvidia/cuopt/tags>`_) in that same line, which won't render as a hyperlink in Markdown — but that's a pre-existing issue, not introduced by this PR, so feel free to ignore it here.
(ᴗ_ ᴗ。)
✏️ Learnings added
Learnt from: gforsyth
Repo: NVIDIA/cuopt PR: 933
File: README.md:139-139
Timestamp: 2026-03-11T17:19:28.053Z
Learning: In NVIDIA/cuopt README.md, the versioned example container tags (e.g., `25.10.0-cuda12.9-py3.13`) are intentionally pinned to the Python version that was supported at the time of that release. Do not flag these as inconsistent when a newer Python version (e.g., py3.14) is added to the `latest` tag examples — older release tags correctly reflect the Python versions available at release time.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: gforsyth
Repo: NVIDIA/cuopt PR: 933
File: .github/workflows/pr.yaml:37-37
Timestamp: 2026-03-11T17:18:07.089Z
Learning: In NVIDIA/cuopt PRs that add support for a new Python version (e.g. Python 3.14), the `.github/workflows/pr.yaml` and `.github/workflows/build.yaml` files intentionally use mutable branch references (e.g. `python-3.14`) for `rapidsai/shared-workflows` reusable workflows. This is a temporary, controlled reference as part of a RAPIDS-wide rollout pattern. Do not flag these as needing to be pinned to immutable commit SHAs — they will be reverted to `main` in a follow-up PR once all RAPIDS repositories add support.
Learnt from: gforsyth
Repo: NVIDIA/cuopt PR: 809
File: python/libcuopt/pyproject.toml:20-20
Timestamp: 2026-01-29T15:24:25.013Z
Learning: In Python packaging, `requires-python` in pyproject.toml should generally only specify a minimum version (e.g., `requires-python = ">=3.11"`), not an upper bound. Setting upper bounds goes against Python packaging best practices and can cause dependency resolution issues. Use the classifiers field to document tested/supported Python versions instead.
jameslamb
left a comment
There was a problem hiding this comment.
Changes look great to me!
I left very very minor comments, would be fine to merge this if you get other approvals, don't let any of them hold you up.
| ) | ||
| parser.add_argument( | ||
| "--compare", action="store_true", help="Compare 1% vs 0.1% gap" | ||
| "--compare", action="store_true", help="Compare 1%% vs 0.1%% gap" |
There was a problem hiding this comment.
Oh wow, I didn't realize that argparse had format specifiers like this. Just read about them at https://docs.python.org/3/library/argparse.html
Ok yeah makes sense.
| ### Python requirements | ||
|
|
||
| * Python >=3.11, <=3.13 | ||
| * Python >=3.11, <=3.14 |
There was a problem hiding this comment.
@tmckayus @rgsl888prabhu can we replace stuff like this with links to the RAPIDS install selector?
https://docs.rapids.ai/install/
Or is there a specific reason that these need to be hard-coded entries?
This type of stuff is a bit of a pain to update when we change the support matrix for RAPIDS.
There was a problem hiding this comment.
I think selector would be an awesome upgrade, we can work this.
| ### Python requirements | ||
|
|
||
| * Python >=3.11, <=3.13 | ||
| * Python >=3.11, <=3.14 |
There was a problem hiding this comment.
I think selector would be an awesome upgrade, we can work this.
|
/merge |
Description
Contributes to rapidsai/build-planning#205
This PR adds support for Python 3.14.
Notes for Reviewers
This is part of ongoing work to add Python 3.14 support across RAPIDS.
It temporarily introduces a build/test matrix including Python 3.14, from rapidsai/shared-workflows#508.
A follow-up PR will revert back to pointing at the
mainbranch ofshared-workflowsonce allRAPIDS repos have added Python 3.14 support.
This will fail until all dependencies have been updated to Python 3.14
CI here is expected to fail until all of this project's upstream dependencies support Python 3.14.
This can be merged whenever all CI jobs are passing.