Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: gxxk-dev/serious-python
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: flet-dev/serious-python
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 17 commits
  • 46 files changed
  • 3 contributors

Commits on Jul 6, 2026

  1. ci: cut GitHub Release on tag runs (flet-dev#225)

    * ci: cut a GitHub Release on tag runs
    
    Add a `release` job that publishes a GitHub Release for v* tags, mirroring
    the release step in flet / python-build.
    
    - needs: publish — cut the release only after all six packages are live on
      pub.dev, so a release always marks a genuinely-published version.
    - Scoped `contents: write` (top-level stays `contents: read`).
    - generate_release_notes: true — notes from merged PRs since the last tag;
      no artifacts to attach (serious_python ships to pub.dev).
    - Hyphen-suffixed tags (e.g. v1.2.0-beta.1) are marked as pre-releases;
      github.ref_name is passed via env, not interpolated (no template injection).
    - softprops/action-gh-release pinned to the same SHA python-build uses.
    
    * update
    ndonkoHenri authored Jul 6, 2026
    Configuration menu
    Copy the full SHA
    8fff330 View commit details
    Browse the repository at this point in the history

Commits on Jul 8, 2026

  1. Bump to 4.3.0: Windows CRT WOW64/Sysnative fix (flet #6436) (flet-dev…

    …#227)
    
    * fix(windows): resolve CRT DLLs via Sysnative to survive WOW64 redirection
    
    Flutter may drive the CMake install step with the 32-bit cmake.exe bundled
    in VS Build Tools. Under WOW64 file-system redirection that process sees
    C:\Windows\System32 rewritten to SysWOW64, which holds x86 CRT DLLs and has
    no vcruntime140_1.dll, so the x64 build copies wrong-arch DLLs and then fails
    with "file INSTALL cannot find vcruntime140_1.dll".
    
    Prefer the Sysnative pseudo-folder (visible only to 32-bit processes, maps to
    the real 64-bit System32) when present, falling back to System32 for native
    64-bit cmake.
    
    Fixes flet-dev/flet#6436
    
    * Bump to 4.3.0: Windows CRT WOW64/Sysnative fix
    
    Bump all serious_python_* packages to 4.3.0. The substantive change is the
    Windows CRT DLL harvesting fix (Sysnative fallback) for flet-dev/flet#6436;
    other platforms are alignment-only bumps.
    FeodorFitsner authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    d262e6c View commit details
    Browse the repository at this point in the history

Commits on Jul 9, 2026

  1. Desktop multiprocessing support: PYTHONINSPECT removal, version-key…

    …ed `dart_bridge` staging, `dart_bridge` 1.5.0 keep-alives (flet-dev#228)
    
    * fix: stop stamping PYTHONINSPECT into the host process environment
    
    All four platform implementations set PYTHONINSPECT=1 among the env vars
    they setenv() before Py_Initialize. The variable has no effect on the
    embedded interpreter itself — nothing in the embedded lifecycle runs
    pymain, which is the only consumer of Py_InspectFlag — but because the
    vars are written into the real process environment, every child process
    the app spawns inherits it.
    
    That inheritance becomes actively harmful with multiprocessing child
    interception (dart_bridge >= 1.5.0, flet-dev/flet#4283): a serviced
    worker child IS a real interpreter run through Py_Main, and an inherited
    PYTHONINSPECT would hold it open in interactive mode after its -c
    command completes instead of exiting. It equally affects any python
    interpreter a user launches via subprocess from a packaged app.
    
    dart_bridge's serious_python_main also unsets the variable defensively
    (apps may run against an older serious_python), but the right fix is to
    stop leaking it in the first place.
    
    * feat(darwin): keep-alive refs for dart_bridge 1.5.0 multiprocessing exports
    
    dart_bridge 1.5.0 adds serious_python_is_mp_invocation / serious_python_main
    (flet-dev/flet#4283): the host app's main.swift dlsym's them before
    NSApplicationMain to detect CPython child command lines produced by
    multiprocessing's spawn machinery and service them as a plain headless
    interpreter instead of booting a second GUI instance.
    
    On Apple platforms dart_bridge is a static archive linked into the host
    executable, and both entry points are dlsym-only — there is no static
    call site anywhere, so the app link's -dead_strip would discard them.
    Extend the existing keep-alive block (which already protects
    serious_python_run and the DartBridge_* exports for Dart FFI's
    DynamicLibrary.process() lookups) with references to the two new symbols.
    
    This is belt-and-braces: dart_bridge 1.5.0 also marks its exports
    __attribute__((used)) (no-dead-strip at the atom level), but the
    keep-alive keeps working against toolchains or archives where that
    attribute is absent, and documents the dlsym contract in the one place
    Apple linkage is wired.
    
    * fix(darwin): re-extract dart_bridge.xcframework when its version changes
    
    prepare_macos.sh / prepare_ios.sh guarded the dart_bridge extraction with
    a bare directory-exists check, so once dist_* held an extracted
    dart_bridge.xcframework, a dart_bridge version bump kept staging the
    stale extraction from the previous version — the freshly downloaded zip
    in the version-keyed cache was never unpacked. (The Python dist half of
    the script already solved the identical problem with a .python_build_id
    marker.)
    
    Key the extraction the same way: a .dart_bridge_version marker next to
    the extracted xcframework, re-extracting (rm -rf + unzip) whenever it is
    missing or disagrees with the requested version.
    
    Also fold the duplicated "$python_full_version-$python_build_date"
    expression into a single pb_id variable used for both the cache dir and
    the dist marker.
    
    * docs: 4.3.0 changelogs + desktop-only multiprocessing caveat
    
    Draft the 4.3.0 CHANGELOG sections across all five packages for the
    multiprocessing work (flet-dev/flet#4283):
    
    - serious_python: the dart_bridge 1.5.0 child-interception contract
      (serious_python_is_mp_invocation / serious_python_main, plus the _w
      wide-char variants on Windows) and the PYTHONINSPECT removal.
    - serious_python_darwin: dead-strip protection for the new exports and
      the version-keyed dart_bridge extraction in prepare_{macos,ios}.sh.
    - serious_python_windows / _linux: platform-specific consumption notes
      (wWinMain / main.cc dlopen; the Python 3.14 forkserver-default angle
      on Linux).
    - serious_python_android: PYTHONINSPECT removal only (no behavior
      change — Android doesn't support process spawning).
    
    Also scope the multiprocessing recommendation in
    docs/dedicated-data-channels.md: it applies to desktop hosts whose
    binary services the spawn re-exec protocol; iOS/Android forbid spawning
    child processes.
    
    The version numbers reference the upcoming dart_bridge 1.5.0 /
    serious_python 4.3.0 releases; the pubspec version bumps and the
    dart_bridge_version pin update land with the release commit once
    dart_bridge 1.5.0 is tagged.
    
    * chore: bump python-build snapshot to 20260708 (dart_bridge 1.5.0, Pyodide 314.0.2)
    
    Regenerated via `dart run serious_python:gen_version_tables --release-date 20260708`.
    Delivers dart_bridge 1.5.0 with the multiprocessing child-interception exports;
    Pyodide for 3.14 bumped 314.0.1 -> 314.0.2. CPython versions unchanged
    (3.12.13 / 3.13.14 / 3.14.6). 4.3.0 changelogs updated to record the snapshot.
    
    * Remove generic version bump notes from platform CHANGELOGs
    
    Remove the generic 'Version bump aligning with the serious_python_* 4.3.0 release' line from the CHANGELOG entries across all platform implementations (Android, Darwin, Linux). The specific technical changes and dart_bridge updates are sufficient to document the release.
    
    ---------
    
    Co-authored-by: Feodor Fitsner <feodor@appveyor.com>
    ndonkoHenri and FeodorFitsner authored Jul 9, 2026
    Configuration menu
    Copy the full SHA
    8f326f8 View commit details
    Browse the repository at this point in the history

Commits on Jul 10, 2026

  1. Bump to 4.3.1: Android x86_64 empty sitepackages.zip fix (flet-dev#229)

    * Bump to 4.3.1: Android empty sitepackages.zip fix for --arch subsets
    
    The substantive change is in serious_python_android: the ABI-common
    sitepackages.zip / extract.zip assets were built from a hardcoded primary
    ABI (abis.first() = arm64-v8a). When `flet build apk --arch x86_64` staged
    only x86_64 site-packages, the primary split task walked a nonexistent
    directory and silently shipped a valid-but-empty sitepackages.zip - the app
    had no Python dependencies and the first import failed at startup.
    
    The primary ABI is now the first manifest ABI whose site-packages tree was
    actually staged under SERIOUS_PYTHON_SITE_PACKAGES. If none is staged
    (legitimate when packaging with no requirements), fall back to abis.first()
    and log a warning instead of staying silent.
    
    All other packages are alignment-only bumps.
    
    * Update CI condition to handle workflow cancellation
    
    ---------
    
    Co-authored-by: ndonkoHenri <robotcoder4@protonmail.com>
    FeodorFitsner and ndonkoHenri authored Jul 10, 2026
    Configuration menu
    Copy the full SHA
    dd67d0f View commit details
    Browse the repository at this point in the history

Commits on Jul 12, 2026

  1. Configuration menu
    Copy the full SHA
    9dc0861 View commit details
    Browse the repository at this point in the history

Commits on Jul 13, 2026

  1. Mobile packaging fixes: iOS interdependent-dylib frameworks + Android…

    … native-__init__ packages (flet-dev#232)
    
    * fix(android): resolve a package whose __init__ IS a native extension
    
    _SorefFinder only probed "<dotted>.soref" for a relocated native module, so a
    package whose __init__ is itself the extension (e.g. apsw ships
    apsw/__init__.<abi>.so, dotted import name `apsw`) was never resolved: the
    marker for it is written at "<dotted>/__init__.soref", not "<dotted>.soref".
    find_spec returned None, the synthesized empty apsw/__init__.py won, and
    `import apsw` yielded an empty module -> AttributeError on apsw.Connection /
    apsw.apswversion().
    
    find_spec now falls back to "<dotted>/__init__.soref" when the plain marker
    misses, loads the extension under the correct top-level name via
    ExtensionFileLoader (its PyInit_<name> matches, e.g. PyInit_apsw), and marks the
    result a package with submodule_search_locations pointing at the package dir in
    the winning sys.path entry (sitepackages.zip or an extract.zip dir) so pure-
    Python submodules (apsw.ext, apsw._unicode, ...) resolve normally. _read_marker
    now also returns the winning entry for that purpose.
    
    Verified on-device (Android arm64, Flet 0.86): apsw 3.53.2.0 imports and runs a
    full in-memory SQLite CREATE/INSERT/SELECT round-trip (2/2 recipe tests pass);
    previously both failed with the empty-__init__ AttributeError.
    
    * darwin: reconcile framework install-names for interdependent dylibs (flet-dev#223)
    
    After sync_site_packages framework-izes each site-package .so/.dylib into a
    framework named by its dotted relative path (opt/lib/libarrow.dylib ->
    opt.lib.libarrow.framework/opt.lib.libarrow), the Mach-O install-ids and every
    interdependent @rpath reference were left at their original bare names
    (@rpath/libarrow.dylib). Because each framework is a Package.swift binaryTarget
    the plugin depends on, dyld links them all at launch, and a bare
    @rpath/libarrow.dylib resolves to Frameworks/libarrow.dylib -- which does not
    exist -- so the app crashes before Python starts (e.g. pyarrow, llama-cpp).
    
    Add reconcile_framework_install_names(): after the conversion loop, set each
    framework binary's own install-id to @rpath/<fw>.framework/<fw> and rewrite
    every dep that pointed at a sibling's old id to that sibling's framework path,
    then re-sign. The python/stdlib xcframeworks are already correct and excluded.
    
    Verified locally: pyarrow 24.0.0 on iOS simulator now launches and passes 4/4
    tests (was a dyld launch crash: Library not loaded @rpath/libarrow.dylib).
    
    * darwin: harden reconcile_framework_install_names (fail-loud + all-slice ids)
    
    Two robustness fixes to the flet-dev#223 reconcile pass (both from code review):
    
    1. Stop swallowing real failures. The install_name_tool/-id/-change and codesign
       calls used `2>/dev/null || true`, which also hid genuine failures — most
       importantly install_name_tool's 'larger updated load commands do not fit'
       (a Mach-O with no header space to grow a load command). A swallowed -change
       leaves a bare @rpath ref and reproduces the exact dyld launch crash this pass
       exists to prevent, silently. Now: -id, a *present-dep* -change (absent deps
       are still a rc-0 no-op), and codesign failures are fatal — the function
       returns non-zero with a clear message, and sync_site_packages.sh propagates it
       (`|| exit 1`) so `flet build` fails loudly instead of shipping a broken app.
       stderr is captured and only printed on error, so the expected
       'will invalidate the code signature' warning stays off the build log.
    
    2. Record every slice's old install-id, not just the first. Pass 1 read oldid
       only from the first slice; a lib whose slices carry divergent install names
       (e.g. an arch-specific absolute build path instead of an @rpath id) would
       leave the other slices' deps unrewritten. Now each distinct old id is mapped
       (deduped) to the same new framework id.
    
    Verified: happy path (padded dylibs) + the real llama ggml->llama chain both
    reconcile to rc 0 with no bare refs; a divergent-slice-id pair rewrites both
    slices; an unpadded binary now fails loudly (rc 1) instead of silently.
    
    * changelog: fold the flet-dev#223 + apsw-soref + reconcile-hardening fixes into the unreleased 4.3.2
    
    4.3.2 is not yet released, so these packaging fixes ship in it rather than a new
    version: darwin gets the interdependent-dylib framework reconcile (flet-dev#223) + its
    fail-loud/all-slice hardening; android gets the native-__init__ soref resolution
    (apsw); the main package aggregates both. Versions unchanged (already 4.3.2).
    ndonkoHenri authored Jul 13, 2026
    Configuration menu
    Copy the full SHA
    884fb94 View commit details
    Browse the repository at this point in the history

Commits on Jul 14, 2026

  1. Configuration menu
    Copy the full SHA
    1f8a742 View commit details
    Browse the repository at this point in the history

Commits on Jul 16, 2026

  1. Fix Windows build failure on non-UTF-8 locales (C4819/C2220) (flet-de…

    …v#234)
    
    serious_python_windows_plugin.cpp contained a non-ASCII character (an em
    dash) in a comment. On a system whose code page isn't UTF-8 (e.g. 936/GBK
    on Simplified-Chinese Windows) MSVC decodes the UTF-8 source as GBK, can't
    represent the bytes and emits warning C4819, which the Flutter template's
    /WX escalates to a fatal C2220 -> `flet build windows` fails.
    
    Remove the character and compile the Windows plugin with /utf-8 so any
    future non-ASCII source byte is read correctly regardless of the build
    machine's code page. Also drop the same stray character from the Linux
    plugin source (GCC tolerated it, no build impact).
    
    Bump all packages 4.3.2 -> 4.3.3 with changelog entries.
    
    Fixes flet-dev/flet#6686
    FeodorFitsner authored Jul 16, 2026
    Configuration menu
    Copy the full SHA
    55e0ca6 View commit details
    Browse the repository at this point in the history

Commits on Jul 18, 2026

  1. Bump to 4.3.4: Android flet debug stale-code fix (flet #6682) (flet…

    …-dev#235)
    
    `flet debug android` kept running previously-unpacked, stale app code after
    a re-run. `prepareApp` copies the app payload out of the APK only when its
    cache key changes, and the key was `versionName+versionCode`. `flet debug`
    reinstalls the same-version APK on each iteration (`flutter run` does an
    update install that preserves app data, including the cache marker), so the
    key never changed and re-extraction was skipped.
    
    `getAppVersion` now appends `PackageManager.lastUpdateTime` to the key,
    which is bumped on every (re)install but stays stable across plain
    relaunches — so a debug reinstall re-extracts the new code while ordinary
    relaunches still hit the cache. `flet build apk` was unaffected.
    FeodorFitsner authored Jul 18, 2026
    Configuration menu
    Copy the full SHA
    1d241a4 View commit details
    Browse the repository at this point in the history

Commits on Jul 19, 2026

  1. Re-pin python-build to 20260719: desktop _pyrepl restored (pydoc/pdb …

    …import, flet-dev#236) (flet-dev#237)
    
    Windows/Linux desktop apps on Python 3.14 crashed at startup with
    ModuleNotFoundError: No module named '_pyrepl' when the app or a dependency
    (e.g. NLTK) imports pydoc/pdb — 3.14's pydoc/pdb import _pyrepl at module
    load, but it was pruned from the desktop stdlib as a dev-only module.
    
    python-build 20260719 un-prunes _pyrepl on Windows/Linux (flet-dev/python-build#31);
    iOS/macOS/Android already shipped it (4.3.2), so those runtimes are byte-identical
    to 20260714. Folded into the not-yet-released 4.3.4.
    
    Fixes flet-dev#236
    FeodorFitsner authored Jul 19, 2026
    Configuration menu
    Copy the full SHA
    59168a8 View commit details
    Browse the repository at this point in the history

Commits on Jul 20, 2026

  1. Bump to 4.3.6: Windows UTF-8 startup fix (dart_bridge 1.5.1, python-b…

    …uild 20260720) (flet-dev#238)
    
    * Bump to 4.3.5: Windows UTF-8 startup fix (dart_bridge 1.5.1, python-build 20260720)
    
    Re-pin the bundled python-build snapshot to 20260720, which bumps dart_bridge
    1.5.0 -> 1.5.1. 1.5.1 fixes Windows startup when app paths or environment
    values contain non-ASCII characters: Dart FFI strings (UTF-8) are now converted
    to UTF-16 before hitting the Windows CRT (_wputenv_s / _wfopen_s), Python UTF-8
    mode is enabled before Py_Initialize(), and embedded env-setup failures are
    fatal. Closes flet-dev/flet#6641.
    
    Windows-only change; iOS/macOS/Android/Linux runtimes are functionally
    unchanged from 20260719. Python versions (3.12.13 / 3.13.14 / 3.14.6) unchanged.
    
    * Retarget release 4.3.5 -> 4.3.6 (4.3.5 was accidentally published and pulled)
    
    4.3.5 was published to pub.dev by mistake before this PR merged and has been
    retracted, so the version number is burned. Bump all packages and CHANGELOG
    sections to 4.3.6. Content is identical: python-build 20260720 / dart_bridge
    1.5.1 Windows UTF-8 startup fix (flet #6641).
    FeodorFitsner authored Jul 20, 2026
    Configuration menu
    Copy the full SHA
    daada1a View commit details
    Browse the repository at this point in the history
  2. fix(android): make PEP 734 subinterpreters work (`concurrent.interpre…

    …ters` / `InterpreterPoolExecutor`) (flet-dev#239)
    
    * fix(android): make subinterpreters able to import relocated native modules
    
    PEP 734 subinterpreters (Python 3.14 concurrent.interpreters /
    InterpreterPoolExecutor) were unusable in Android apps: the main
    interpreter works, but every subinterpreter failed to import any C
    extension (ModuleNotFoundError: _struct / _interpqueues / ...), which
    breaks the whole feature (its cross-interpreter transport pickles ->
    _struct, and its queues need _interpqueues). iOS and desktop are
    unaffected.
    
    Root cause: Android relocates C extensions (native-mmap packaging) and
    resolves them through the custom _SorefFinder installed on
    sys.meta_path. sys.meta_path is per-interpreter, and install() only ran
    in the main interpreter, so a freshly created subinterpreter had a
    meta_path without the finder and could import no relocated .so. Verified
    on-device: main meta_path has _SorefFinder, a subinterpreter's does not.
    
    Fix: teach every new subinterpreter to install the finder. Split the
    finder insertion into _install_finder(), and make install() also call a
    new _patch_subinterpreters() that wraps concurrent.interpreters.create()
    so each new interpreter runs `import _sp_bootstrap; _sp_bootstrap.install()`.
    The setup runs via Interpreter.exec() -- a source string, which is
    pickle-free (unlike Interpreter.call()), so it works BEFORE _struct is
    importable in the child. (A fresh subinterpreter inherits the
    process-wide sys.path, so no sys.path seeding is needed --
    verified on-device.)
    
    Notes:
    - No dart-bridge / C change: the existing Android bootstrap already calls
      install(), which now triggers the patch. The wrapper is tagged
      `_sp_patched` for idempotency.
    - create() is the factory InterpreterPoolExecutor uses
      (WorkerContext.initialize -> interpreters.create()), so patching it
      fixes the pool transparently -- with no user code change.
    - A user-supplied InterpreterPoolExecutor(initializer=...) can NOT fix
      this: the initializer is delivered over the same broken pickle path, so
      the finder must be installed at interpreter-creation time.
    - No-op before 3.14 (module absent) and on iOS/desktop (this file is
      Android-only). Idempotent; supports nested subinterpreters.
    
    Verified end-to-end on an Android 15 / arm64-v8a emulator (Python
    3.14.6): the clean probe app -- with no app-level workaround -- runs a
    low-level create+queue round-trip, an InterpreterPoolExecutor across 4
    interpreters in one process, and imports a C extension inside a
    subinterpreter.
    
    * docs: note the Android subinterpreter fix under 4.3.6
    
    Fold the subinterpreter fix into the existing 4.3.6 section (main jumped
    4.3.4 -> 4.3.6 with the Windows UTF-8 release; our 4.3.5 draft was
    rebased away): a detailed bullet in serious_python_android and a
    summary bullet in serious_python (umbrella). The Apple/Windows/Linux/
    interface packages already carry their 4.3.6 entries from the Windows
    release and are unaffected by this Android-only change. No pubspec bump
    needed — this rides in the same 4.3.6 that main is already on.
    
    * docs+debug: note create()-attribute assumption; stderr breadcrumb on child finder-install failure
    
    ---------
    
    Co-authored-by: Feodor Fitsner <feodor@appveyor.com>
    ndonkoHenri and FeodorFitsner authored Jul 20, 2026
    Configuration menu
    Copy the full SHA
    7e8a923 View commit details
    Browse the repository at this point in the history

Commits on Jul 25, 2026

  1. Bump to 4.4.0: dart_bridge as a dynamic framework on Apple platforms (f…

    …let-dev#240)
    
    * Bump to 4.4.0: dart_bridge as a dynamic framework on Apple platforms
    
    Fixes built iOS apps crashing at startup with 'Failed to lookup symbol
    serious_python_run: dlsym(RTLD_DEFAULT, serious_python_run): symbol not
    found'.
    
    dart_bridge's FFI entry points (serious_python_run, DartBridge_*,
    PyInit_dart_bridge) are resolved at runtime via dlsym -- from Dart through
    DynamicLibrary.process() and from Python through 'import dart_bridge'. It
    previously shipped as a static archive linked into the host app executable,
    and an iOS executable exports nothing to the dynamic symbol table by default
    (release builds also strip local symbols), so those lookups failed. Only
    release/archive device builds were affected: debug/simulator don't
    dead-strip. Android was never affected -- its dart_bridge is a dynamic .so.
    
    dart_bridge 1.6.0 now builds dart_bridge.xcframework as a dynamic framework
    (flet-dev/dart-bridge#11), so it is embedded + signed into the app like
    Python.xcframework and its symbols stay exported. Removes what a loaded
    image no longer needs: the SwiftPM -all_load/-force_load retention, the
    CocoaPods -all_load, and the plugin's dead-strip keep-alive references.
    
    Re-pins the bundled python-build snapshot to 20260725 (dart_bridge
    1.5.1 -> 1.6.0, Pyodide 3.14 314.0.2 -> 314.0.3). Python versions
    (3.12.13 / 3.13.14 / 3.14.6) are unchanged and all platform runtimes are
    byte-identical to 20260720.
    
    Also bumps .fvmrc to Flutter 3.44.8.
    
    * Re-pin dart_bridge to 1.6.1 (macOS framework symlink fix)
    
    python-build's 20260725 manifest was updated in place to dart_bridge 1.6.1,
    so regenerate the version tables against it.
    
    1.6.1 zips the Apple xcframework with -y so the macOS slice's versioned
    framework symlinks (Versions/Current -> A, dart_bridge and Resources ->
    Versions/Current/...) survive publishing. Under 1.6.0 they were followed and
    stored as real files/directories, producing a malformed bundle that macOS
    codesign rejected ('Couldn't resolve framework symlink for
    .../Versions/Current', 'code object is not signed at all'). iOS was
    unaffected -- its slices use a flat layout with no symlinks. See
    flet-dev/dart-bridge#12.
    
    Binaries are unchanged from 1.6.0; only the artifact packaging differs.
    FeodorFitsner authored Jul 25, 2026
    Configuration menu
    Copy the full SHA
    d0c8f9d View commit details
    Browse the repository at this point in the history

Commits on Jul 26, 2026

  1. Bump to 4.4.1: OpenSSL privacy manifest for iOS _ssl/_hashlib (flet-d…

    …ev#241)
    
    Re-pins the bundled python-build snapshot to 20260726, which replaces the
    stub PrivacyInfo.xcprivacy bundled into _ssl.framework and _hashlib.framework
    with the manifest OpenSSL publishes for its Apple builds
    (flet-dev/python-build#35).
    
    No versions moved: Python 3.12.13 / 3.13.14 / 3.14.6, Pyodide, and
    dart_bridge 1.6.1 are all unchanged from 20260725.
    
    This is a correctness fix, not a fix for the ITMS-91065 rejection in
    flet-dev/flet#6724 — see the serious_python_darwin 4.4.1 entry for what was
    ruled out and what remains open.
    FeodorFitsner authored Jul 26, 2026
    Configuration menu
    Copy the full SHA
    3ee5620 View commit details
    Browse the repository at this point in the history

Commits on Jul 27, 2026

  1. Bump to 4.4.2: Xcode build-provenance keys in iOS framework Info.plis…

    …ts (flet-dev#242)
    
    * Bump to 4.4.2: Xcode build-provenance keys in iOS framework Info.plists
    
    Re-pins the bundled python-build snapshot to 20260727, which stamps the DT*
    build-provenance keys Xcode writes into a real framework's Info.plist into
    every framework generated from a lib-dynload .so, and labels the simulator
    slice as iPhoneSimulator instead of iPhoneOS (flet-dev/python-build#36).
    
    No versions moved: Python 3.12.13 / 3.13.14 / 3.14.6, Pyodide, and
    dart_bridge 1.6.1 are all unchanged from 20260726.
    
    This is the next hypothesis under test for the ITMS-91065 rejection in
    flet-dev/flet#6724, not a confirmed fix — see the serious_python_darwin 4.4.2
    entry for what was ruled out experimentally and what remains open.
    
    * iOS: namespace framework bundle identifiers under the host app
    
    Every Python C-extension ships as its own embedded framework, and each carried
    a fixed `org.python.<module>` CFBundleIdentifier -- org.python.ssl,
    org.python.hashlib, ... -- byte-identical in every app ever built with
    serious_python.
    
    A framework's bundle identifier also becomes its CODE SIGNING identifier, and
    that is the one field that survives the `codesign -f` Xcode applies at embed
    and again at exportArchive (everything else -- certificate chain, team
    identifier, secure timestamp -- is destroyed). A globally-shared identifier on
    a framework Apple fingerprints as a listed third-party SDK is the leading
    explanation for the ITMS-91065 rejection in flet-dev/flet#6724.
    
    Setting SERIOUS_PYTHON_BUNDLE_ID rewrites them to `<app id>.<module>` with
    underscores mapped to hyphens, matching CPython's own iOS support
    (Platforms/Apple/testbed/Python.xcframework/build/utils.sh). The leading hyphen
    for underscore-prefixed modules (`_ssl` -> `<app>.-ssl`) is deliberate: it is
    what keeps `_ssl` distinct from `ssl`, and it is the form CPython ships.
    
    The rewrite runs before reconcile_framework_install_names, whose ad-hoc re-sign
    reseals the modified plists; the stdlib xcframeworks are unsigned at that point
    so editing them invalidates nothing. Module names come from arbitrary wheels,
    so anything outside CFBundleIdentifier's [A-Za-z0-9.-] is mapped to a hyphen,
    and an invalid SERIOUS_PYTHON_BUNDLE_ID leaves the defaults in place with a
    warning rather than emitting a plist that fails late at export.
    
    flet passes the value from flet-dev/flet#6731.
    
    * iOS: namespace Python.framework's bundle id too
    
    Python.xcframework is staged straight out of dist/xcframeworks by stage_spm.sh
    and vendored from there by the podspec, so it never passes through
    site-xcframeworks and kept a shared `org.python.python` -- identical in every
    app, the same class of identifier the previous commit fixed for the extension
    frameworks.
    
    Verified inert at runtime before renaming: `org.python.python` appears in no
    shipped binary, and neither Python.framework nor App.framework contains a
    CFBundleGetBundleWithIdentifier / bundleWithIdentifier lookup. serious_python
    sets PYTHONHOME explicitly and resolves extensions through the .fwork/.origin
    path mechanism, not bundle identifiers.
    
    rewrite_framework_bundle_ids takes an optional skip list so dart_bridge keeps
    `dev.flet.dartbridge` -- a vendor-owned reverse-DNS identifier is the shape
    we're aiming for, not the problem we're fixing.
    
    Confirmed against a real build (flet playground abc1.xcarchive): 93 of 98
    frameworks were already namespaced, no duplicate identifiers; this covers
    Python.framework, leaving only Flutter's own three (App, Flutter, objective_c)
    and dart_bridge.
    
    * examples: pin jni to 1.0.0 (1.0.1 breaks aarch64 Linux builds)
    
    jni 1.0.1, published 2026-07-27T01:10Z, added global_jni_env.c, which passes a
    `va_list` where a `void *` is expected. On x86_64 va_list is an array type that
    decays to a pointer so it compiles; on aarch64 it is a struct, so it is a hard
    error and `flutter build linux` fails with 19 of them. Tracked upstream at
    dart-lang/native#3498.
    
    This surfaced on the release PR rather than as a scheduled failure because the
    examples depend on the serious_python packages by path: bumping their version
    invalidates the committed pubspec.lock, pub re-resolves the whole graph, and
    picks up the newest transitive versions. Any PR touching package versions after
    2026-07-27T01:10Z would have hit it. jni itself arrives via
    path_provider -> path_provider_android -> jni_flutter -> jni.
    
    jni_flutter 1.0.1 declares `jni: ^1.0.0`, so 1.0.0 satisfies it -- the override
    narrows within the allowed range rather than overriding a constraint. Applied to
    all three examples; only bridge_example runs in CI, but the other two break
    identically for anyone building them on an ARM64 Linux host.
    
    The flask_example / run_example locks also pick up the current path-dependency
    version (4.0.0 -> 4.4.1); they were simply stale.
    FeodorFitsner authored Jul 27, 2026
    Configuration menu
    Copy the full SHA
    2792729 View commit details
    Browse the repository at this point in the history

Commits on Jul 29, 2026

  1. Bump to 4.5.0: preserve provider XCFramework signatures through stagi…

    …ng (flet-dev#244)
    
    Xcode records the state of every .xcframework an app links against AS ITS
    PUBLISHER SHIPPED IT and writes that into the IPA as
    Signatures/<name>.xcframework-<platform>.signature. ITMS-91065: Missing signature
    (flet-dev/flet#6724) reports on THOSE receipts -- not on the embedded copy, which
    Xcode re-signs with the submitting team's identity at embed and again at
    exportArchive.
    
    This retracts the reasoning behind 4.4.2. That release namespaced framework
    CFBundleIdentifiers under the host app on the theory that a shared org.python.*
    identifier was what Apple keyed on, and argued that "a signature applied at the
    source can't matter" because exportArchive overwrites it. The overwrite is real;
    the conclusion was not. Worse, the fix was counterproductive: rewriting an
    Info.plist inside a provider XCFramework is exactly what destroys the SDK-origin
    signature the receipt reports on.
    
    So provider artifacts are now immutable here. Locally built site-package
    frameworks are created in their own temporary directory, mutated there (bundle
    ids, install names, ad-hoc re-sign), and merged over verbatim provider copies
    afterwards. Both rewrite_framework_bundle_ids calls on provider directories are
    gone; the helper's contract now says provider bundles are off limits and why.
    Provider frameworks carry stable dev.flet.python.* / dev.flet.dartbridge
    identifiers assigned upstream, so there was nothing left for it to fix anyway.
    
    xcframework_verify.sh adds two independent guards at every staging step:
    
      * A SHA-256 manifest (files plus symlink targets) recorded when the archives
        are extracted, re-checked after site-package sync and after SwiftPM staging.
        Always fatal -- a mismatch is a bug in this repo, not a property of whatever
        upstream release is pinned. This keeps working even against unsigned
        artifacts, which is what makes the guarantee testable rather than aspirational.
      * codesign verification of the provider signature: real Timestamp=, expected
        authority, and TeamIdentifier when SERIOUS_PYTHON_EXPECTED_TEAM_ID is set.
        Gated by SERIOUS_PYTHON_VERIFY_PROVIDER_SIGNATURES (warn default / require /
        off). The default is warn so pinning a pre-signing python-build or dart-bridge
        release still builds; use require for App Store submissions.
    
    prepare_macos.sh's Python.app removal now runs before the snapshot rather than
    after it. python-build has excluded Python.app upstream for some time so it
    matches nothing on current artifacts, but it does delete a file from inside a
    provider bundle, so it cannot sit after the provenance check.
    
    iOS packaging: the CocoaPods path installs stdlib and site-package extensions by
    copying INNER .framework bundles in a Pods-Runner-frameworks.sh script phase.
    Xcode only writes SDK-origin receipts for xcframeworks it consumes as declared
    binary dependencies, so that path cannot produce complete receipts however well
    the source is signed. It now emits an Xcode `warning:` saying so, and the README
    documents SwiftPM as the required path for App Store submissions.
    
    Re-pins python-build to 20260729 and dart_bridge to 1.7.0, the first releases of
    each whose Apple XCFrameworks are provider-signed. No Python version moved
    (3.12.13 / 3.13.14 / 3.14.6). dart_bridge's Android .so's and Linux .so are
    byte-identical to 1.6.1 (verified); the Windows DLL is rebuilt because MSVC stamps
    a timestamp and PDB GUID into every build, with no Windows source change.
    
    Verified end to end against the signed artifacts with require mode and the real
    team id: 57 provider signatures verified at extraction, digests unchanged after
    sync and SwiftPM staging, and the staged _ssl.xcframework inside the Swift package
    still reporting Identifier=dev.flet.python.-ssl with its original signing
    timestamp -- i.e. the signature survived download, extract, sync and staging
    untouched.
    FeodorFitsner authored Jul 29, 2026
    Configuration menu
    Copy the full SHA
    ffb16ff View commit details
    Browse the repository at this point in the history

Commits on Jul 31, 2026

  1. Bump to 4.5.1: sign and verify both XCFramework layers (flet-dev#245)

    * Bump to 4.5.1: sign and verify both XCFramework layers
    
    4.5.0 shipped provider artifacts whose outer .xcframework was signed but whose
    inner .framework bundles were not. An App Store IPA built against it reported
    `signed = true` -- the 4.5.0 fix working, with receipt cdhashes matching the
    published artifacts byte for byte -- but `isSecureTimestamp = false` for
    Python-ios, _ssl, _hashlib and dart_bridge. Identical in a development archive
    and an App Store export, so the export method was not the variable.
    
    The control that settles it: krzyzanowskim/OpenSSL 3.6.3000, an XCFramework
    Apple's scan demonstrably accepts, signs all ten of its slices with an Apple
    Distribution identity and a secure timestamp and signs the outer bundle last. An
    unsigned inner framework was the only structural difference left. python-build
    20260730 and dart_bridge 1.7.1 now sign both layers.
    
    Consumer verification follows: spv_verify_provider checks each slice's inner
    framework as well as the outer bundle, so an unsigned slice fails during
    packaging instead of surfacing in a submission. Two lookup bugs found while
    building negative controls for it are fixed here too:
    
      * Slice frameworks are located by glob rather than by the xcframework's name.
        stage_spm.sh stages Python.xcframework as Python-<platform>.xcframework, and
        a name-keyed lookup silently finds nothing there -- turning "this slice is
        unsigned" into "there was nothing to check".
      * Signature presence is probed with `codesign -dv` rather than by looking for a
        _CodeSignature directory. A versioned macOS bundle keeps it under
        Versions/<name>/ and that name is not always "A": CPython uses Versions/3.14,
        so a correctly signed macOS framework was reported as unsigned.
    
    Re-pins python-build to 20260730 and dart_bridge to 1.7.1. No Python version
    moved (3.12.13 / 3.13.14 / 3.14.6); nothing about Android, Linux or Windows
    changed. 20260730 also fixes the macOS Python.framework layout -- Headers and
    Modules were real directories at the framework root, which codesign rejects for a
    versioned bundle -- so they are now symlinks into Versions/Current.
    
    Verified end to end against the signed artifacts in require mode with the real
    team id: 57 xcframeworks and 115 slice frameworks verified at extraction, digests
    unchanged through sync and both SwiftPM stagings, and the staged _ssl.xcframework
    inside the Swift package reporting Apple Distribution on BOTH layers with its
    original signing timestamp. Stripping an inner signature fails the run.
    
    * Record that inner signing did not flip isSecureTimestamp
    
    The 4.5.1 entry implied that signing both layers was the fix for
    `isSecureTimestamp = false`. It is not, and shipping that claim unamended would
    be wrong.
    
    With both layers signed, the App Store receipts still read `signed = true` /
    `isSecureTimestamp = false`. Three findings pin this down:
    
      * The receipt's cdhash matches the OUTER xcframework's CDHash exactly
        (dart_bridge 582388d2..., _ssl df6220fd...), not the inner framework's. Xcode
        reads the outer signature -- the one that carries the TSA timestamp -- and
        reports false anyway.
      * Decoding the CMS in _CodeSignature/CodeSignature shows a genuine RFC 3161
        id-smime-aa-timeStampToken (1.2.840.113549.1.9.16.2.14) unsigned attribute,
        not merely a self-asserted signingTime.
      * That CMS attribute set is structurally identical to the accepted OpenSSL
        artifact's, down to the Apple certificate extensions -- so there is no
        observable difference left between a signature Apple accepts and ours.
    
    Every receipt in the archive reports false, and all record
    signatureType = AppleDeveloperProgram; the accepted artifact is signed by an
    Apple Distribution identity too and would carry the same type. The reasonable
    reading is that ITMS-91065 tests `signed`, which is now true, and that
    isSecureTimestamp is not reachable by signing.
    
    Signing both layers is kept regardless: it matches what an accepted artifact
    does, and it is correct practice for a distributed binary framework. No code
    changes -- changelog only.
    FeodorFitsner authored Jul 31, 2026
    Configuration menu
    Copy the full SHA
    9896a51 View commit details
    Browse the repository at this point in the history
Loading