Skip to content

for windows installer, leave venv creation for the user machine - #1698

Open
barentine wants to merge 4 commits into
python-microscopy:masterfrom
barentine:installerz
Open

for windows installer, leave venv creation for the user machine#1698
barentine wants to merge 4 commits into
python-microscopy:masterfrom
barentine:installerz

Conversation

@barentine

Copy link
Copy Markdown
Member

Addresses issue following #1697 .

I had a quick go at the windows installer usage, and ran into the same issues @csoeller mentioned (uv trampoline failed to canonicalize script path).

The issue seems to be, as @David-Baddeley pointed out, that venv's aren't relocatable. I let Claude chew on it / pushed it through a local test on a Win11 machine.

This PR

  • moves the setup-uv out of our CI (make_installers.yaml) and the install-python-microscopy.bat bundling, so CI no longer builds the venv for the windows installer.
  • A regex grabs the version information from pyproject.toml (instead of installing PYME and using package metadata).
  • ISCC.exe is invoked with the new /DRepoDir define (pointing at the checkout) instead of /DAppSourceDir (which pointed at the now-removed bundle).
  • Removes two UTF-8 em dashes from install-python-microscopy.bat comments that corrupted cmd.exe's tokenizer
  • Sets UV_PYTHON_INSTALL_DIR (and use --no-bin) so uv installs Python under the destination directory instead of the user's roaming profile
  • Switched the installer's [Run] step to Flags: shellexec instead of a hand-built cmd /C "script" "arg" line, avoiding a cmd.exe quote-stripping edge case that corrupts the command line whenever both the script path and argument are quoted
  • Added RedirectionGuard=no to [Setup]: Inno Setup 6 enables Windows' RedirectionGuard mitigation by default on Windows 11/10 22H2+, which blocks a non-elevated process from traversing junctions it creates — exactly what uv python install does for its per-minor-version Python link, causing it to fail with os error 448

Works locally building with inno setup 6, running the produced exe, and opening PYMEVis.

@David-Baddeley - I haven't looked into any implications of the RedirectionGuard=no flag.

…co files, waiting to build the venv on the user machine
…in the destination directory instead of the user's roaming profile to keep everything self-contained
…tionGuard mitigation by default on Windows 11/10 22H2+, which blocks a non-elevated process from traversing junctions it creates — exactly what uv python install does for its per-minor-version Python link
@David-Baddeley

Copy link
Copy Markdown
Contributor

