Skip to content

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

Open
FeodorFitsner wants to merge 9 commits into
mainfrom
multi-python
Open

Multi-version Python support (3.12 / 3.13 / 3.14)#207
FeodorFitsner wants to merge 9 commits into
mainfrom
multi-python

Conversation

@FeodorFitsner
Copy link
Copy Markdown
Contributor

Summary

  • Add a _pythonReleases registry mapping each supported short Python version to its CPython-standalone build, Pyodide release, Pyodide wheel platform tag, and a prerelease flag. Defaults to the latest supported stable (3.14).
  • The package command gains --python-version X.Y (also reads SERIOUS_PYTHON_VERSION env var). The Emscripten wheel platform tag is now derived per release instead of hardcoded.
  • Each platform plugin (android/build.gradle, darwin/*.podspec, linux/CMakeLists.txt + plugin .cc, windows/CMakeLists.txt) reads SERIOUS_PYTHON_VERSION so the flet-dev/python-build download URL, bundled library filenames, and runtime module path all track the selected version.
  • serious_python_android.dart replaces the hardcoded libpython3.12.so constant with a runtime scan of nativeLibraryDir for libpython3.*.so, removing Dart-side version coupling.
  • sitecustomize.py adds an android_ver shim so newer pip / packaging can compute Android wheel tags on any host (Python 3.13+ added the API; Python 3.12 didn't have it; even on 3.13+ hosts it returns 0 for api_level off-device).
  • Android abiFilters and the per-arch pip-install loop drop armeabi-v7a / x86 on Python 3.13+ (PEP 738 — no 32-bit Android builds in python-build v3.13+ releases).

Breaking changes (2.0.0)

  • Default Python is now 3.14 when --python-version and SERIOUS_PYTHON_VERSION are both omitted (was implicitly 3.12). Pin with --python-version 3.12 to preserve the old behavior.
  • Android sysconfig.get_platform() tag changes from android-24-arm64-v8a to android-24-arm64_v8a (and similarly for armeabi-v7a). The wheel tag emitted by pip (android_24_arm64_v8a) is unchanged.
  • Windows arch identifier drops the -shared suffix to match what astral-sh/python-build-standalone still publishes (which is already the shared build).

CI

ci.yml now runs the full matrix: each platform job (macOS / iOS / Android / Windows / Linux) across python_version: [3.12, 3.13, 3.14] with fail-fast: false. Linux keeps its existing arch: [arm64, amd64] matrix as an orthogonal dimension. The example app prints the bundled runtime version (Python version: X.Y.Z), and the integration test asserts it matches EXPECTED_PYTHON_VERSION (passed via --dart-define per matrix entry).

Adjacent

  • Includes commit 9835923 (unpin numpy in run_example, refresh app.zip.hash).

Test plan

  • All 18 matrix combinations green on multi-python (see linked CI run).
  • Local sanity: dart run serious_python:main package app/src --platform Android --python-version 3.14 -r flet==0.28.3 installs only arm64-v8a + x86_64 site-packages.
  • Local sanity: same with --python-version 3.12 installs all four ABIs.
  • After merge: publish serious_python 2.0.0 to pub.dev before the matching flet branch lands (flet's build template pins serious_python: 2.0.0).

🤖 Generated with Claude Code

FeodorFitsner and others added 9 commits June 5, 2026 17:12
`package_command.dart` gains a `--python-version` option (with
`SERIOUS_PYTHON_VERSION` env-var fallback) driving a new `_pythonReleases`
table that maps each short version to its CPython-standalone build, Pyodide
release, and Pyodide wheel platform tag. The Emscripten `pip install
--platform` tag is now resolved from the chosen release rather than the
static `platforms` map.

Each platform plugin (`android/build.gradle`, `darwin/*.podspec`,
`linux/CMakeLists.txt` + plugin `.cc`, `windows/CMakeLists.txt`) reads
`SERIOUS_PYTHON_VERSION` (default `3.14`) so `flet-dev/python-build`
downloads, library filenames, and runtime module paths track the selected
version. The Android Dart runtime now scans `nativeLibraryDir` for
`libpython3.*.so` instead of hardcoding `libpython3.12.so`, removing version
coupling from the Dart side entirely.

CI: each platform job (macOS / iOS / Android / Windows / Linux) now runs
across the full `[3.12, 3.13, 3.14]` Python matrix with `fail-fast: false`.

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

Two regressions surfaced by the wider Python matrix on the newer
python-build-standalone (20260602) and the newer pip vendored packaging
that ships with it:

* Windows: astral-sh dropped the explicit `-shared` MSVC build; only the
  combined `x86_64-pc-windows-msvc-install_only_stripped` variant remains
  (which is itself shared). Drop the `-shared` suffix from the constructed
  archive name.

* Android: packaging.tags.android_platforms now calls
  `platform.android_ver().api_level` (3.13+ API, returns 0 on non-Android
  hosts even where present), and derives the wheel ABI from
  `sysconfig.get_platform().split("-")[-1]`. Shim `platform.android_ver` in
  sitecustomize.py to return a namedtuple with the api_level encoded in the
  custom tag, and switch the Android platform tags from
  `android-24-arm64-v8a` to `android-24-arm64_v8a` so the split-by-dash gives
  the full ABI string. The wheel tag emitted by both old and new packaging
  remains `android_24_arm64_v8a`, matching the wheels on pypi.flet.dev.

The example app now prints/displays the runtime CPython version, and the
integration test verifies it matches `--dart-define=EXPECTED_PYTHON_VERSION`
(passed per matrix entry from CI). The assertion is skipped when the define
is empty, so local runs are unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`flet-dev/python-build` stopped publishing the 32-bit
`python-android-dart-<ver>-armeabi-v7a.tar.gz` tarball for Python 3.13+
(64-bit only), so the gradle download task that's driven by abiFilters
fails for those versions. Keep all three ABIs on 3.12, restrict to
arm64-v8a + x86_64 from 3.13 onward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
python-build dropped 32-bit Android (armeabi-v7a, x86) in 3.13 (PEP 738),
and the serious_python_android plugin already restricts abiFilters
accordingly. Without a matching guard in the package command, the pip
install loop still iterates the 32-bit ABIs and produces site-packages
trees that the Flutter build then ignores — pure wasted work. Skip those
arches when --python-version is anything other than 3.12.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the strict numpy==1.26.4 pin with an unpinned 'numpy' in run_example requirements to allow flexible numpy versions. Also update the flet_example app.zip.hash to the new checksum matching the updated packaged app.
The default Python version bumped from 3.12 to 3.14 (latest stable) — a
breaking change for any caller of `dart run serious_python:main package`
that omits `--python-version`. Bump all six pub packages to 2.0.0 and call
this out in the CHANGELOGs alongside the other breaking surfaces
(Android `sysconfig.get_platform()` separator, Windows arch identifier).

`_pythonReleases` entries gain a required `prerelease` field. The Dart
side keeps the version-print line honest by appending " — pre-release"
when applicable; the Flet CLI mirrors the field in its `PythonRelease`
dataclass and gates `requires-python` resolution: stable rows win,
prereleases are a fallback so explicit specifiers like `==3.15.*` (and
`>=3.15` when no stable matches) still opt in without exposing a CLI flag
or making the default jump to a beta line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1.0.1 was prepared on `release-1.0.1` but never published, so the
PIP_REQUIRE_VIRTUALENV=false fix should ship as part of 2.0.0 rather
than as its own release header.

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

* All six pubspec.yaml files: keep multi-python's 2.0.0 bump
  (supersedes main's 1.0.1 prep). build.gradle and podspec version
  labels follow suit.
* All six CHANGELOG.md files: keep multi-python's 2.0.0 entry, then
  restore main's 1.0.1 entry as its own released section between 2.0.0
  and 1.0.0 (1.0.1 has now actually been cut on main, so the prior
  "fold into 2.0.0" rationale no longer applies). Dropped the duplicated
  PIP_REQUIRE_VIRTUALENV bullet from each 2.0.0 entry since 1.0.1 below
  records it under "Bug fixes".
* serious_python_android/android/build.gradle: auto-merged cleanly —
  keeps multi-python's `python_version` parameterization and
  conditional `abiFilters`, picks up main's persistent Python tarball
  cache (`onlyIfModified`, `useETag`, `tempAndMove`) and the
  `pythonCacheDir` path now using the resolved `python_version`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Targeted documentation pass after the 1.0.0 (Pyodide -> Emscripten) and
2.0.0 (multi-version Python) releases:

* Fix `environmnent` typo and iOS Podfile target (`12.0` -> `13.0` to
  match the podspec).
* Platform list under `-p {platform}`: `macOS` -> `Darwin` to match the
  `allowed:` constant in `package_command.dart`.
* Rewrite both `--requirements` examples to the modern
  `-r DEP_1 -r DEP_2` / `-r -r -r requirements.txt` syntax with a
  callout that the comma-separated form was removed in 0.9.2 (so
  specifiers like `pandas>=2.2,<3` work).
* New `Selecting a Python version` subsection covering
  `--python-version`, `SERIOUS_PYTHON_VERSION`, and the fact that a
  single env-var export covers both the package phase and the later
  `flutter build` phase.
* Expand the Python versions section with the default-3.14 rule and
  document how a future pre-release CPython line (e.g. 3.15) is
  expressed via `prerelease: true` without becoming the auto-resolved
  default.
* Document the previously-undocumented `sync: true` parameter on
  `SeriousPython.run`.
* Brief `flet build` pointer at the top of the Packaging section
  (https://flet.dev/docs/publish/) — direct CLI usage remains the
  canonical documentation below it.
* Fix all three example links at the bottom (drop the stale
  `src/serious_python/` prefix so they resolve on pub.dev and GitHub).

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