Skip to main content

A greedy Python standalone application bundler

Project description

shenzi

shenzi helps you create standalone Python applications from your development virtual environment. Using shenzi, you can create standalone folders which can be distributed to any machine, and the application will work (even when python is not installed on the target system).

The python packaging problem

Given a development environment (a virtual environment), we want to produce a single directory containing ALL the dependencies that the application needs. Other languages like rust and go provide easy way to create statically linked executables, which makes them very easy to distribute.
Python struggles in this area mainly because of how flexible it is when it comes to delegating work to C code (shared libraries on your system).

Out in the wild, python libraries regularly links to shared libraries in your system:

  • C Extensions
  • loading shared libraries using dlopen and equivalents

Even creating a development environment for some pip package might require you to install some system dependencies (a good example is weasyprint)
It becomes difficult to ship applications if we need to install system dependencies in target machines. Docker solves this problem by packaging everything in a single docker image.
shenzi does not compete with docker, if you can use docker, you should. shenzi is useful for shipping desktop applications.

Getting Started

First install shenzi in your virtual environment.

pip install shenzi

In you main script, add the following lines

import os

if os.environ.get("SHENZI_INIT_DISCOVERY", "False") == "True":
    from shenzi.discovery import shenzi_init_discovery
    shenzi_init_discovery()

Run your application as you normally do. shenzi will start intercepting all shared libraries that your code is importing.
You should run as much of your application code as possible, like running all the tests. This allows shenzi to detect every dependency linked to your application at runtime.

Once you stop the application, a file shenzi.json (called the manifest) will be dumped in the current directory. This file contains all the shared library loads that shenzi detected. It also contains some information about your virtual environment.
Now run the shenzi CLI with this manifest file

RUST_LOG=INFO shenzi build ./shenzi.json

This can take a moment, after it is done, your application would be packaged in a dist folder.
You can ship this dist folder to any target machine and it should work out of the box. The only required dependency is bash.

Run dist/bootstrap.sh to run your application.

# bootstrap.sh is the entrypoint for your application
# you can run this from any directory generally
bash dist/bootstrap.sh

You should at least read the doc which describes the structure of shenzi.json here.

If you use this, feel free to raise an issue on any problem, I need feedback for this :)

How is this different?

I will add a small comparison to PyInstaller, which I feel is the most mature tool in the ecosystem.
From what I've seen, PyInstaller statically analyses your python code (and does some imports too) to create the smallest possible packaged application. It is smarter than shenzi.

shenzi is much simpler, all it does it greedily take everything in your python path and put it in the final distribution. For shared libraries, it closely tries to resemble the linker to find all the dependencies of each shared library, and put that in the application too.
The motive here is to be as similar to the original development environment as possible, shenzi only changes how the shared libraries in the codebase find dependencies.
This makes shenzi faster in some cases (where you have complex applications, as we do not do any static analysis), but slower in others (mainly if your virtual environment is huge, and not all dependencies are used by your application normally)

Apart from that, there are some other internal differences that may or may not matter

  • The structure of the final application (described here)
  • The bootstrap script in shenzi is pretty a simple bash script, it simply sets up the correct Python environment variables and starts the interpreter. PyInstaller has a very sophisticated bootstrapping CLI written in C

Supported Platforms

Currently only Mac and Linux are supported.
The project is very new right now, I've tested it on Ubuntu 20.04 and MacOS Sequoia with Python 3.9

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shenzi-0.0.2.tar.gz (2.2 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

shenzi-0.0.2-py3-none-manylinux_2_31_x86_64.whl (2.6 MB view details)

Uploaded Python 3manylinux: glibc 2.31+ x86-64

shenzi-0.0.2-py3-none-macosx_10_9_universal2.whl (2.2 MB view details)

Uploaded Python 3macOS 10.9+ universal2 (ARM64, x86-64)

File details

Details for the file shenzi-0.0.2.tar.gz.

File metadata

  • Download URL: shenzi-0.0.2.tar.gz
  • Upload date:
  • Size: 2.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.4

File hashes

Hashes for shenzi-0.0.2.tar.gz
Algorithm Hash digest
SHA256 458108e203b478ce910a1c1c7fca428e2179a388508fb9c8d3557812e0174cc4
MD5 e6c900e01a4533b30ffd8fad37ad9b0a
BLAKE2b-256 111c217ac9043ead298d86cf48c46fb6a9aa3ec4bf3635708cafc57f76100ced

See more details on using hashes here.

File details

Details for the file shenzi-0.0.2-py3-none-manylinux_2_31_x86_64.whl.

File metadata

File hashes

Hashes for shenzi-0.0.2-py3-none-manylinux_2_31_x86_64.whl
Algorithm Hash digest
SHA256 7dcfc0e1d526578e21d1623e42eeaf96f7e981ec758097d4d90f1e57bb24bf71
MD5 4a178124ea584270cb1718456942af9a
BLAKE2b-256 84055493e848d186fed33f1bee2ae474b711cf3011d47dfe00fa7ca9d5590861

See more details on using hashes here.

File details

Details for the file shenzi-0.0.2-py3-none-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for shenzi-0.0.2-py3-none-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 05d1a02f355afeec6365e09dfbf898e0bc007a4a78d80d9e8399d9bae7d261fb
MD5 6a159ef2b73492753187e90e7e291850
BLAKE2b-256 949f3f294249c1bdfd869382257d6bb352020bca877e6c03259c310996d853f4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page