Package your python code into one zip file, even a virtual environment.
Project description
zipapps
Package your python code(with requirements) into a standalone file (like the jar
). This is a pure-python library, without 3rd-party dependencies.
Inspired by shiv. But unlike shiv
, this lib will not always create new cache folders while running.
What is the pyz
?
.pyz
to Python is like .jar
to Java. They are both zipped archive files which aggregate many packages and associated metadata and resources (text, images, etc.) into one file for distribution. Then what you only need is a Python Interpreter as the runtime environment.
PS: The pyz ext could be any other suffixes even without ext names, so you can rename app.pyz
to app.zip
as you wish. Depends on PEP441, then the apps may be cross-platform as long as written with pure python code.
Where to Use it?
- Hadoop-Streaming's mapper & reducer scripts.
- Simple deployment towards different servers with
jenkins
, or other CI/CD tools.- Easy to uploads and with a clean standalone zipped file.
- Distribute zipapp with embedded python.
- Use as a requirements zip path, or some venv usages.
import sys;sys.path.insert(0, 'app.pyz')
(without .so/.pyd)python3 app.pyz script.py
- Other usages need to be found, and enjoy yourself.
Install
pip install zipapps -U
Quick Start
zip as the app
- zipapps with requirements
-
python3 -m zipapps -u AUTO -a entry.py -m entry:main -o app.pyz aiohttp,psutils
-
- run app.pyz
-
python3 app.pyz
- cache will be unzipped to
./zipapps_cache/app
-
zip as the venv
- zipapps with requirements
-
python3 -m zipapps -u AUTO -o venv.pyz -r requirements.txt
-
- run entry.py with venv.pyz
-
python3 app.pyz entry.py
- cache will be unzipped to
./zipapps_cache/venv
-
Use cases
Scene-1: Package your code with requirements as a standalone application.
Package zippapps
self
- Package with
zipapps
python3 -m zipapps -c -m zipapps.__main__:main -o zipapps.pyz -p /usr/bin/python3 zipapps
- Check whether success
./zipapps.pyz --version
orpython3 zipapps.pyz --version
- output:
2020.11.21
What do the args
mean?
-c / --compress
- whether to compress the files to reduce file size.
-m / --main
- The main function of the application, such as
package.module:function
.
- The main function of the application, such as
-o / --output
- The path of the output file, defaults to
./app.pyz
.
- The path of the output file, defaults to
-p / --python
- The path of the Python interpreter to use, defaults to null (no shebang line).
- With the shebang line, you can use
./zipapps.pyz
instead ofpython3 zipapps.pyz
for short.
- the tail
zipapps
arg- all the unknown args will be sent to the tail of
pip install
. - so you can use
-r requirements.txt
or-i https://pypi.org/simple
here.
- all the unknown args will be sent to the tail of
Scene-2: Package your code with requirements as a standalone application, but there are .pyd
or .so
files.
zipimport
could accept .py
and .pyc
files but reject .pyd
and .so
files, so we have to unzip them and add the cache folder to sys.path
, view more from the Doc.
Package psutils
and check the import path
- Package with
zipapps
python3 -m zipapps -c -u psutil psutil
- Check whether success
λ python3 app.pyz -c "import psutil;print(psutil.__file__)"
- output:
{CWD}/zipapps_cache/app/psutil/__init__.py
{CWD}
is the current work directory.- If you didn't set
-u psutil
, the output will be{CWD}/app.pyz/psutil/__init__.py
New args
?
-u / --unzip
- choose the files/folders to unzip while running,
- multiple names can be splited by the ",", like
bottle,dir_name
, this arg support*
forglob
usage, - if you are not sure which to unzip, use
*
for all, - the files/folders will not be unzipped duplicately if there is an old cache contains the same
_zip_time_
file.
Scene-3: Package the main package with the requirements.txt
Similar to Scene-1, and add the package folder togather
python3 -m zipapps -c -a package_name,static_file_path -m package_name.__main__:main -u=* -up "./cache" -r requirements.txt
python3 app.pyz
New args
, again?
-up / --unzip-path
- If
-u / --unzip
arg is not null, cache files will be unzipped to the given path. - Defaults to
./zipapps_cache
, supportTEMP/HOME/SELF
as internal variables. - And you can overwrite it with environment variable
ZIPAPPS_CACHE
orUNZIP_PATH
while running. TEMP
meanstempfile.gettempdir()
HOME
meansPath.home()
SELF
means.pyz
file path
- If
-a / --add / --includes
- add some files/folders into zipped file, so you can unzip (or import) them (with the
-u
arg) while running. - multiple paths will be splited by ",".
- add some files/folders into zipped file, so you can unzip (or import) them (with the
Scene-4: Package the whole requirements.txt
as a zipped virtual environment
Package the requirements.txt
python3 -m zipapps -c -o venv.pyz -p /usr/bin/python3 -r requirements.txt
Run script like using a python Interpreter
python3 venv.pyz script.py
- or
./venv.pyz script.py
- or
Scene-5: Package multiple requirements.txt
files and import them together
Package all the requirements.txt
python3 -m zipapps -c -o venv1.pyz -p /usr/bin/python3 bottle
python3 -m zipapps -c -o venv2.pyz -p /usr/bin/python3 -u AUTO psutil
Run script with adding new path to sys.path
, unzip files/folders if necessary
There are 3 ways to active
PYTHONPATH
below
- [Easy] After
2020.12.27
version, you can use--zipapps
arg for otherpyz
files.
python3 venv1.pyz --zipapps="venv2.pyz" -c "import bottle,psutil;print(bottle.__file__,psutil.__file__)"
- Activate pyz files if unzip is no null
import os
import sys
# reset the unzip cache path to temp dir
os.environ['ZIPAPPS_CACHE'] = 'TEMP/_cache'
# add new import paths
sys.path.insert(0, 'venv1.pyz')
sys.path.insert(0, 'venv2.pyz')
import bottle
# unzip psutil for importing
import ensure_venv2 # or import ensure_zipapps_venv2
import psutil
print(bottle.__file__) # venv1.pyz/bottle.py
print(psutil.__file__) # /tmp/_cache/venv2/psutil/__init__.py
- Use the
activate
function in anyzipapps
zipped file- or use the
activate
function ofzipapps.activate_zipapps
if zipapps has been installed:-
from zipapps import activate
-
- or use the
import os
import sys
# reset the unzip cache path to temp dir
os.environ['ZIPAPPS_CACHE'] = 'TEMP/_cache'
print(sys.path) # old sys.path including cwd path at index 0
# add PYTHONPATH to import activate_zipapps
sys.path.insert(0, 'venv1.pyz')
print(sys.path) # including `venv1.pyz` at index 0
from activate_zipapps import activate
activate('venv1.pyz')
print(sys.path) # absolute path of `venv1.pyz` has been insert to index 0
activate('venv2.pyz')
print(sys.path) # $(TEMP)/_cache/venv2 and absolute path of `venv2.pyz` added
View more
python3 -m zipapps -h
Using as the venv zip file example
As you see,
import ensure_zipapps_bottle_env
only works for packaging with a non-nullunzip
arg.If you don't need to unzip any files/folders,
sys.path.append('app.pyz')
is enough.
WARNING: multiple pyz files for venv, you need to ensure each file by special name like import ensure_zipapps_{output_file_name}
(such as import ensure_zipapps_bottle
) instead of import ensure_zipapps
.
'''
zip env as usual:
python3 -m zipapps -u bottle -o bottle_env.pyz bottle
'''
import sys
# add `bottle_env.pyz` as import path
sys.path.append('bottle_env.pyz')
# now import bottle to see where it located
import bottle
print(bottle.__file__)
# yes, it's in the bottle_env.pyz: bottle_env.pyz/bottle.py
# now `import ensure_zipapps` to activate the unzip step
import ensure_zipapps_bottle_env
# reload bottle module to check if the location of bottle changed
import importlib
importlib.reload(bottle)
# now import bottle to see where it located
print(bottle.__file__)
# yes again, it changed to the unzip path: zipapps_cache/bottle_env/bottle.py
FAQ
- How to zip apps with C-Lib requirements for
zipimport
ingore.pyd
,.so
files?- as https://docs.python.org/3/library/zipimport.html
- we can unzip those packages in temp dirs with
-u
args -
python3 -m zipapps -c -u selectolax selectolax
-
python3 app.pyz xxx.py
- How to avoid unlimited unzip cachefolder size growth?
- There is a null file named like
zip-time
in zip files and unzip folders - The cache with same
zip-time
will not be unzipped duplicately.
- There is a null file named like
PYTHONPATH
between zipapps's zip file and global python environment?- If you set
-spp
for strictPYTHONPATH
, you will not use the globalPYTHONPATH
. - else you will use global libs as a second choice.
- If you set
- How to use multiple venv
pyz
files in one script?os.environ['UNZIP_PATH'] = '/tmp/unzip_caches'
or os.environ['ZIPAPPS_CACHE'] = '/tmp/unzip_caches'
sys.path.insert(0, 'PATH_TO_PYZ_1')
sys.path.insert(0, 'PATH_TO_PYZ_2')
import ensure_zipapps_{output_name_2}
- only if app2 needs to unzip files while running
Todos
- Zip pure python code without cache folder while running.
- pure python code will not unzip anything by default.
- Zip files/folders by your choice, and unzip which you want.
- files/libs/folders will be unzip to
-up
/--unzip-path
, default is./zipapps_cache
while running. unzip_path
could use the given variableHOME
/TEMP
/SELF
, for example- HOME/cache => ~/cache folder
- TEMP/cache => /tmp/cache in linux
- or C:\Users\user\AppData\Local\Temp\cache in win32
- SELF/cache => app.pyz/../cache
- SELF equals to the parent folder of pyz file
- or you can reset a new path with environment variable
UNZIP_PATH
orZIPAPPS_CACHE
- have a try:
- linux:
python3 -m zipapps -u bottle -o bottle_env.pyz bottle&&export UNZIP_PATH=./tmp&&python3 bottle_env.pyz -c "import bottle;print('here is bottle unzip position:', bottle.__file__)"
- win:
python3 -m zipapps -u bottle -o bottle_env.pyz bottle&&set UNZIP_PATH=./tmp&&python3 bottle_env.pyz -c "import bottle;print('here is bottle unzip position:', bottle.__file__)"
- linux:
- have a try:
- files/libs/folders will be unzip to
- Zip the dynamic modules (.pyd, .so) which
zipimport
not support.- package with
-u
for these libs.
- package with
- Reuse the unzip cache folder for the same zip timestamp.
zip-timestamp
will play as abuild_id
- Use like a
venv
or interpreter withpython3 ./env.pyz script.py
, script.py will enjoy the PYTHONPATH of env.pyz.- package without
-m
arg, then run codes inPopen
.
- package without
- Fix
psutil
ImportError of DLL loading.- package with
-ss
to usePopen
instead of import directly.
- package with
- Support import
pyz
as venv zip file.- activate auto-unzip by
import ensure_zipapps
aftersys.path.append("app.pyz")
- or active with accurate import
import ensure_zipapps_bottle_env
while activating multiple environments - or run
python3 ./app.pyz script.py
directly.
- or active with accurate import
- view the example below for more infomation.
- activate auto-unzip by
- Support compile to
pyc
for better performance.- activate compile by
--compile
or-cc
. - but
__pycache__
folder in zip file will not work, - so you can unzip them by
--unzip=xxx
, - to check whether
pyc
worked byimport bottle;print(bottle.__cached__)
- activate compile by
- Support
build_id
to skip duplicate builds.- using like
python3 -m zipapps -b requirements.txt -r requirements.txt
python3 -m zipapps --build-id=a.py,b.py -r requirements.txt
python3 -m zipapps --build-id=./*.py -r requirements.txt
python3 -m zipapps --build-id=efdd0a5584169cdf791 -r requirements.txt
python3 -m zipapps --build-id=version1.0 -r requirements.txt
- using like
- A simple way to active multiple zipped venv
pyz
files. - Support auto-check
.pyd/.so
to be unzipped. - Combile multiple
pyz
files.
Changelogs
- 2020.12.27
- Combile multiple
pyz
files, do like this:- python3 -m zipapps -o six.pyz six
- python3 -m zipapps -o psutil.pyz -u AUTO psutil
- python3 six.pyz --zipapps=psutil.pyz -c "import six,psutil;print(six.file, psutil.file)"
- Combile multiple
- 2020.12.23
--unzip
support auto-check by-u AUTO
, alias for--unzip=AUTO_UNZIP
- fix
run_module
bug while running./app.pyz -m module
- 2020.12.21
- now will not run a new subprocess in most cases.
- using
runpy.run_path
andrunpy.run_module
- and using
subprocess.run
instead ofsubprocess.call
- using
- now will not run a new subprocess in most cases.
- 2020.12.13
--unzip
support complete path--unzip
support auto-check by--unzip=AUTO_UNZIP
- 2020.11.23
- add
activate_zipapps
to activate zipappsPYTHONPATH
easily
- add
- 2020.11.21
- reset unzip_path as the parent folder to unzip files
- so the cache path will be like
./zipapps_cache/app/
forapp.pyz
, - this is different from old versions.
- so the cache path will be like
- add environment variable
ZIPAPPS_CACHE
for argunzip_path
- add environment variable
ZIPAPPS_UNZIP
for argunzip
- reset unzip_path as the parent folder to unzip files
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file zipapps-2020.12.27-py3-none-any.whl
.
File metadata
- Download URL: zipapps-2020.12.27-py3-none-any.whl
- Upload date:
- Size: 14.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.0.3 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 532549569a7b6d21e1b1b70dca01fe18bd3212c2ca3090f1726840b1568116dd |
|
MD5 | be8dd43327b63eb342cbaf9fd72db14f |
|
BLAKE2b-256 | d9962f8bda87836a3ebbc8b6dedd2f06d8015387abd027fdbe86d9763ba72b4c |