Skip to content

Fix cx_Freeze Windows build, PPTX export, and portable-build tooling#2

Open
magnesj wants to merge 9 commits into
Denisov21:mainfrom
magnesj:main
Open

Fix cx_Freeze Windows build, PPTX export, and portable-build tooling#2
magnesj wants to merge 9 commits into
Denisov21:mainfrom
magnesj:main

Conversation

@magnesj

@magnesj magnesj commented Jul 22, 2026

Copy link
Copy Markdown

Background

Thanks for this useful tool. I do not know Italian, but my AI tool added comments in Italian to fit the existing comment style. Hope you find this contribution useful.

Summary

The cx_Freeze configuration produced an executable that crashed on launch, and the portable-build script/CI were unusable. This PR makes the frozen Windows build work end-to-end, fixes a PPTX-export bug, and repairs the portable-build tooling.

All changes were verified: the frozen app launches and renders correctly, PPTX export works, installer/Build-Portable.ps1 runs to completion, and the new GitHub Actions workflow builds the portable ZIP successfully on a Windows runner.

Frozen build (cx_Freeze)

  • Entry point: main.py uses package-relative imports, so it can't be frozen as a top-level __main__ script (ImportError: attempted relative import with no known parent package). Added a small launcher (src/spp_frozen_main.py) that imports the package and calls main(), and pointed the cx_Freeze script at it. Referenced the package by its real directory case (songpressPlusPlus) since Python imports are case-sensitive even on Windows.
  • Resource paths: when frozen, cx_Freeze copies xrc/, img/, templates/, locale/ next to the executable, not inside lib/. Several places derived resource paths from __file__ and broke:
    • Globals.path now uses the executable directory when frozen (fixes the startup XRC-load crash and everything routed through glb).
    • Editor right-click context-menu icons, theme-button icons, and the Help/Guide viewer (guida_*.md + img/GUIDE) now resolve via glb.
    • Bundled the guida_*.md quick-guide files next to the exe.

Bug fix

  • PPTX export: SongPresentation defined __exit__ but not __enter__, so with SongPresentation(...) as c raised TypeError and export always failed. Added __enter__. (This bug affected non-frozen runs too.)

Build tooling & CI

  • installer/Build-Portable.ps1: never ran under Windows PowerShell 5.1. Re-saved as UTF-8 with BOM (BOM-less UTF-8 was misread as CP1252, corrupting accented characters and tokenization); switched pip install to an array + splatting (the backtick-continued form with < version specs mis-parses on 5.1); added PYTHONPATH=src around cx_Freeze build_exe; added the missing pywin32 dependency; fixed the fonts source path.
  • CI: added .github/workflows/build-portable.yml — builds the portable ZIP on windows-latest by reusing Build-Portable.ps1, on manual dispatch and on v* tags; uploads the ZIP as an artifact and attaches it to the Release on tags. Uses current action majors.
  • .gitignore: ignore *.egg-info/ at any depth (the anchored rule missed src/).

🤖 Generated with Claude Code

magnesj and others added 9 commits July 22, 2026 09:40
Freeze a launcher (spp_frozen_main.py) that imports the package and calls
main(): main.py uses package-relative imports and cannot be frozen as a
top-level __main__ script. Reference the package by its real directory
case (songpressPlusPlus) since Python imports are case-sensitive even on
Windows, and bundle the guida_*.md quick-guide files next to the exe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When frozen, cx_Freeze copies xrc/, img/, templates/ and locale/ next to
the executable, not inside lib/songpressPlusPlus/. Base Globals.path on
sys.executable so resource lookups (starting with the XRC load at startup)
resolve correctly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OnContextMenu built image paths from __file__, pointing at the nonexistent
lib/songpressPlusPlus/img/ in frozen builds. Use glb.AddPath('img').

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Theme Load/Save/Delete button icons used a __file__-relative img/ path.
Use glb.AddPath('img') so they resolve in frozen builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The quick-guide viewer loaded guida_*.md and img/GUIDE from __file__.
Base them on glb.path so they resolve next to the exe when frozen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SongPresentation defined __exit__ but not __enter__, so 'with
SongPresentation(...) as c' raised TypeError (no context manager protocol)
and PPTX export always failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The anchored /*.egg-info/ rule missed src/SongpressPlusPlus.egg-info
generated by the cx_Freeze build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The script never ran under Windows PowerShell 5.1:

- Saved as UTF-8 without BOM, so PS 5.1 read accented chars (puo/gia) as
  CP1252 and corrupted tokenization -> re-save as UTF-8 with BOM.
- pip install used backtick continuation with '<' version specs that
  PS 5.1 mis-parses -> pass deps as an array via splatting.
- Add PYTHONPATH=src around cx_Freeze build_exe (required now that
  [tool.cxfreeze.build_exe] lists packages=["songpressPlusPlus"]).
- Add missing pywin32 dependency (win32print/win32api).
- Fix fonts source path (src/songpress -> src/songpressPlusPlus).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build the cx_Freeze portable ZIP on windows-latest by reusing
installer/Build-Portable.ps1. Runs on manual dispatch and on v* tags;
uploads the ZIP as a build artifact and attaches it to the GitHub
Release on tags. Uses latest action majors (checkout@v7,
setup-python@v7, upload-artifact@v7, action-gh-release@v3).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant