Shiv: Python Zipapp Builder
Shiv is a command-line utility for building fully self-contained Python zipapps (.pyz files) in compliance with PEP 441. It packages a Python application, its dependencies, and a Python interpreter bootstrap into a single executable file. The current version is 1.0.8, with a release cadence of relatively frequent minor releases.
Common errors
-
bash: ./my_app.pyz: Permission denied
cause The generated zipapp file does not have execute permissions.fixRun `chmod +x my_app.pyz` before attempting to execute it. -
Error: No such file or directory: '...' (or similar ModuleNotFoundError from within the zipapp)
cause A required dependency or a local module was not included in the zipapp, or the Python path inside the zipapp is misconfigured.fixEnsure all required packages are listed in a `requirements.txt` file and passed with `-r requirements.txt`, or include local directories using the `.` argument if they contain your code. Check for `-S` (`--no-site-packages`) if you expect installed packages to be present. -
AttributeError: module 'my_script' has no attribute 'main'
cause The entry point specified with `-e` (e.g., `my_script:main`) does not correctly point to a callable function within the packaged application.fixDouble-check the entry point string. Ensure the module exists and the function name is spelled correctly and is accessible from the module. For instance, if `main` is inside a class, you might need `module:ClassName.main_method`.
Warnings
- breaking Shiv versions 1.0.4 and newer officially drop support for Python 3.6 and 3.7. While `requires_python` might still state `>=3.6` on PyPI, testing and full compatibility are only maintained for Python 3.8 and above.
- gotcha When trying to execute a `shiv` built `.pyz` file directly (e.g., `./my_app.pyz`), you may encounter 'Permission denied' errors if the file does not have execute permissions.
- gotcha The `-e` or `--entry-point` argument must correctly specify a callable in the format `module:function`. A common mistake is providing an incorrect module path or function name, leading to `AttributeError` or `ModuleNotFoundError` at runtime.
- deprecated Shiv 1.0.5 replaced deprecated `importlib.resources.*` calls internally. While this primarily affects Shiv's internal workings, users with highly customized `shiv` environments or those relying on older internal resource handling might see minor behavior changes.
Install
-
pip install shiv
Quickstart
import subprocess
import sys
import os
# 1. Create a simple Python script to be packaged
script_content = """
# hello_app.py
import sys
def main():
print(f"Hello from shiv zipapp! Python version: {sys.version.split()[0]}")
if __name__ == '__main__':
main()
"""
with open("hello_app.py", "w") as f:
f.write(script_content)
# 2. Build the zipapp using shiv (assuming shiv is installed)
print("Building hello_app.pyz...")
try:
subprocess.run(
[sys.executable, "-m", "shiv", "-o", "hello_app.pyz", "-e", "hello_app:main", "."],
check=True,
capture_output=True,
text=True
)
print("Zipapp built successfully.")
except subprocess.CalledProcessError as e:
print(f"Error building zipapp: {e.stderr}")
sys.exit(1)
# 3. Execute the built zipapp
print("Executing hello_app.pyz...")
try:
result = subprocess.run(
[sys.executable, "hello_app.pyz"],
check=True,
capture_output=True,
text=True
)
print("Zipapp output:")
print(result.stdout.strip())
except subprocess.CalledProcessError as e:
print(f"Error executing zipapp: {e.stderr}")
sys.exit(1)
finally:
# 4. Clean up generated files
if os.path.exists("hello_app.py"):
os.remove("hello_app.py")
if os.path.exists("hello_app.pyz"):
os.remove("hello_app.pyz")
print("Cleanup complete.")