diff --git a/docs/dedicated-data-channels.md b/docs/dedicated-data-channels.md index aab40476..e6c4f5df 100644 --- a/docs/dedicated-data-channels.md +++ b/docs/dedicated-data-channels.md @@ -288,7 +288,11 @@ def _pump(self): Real parallelism comes from C extensions that **release the GIL during their work** — NumPy, PyTorch, Pillow, cryptography. Pure-Python CPU work serialises on the GIL; for that, use `multiprocessing` or -PEP 684 subinterpreters. +PEP 684 subinterpreters. Caveat: `multiprocessing` works in the embedded +runtime only on **desktop** hosts whose binary services the spawn re-exec +protocol via `serious_python_main` (dart_bridge >= 1.5.0, flet >= 0.86 build +template); it is not available on iOS/Android, where the OS forbids spawning +child processes. ### Dart side — Isolate scope diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index 29fbeb75..2fb1b29b 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -1,5 +1,8 @@ ## 4.3.0 +* **Desktop multiprocessing support** ([flet-dev/flet#4283](https://github.com/flet-dev/flet/issues/4283)). `dart_bridge` **1.5.0** adds `serious_python_is_mp_invocation` / `serious_python_main` (+ `_w` wide-char variants on Windows): host apps call them first thing in `main` to detect CPython child command lines (`--multiprocessing-fork`, `-c "from multiprocessing..."` — spawn workers, the resource tracker, and the forkserver) and service them as a plain headless interpreter (`Py_Main`/`Py_BytesMain`, stable ABI) instead of re-launching the GUI. The exports rely on the `PYTHONHOME`/`PYTHONPATH` the parent already stamped process-wide. +* `PYTHONINSPECT=1` is no longer set by any platform implementation. It had no effect on the embedded interpreter, but it leaked into the process environment where any *real* interpreter child (e.g. a serviced multiprocessing worker) would inherit it and hang in interactive mode after its command completed. +* Bump the bundled python-build snapshot to `20260708`, which delivers `dart_bridge` **1.5.0**; Pyodide for 3.14 bumped **314.0.1 → 314.0.2**. Bundled Python versions are unchanged from 4.2.1 (**3.12.13 / 3.13.14 / 3.14.6**). * **Windows:** fix `flet build windows` failing with `file INSTALL cannot find "C:/WINDOWS/System32/vcruntime140_1.dll"` for users who build with VS Build Tools rather than full Visual Studio (a WOW64 file-system-redirection issue with the bundled 32-bit cmake). See `serious_python_windows` 4.3.0. ## 4.2.1 diff --git a/src/serious_python/lib/src/python_versions.dart b/src/serious_python/lib/src/python_versions.dart index d654a80b..f9fbf091 100644 --- a/src/serious_python/lib/src/python_versions.dart +++ b/src/serious_python/lib/src/python_versions.dart @@ -1,5 +1,5 @@ // GENERATED by `dart run serious_python:gen_version_tables` from python-build's -// manifest.json (release 20260701). Do not edit by hand — edit python-build's +// manifest.json (release 20260708). Do not edit by hand — edit python-build's // manifest.json, cut a release, bump `pythonReleaseDate`, and regenerate. const pythonVersionEnvironmentVariable = "SERIOUS_PYTHON_VERSION"; @@ -10,8 +10,8 @@ const pyodideVersionEnvironmentVariable = "SERIOUS_PYTHON_PYODIDE_VERSION"; const dartBridgeVersionEnvironmentVariable = "DART_BRIDGE_VERSION"; /// python-build release the bundled runtimes come from (YYYYMMDD). -const pythonReleaseDate = "20260701"; -const dartBridgeVersion = "1.4.1"; +const pythonReleaseDate = "20260708"; +const dartBridgeVersion = "1.5.0"; const defaultPythonVersion = "3.14"; class PythonRelease { @@ -56,7 +56,7 @@ const pythonReleases = { "3.14": PythonRelease( standaloneVersion: "3.14.6", standaloneReleaseDate: "20260623", - pyodideVersion: "314.0.1", + pyodideVersion: "314.0.2", pyodidePlatformTag: "pyemscripten-2026.0-wasm32", androidAbis: ["arm64-v8a", "x86_64", "armeabi-v7a"], prerelease: false, diff --git a/src/serious_python_android/CHANGELOG.md b/src/serious_python_android/CHANGELOG.md index 5a5547c2..c44e2a94 100644 --- a/src/serious_python_android/CHANGELOG.md +++ b/src/serious_python_android/CHANGELOG.md @@ -1,6 +1,7 @@ ## 4.3.0 -* Version bump aligning with the `serious_python_*` 4.3.0 release. +* `PYTHONINSPECT=1` is no longer set by any platform implementation. It had no effect on the embedded interpreter, but it leaked into the process environment where any *real* interpreter child (e.g. a serviced multiprocessing worker) would inherit it and hang in interactive mode after its command completed. No functional change on Android, which doesn't support process spawning. +* Bump the bundled python-build snapshot to `20260708` (`dart_bridge` **1.5.0**). The new multiprocessing child-interception exports are present in the runtime but not wired up on Android, which doesn't support process spawning. ## 4.2.1 diff --git a/src/serious_python_android/android/python_versions.properties b/src/serious_python_android/android/python_versions.properties index faf98a2e..c0f41b51 100644 --- a/src/serious_python_android/android/python_versions.properties +++ b/src/serious_python_android/android/python_versions.properties @@ -1,8 +1,8 @@ # GENERATED by `dart run serious_python:gen_version_tables` from -# python-build manifest.json (release 20260701). Do not edit by hand. +# python-build manifest.json (release 20260708). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.4.1 -python_build_release_date=20260701 +dart_bridge_version=1.5.0 +python_build_release_date=20260708 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a 3.13.full_version=3.13.14 diff --git a/src/serious_python_android/lib/serious_python_android.dart b/src/serious_python_android/lib/serious_python_android.dart index 3b3f779b..f2cf4f21 100644 --- a/src/serious_python_android/lib/serious_python_android.dart +++ b/src/serious_python_android/lib/serious_python_android.dart @@ -116,7 +116,6 @@ class SeriousPythonAndroid extends SeriousPythonPlatform { } final env = { - 'PYTHONINSPECT': '1', 'PYTHONDONTWRITEBYTECODE': '1', 'PYTHONNOUSERSITE': '1', 'PYTHONUNBUFFERED': '1', diff --git a/src/serious_python_darwin/CHANGELOG.md b/src/serious_python_darwin/CHANGELOG.md index 004a08e6..8b2f210a 100644 --- a/src/serious_python_darwin/CHANGELOG.md +++ b/src/serious_python_darwin/CHANGELOG.md @@ -1,6 +1,8 @@ ## 4.3.0 -* Version bump aligning with the `serious_python_*` 4.3.0 release. +* Bump `dart_bridge` to **1.5.0** (python-build snapshot `20260708`): multiprocessing child-interception exports (`serious_python_is_mp_invocation` / `serious_python_main`), kept alive against the host link's `-dead_strip` both by `__attribute__((used))` in the archive and by keep-alive references in `SeriousPythonPlugin.swift`. See the `serious_python` 4.3.0 notes. +* `prepare_macos.sh` / `prepare_ios.sh`: the extracted `dart_bridge.xcframework` in `dist_*` is now keyed to the dart_bridge version (`.dart_bridge_version` marker) — previously a version bump kept staging the stale extraction from the earlier version. +* `PYTHONINSPECT=1` is no longer set by any platform implementation. It had no effect on the embedded interpreter, but it leaked into the process environment where any *real* interpreter child (e.g. a serviced multiprocessing worker) would inherit it and hang in interactive mode after its command completed. ## 4.2.1 diff --git a/src/serious_python_darwin/darwin/prepare_ios.sh b/src/serious_python_darwin/darwin/prepare_ios.sh index 279c99b8..49902602 100755 --- a/src/serious_python_darwin/darwin/prepare_ios.sh +++ b/src/serious_python_darwin/darwin/prepare_ios.sh @@ -15,7 +15,8 @@ cache_root="${FLET_CACHE_DIR:-$HOME/.flet/cache}" # date — e.g. a rebuild that only re-signs binaries) downloads fresh instead of # being served stale from the previous release's cache. dart-bridge stays # version-keyed (its re-releases bump the version). -pb_cache="$cache_root/python-build/v$python_full_version-$python_build_date" +pb_id="$python_full_version-$python_build_date" +pb_cache="$cache_root/python-build/v$pb_id" db_cache="$cache_root/dart-bridge/v$dart_bridge_version" mkdir -p "$pb_cache" "$db_cache" @@ -34,14 +35,13 @@ fi # 3.14 site-packages, which trips C-extension ABI errors ("unknown slot ID") at # import. The marker keys the extracted dist to the version + release date, so a # same-version re-release (new build date) also re-extracts. -build_id="$python_full_version-$python_build_date" marker="$dist/.python_build_id" -if [ ! -d "$dist" ] || [ "$(cat "$marker" 2>/dev/null)" != "$build_id" ]; then +if [ ! -d "$dist" ] || [ "$(cat "$marker" 2>/dev/null)" != "$pb_id" ]; then rm -rf "$dist" mkdir -p "$dist" tar -xzf "$python_ios_dist_path" -C "$dist" mv "$dist/python-stdlib" "$dist/stdlib" - echo "$build_id" > "$marker" + echo "$pb_id" > "$marker" fi # ---- flet-dev/dart-bridge (xcframework) ----------------------------------- @@ -55,7 +55,11 @@ if [ ! -f "$dart_bridge_path" ]; then mv "$dart_bridge_path.tmp" "$dart_bridge_path" fi -if [ ! -d "$dist/xcframeworks/dart_bridge.xcframework" ]; then +# Cache dart_bridge.xcframework by version; extract it if missing or if the version marker differs. +db_marker="$dist/xcframeworks/.dart_bridge_version" +if [ ! -d "$dist/xcframeworks/dart_bridge.xcframework" ] || [ "$(cat "$db_marker" 2>/dev/null)" != "$dart_bridge_version" ]; then + rm -rf "$dist/xcframeworks/dart_bridge.xcframework" mkdir -p "$dist/xcframeworks" unzip -q "$dart_bridge_path" -d "$dist/xcframeworks/" + echo "$dart_bridge_version" > "$db_marker" fi diff --git a/src/serious_python_darwin/darwin/prepare_macos.sh b/src/serious_python_darwin/darwin/prepare_macos.sh index 251c0a39..cd0f516b 100755 --- a/src/serious_python_darwin/darwin/prepare_macos.sh +++ b/src/serious_python_darwin/darwin/prepare_macos.sh @@ -16,7 +16,8 @@ cache_root="${FLET_CACHE_DIR:-$HOME/.flet/cache}" # date — e.g. a rebuild that only re-signs binaries) downloads fresh instead of # being served stale from the previous release's cache. dart-bridge stays # version-keyed (its re-releases bump the version). -pb_cache="$cache_root/python-build/v$python_full_version-$python_build_date" +pb_id="$python_full_version-$python_build_date" +pb_cache="$cache_root/python-build/v$pb_id" db_cache="$cache_root/dart-bridge/v$dart_bridge_version" mkdir -p "$pb_cache" "$db_cache" @@ -36,9 +37,8 @@ fi # 3.14 site-packages, which trips C-extension ABI errors ("unknown slot ID") at # import. The marker keys the extracted dist to the version + release date, so a # same-version re-release (new build date) also re-extracts. -build_id="$python_full_version-$python_build_date" marker="$dist/.python_build_id" -if [ ! -d "$dist" ] || [ "$(cat "$marker" 2>/dev/null)" != "$build_id" ]; then +if [ ! -d "$dist" ] || [ "$(cat "$marker" 2>/dev/null)" != "$pb_id" ]; then rm -rf "$dist" mkdir -p "$dist" tar -xzf "$python_macos_dist_path" -C "$dist" @@ -54,7 +54,7 @@ if [ ! -d "$dist" ] || [ "$(cat "$marker" 2>/dev/null)" != "$build_id" ]; then # unexpectedly" crash dialog. We don't need this launcher for embedded # use; libdart_bridge dlopens Python.framework's main binary directly. find "$dist/xcframeworks" -type d -name 'Python.app' -prune -exec rm -rf {} + - echo "$build_id" > "$marker" + echo "$pb_id" > "$marker" fi # ---- flet-dev/dart-bridge (xcframework, same archive for macOS + iOS) ----- @@ -68,7 +68,11 @@ if [ ! -f "$dart_bridge_path" ]; then mv "$dart_bridge_path.tmp" "$dart_bridge_path" fi -if [ ! -d "$dist/xcframeworks/dart_bridge.xcframework" ]; then +# Cache dart_bridge.xcframework by version; extract it if missing or if the version marker differs. +db_marker="$dist/xcframeworks/.dart_bridge_version" +if [ ! -d "$dist/xcframeworks/dart_bridge.xcframework" ] || [ "$(cat "$db_marker" 2>/dev/null)" != "$dart_bridge_version" ]; then + rm -rf "$dist/xcframeworks/dart_bridge.xcframework" mkdir -p "$dist/xcframeworks" unzip -q "$dart_bridge_path" -d "$dist/xcframeworks/" + echo "$dart_bridge_version" > "$db_marker" fi diff --git a/src/serious_python_darwin/darwin/python_versions.properties b/src/serious_python_darwin/darwin/python_versions.properties index faf98a2e..c0f41b51 100644 --- a/src/serious_python_darwin/darwin/python_versions.properties +++ b/src/serious_python_darwin/darwin/python_versions.properties @@ -1,8 +1,8 @@ # GENERATED by `dart run serious_python:gen_version_tables` from -# python-build manifest.json (release 20260701). Do not edit by hand. +# python-build manifest.json (release 20260708). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.4.1 -python_build_release_date=20260701 +dart_bridge_version=1.5.0 +python_build_release_date=20260708 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a 3.13.full_version=3.13.14 diff --git a/src/serious_python_darwin/darwin/serious_python_darwin/Sources/serious_python_darwin/SeriousPythonPlugin.swift b/src/serious_python_darwin/darwin/serious_python_darwin/Sources/serious_python_darwin/SeriousPythonPlugin.swift index d676aa0b..bc9ba68e 100644 --- a/src/serious_python_darwin/darwin/serious_python_darwin/Sources/serious_python_darwin/SeriousPythonPlugin.swift +++ b/src/serious_python_darwin/darwin/serious_python_darwin/Sources/serious_python_darwin/SeriousPythonPlugin.swift @@ -16,6 +16,17 @@ private func _sp_init_keepalive(_ data: UnsafeMutableRawPointer?) -> Int @_silgen_name("DartBridge_EnqueueMessage") private func _sp_enqueue_keepalive(_ data: UnsafePointer?, _ len: Int) +// multiprocessing child-interception entry points, +// dlsym'd by the host app's main.swift before NSApplicationMain. +@_silgen_name("serious_python_is_mp_invocation") +private func _sp_is_mp_keepalive( + _ argc: Int32, _ argv: UnsafeMutablePointer?>? +) -> Int32 +@_silgen_name("serious_python_main") +private func _sp_main_keepalive( + _ argc: Int32, _ argv: UnsafeMutablePointer?>? +) -> Int32 + /// Thin Flutter plugin: surfaces the python.bundle resource path to Dart. /// All Python lifecycle now lives in `serious_python_run` /// (dart_bridge.xcframework), invoked from Dart. @@ -39,6 +50,8 @@ public class SeriousPythonPlugin: NSObject, FlutterPlugin { _ = _sp_run_keepalive(nil) _ = _sp_init_keepalive(nil) _sp_enqueue_keepalive(nil, 0) + _ = _sp_is_mp_keepalive(0, nil) + _ = _sp_main_keepalive(0, nil) } } diff --git a/src/serious_python_darwin/lib/serious_python_darwin.dart b/src/serious_python_darwin/lib/serious_python_darwin.dart index 4e8cb76f..9b8ef7c0 100644 --- a/src/serious_python_darwin/lib/serious_python_darwin.dart +++ b/src/serious_python_darwin/lib/serious_python_darwin.dart @@ -55,7 +55,6 @@ class SeriousPythonDarwin extends SeriousPythonPlatform { ]; final env = { - 'PYTHONINSPECT': '1', 'PYTHONDONTWRITEBYTECODE': '1', 'PYTHONNOUSERSITE': '1', 'PYTHONUNBUFFERED': '1', diff --git a/src/serious_python_linux/CHANGELOG.md b/src/serious_python_linux/CHANGELOG.md index 90a95a89..6e38240e 100644 --- a/src/serious_python_linux/CHANGELOG.md +++ b/src/serious_python_linux/CHANGELOG.md @@ -1,6 +1,7 @@ ## 4.3.0 -* Version bump aligning with the `serious_python_*` 4.3.0 release. +* Bump `dart_bridge` to **1.5.0** (python-build snapshot `20260708`): multiprocessing child-interception exports (`serious_python_is_mp_invocation` / `serious_python_main`), consumed by the flet build template's `main.cc` via `dlopen("libdart_bridge.so")`. Relevant on Linux since Python 3.14 made `forkserver` (which execs `sys.executable`) the default start method. See the `serious_python` 4.3.0 notes. +* `PYTHONINSPECT=1` is no longer set by any platform implementation. It had no effect on the embedded interpreter, but it leaked into the process environment where any *real* interpreter child (e.g. a serviced multiprocessing worker) would inherit it and hang in interactive mode after its command completed. ## 4.2.1 diff --git a/src/serious_python_linux/lib/serious_python_linux.dart b/src/serious_python_linux/lib/serious_python_linux.dart index 0c2a39cc..ea9c3147 100644 --- a/src/serious_python_linux/lib/serious_python_linux.dart +++ b/src/serious_python_linux/lib/serious_python_linux.dart @@ -48,7 +48,6 @@ class SeriousPythonLinux extends SeriousPythonPlatform { ]; final env = { - 'PYTHONINSPECT': '1', 'PYTHONDONTWRITEBYTECODE': '1', 'PYTHONNOUSERSITE': '1', 'PYTHONUNBUFFERED': '1', diff --git a/src/serious_python_linux/linux/python_versions.properties b/src/serious_python_linux/linux/python_versions.properties index faf98a2e..c0f41b51 100644 --- a/src/serious_python_linux/linux/python_versions.properties +++ b/src/serious_python_linux/linux/python_versions.properties @@ -1,8 +1,8 @@ # GENERATED by `dart run serious_python:gen_version_tables` from -# python-build manifest.json (release 20260701). Do not edit by hand. +# python-build manifest.json (release 20260708). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.4.1 -python_build_release_date=20260701 +dart_bridge_version=1.5.0 +python_build_release_date=20260708 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a 3.13.full_version=3.13.14 diff --git a/src/serious_python_windows/CHANGELOG.md b/src/serious_python_windows/CHANGELOG.md index ed6d6b2e..266185f2 100644 --- a/src/serious_python_windows/CHANGELOG.md +++ b/src/serious_python_windows/CHANGELOG.md @@ -1,5 +1,7 @@ ## 4.3.0 +* Bump `dart_bridge` to **1.5.0** (python-build snapshot `20260708`): multiprocessing child-interception exports, including the Windows wide-char variants `serious_python_is_mp_invocation_w` / `serious_python_main_w` (→ `Py_Main`) consumed by the flet build template's `wWinMain`. See the `serious_python` 4.3.0 notes. +* `PYTHONINSPECT=1` is no longer set by any platform implementation. It had no effect on the embedded interpreter, but it leaked into the process environment where any *real* interpreter child (e.g. a serviced multiprocessing worker) would inherit it and hang in interactive mode after its command completed. * **Fix `flet build windows` failing with `file INSTALL cannot find "C:/WINDOWS/System32/vcruntime140_1.dll"`** for users who have VS Build Tools installed rather than full Visual Studio. The plugin harvests the CRT runtime DLLs (`msvcp140.dll` / `vcruntime140.dll` / `vcruntime140_1.dll`) from `%WINDIR%\System32`, but Flutter drives the CMake install step with the **32-bit** `cmake.exe` bundled in VS Build Tools. Under WOW64 file-system redirection that process sees `System32` transparently rewritten to `SysWOW64`, which holds the x86 CRT and doesn't contain `vcruntime140_1.dll` at all — so the x64 build copied wrong-arch DLLs and then failed. The CRT directory is now resolved via the `Sysnative` pseudo-folder (visible only to 32-bit processes, mapping back to the real 64-bit `System32`) when present, falling back to `System32` for native 64-bit cmake. See flet-dev/flet#6436. ## 4.2.1 diff --git a/src/serious_python_windows/lib/serious_python_windows.dart b/src/serious_python_windows/lib/serious_python_windows.dart index de0a6a8a..5c6861ba 100644 --- a/src/serious_python_windows/lib/serious_python_windows.dart +++ b/src/serious_python_windows/lib/serious_python_windows.dart @@ -46,7 +46,6 @@ class SeriousPythonWindows extends SeriousPythonPlatform { ]; final env = { - 'PYTHONINSPECT': '1', 'PYTHONDONTWRITEBYTECODE': '1', 'PYTHONNOUSERSITE': '1', 'PYTHONUNBUFFERED': '1', diff --git a/src/serious_python_windows/windows/python_versions.properties b/src/serious_python_windows/windows/python_versions.properties index faf98a2e..c0f41b51 100644 --- a/src/serious_python_windows/windows/python_versions.properties +++ b/src/serious_python_windows/windows/python_versions.properties @@ -1,8 +1,8 @@ # GENERATED by `dart run serious_python:gen_version_tables` from -# python-build manifest.json (release 20260701). Do not edit by hand. +# python-build manifest.json (release 20260708). Do not edit by hand. default_python_version=3.14 -dart_bridge_version=1.4.1 -python_build_release_date=20260701 +dart_bridge_version=1.5.0 +python_build_release_date=20260708 3.12.full_version=3.12.13 3.12.android_abis=arm64-v8a,x86_64,armeabi-v7a 3.13.full_version=3.13.14