Using Python 3.5+ Zipapp on Win32

Date: 2021-04-18
categories: python, programming;

I recently learned about the zipapp feature in Python 3.5+ and I'm pretty excited about it. Somehow this managed to sneak under my radar even though it's something I've wanted for a long time. I use Python a lot, both for general-purpose scripting and in more comprehensive applications. While Python is really useful for getting things done, it doesn't make it entirely straightforward to distribute applications.

Setting up a virtual environment is great, but requires some understanding of Python and the command line. (It's pretty common to have to remind casual Python users to active their venv, for example). Tools like PyExe are fantastic, but something cross-platform and built in would be better.

The zippapp format solves most of these problems. It's a zip file which Python can execute, similar to a Java jar file. It bundles up your code and dependencies into a single file, which a user can run from the command line python myapp.pyz or by double-clicking (on some platforms like Windows). It still requires a compatible Python installation to run, but it's a lot more convenient to get everything wrapped up into a single, runnable file.

There are also a lot of options for distributing the application as a .pyz:

  1. As a standalone pyz file as mentioned above (requires a Python installation on the target system).
  2. Bundled with an executable launch wrapper (requires a Python installation on the target system).
  3. Bundled with an executable launch wrapper, as part of a full Python Embedded distribution.

Especially on Windows option 2 is particularly interesting, and can be combined with option 3 if you want a truly standalone distribution. You create the .pyz[w] zipapp file first, and then build a really simple Win32 application to launch it, and append the bytes directly to the end of the wrapper exe file.

I put together a Github repo demonstrating this technique, since the official documentation left a few questions unanswered. I've adapted the script to build the wrapper console, windowed exe and pyz and combine them together. You'll need a C compiler installed (I used MSVC) and a recent version of Python. I also demonstrate how to include dependencies with your app, specifically Tkinter in this case.

You can find step-by-step instructions in the README.