Skip to content

Multi-version Python support (3.12 / 3.13 / 3.14)#6577

Merged
FeodorFitsner merged 11 commits into
flet-0.86from
multi-python
Jun 11, 2026
Merged

Multi-version Python support (3.12 / 3.13 / 3.14)#6577
FeodorFitsner merged 11 commits into
flet-0.86from
multi-python

Conversation

@FeodorFitsner

@FeodorFitsner FeodorFitsner commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Description

Adds multi-version bundled CPython support to flet build and flet publish. Users pick which interpreter ships with their app via a new --python-version flag (3.12 / 3.13 / 3.14) or via [project].requires-python in their pyproject.toml; the default is the latest supported stable (currently 3.14). Pyodide is no longer pre-baked into the build template — the matching release for each Python version is downloaded into the build output and cached under ~/.flet/pyodide/<version>/ per build.

Companion to flet-dev/serious-python#207 (the 2.0.0 release where the platform plugins and packager learned to parameterize the bundled Python version). The build template here pins serious_python: 2.0.0, so this branch should land after serious_python 2.0.0 publishes to pub.dev.

Highlights

  • New registry + resolver: flet_cli/utils/python_versions.py — single source of truth for Python ↔ CPython-standalone ↔ Pyodide ↔ wheel-platform-tag. prerelease: True rows are opt-in (skipped in open-ended requires-python resolution; reachable via explicit --python-version 3.15 / ==3.15.*).
  • build_base.py plumbing: resolves once in initialize_command, threads --python-version + SERIOUS_PYTHON_VERSION into both the serious_python package step and the later flutter build, and exposes the resolved short version to the cookiecutter template as cookiecutter.options.python_version so the Android abiFilters can drop armeabi-v7a for 3.13+ (PEP 738).
  • Pyodide download + caching: flet_cli/utils/pyodide.py fetches pyodide-core-<version>.tar.bz2 + micropip / packaging wheels into a per-version cache, idempotent.
  • patch_index.py: injects flet.pyodideUrl per build (CDN or local pyodide/pyodide.js); the hardcoded defaultPyodideUrl constant is removed from both client/web/python.js and the build template python.js. Pre-baked pyodide bundle deleted from the build template.
  • flet --version: lists supported Python versions (newest first) instead of a single static Pyodide line — the global flet.version.pyodide_version export is removed.
  • Docs: "Choosing a Python version" section on the publish guide, Pyodide / Python pairing table on the static-website page, --pre vs --python-version clarification on flet publish.
  • CI: flet-build-test now runs against the full 3.12 / 3.13 / 3.14 grid (14 build targets × 3 versions = 42 jobs), grouped via a reusable workflow so the Actions UI shows three cards instead of a flat 42-row list. workflow_dispatch gains a python_version choice input (all / 3.12 / 3.13 / 3.14) for targeted manual runs.
  • Bugfix: dev-package file:// URLs on Windows now use `Path.as_uri()` so paths render as file:///D:/... instead of being misparsed as UNC.

Type of change

  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue) — Windows dev-install file:// URL
  • Breaking change
  • This change requires a documentation update — included

