Enabling Easy Zipapp Installs on Windows
Tags: windows, python, devops, configuration
Published: 2020-03-12 05:52:57

---
title: Enabling Easy Zipapp Installs on Windows
published: true
date: 2020-02-29 06:00:00 UTC
tags: windows, python, devops, configuration
series: Deploying Python Software to Production
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/60zcad9bkexi6zk9ip37.png
canonical_url: https://jhermann.github.io/blog/python/deployment/2020/02/29/python_zippapps_on_windows.html
---
> *How to prepare a Windows system for a good PYZ experience.*

## Zipapps in a Nutshell

Zipapps are a way to distribute Python applications and all of their dependencies in a single binary file.This is comparable to statically linked golang apps or Java's ‘executable JARs’. Their main advantage is that distributing and installing them is quite simple.

Running Python code directly from ZIP archives is nothing new, [PEP 273](https://www.python.org/dev/peps/pep-0273/) made its debut in 2001, as part of Python 2.3 in the form of the `zipimport` module. [PEP 441](https://www.python.org/dev/peps/pep-0441/) builds on this and describes mechanisms to bundle full applications into a single ZIP file that can be made executable. It was approved in 2015 and a first implementation appeared in Python 3.5 via the `zipapp` module.

See the PEP for details on how making a ZIP into an executable file works, but basically on POSIX systems the Python interpreter is called in a ‘bang path’ that is followed by the ZIP archive. The interpreter recognizes the ‘script’ is a whole application archive and acts accordingly. On Windows, zipapps _MUST_ carry the `.pyz` extension which is bound to the `py` dispatcher command, which in turn looks at the bang path and calls a matching Python interpreter from the installed set.

To display the bang path of a zipapp, use this command:

```
python3 -m zipapp --info foo.pyz

```

If you want to change the requested Python version to one that is actually installed or that you prefer, change the bang path as part of the installation process:

```
python3 -m zipapp -p '/usr/bin/env python3.8' -o ~/bin/foo foo.pyz

```

This can also be done on an ad-hoc basis, by explicitly calling the desired interpreter:

```
python3.8 foo.pyz … # POSIX
py -3.8 foo.pyz … # Windows

```

Well-known tools to build new zipapps, outside of the Python core, are [pex](https://github.com/pantsbuild/pex) (Twitter) and [shiv](https://github.com/linkedin/shiv) (LinkedIn). See their documentation for details on bundling your own applications.


## Setting Up Windows 10 for Zipapps

On Windows, because there is no ‘+x’ flag, things are a bit more complicated than on POSIX. Zipapps **MUST** have a `.pyz` extension, for which the `py` launcher is registered as the default application.The net effect is that such files become executable and are handed over to the launcher _if_ you add a few environment settings to your machine.

In the user-specific environment settings, add a new `PATHEXT` variable (or extend an existing one), with the value `%PATHEXT%;.PYZ`. Also edit the `PATH` one and add a new `%LOCALAPPDATA%\bin` entry. Save everything (click “OK”), open a _new_ command window, and verify the changes with

```
 echo %PATHEXT% & echo %PATH%

```

Create the new bin directory by calling `md %LOCALAPPDATA%\bin`. Now you can place a zipapp file like `foo.pyz` in that directory, and it is immediately callable as `foo`.

To get such a test subject, you can build [shiv](https://github.com/linkedin/shiv) with itself:

```
git clone https://github.com/linkedin/shiv.git
cd shiv
py -3 -m venv --prompt shiv venv
venv\Scripts\activate.bat
python -m pip install -e .
shiv -e shiv.cli:main -o %LOCALAPPDATA%\bin\shiv.pyz .
deactivate
shiv --version
```


## Variations

If that makes more sense to you, you can change the system-wide variables instead of the user-specific ones, and choose paths that are global for all users (like `C:\usr\bin` or similar).

To make zipapps available network-wide, you can use `%APPDATA%` to store the zipapps, so you only have to maintain them once in case you regularly work on several machines in the same network. Just make sure the same version of Python is used everywhere then.