diff --git a/scripts/build-python-env-win.ps1 b/scripts/build-python-env-win.ps1 index 3fb059b7..fe6166ea 100644 --- a/scripts/build-python-env-win.ps1 +++ b/scripts/build-python-env-win.ps1 @@ -165,14 +165,16 @@ Write-Host "Trimming .pyi type stubs..." Get-ChildItem -Path $PythonEnvDir -Recurse -Filter '*.pyi' -File -ErrorAction SilentlyContinue ` | Remove-Item -Force -ErrorAction SilentlyContinue -# Pre-compile bytecode so cold backend startup skips parse+compile on -# every imported .py. Worth ~5-10s on Windows under Defender (parsing -# Python source is parser-bound; loading .pyc is just bytes). We cap -# concurrency at 4 — `-j 0` (all cores) is fine on dev boxes but -# unstable on small CI runners. Missing .pyc is non-fatal at runtime -# (Python falls back to in-memory compile), so we warn rather than fail. +# Pre-compile bytecode so cold backend startup skips parse+compile per import. +# invalidation-mode unchecked-hash is load-bearing: the default timestamp mode +# ties each .pyc to its source mtime, but the installer rewrites mtimes on extract, +# so every .pyc looks stale and Python recompiles the whole stdlib+deps from source +# on EVERY launch (and runtime PYTHONDONTWRITEBYTECODE means it never caches the +# result), which is the multi-minute Windows cold-start. unchecked-hash makes the +# .pyc valid regardless of mtime, which is the correct mode for a frozen bundle. +# Concurrency capped at 4; missing .pyc is non-fatal (runtime in-memory fallback). Write-Host "Pre-compiling bytecode..." -& $PythonBin -m compileall -q -j 4 (Join-Path $PythonEnvDir 'lib') +& $PythonBin -m compileall -q -j 4 --invalidation-mode unchecked-hash (Join-Path $PythonEnvDir 'lib') if ($LASTEXITCODE -ne 0) { Write-Host "WARNING: some files failed to compile; runtime will fall back to in-memory compile." -ForegroundColor Yellow } diff --git a/scripts/build-python-env.sh b/scripts/build-python-env.sh index b62db1b0..c00eca93 100755 --- a/scripts/build-python-env.sh +++ b/scripts/build-python-env.sh @@ -224,8 +224,12 @@ find "$PYTHON_ENV_DIR" -name 'libpython*.a' -delete 2>/dev/null || true # version-shim packages); a non-zero exit here would rather be visible # than silent so we don't `|| true` the whole thing — but missing .pyc # is non-fatal at runtime, so a hard fail isn't warranted either. +# invalidation-mode unchecked-hash: default timestamp mode ties each .pyc to its +# source mtime, which installers rewrite on extract, silently invalidating every +# .pyc so Python recompiles from source on every launch. unchecked-hash is mtime- +# independent (correct for a frozen bundle), so the precompiled .pyc actually get used. echo "Pre-compiling bytecode..." -"$PYTHON_BIN" -m compileall -q -j 4 "$PYTHON_ENV_DIR/lib" || \ +"$PYTHON_BIN" -m compileall -q -j 4 --invalidation-mode unchecked-hash "$PYTHON_ENV_DIR/lib" || \ echo "WARNING: some files failed to compile; runtime will fall back to in-memory compile." # ----- macOS: hide bundled python from the Dock -----