Checklist

  • I signed the CLA.
  • I have performed a self-review of my own code.
  • My code follows the style guidelines of this project.
  • I have commented my code, particularly in hard-to-understand areas.
  • My changes generate no new warnings.
  • New and existing tests pass locally with my changes. (CI matrix in Multi-version Python support (3.12 / 3.13 / 3.14) serious-python#207 covers the platform plugin side.)
  • I have made corresponding documentation changes, if applicable.
  • I have added changelog entries for user-facing changes, if applicable.
  • I have updated release guide pages and website/sidebars.yml for breaking changes, removals, and deprecations, if applicable. (Not breaking from end-user perspective; existing builds keep working with --python-version 3.12 if pinned.)

Additional details

Release sequencing: this branch's build template pins serious_python: 2.0.0. Don't merge until serious_python 2.0.0 is live on pub.dev (flet-dev/serious-python#207).

🤖 Generated with Claude Code

Summary by Sourcery

Add configurable bundled Python version support to Flet builds and publishes, wiring version resolution through the CLI, web runtime, templates, and CI, and switch Pyodide to a per-version, cached download instead of a baked-in bundle.

New Features:

  • Allow flet build and flet publish to select the bundled Python interpreter via a new --python-version flag or project.requires-python, with 3.12, 3.13, and 3.14 supported.
  • Introduce a centralized Python version registry that maps supported CPython releases to their corresponding Pyodide versions and wheel platform tags.
  • Emit a detailed supported-Python-versions listing from flet --version, including which version is the default and associated Pyodide releases.

Bug Fixes:

  • Fix dev-package file:// URLs on Windows by using Path.as_uri() so pip resolves drive-letter paths correctly instead of treating them as UNC paths.

Enhancements:

  • Parameterize serious_python and Flutter build steps with the resolved Python version, exposing it to templates so Android ABIs match the selected runtime and PEP 738 constraints.
  • Refine the web runtime so each build injects a Python-version-specific Pyodide CDN or local URL, removing hardcoded Pyodide defaults from the client and templates.
  • Download and cache per-version Pyodide runtimes (including required wheels) under a shared cache directory, copying them into each web build or publish output as needed.

Build:

  • Refactor the flet-build-test workflow into a reusable matrix workflow invoked once per supported Python version, and add a workflow_dispatch input to target specific Python versions while preserving full matrix coverage by default.

CI:

  • Expand the build CI matrix to cover all supported bundled Python versions across platforms, grouping jobs by Python version for clearer visibility in GitHub Actions.

Documentation:

  • Document how to choose the bundled Python version, including the CPython/Pyodide compatibility matrix, and clarify the distinction between --pre and --python-version in the publish docs.
  • Update web publishing docs to describe how Python version selection affects Pyodide, and adjust examples and comparison tables to reference the new default Python requirement.

FeodorFitsner and others added 9 commits May 31, 2026 12:02
Delete generated web/canvaskit build artifacts from sdk/python/templates/build/{{cookiecutter.out_dir}} (canvaskit.js, .symbols, .wasm and chromium/skwasm variants). These are built/WebAssembly output files and have been removed from the template to avoid committing generated binaries and reduce repository/template size.
Add a `python_versions` registry that maps each supported short Python
version to its CPython-standalone build, Pyodide release, and Emscripten
wheel platform tag. `flet build` and `flet publish` resolve the version
in this order: `--python-version X.Y` (new flag) -> `[project].requires-
python` (highest matching stable; pre-release rows are skipped unless an
explicit specifier like `==3.15.*` opts in) -> default `3.14`.

`build_base.py` threads the resolved version through to serious_python
(via `--python-version` and `SERIOUS_PYTHON_VERSION`) and the Flutter
build env, and exposes it to the cookiecutter template as
`cookiecutter.options.python_version` so the Android `abiFilters` can
drop `armeabi-v7a` for 3.13+ (PEP 738 dropped 32-bit Android in
python-build releases).

Pyodide is no longer pre-baked into the build template. On each web
build/publish, the matching pyodide-core tarball plus the micropip /
packaging wheels are downloaded into the build output and cached under
`~/.flet/pyodide/<version>/`. `client/web/python.js` and the templated
`python.js` drop the hardcoded `defaultPyodideUrl`; `patch_index.py`
injects `flet.pyodideUrl` at build time (CDN for normal builds, local
`pyodide/pyodide.js` when `--no-cdn`).

Other:

* Bump the `serious_python` pin in the build template to 2.0.0
  (multi-version support landed there as a breaking release; pin must
  follow once 2.0.0 is published to pub.dev).
* Add `python_version`-aware section to the publish docs ("Choosing a
  Python version"), Pyodide pairing table on the static-website page,
  and a `--pre` clarification on `flet publish`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…odide

With multi-version Python, Pyodide is selected per build from
`SUPPORTED_PYTHON_VERSIONS` (currently 0.27.7 / 0.29.4 / 314.0.0a2 for
Python 3.12 / 3.13 / 3.14). The old single-line `Pyodide: 0.27.7` field
on `flet.version` was both stale and misleading once it stopped tracking
what `flet build` actually bundles.

Replace it with a multi-line listing rendered from the registry:

    Flet: 0.85.3
    Flutter: 3.41.7
    Supported Python versions:
      3.12 (Pyodide 0.27.7)
      3.13 (Pyodide 0.29.4)
      3.14 (Pyodide 314.0.0a2, default)

Pre-release rows render with ", pre-release" appended. `PYODIDE_VERSION`
and the `pyodide_version` export on `flet.version` are removed (the only
external consumer was the CLI version output, now updated).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings in build template + Windows runner fixes (#6558, #6559, #6561,
#6562) and the 0.85.3 changelog entry. Conflict in
`sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml`
resolved by keeping multi-python's `serious_python: 2.0.0` pin.
Sort SUPPORTED_PYTHON_VERSIONS by `packaging.version.Version(r.short)`
in reverse before rendering, so users see the default (newest stable) at
the top instead of having to scan to the bottom of the list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`flet build` rewrites local-path dev dependencies as `<pkg> @
file://<path>` so pip installs them in place. On Windows the literal
f"file://{dev_path}" rendered `file://D:\a\...\flet`, which pip parsed
as a UNC path (`\\D:\a\...`) and failed with:

  ERROR: Could not install packages due to an OSError: [Errno 2]
  No such file or directory: '\\\\D:\\a\\flet\\flet\\sdk\\python\\packages\\flet'

`Path.as_uri()` produces the correct three-slash form
(`file:///D:/a/flet/...` on Windows, `file:///Users/...` on POSIX) and
URL-encodes any special characters, so it's safe on every platform.

Surfaces on flet's own apk-windows CI job
(flet-dev/flet#27111512526 job 80010220246).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each of the 14 build targets (linux/macos/windows + Android aab+apk on
all three hosts + ipa + ios-simulator + web on all three hosts) now runs
against every supported bundled CPython, producing 42 jobs total.

Matrix gains a `python_version` scalar axis and promotes `name` from an
`include` row to a base axis so GH Actions takes the cartesian product;
the existing `include` entries are kept as-is and matched by `name` to
supply per-target runner / build_cmd / artifact_path. The build step now
passes `--python-version ${{ matrix.python_version }}` to `flet build`,
and the upload step disambiguates the artifact name with a `-pyX.Y`
suffix so the 42 uploads don't collide.

`fail-fast: false` is unchanged so a single failing combo doesn't kill
the rest of the grid.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Split the 14-target build matrix into a reusable workflow
(`flet-build-test-matrix.yml`) that takes the bundled Python version as
an input, and call it three times from the entrypoint — once per
supported CPython release. The Actions UI now renders each call as its
own collapsible "Matrix: build" card (`0/14 jobs completed`) instead of
a single flat 42-row list.

Adds a `python_version` choice input to `workflow_dispatch` (`all` |
`3.12` | `3.13` | `3.14`) so manual runs can target a single version.
push and pull_request triggers always fire all three. Each call is
gated by `if: github.event_name != 'workflow_dispatch' || inputs.python_version == 'all' || inputs.python_version == 'X.Y'`.

The pack job stays at the top level (its host-Python PyInstaller bundle
is independent of the bundled CPython that `flet build` ships, so it
doesn't need a per-Python axis). path-filter triggers now reference
both workflow files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

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.

We've reviewed this pull request using the Sourcery rules engine

FeodorFitsner and others added 2 commits June 11, 2026 13:35
Bumps the Dart-side `flet` package to 0.86.0 and adds the user-facing
0.86.0 entry to the top-level changelog: new `--python-version` flag,
per-version Pyodide download/cache, `flet --version` listing change,
the default-3.14 breaking note, removal of `flet.version.pyodide_version`,
and the Windows `file://` dev-package URL fix. The Dart `flet` package
gets the usual italic release-coordination note since this branch
doesn't touch the Dart side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match the same descending order applied to `flet --version` so users see
the default (3.14) at the top of every supported-Python table instead of
having to scan to the bottom of the list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FeodorFitsner FeodorFitsner merged commit 59d9f23 into flet-0.86 Jun 11, 2026
54 of 73 checks passed
@FeodorFitsner FeodorFitsner deleted the multi-python branch June 11, 2026 21:21
ndonkoHenri added a commit that referenced this pull request Jun 11, 2026
The multi-version Python PR (#6577) removed flet.version.pyodide_version
but the 'Get Pyodide version' step still read it, failing every
'Build Flet Client for Web' run. Resolve the version from the
flet_cli.utils.python_versions registry instead (default release's
Pyodide), and replace the hand-rolled tarball + wheel downloads with
flet_cli.utils.pyodide.ensure_pyodide — the hardcoded
micropip-0.8.0/packaging-24.2 filenames would have silently broken on
the new Pyodide line (3.14's lock resolves micropip 0.11.1), since
curl without -f writes 404 pages into the .whl files.
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.

1 participant