From 67b73076cd0f47fef4486aa4f7e6b90e9c563570 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 17 Aug 2026 19:36:46 +0200 Subject: [PATCH 1/3] fix(package): pass --no-input and bounded timeouts to pip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pip prompts for credentials when an index answers 401 — a corporate mirror, an authenticating proxy. The prompt has no trailing newline and this process has no interactive stdin, so it can never be answered or even seen, and the install blocks forever with "Looking in indexes: ..." as its last output. That is what `flet build` users see as a frozen "Packaging Python app..." (flet-dev/flet#5989, #5013, #5507). --no-input makes it a readable error instead. --timeout/--retries bound each attempt rather than inheriting whatever ambient pip config applies. --- src/serious_python/bin/package_command.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index 7aebb9e5..fd721b4b 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -441,7 +441,16 @@ class PackageCommand extends Command { stdout.writeln( "Installing $requirements with pip command to $sitePackagesDir"); - List pipArgs = ["--disable-pip-version-check"]; + List pipArgs = [ + "--disable-pip-version-check", + // Without it, a 401 from an index makes pip prompt, and hang. + "--no-input", + // Bound each attempt instead of inheriting ambient pip config. + "--timeout", + "30", + "--retries", + "3", + ]; if (isMobile || isWeb) { pipArgs.addAll(["--only-binary", ":all:"]); From d02fd2a8fe2b444f090fd8e813dd3eddd90777c8 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 17 Aug 2026 19:57:33 +0200 Subject: [PATCH 2/3] chore: dart format and sort imports in package_command.dart Pre-existing drift, separated from the fix so it doesn't bury it. --- src/serious_python/bin/package_command.dart | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/serious_python/bin/package_command.dart b/src/serious_python/bin/package_command.dart index fd721b4b..bbe4f628 100644 --- a/src/serious_python/bin/package_command.dart +++ b/src/serious_python/bin/package_command.dart @@ -8,8 +8,8 @@ import 'package:glob/glob.dart'; import 'package:glob/list_local_fs.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; -import 'package:shelf/shelf.dart'; import 'package:serious_python/src/python_versions.dart'; +import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as shelf_io; import 'macos_utils.dart' as macos_utils; @@ -344,10 +344,8 @@ class PackageCommand extends Command { // site-packages root String sitePackagesRoot = path.join(currentPath, "build", "site-packages"); - if (Platform.environment - .containsKey(sitePackagesEnvironmentVariable)) { - final envValue = - Platform.environment[sitePackagesEnvironmentVariable]; + if (Platform.environment.containsKey(sitePackagesEnvironmentVariable)) { + final envValue = Platform.environment[sitePackagesEnvironmentVariable]; if (envValue != null && envValue.isNotEmpty) { sitePackagesRoot = envValue; } @@ -382,7 +380,8 @@ class PackageCommand extends Command { // minor (per python-build's manifest `android_abis`); installing // for an unpublished ABI would be wasted work. if (platform == "Android" && - !pythonReleases[_pythonShortVersion]!.androidAbis + !pythonReleases[_pythonShortVersion]! + .androidAbis .contains(arch.key)) { continue; } @@ -443,13 +442,12 @@ class PackageCommand extends Command { List pipArgs = [ "--disable-pip-version-check", - // Without it, a 401 from an index makes pip prompt, and hang. - "--no-input", - // Bound each attempt instead of inheriting ambient pip config. "--timeout", "30", "--retries", "3", + // Prevent pip from prompting and hanging for input. + "--no-input", ]; if (isMobile || isWeb) { @@ -685,7 +683,8 @@ class PackageCommand extends Command { Future _stageDarwinSpm(String platform, String projectPath) async { final darwinDir = await _resolveDarwinDir(projectPath); if (darwinDir == null) { - stdout.writeln("SPM staging skipped: could not resolve serious_python_darwin " + stdout.writeln( + "SPM staging skipped: could not resolve serious_python_darwin " "(set $darwinDirEnvironmentVariable or ensure " ".dart_tool/package_config.json is present)."); return; From cf121b67ffa279c6287b4e1aacb6a74820523145 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Mon, 17 Aug 2026 20:06:12 +0200 Subject: [PATCH 3/3] docs: changelog entry for the pip --no-input fix --- src/serious_python/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/serious_python/CHANGELOG.md b/src/serious_python/CHANGELOG.md index 8e4d189a..4e60fc7e 100644 --- a/src/serious_python/CHANGELOG.md +++ b/src/serious_python/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.5.2 + +* **Packaging:** `pip install` no longer hangs when an index answers `401` — an authenticating mirror or proxy. pip prompted for credentials on a stdin nothing could answer, and wrote the prompt without a newline so callers never displayed it; the install blocked with `Looking in indexes: ...` as its last output, which `flet build` showed as a frozen `Packaging Python app...`. pip now runs with `--no-input` and bounded `--timeout`/`--retries`. See flet-dev/flet#5989, flet-dev/flet#5013 and flet-dev/flet#5507. + ## 4.5.1 * **iOS/macOS:** the bundled `Python`, `dart_bridge` and stdlib extension XCFrameworks are now signed on both layers — each slice's inner `.framework` as well as the outer `.xcframework`. 4.5.0 signed only the outer bundle. Note this did **not** change `isSecureTimestamp`, which still reports false — that field appears not to be reachable by signing; `signed`, which `ITMS-91065` names, is true. See `serious_python_darwin` 4.5.1.