Skip to content

Example of packaging Python application as an executable ZIP archive

Notifications You must be signed in to change notification settings

va1da5/python-application-bundle

Repository files navigation

Bundle Python Application Using Zip

This is a small proof-of-concept (PoC) setup for packaging application as a single Python executable ZIP archive.

The idea is that the archive includes all (most) of the dependencies of the application and could be easily distributed to other interested parties.

A minimal FastAPI setup is used to simulate an application with a number of dependencies, like Uvicorn server.

Python includes an awesome utility module zipapp for packaging the application, however this example uses the standard zip command line utility to bundle up the application. This is because the PoC uses a custom __main__.py file which updates sys.path list, because the dependencies are placed in a dedicated directory ./site-packages that are not part of the standard locations where Python looks for modules.

Results

The archived Python code gets executed. However, there are issues with static assets that are later used by code. There are ways to access the files from archived modules, but libraries like FastAPI or Django do not take such setup into account and the static file loading fails.

This is something to be aware and evaluate before developing application with intend to distribute it as an executable archive.

Possible solutions:

  • Write utility function which would extract contents of the archive into some temporary location and allow code to access files from there;
  • Implement an abstraction layer that would take ZIP archive and simply emulate it as a directory within regular filesystem.

The possible solution are out of the scope for this PoC.

Application Packaging

# create a temporary locations for bundling the application
mkdir -p .tmp/ build

# copy the application code to the temporary location
cp -r *.py public server .tmp/

# install required dependencies to a dedicated directory
pip install -r requirements.txt --target .tmp/site-packages


# bundle up the application with dependencies
cd .tmp/
zip -r9 ../build/server.pyz .
cd ..

# run the application
python3 ./build/server.pyz

# make archive executable on its own
mv ./build/server.pyz ./build/server.pyz.tmp
echo '#!/usr/bin/env python3' > ./build/server.pyz
cat ./build/server.pyz.tmp >> ./build/server.pyz
rm ./build/server.pyz.tmp
chmod +x ./build/server.pyz

# start the application
./build/server.pyz


# the service could also be started using standard Uvicorn command
# Python path needs to be updated to point to the bundled application internals
PYTHONPATH="./build/server.pyz/site-packages:./build/server.pyz" python -m uvicorn server:app --host localhost --port 4000


# most of the actions could be performed using Make utility
make
Usage: make [build|clean|run|dev]
        build           : creates the application bundle
        clean           : removes all traces of build artifacts
        run             : runs built application
        dev             : runs the application in development mode

References