Skip to content

Commit 8fc2564

Browse files
committed
fix(test): pass serious_python native-build env to flet test
flet test spawns its own 'flutter test integration_test' (via FletTestApp) instead of going through _run_flutter_command, so it never received the serious_python build-time env that flet build sets. Most critically SERIOUS_PYTHON_APP was unset, which makes the Android packageApp Gradle task early-return and leave a stale app.zip (old-Python main.pyc) in the APK, crashing the embedded runtime with 'ImportError: bad magic number'. Extract the serious_python native-build env into a shared _serious_python_build_env() and use it from both _run_flutter_command and flet test's _flutter_path_env, so the two paths bundle an identical app and can't drift. Adds SERIOUS_PYTHON_APP, SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES and SP_NATIVE_SET to the test env (and _TEST_ENV_KEYS).
1 parent 0af4bd7 commit 8fc2564

2 files changed

Lines changed: 73 additions & 42 deletions

File tree

sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2479,6 +2479,60 @@ def run_flutter(self):
24792479

24802480
self._run_flutter_command()
24812481

2482+
def _serious_python_build_env(self) -> dict:
2483+
"""
2484+
serious_python environment for the platform NATIVE build (the Gradle /
2485+
CMake / podspec steps run by `flutter build`).
2486+
2487+
These tell the native build where the `package` step staged the app and
2488+
site-packages and which embedded Python runtime to bundle. `flet build`
2489+
applies them via `_run_flutter_command`; `flet test` applies the SAME set
2490+
to the `flutter test` it spawns (see test.py `_flutter_path_env`) so both
2491+
bundle an identical app. In particular, without `SERIOUS_PYTHON_APP` the
2492+
Android `packageApp` Gradle task early-returns and a stale `app.zip` (e.g.
2493+
an old-Python `main.pyc`) survives in the APK — `ImportError: bad magic
2494+
number`. Built defensively so it is safe to call before the full build
2495+
pipeline has populated every attribute.
2496+
"""
2497+
2498+
env: dict = {}
2499+
python_release = getattr(self, "python_release", None)
2500+
if python_release is not None:
2501+
# Only the short version is passed; serious_python derives the rest
2502+
# from its committed manifest snapshot.
2503+
env["SERIOUS_PYTHON_VERSION"] = python_release.short
2504+
2505+
build_dir = getattr(self, "build_dir", None)
2506+
package_platform = getattr(self, "package_platform", None)
2507+
if build_dir is not None and package_platform != "Emscripten":
2508+
env["SERIOUS_PYTHON_SITE_PACKAGES"] = str(build_dir / "site-packages")
2509+
# app staging dir: read by the platform native build (CMake / podspec
2510+
# / Android Gradle) at `flutter build` time to place the unpacked app
2511+
# into the bundle.
2512+
env["SERIOUS_PYTHON_APP"] = str(build_dir / "python-app")
2513+
2514+
# Swift Package Manager (darwin): export the cache-bust key the package
2515+
# step computed so the plugin's Package.swift re-resolves when the staged
2516+
# native set changes (SwiftPM caches its graph on manifest text + env).
2517+
if (
2518+
build_dir is not None
2519+
and package_platform in ("iOS", "Darwin")
2520+
and self._darwin_spm_active()
2521+
):
2522+
spm_key_file = build_dir / ".serious_python_spm_key"
2523+
if spm_key_file.exists():
2524+
env["SP_NATIVE_SET"] = spm_key_file.read_text().strip()
2525+
2526+
# Path-hungry packages to ship extracted to disk: consumed by the
2527+
# serious_python_android Gradle split during `flutter build`.
2528+
if package_platform == "Android" and getattr(
2529+
self, "android_extract_packages", None
2530+
):
2531+
env["SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES"] = ",".join(
2532+
self.android_extract_packages
2533+
)
2534+
return env
2535+
24822536
def _run_flutter_command(self):
24832537
"""
24842538
Build final Flutter CLI command, configure environment, and run it.
@@ -2500,36 +2554,10 @@ def _run_flutter_command(self):
25002554
]
25012555
)
25022556

2503-
# Only the short version is passed; serious_python derives the rest
2504-
# from its committed manifest snapshot.
2505-
build_env = {
2506-
"SERIOUS_PYTHON_VERSION": self.python_release.short,
2507-
}
2508-
2509-
# site-packages variable
2510-
if self.package_platform != "Emscripten":
2511-
build_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str(
2512-
self.build_dir / "site-packages"
2513-
)
2514-
# app staging dir: read by the platform native build (CMake /
2515-
# podspec / Android Gradle) at `flutter build` time to place the
2516-
# unpacked app into the bundle.
2517-
build_env["SERIOUS_PYTHON_APP"] = str(self.build_dir / "python-app")
2518-
2519-
# Swift Package Manager (darwin): export the cache-bust key the package
2520-
# step computed so the plugin's Package.swift re-resolves when the staged
2521-
# native set changes (SwiftPM caches its graph on manifest text + env).
2522-
if self._darwin_spm_active():
2523-
spm_key_file = self.build_dir / ".serious_python_spm_key"
2524-
if spm_key_file.exists():
2525-
build_env["SP_NATIVE_SET"] = spm_key_file.read_text().strip()
2526-
2527-
# Path-hungry packages to ship extracted to disk: consumed by the
2528-
# serious_python_android Gradle split during `flutter build`.
2529-
if self.package_platform == "Android" and self.android_extract_packages:
2530-
build_env["SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES"] = ",".join(
2531-
self.android_extract_packages
2532-
)
2557+
# serious_python env for the native build, shared verbatim with `flet
2558+
# test` (which spawns its own `flutter test`) so both bundle an identical
2559+
# app — see `_serious_python_build_env`.
2560+
build_env = self._serious_python_build_env()
25332561

25342562
if self.package_platform == "Emscripten" and not self.template_data["no_wasm"]:
25352563
build_args.append("--wasm")

sdk/python/packages/flet-cli/src/flet_cli/commands/test.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,23 @@ def _provision_steps(cmd: "BaseBuildCommand") -> Path:
5050

5151
# Env vars set by `flet test` (and `provision_test_host`) for the pytest
5252
# subprocess. `flutter test integration_test` (spawned by FletTestApp) runs the
53-
# platform's native build, whose serious_python build phase bundles
54-
# site-packages into the app from SERIOUS_PYTHON_SITE_PACKAGES — without it the
55-
# embedded Python can't import its dependencies (e.g. ModuleNotFoundError:
56-
# certifi). `flet build`/`flet debug` set the same vars for their flutter build
57-
# (see build_base.py `_run_flutter_command`).
53+
# platform's native build, whose serious_python build phase bundles the staged
54+
# app + site-packages — without these vars the embedded Python can't import its
55+
# dependencies (e.g. ModuleNotFoundError: certifi) and, on Android, the
56+
# `packageApp` Gradle task no-ops so a stale `app.zip` (old-Python `main.pyc`)
57+
# survives in the APK (ImportError: bad magic number). `flet build`/`flet debug`
58+
# set the SAME serious_python vars for their flutter build via
59+
# `_serious_python_build_env` (build_base.py `_run_flutter_command`); we reuse it
60+
# here so the two paths can't drift.
5861
_TEST_ENV_KEYS = (
5962
"PATH",
6063
"FLET_TEST_DISABLE_FVM",
6164
"FLET_TEST_FLUTTER_EXE",
6265
"SERIOUS_PYTHON_VERSION",
6366
"SERIOUS_PYTHON_SITE_PACKAGES",
67+
"SERIOUS_PYTHON_APP",
68+
"SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES",
69+
"SP_NATIVE_SET",
6470
"SERIOUS_PYTHON_FLUTTER_PACKAGES",
6571
)
6672

@@ -81,13 +87,10 @@ def _flutter_path_env(cmd: "BaseBuildCommand") -> dict:
8187
# on Windows can't resolve a bare "flutter" (no PATHEXT lookup).
8288
env["FLET_TEST_FLUTTER_EXE"] = str(cmd.flutter_exe)
8389
env["FLET_TEST_DISABLE_FVM"] = "1"
84-
if getattr(cmd, "python_release", None) is not None:
85-
env["SERIOUS_PYTHON_VERSION"] = cmd.python_release.short
86-
if (
87-
getattr(cmd, "build_dir", None) is not None
88-
and getattr(cmd, "package_platform", None) != "Emscripten"
89-
):
90-
env["SERIOUS_PYTHON_SITE_PACKAGES"] = str(cmd.build_dir / "site-packages")
90+
# Same serious_python env `flet build` hands its native build, so the app
91+
# `flutter test` builds is bundled identically (incl. SERIOUS_PYTHON_APP →
92+
# a fresh app.zip with a matching-Python main.pyc).
93+
env.update(cmd._serious_python_build_env())
9194
if getattr(cmd, "flutter_packages_temp_dir", None) is not None:
9295
env["SERIOUS_PYTHON_FLUTTER_PACKAGES"] = str(cmd.flutter_packages_temp_dir)
9396
return env

0 commit comments

Comments
 (0)