From a459b0f29d0abaefcd6461d217f54200ea58d57e Mon Sep 17 00:00:00 2001 From: mohamed-elkholy95 Date: Tue, 2 Jun 2026 22:13:44 -0400 Subject: [PATCH 1/2] fix(windows): wipe _internal before upgrade to prevent stale dist-info version Inno Setup's ignoreversion recursesubdirs adds files but never removes obsolete ones, so in-place upgrades left both pythinker_code-0.28.0.dist-info and pythinker_code-0.31.0.dist-info under _internal. importlib.metadata picks the first path-finder match, which is the alphabetically-lower (older) version, causing the UI to show the old version number and re-trigger the update prompt after every successful upgrade. Uninstall+reinstall worked cleanly because the uninstaller wiped {app} entirely. Add [InstallDelete] to remove {app}\_internal before [Files] runs so each upgrade starts from a clean directory. _internal is 100% PyInstaller app payload; no user data lives there. Add a regression assertion to prevent this section from being silently dropped. --- packages/windows-installer/installer.iss | 10 ++++++++++ tests/test_release_update_pipeline.py | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/windows-installer/installer.iss b/packages/windows-installer/installer.iss index 4b1473ce..cfce572a 100644 --- a/packages/windows-installer/installer.iss +++ b/packages/windows-installer/installer.iss @@ -47,6 +47,16 @@ Name: "modifypath"; Description: "Add Pythinker to your PATH"; \ Name: "modifypathmachine"; Description: "Add Pythinker to the system PATH"; \ GroupDescription: "Shell integration:"; Check: IsAdminInstallMode +[InstallDelete] +; Remove the entire _internal directory before installing new files so that +; in-place upgrades do not accumulate stale version-stamped dist-info dirs +; (e.g. pythinker_code-0.28.0.dist-info alongside 0.31.0.dist-info). +; importlib.metadata.version() picks the first match it finds, which is the +; alphabetically-lower (older) version, causing the UI to display a stale +; version number and re-trigger the update prompt after every upgrade. +; _internal is 100% app payload — no user data lives there. +Type: filesandordirs; Name: "{app}\_internal" + [Files] Source: "..\..\dist\pythinker\*"; DestDir: "{app}"; \ Flags: ignoreversion recursesubdirs createallsubdirs diff --git a/tests/test_release_update_pipeline.py b/tests/test_release_update_pipeline.py index d1561d48..d3931b79 100644 --- a/tests/test_release_update_pipeline.py +++ b/tests/test_release_update_pipeline.py @@ -137,6 +137,14 @@ def test_windows_installer_signs_update_artifacts_when_credentials_are_available assert re.search(r"NewPath\s*:=\s*Param\s*\+\s*';'\s*\+\s*OrigPath", installer_script) assert not re.search(r"NewPath\s*:=\s*OrigPath\s*\+\s*';'\s*\+\s*Param", installer_script) assert not re.search(r"StringChangeEx\(\s*OrigPath\s*,\s*Param\s*,", installer_script) + # [InstallDelete] must wipe _internal before [Files] runs so that in-place + # upgrades never accumulate stale dist-info dirs (pythinker_code-0.28.0.dist-info + # alongside 0.31.0 makes importlib.metadata pick the old version first). + assert re.search( + r"\[InstallDelete\].*filesandordirs.*\{app\}\\_internal", + installer_script, + re.DOTALL, + ) # Signing only the final setup executable leaves Smart App Control and AV # heuristics to inspect unsigned bundled/native helper files. Keep signing From 65c733a7480fa1ac3799a3efb941edc71efa03c2 Mon Sep 17 00:00:00 2001 From: mohamed-elkholy95 Date: Tue, 2 Jun 2026 22:16:44 -0400 Subject: [PATCH 2/2] chore: add changelog entry for Windows upgrade version fix --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4808053e..a341e704 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ GitHub Releases page; `0.8.0` is the new starting line. ## Unreleased +- **Windows upgrade version display fix.** In-place upgrades no longer show a stale version number or re-trigger the update prompt. Inno Setup now wipes `_internal` before installing new files, preventing old `dist-info` directories from accumulating and causing `importlib.metadata` to report the previous version. + ## 0.31.0 (2026-06-02) ### What changed in this release