From 4bd2d6351d3ac3cc10f84196c376a3883fb84afb Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 11 May 2026 12:33:23 -0700 Subject: [PATCH 1/5] refactor: rename web build platform identifier from `Pyodide` to `Emscripten` Aligns the value with `platform.system()` inside Pyodide, so PEP 508 markers on `flet`'s deps (`oauthlib`, `httpx`) work both via `flet build web` (through serious_python's sitecustomize) and when `flet` is installed directly via micropip in a Pyodide runtime. Requires the matching rename in serious_python. --- .../packages/flet-cli/src/flet_cli/commands/build_base.py | 8 ++++---- sdk/python/packages/flet/pyproject.toml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py index 29bff9fd2c..29faa3ab1f 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py @@ -95,7 +95,7 @@ def __init__(self, parser: argparse.ArgumentParser) -> None: "can_be_run_on": ["Linux"], }, "web": { - "package_platform": "Pyodide", + "package_platform": "Emscripten", "config_platform": "web", "flutter_build_command": "web", "status_text": "web app", @@ -1833,7 +1833,7 @@ def package_python_app(self): package_args.extend(["-r", f"flet=={flet.version.flet_version}"]) # site-packages variable - if self.package_platform != "Pyodide": + if self.package_platform != "Emscripten": package_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str( self.build_dir / "site-packages" ) @@ -2043,12 +2043,12 @@ def _run_flutter_command(self): build_env = {} # site-packages variable - if self.package_platform != "Pyodide": + if self.package_platform != "Emscripten": build_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str( self.build_dir / "site-packages" ) - if self.package_platform == "Pyodide" and not self.template_data["no_wasm"]: + if self.package_platform == "Emscripten" and not self.template_data["no_wasm"]: build_args.append("--wasm") android_signing_key_store = ( diff --git a/sdk/python/packages/flet/pyproject.toml b/sdk/python/packages/flet/pyproject.toml index a54bf04509..c6a20b80f2 100644 --- a/sdk/python/packages/flet/pyproject.toml +++ b/sdk/python/packages/flet/pyproject.toml @@ -9,8 +9,8 @@ requires-python = ">=3.10" dependencies = [ "flet-cli; extra == 'cli'", "flet-web; extra == 'web'", - "oauthlib >=3.2.2; platform_system != 'Pyodide'", - "httpx >=0.28.1; platform_system != 'Pyodide'", + "oauthlib >=3.2.2; platform_system != 'Emscripten'", + "httpx >=0.28.1; platform_system != 'Emscripten'", "repath >=0.9.0", "msgpack >=1.1.0", "typing-extensions; python_version < '3.11'" From 534b939c9d14f593d04e0faa0f7295fafbb7490e Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 11 May 2026 20:40:45 -0700 Subject: [PATCH 2/5] chore: bump `serious_python` to 1.0.0 in build template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Required for the `Pyodide` → `Emscripten` platform-argument rename to take effect on `flet build` runs. --- .../templates/build/{{cookiecutter.out_dir}}/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml index e3439b98d0..8046108d96 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: flet: path: ../../../../../packages/flet - serious_python: 0.9.12 + serious_python: 1.0.0 package_info_plus: ^9.0.0 path_provider: ^2.1.4 From f1348131094330f6bc8b150cf2f9dc9958b83e5e Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 11 May 2026 20:47:52 -0700 Subject: [PATCH 3/5] =?UTF-8?q?Add=20CHANGELOG=20entry=20for=20`Pyodide`?= =?UTF-8?q?=20=E2=86=92=20`Emscripten`=20rename=20(#6492)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5099208ec..60e3d038d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Bug fixes * Fix `flet-geolocator.Geolocator` reliability on web and desktop: `get_last_known_position()` no longer crashes with `TypeError: argument after ** must be a mapping, not NoneType` and now returns `Optional[GeolocatorPosition]`; `get_current_position()` no longer hangs forever on web (Dart-side workaround for the upstream [`geolocator_web` 4.1.3](https://pub.dev/packages/geolocator_web) `inMicroseconds`/`inMilliseconds` timeout typo) and uses sensible web defaults (`time_limit: 30s`, `maximum_age: 5m`); the previously-dropped `configuration` argument now actually reaches `getCurrentPosition` on the Dart side; the position stream is gated behind a registered `on_position_change`/`on_error` handler (with cancel-on-update to prevent leaks); and platform exceptions (`LocationServiceDisabledException`, `PermissionDeniedException`, `PermissionDefinitionsNotFoundException`, `PermissionRequestInProgressException`, `PositionUpdateException`, `TimeoutException`) are now translated into actionable error messages and surfaced to Python as `RuntimeError` without the default `Exception:` prefix ([#6487](https://github.com/flet-dev/flet/pull/6487)) by @FeodorFitsner. +* Fix PEP 508 markers on `flet`'s `oauthlib`/`httpx` deps not actually excluding those packages under Pyodide: the `flet build web` package platform has been renamed from `Pyodide` to `Emscripten` to match `platform.system()` inside the Pyodide runtime, and the markers now use `platform_system != 'Emscripten'`, so the exclusion works both via `flet build` and a direct `micropip.install("flet")` in a Pyodide REPL. Requires `serious_python` `>= 1.0.0`, which is now pinned in the `flet build` template ([#6492](https://github.com/flet-dev/flet/pull/6492)) by @FeodorFitsner. ## 0.85.0 From 63d864932b30bdc53b8f181f6e8141c0d4b06684 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Mon, 11 May 2026 21:14:30 -0700 Subject: [PATCH 4/5] python-worker: load msgpack explicitly so prints from flet-less scripts reach the host Console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msgpack was only ever imported if the user's deps pulled it in (typically via flet). Apps with no flet dependency — or no pyproject.toml at all — left the python_output bridge unregistered, and their prints fell through to the browser dev console silently. Load msgpack from Pyodide's prebuilt repodata when it isn't already importable; the bridge install is now unconditional. --- client/web/python-worker.js | 28 +++++++++++-------- .../web/python-worker.js | 28 +++++++++++-------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/client/web/python-worker.js b/client/web/python-worker.js index 8df242310b..40c6083afc 100644 --- a/client/web/python-worker.js +++ b/client/web/python-worker.js @@ -149,23 +149,27 @@ self.initPyodide = async function () { micropip = await ensure_micropip() await micropip.install(py_args["dependencies"], pre=micropip_include_pre) - # Install the python_output bridge using msgpack from the - # already-loaded user deps (typically pulled in via flet). If - # msgpack isn't around — apps that don't depend on flet — skip - # silently; stdout/stderr just stays in the dev console. + # Install the python_output bridge. msgpack normally rides in + # with the user's flet dependency, but apps without a flet dep + # (or without a pyproject.toml at all) would otherwise leave the + # bridge unregistered and their prints stranded in the dev + # console. Pyodide ships msgpack as a prebuilt package, so we + # load it explicitly when it isn't already importable. try: import msgpack as _msgpack + except ImportError: + import pyodide_js + await pyodide_js.loadPackage("msgpack") + import msgpack as _msgpack - def _send_python_output(text, is_stderr): - flet_js.receive_callback( - _msgpack.packb( - [7, {"text": text, "is_stderr": bool(is_stderr)}] - ) + def _send_python_output(text, is_stderr): + flet_js.receive_callback( + _msgpack.packb( + [7, {"text": text, "is_stderr": bool(is_stderr)}] ) + ) - flet_js.send_python_output = _send_python_output - except ImportError: - pass + flet_js.send_python_output = _send_python_output # Flip the worker into "user code" mode so stdout/stderr starts # flowing to the host page's Console pane instead of dev console. diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js index 8df242310b..40c6083afc 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js @@ -149,23 +149,27 @@ self.initPyodide = async function () { micropip = await ensure_micropip() await micropip.install(py_args["dependencies"], pre=micropip_include_pre) - # Install the python_output bridge using msgpack from the - # already-loaded user deps (typically pulled in via flet). If - # msgpack isn't around — apps that don't depend on flet — skip - # silently; stdout/stderr just stays in the dev console. + # Install the python_output bridge. msgpack normally rides in + # with the user's flet dependency, but apps without a flet dep + # (or without a pyproject.toml at all) would otherwise leave the + # bridge unregistered and their prints stranded in the dev + # console. Pyodide ships msgpack as a prebuilt package, so we + # load it explicitly when it isn't already importable. try: import msgpack as _msgpack + except ImportError: + import pyodide_js + await pyodide_js.loadPackage("msgpack") + import msgpack as _msgpack - def _send_python_output(text, is_stderr): - flet_js.receive_callback( - _msgpack.packb( - [7, {"text": text, "is_stderr": bool(is_stderr)}] - ) + def _send_python_output(text, is_stderr): + flet_js.receive_callback( + _msgpack.packb( + [7, {"text": text, "is_stderr": bool(is_stderr)}] ) + ) - flet_js.send_python_output = _send_python_output - except ImportError: - pass + flet_js.send_python_output = _send_python_output # Flip the worker into "user code" mode so stdout/stderr starts # flowing to the host page's Console pane instead of dev console. From 67b163c0da123bb61e8c9e62627633cf98e440ca Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Tue, 12 May 2026 07:46:10 -0700 Subject: [PATCH 5/5] Restore main(page) wrapper in use_dialog_* examples Integration test packages/flet/integration_tests/examples/apps/test_use_dialog.py imports `main` from each example expecting a `main(page)` callable. The wrapper was inadvertently removed in #6489, breaking pytest collection. --- .../examples/apps/declarative/use_dialog_basic/main.py | 6 +++++- .../examples/apps/declarative/use_dialog_chained/main.py | 6 +++++- .../examples/apps/declarative/use_dialog_multiple/main.py | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sdk/python/examples/apps/declarative/use_dialog_basic/main.py b/sdk/python/examples/apps/declarative/use_dialog_basic/main.py index 7755320678..59df7b72ea 100644 --- a/sdk/python/examples/apps/declarative/use_dialog_basic/main.py +++ b/sdk/python/examples/apps/declarative/use_dialog_basic/main.py @@ -53,5 +53,9 @@ async def handle_delete(): ) +def main(page: ft.Page): + page.render(App) + + if __name__ == "__main__": - ft.run(lambda page: page.render(App)) + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/use_dialog_chained/main.py b/sdk/python/examples/apps/declarative/use_dialog_chained/main.py index 553e57465b..c16b2aa30e 100644 --- a/sdk/python/examples/apps/declarative/use_dialog_chained/main.py +++ b/sdk/python/examples/apps/declarative/use_dialog_chained/main.py @@ -78,5 +78,9 @@ def on_confirm_dismiss(): ) +def main(page: ft.Page): + page.render(App) + + if __name__ == "__main__": - ft.run(lambda page: page.render(App)) + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/use_dialog_multiple/main.py b/sdk/python/examples/apps/declarative/use_dialog_multiple/main.py index 39d845975a..a6ff382560 100644 --- a/sdk/python/examples/apps/declarative/use_dialog_multiple/main.py +++ b/sdk/python/examples/apps/declarative/use_dialog_multiple/main.py @@ -145,5 +145,9 @@ def handler(): ) +def main(page: ft.Page): + page.render(App) + + if __name__ == "__main__": - ft.run(lambda page: page.render(App)) + ft.run(main)