I'd already got a bit out of step with what I'd explored and what I'd posted. I'd also come up with this idea (with a bit of agentic help). Downside to getting an installer to run uv on the client side is that we get whatever mix of packages uv decides to pull resolve when it runs (ie we don't get know good or consistent behaviour, unless we manually pin everything. For this reason, I'd pretty much settled on trying to use py-app-standalone which bootstraps a truely relocatable install using uv.

@David-Baddeley

Copy link
Copy Markdown
Contributor

Copilots analysis on my machine ...

User: next issue is that uv does not create a relocatable install. What options do I have?

GitHub Copilot: The core problem: uv venv embeds absolute paths in the script stubs, so copying the bundle from PYME_bundle\ to {app}\ breaks them. Three practical options:


1. uv venv --relocatable (simplest)
Add the flag to the uv venv call in install-python-microscopy.bat. uv rewrites the script stubs to use relative paths to the interpreter. Worth trying first — it should work, but it's relatively new and Windows edge cases are possible.


2. Online installer — install directly to {app} during setup
Remove the pre-built bundle step entirely. InnoSetup packages install-python-microscopy.bat as a resource, then runs it pointing at {app} in the [Run] section. The venv is created at its final path, relocation is never needed.

  • Pros: conceptually clean, smaller installer download, paths always correct
  • Cons: internet required during installation; install takes longer from the user's perspective; can't run install silently without a console window

3. python-build-standalone + manual install (most robust)
Fetch a pre-built, genuinely relocatable CPython from python-build-standalone into the bundle, install packages into it with pip --prefix. No venv relocation issues because the interpreter itself is designed to be moved.

  • This is essentially what uv python install fetches under the hood, but you'd unpack it into the bundle directly rather than going through the venv layer
  • More assembly required in the bat script

Recommendation: try option 1 first — it's a one-word change. If it misbehaves on Windows (broken shortcuts, missing DLLs), option 2 (online installer) is the cleanest fallback with minimal script changes.

User: Can rule 2 out, as the main goal of packaging is to get a fairly stable (and testable) set of dependencies between releases without having to manage huge numbers of pins. What about py-app-standalone?

GitHub Copilot: PBS is a solid choice here. The key insight: skip the venv layer entirely and install directly into the PBS distribution. The PBS Python is designed to be moved — it finds its own standard library via relative paths, and pythonw.exe (no console) ships alongside python.exe.

How it would work:

install-python-microscopy.bat changes to:

  1. Download cpython-3.13.x-x86_64-pc-windows-msvc-install_only.tar.gz from the PBS releases into %DEST%\python\
  2. Run %DEST%\python\python.exe -m pip install python-microscopy
  3. Don't use pip's .exe stubs — they still embed absolute paths. Instead, write .cmd wrappers that invoke the entry points via -c:
    @echo off
    start "" "%~dp0python\pythonw.exe" -c "from PYME.DSView.PYMEImage import main; main()" %*
    %~dp0 is always the folder containing the .cmd, so it's fully relocatable.
  4. Console helper sets PATH manually:
    set "PATH=%~dp0python;%~dp0python\Scripts;%PATH%"
    cmd.exe /k

pyme_setup.iss [Icons] entries then point directly to {app}\python\pythonw.exe with the module invocation as Parameters, which is cleaner than going through cmd.exe:

Filename: "{app}\python\pythonw.exe"; Parameters: "-c ""from PYME.DSView.PYMEImage import main; main()"""

Tradeoffs vs. uv venv:

  • You need to maintain the PBS download URL (versioned, but stable between uv-managed versions)
  • Entry point module paths (PYME.DSView.PYMEImage:main etc.) need to be hardcoded in the bat script — they're in pyproject.toml already so this is just transcription
  • No activate.bat mechanism, but the PATH approach works fine for the console

Shortcut: uv actually downloads PBS distributions internally. uv python find 3.13 returns the path to the uv-cached PBS install, which you could xcopy into the bundle — bypassing the separate download entirely. Worth exploring but slightly fragile if uv changes its internal layout.

Want me to rework install-python-microscopy.bat and pyme_setup.iss for this approach?

User: I mean py-app-standalone (https://github.com/jlevy/py-app-standalone), not python-build-standalone

GitHub Copilot:

Fetched https://github.com/jlevy/py-app-standalone

Good find. py-app-standalone is essentially a thin orchestration wrapper that does exactly the manual steps we were discussing:

  1. uv python install → downloads PBS Python to the output dir
  2. Creates a temporary --relocatable venv to generate a pyvenv.cfg
  3. uv pip install --break-system-packages → installs directly into the PBS Python
  4. Patches absolute paths out of scripts, .py config files, and on macOS the .dylib id

The key question for your use case is whether it actually fixes the Windows .exe script stubs, since those are compiled launchers, not text-shebang scripts. The README only mentions shebang replacement and the macOS dylib fix — it says "on Linux and Windows something like this [dylib fix] doesn't seem to be necessary" but is silent on whether the .exe stubs in Scripts\ are patched. Given the author's note that Windows is "very lightly tested", this is the main risk.

If it works on Windows, the installer change is clean and simple — replace the venv block in install-python-microscopy.bat with:

uvx py-app-standalone --install-dir "%DEST%" %PACKAGE_NAME%
:: Rename the cpython-x.y.z-platform dir to a stable name
for /d %%d in ("%DEST%\cpython-*") do move "%%d" "%DEST%\python"

Then update .iss paths from venv\Scripts\python\Scripts\ and venv\Lib\site-packages\python\Lib\site-packages\.

Honest assessment:

  • Very small project (54 stars, 1 maintainer), last touched a year ago — dependency risk
  • Genuinely solves the problem if the Windows .exe stubs are handled
  • Worth a quick local test on Windows before committing to it

Would you like to proceed with the integration, or first validate that the .exe stubs are actually relocatable on Windows?

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.

2 participants