Skip to content

Add Python 3.13 support - #3465

Open
bochinski wants to merge 5 commits into
flyteorg:masterfrom
bochinski:feat/python-3.13-3.14-support
Open

Add Python 3.13 support#3465
bochinski wants to merge 5 commits into
flyteorg:masterfrom
bochinski:feat/python-3.13-3.14-support

Conversation

@bochinski

@bochinski bochinski commented Sep 3, 2026

Copy link
Copy Markdown

Tracking issue

Closes flyteorg/flyte#6993

Why are the changes needed?

flytekit declares requires-python = ">=3.10,<3.13" and cannot be installed on Python 3.13. This PR adds 3.13 to the supported and tested versions. Python 3.14 is out of scope: flyteidl declares requires-python <3.14, so flytekit cannot be installed on 3.14 regardless of this repo.

What changes were proposed in this pull request?

  • pyproject.toml: requires-python = ">=3.10,<3.14", 3.13 classifier. uv.lock regenerated (not used by CI); the lock was also behind pyproject.toml on master, so the diff additionally catches up flyteidl 1.16.4 -> 1.16.8 and the fsspec/gcsfs/s3fs bounds.
  • PythonVersion enum and default image prefixes: add 3.13 (core, sqlalchemy and openai-batch images). Without it DefaultImages.find_image_for() raises ValueError on 3.13.
  • CI: PRs run 3.13 only (a single version, as before with 3.12), nightly runs 3.10–3.13. On 3.13 pandas<2 is excluded (no wheels). The plugin matrix mirrors the 3.12 exclusions (not verified on 3.13; several of the underlying issues are closed by now) and adds duckdb (python_requires<3.13); mlflow stays excluded because its tests need tensorflow, which on 3.13 requires protobuf 5+. flytekit-onnx-scikitlearn failed on 3.13 in the first CI run (its onnx<1.18 pin has no 3.13 wheels) and is fixed by the last bullet instead of being excluded.
  • dev-requirements.in: tensorflow on >=3.12 and torch on >=3.11, and the 3.12 skip of the extras job is removed (Support Python 3.12 tensorflow/tensorflow#62003 and Pytorch for Python 3.12 not available pytorch/pytorch#110436 are closed). protobuf<5 (and types-protobuf<5) is kept on <3.13 only: tensorflow releases with 3.13 wheels need protobuf 5+, and the reason for the pin ([Housekeeping] Add support for protobuf version 5 in flytekit flyte#5448) was fixed upstream. 3.10 and 3.11 resolve to the same versions as before. On 3.12 every job that installs this file now also gets tensorflow 2.19 and torch 2.14 (with CUDA wheels on linux), and numpy is capped to 2.1.x by tensorflow 2.19.
  • Publish py3.13-* images.
  • pytorch extras: torch.load(..., weights_only=False) for nn.Module and checkpoint objects, where the keyword exists. The default flipped to True in torch 2.6 and cannot unpickle those (this is also the current nightly 3.11 failure on master). Tensors keep torch's default. weights_only=False executes pickle code from the blob, the same trust model as FlytePickle.
  • flytekit.lazy_import.lazy_module: for a dotted name, importlib.util.find_spec imports the parent packages, and if a parent's __init__ imports the requested module itself, lazy_module replaced that module with a lazy placeholder and it got executed a second time, producing a second set of class objects. skl2onnx>=1.19 does exactly that with skl2onnx.common.data_types, which is why flytekit-onnx-scikitlearn got the caps onnx<1.18 / skl2onnx<1.19 in [CI] Fix plugin errors #3257 ("shape must be a DataType"). The fix re-checks sys.modules after find_spec; a regression test covers it. The same duplication affected the spark, sqlalchemy and polars plugins (pyspark.sql.dataframe, pandas.io.sql, fsspec.utils) without a visible failure. With the fix the plugin's two caps are removed (they were coupled: skl2onnx 1.18 imports helpers that onnx 1.18 removed) and the plugin requires flytekit>=1.16.29 (assumed to be the next release, the first one containing the fix), so upgrading the plugin alone cannot pair a new skl2onnx with a flytekit that lacks the fix.

How was this patch tested?

Locally on Linux x86_64 with uv and docker.

  • 3.13: make unit_test 1970 + 25 passed, make test_serialization 78411 passed, make unit_test_extras 128 passed (tensorflow 2.21 / torch 2.14 / protobuf 7).
  • 3.12: make unit_test and make unit_test_extras pass (tensorflow 2.19 / torch 2.14 / protobuf 4.25).
  • dev-requirements.in resolves for 3.10–3.13 on linux and 3.12/3.13 on windows and macos; every plugin dry-run resolves on 3.13 except mlflow and duckdb.
  • flytekit-onnx-scikitlearn: the build-plugins job replayed locally (same install steps, including the forced numpy<2) passes on 3.12 and 3.13 with onnx 1.22 / skl2onnx 1.20 and with the previously pinned onnx 1.17 / skl2onnx 1.18. The new lazy_module test fails on master and passes with the fix.
  • First CI run on the PR: 54 of 56 checks passed; the two failures were the onnx-scikitlearn plugin job on 3.13 (fixed above) and integration (3.13) on test_signal_approve_reject, a signal-timing flake unrelated to this PR (the same job passes on master; Bump timeout in integration tests to 10 minutes #3146 documents the flakiness).

Check all the applicable boxes

  • I updated the documentation accordingly. (no docs mention supported versions)
  • All new and existing tests passed.
  • All commits are signed-off.

Related PRs

Supersedes #3401 and #3368.

🤖 Generated with Claude Code

@bochinski
bochinski marked this pull request as draft September 3, 2026 16:26
@bochinski
bochinski force-pushed the feat/python-3.13-3.14-support branch from 1310769 to 564041e Compare September 3, 2026 16:35
@bochinski bochinski changed the title Add Python 3.13 support (and unblock 3.14) Add Python 3.13 support Sep 3, 2026
- pyproject.toml: requires-python ">=3.10,<3.14", add the 3.13 classifier;
  regenerate uv.lock accordingly.
- PythonVersion enum and default image prefixes: add 3.13 in flytekit
  core, the sqlalchemy plugin and the openai batch plugin. Without it,
  DefaultImages.find_image_for() raises "(3, 13) is not a valid
  PythonVersion" on 3.13.
- CI (pythonbuild.yml): run 3.13 on pull requests and in the nightly
  matrix, enable the extras (tensorflow/pytorch) tests on 3.13, exclude
  pandas<2 and plugins whose dependencies do not support 3.13 yet.
- dev-requirements.in: tensorflow>=2.21 and torch>=2.6 on 3.13; lift the
  protobuf<5 dev pin on 3.13 only (tensorflow 2.21 needs protobuf>=6, and
  the issue behind the pin, flyteorg/flyte#5448, was fixed upstream).
- Publish py3.13 images in pythonpublish.yml and build_image.yml.
- pytorch extras: torch>=2.6 defaults torch.load(weights_only=True), which
  cannot load the whole nn.Module / checkpoint objects flytekit stores.
  Pass weights_only=False where the keyword exists. This is required for
  the extras tests on 3.13 and already fails in the nightly 3.11 run.

Closes flyteorg/flyte#6993

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: bochinski <30434375+bochinski@users.noreply.github.com>
@bochinski
bochinski force-pushed the feat/python-3.13-3.14-support branch from 564041e to 605e0b1 Compare September 3, 2026 16:52
bochinski and others added 3 commits September 3, 2026 20:23
The tensorflow and pytorch transformer tests were skipped on 3.12 because
neither library had 3.12 wheels when 3.12 support was added. Both upstream
issues have been closed since: tensorflow ships 3.12 wheels from 2.16
(tensorflow/tensorflow#62003) and pytorch from 2.2
(pytorch/pytorch#110436).

- dev-requirements.in: install tensorflow on >=3.12 and torch on >=3.11
  with a single line each instead of per-version lines. With the
  protobuf<5 pin that is kept on <3.13, 3.12 resolves to tensorflow 2.19
  and 3.13 to the latest release.
- pythonbuild.yml: drop the 3.12 skip of the extras step.

Effect on the resolved dev environments: 3.10, 3.11 and 3.13 are
unchanged. On 3.12 every job that installs dev-requirements.in now also
gets tensorflow 2.19 and torch 2.14 (including the CUDA wheels torch pulls
in on linux), and numpy is capped to 2.1.x by tensorflow 2.19.

Verified locally on 3.12 with tensorflow 2.19.1 / torch 2.14.0 /
protobuf 4.25.9: unit_test_extras 123 passed, unit_test 1970 + 25 passed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: bochinski <30434375+bochinski@users.noreply.github.com>
Commit 605e0b1 passed weights_only=False to torch.load for every
pytorch transformer. Plain tensors load fine under torch's default
(weights_only=True since torch 2.6), so there is no reason to give up the
restricted unpickler for them. Only whole nn.Module objects and checkpoint
dicts, whose hyperparameters can be arbitrary objects, need full
unpickling.

- native.py: rename the helper to load_torch_object and give it a
  weights_only parameter; None keeps torch's default. The base transformer
  carries a WEIGHTS_ONLY class attribute (None), the module transformer
  sets it to False. The docstring states that weights_only=False executes
  pickle code from the blob, with the same trust model as FlytePickle.
- checkpoint.py: call load_torch_object(..., weights_only=False).
- tests: cover the keyword handling (default, explicit, and torch<1.13
  without the keyword), the per-transformer setting, and a module round
  trip through the full unpickler.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: bochinski <30434375+bochinski@users.noreply.github.com>
- Pull requests run a single interpreter version again (the convention
  since flyteorg#3380), now 3.13 instead of 3.12. The nightly matrix still covers
  3.10 to 3.13. This halves the pull request matrix and keeps the heavier
  3.12 dev environment (tensorflow/torch) out of pull request runs.
- Reword the comment on the 3.13 plugin exclusions: they mirror the 3.12
  list but have not been verified on 3.13, several of the underlying
  issues are closed by now.
- The tensorflow releases with 3.13 wheels require protobuf>=5, not >=6
  (2.20 needs 5.28, 2.21 needs 6.31).
- dev-requirements.in: give types-protobuf the same version split as
  protobuf, so the stubs match the runtime on 3.13.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: bochinski <30434375+bochinski@users.noreply.github.com>
@bochinski
bochinski force-pushed the feat/python-3.13-3.14-support branch from 51bac2f to 750bea8 Compare September 3, 2026 18:35
@bochinski
bochinski marked this pull request as ready for review September 3, 2026 18:47
lazy_module() checks sys.modules before importlib.util.find_spec(), but
for a dotted name find_spec() imports the parent packages, and a parent's
__init__ may import the requested module itself. lazy_module() then
overwrote that real module in sys.modules with a LazyLoader placeholder,
so the module was executed a second time on first use and produced a
second set of class objects.

skl2onnx>=1.19 imports skl2onnx.common.data_types from its own __init__,
which made flytekitplugins-onnxscikitlearn fail with "shape must be a
DataType": the FloatTensorType the user passes in came from the second
execution, the DataType skl2onnx checks against from the first. The same
duplication affected other plugins that lazy-load a submodule the parent
imports (pyspark.sql.dataframe, pandas.io.sql, fsspec.utils), just
without a visible failure.

- lazy_module: re-check sys.modules after find_spec() and return the
  module the parent import created.
- flytekit-onnx-scikitlearn: drop the onnx<1.18 and skl2onnx<1.19 caps
  from flyteorg#3257. They were coupled (skl2onnx 1.18 imports helpers that onnx
  1.18 removed) and onnx<1.18 has no Python 3.13 wheels, which broke the
  plugin job on 3.13. Require flytekit>=1.16.29, the first release with
  this fix, so an upgrade of the plugin alone cannot combine a new
  skl2onnx with an old flytekit.
- Regression test with a temporary package whose __init__ imports the
  lazily requested submodule.

Verified by replaying the build-plugins job for the plugin on 3.12 and
3.13 with onnx 1.22 / skl2onnx 1.20 and with the previously pinned onnx
1.17 / skl2onnx 1.18: all pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: bochinski <30434375+bochinski@users.noreply.github.com>
@bochinski

Copy link
Copy Markdown
Author

CI finished with two failures, so one more commit went in:

  • build-plugins (3.13, flytekit-onnx-scikitlearn) failed because the plugin's onnx<1.18 pin has no 3.13 wheels. The root cause of that pin turned out to be a bug in flytekit.lazy_import.lazy_module: a lazily requested submodule that the parent package already imports got executed twice, which broke the plugin with skl2onnx>=1.19. The last commit fixes lazy_module (5 lines plus a regression test), removes the plugin's onnx/skl2onnx caps and gives it a flytekit>=1.16.29 lower bound. Details are in the commit message and the updated description.
  • integration (3.13) failed on test_signal_approve_reject with a signal timeout; the same job passes on master and the test is a known flake (Bump timeout in integration tests to 10 minutes #3146). A re-run should be enough.

One thing I cannot decide: the flytekit>=1.16.29 bound is a guess and assumes the next release is the first one containing the fix. If the next version will be numbered differently, please tell me and I'll adjust it.

Happy to split the lazy_module fix into its own PR if you prefer that scope. In that case this PR would exclude flytekit-onnx-scikitlearn from the 3.13 plugin matrix, and the follow-up PR would carry the fix and re-enable the plugin.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Python 3.13 support to Flytekit

2 participants