Skip to content

Commit dbf3e5b

Browse files
committed
add --unzip-exclude
1 parent 11dd9a0 commit dbf3e5b

File tree

6 files changed

+68
-22
lines changed

6 files changed

+68
-22
lines changed

README.md

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -406,50 +406,54 @@ Details:
406406
1. The names which need to be unzipped while running, splited by "," `without ext`, such as `bottle,aiohttp`, or the complete path like `bin/bottle.py,temp.py`. For `.so/.pyd` files(which can not be loaded by zipimport), or packages with operations of static files.
407407
1. if unzip is set to "*", then will unzip all files and folders.
408408
2. if unzip is set to **AUTO**, then will add the `.pyd` and `.so` files automatically.
409-
2. the `unzip` arg of `zipapps.create_app`
410-
8. `--unzip-path, -up`
411-
1. If `unzip` arg is not null, cache files will be unzipped to the given path while running. Defaults to `zipapps_cache`, support some internal variables as runtime args:
409+
2. Can be overwrite with environment variable `ZIPAPPS_UNZIP`
410+
3. the `unzip` arg of `zipapps.create_app`
411+
8. `--unzip-exclude, -ue`
412+
1. The opposite of `--unzip` / `-u` which will not be unzipped, should be used with `--unzip` / `-u`.
413+
2. Can be overwrite with environment variable `ZIPAPPS_UNZIP_EXCLUDE`
414+
9. `--unzip-path, -up`
415+
3. If `unzip` arg is not null, cache files will be unzipped to the given path while running. Defaults to `zipapps_cache`, support some internal variables as runtime args:
412416
1. `TEMP/HOME/SELF` as prefix, for example `HOME/zipapps_cache`
413417
1. `TEMP` means `tempfile.gettempdir()`
414418
2. `HOME` means `Path.home()`
415419
3. `SELF` means `.pyz` file path.
416420
2. And you can also **overwrite** it with environment variables:
417421
1. `ZIPAPPS_CACHE` or `UNZIP_PATH`
418-
2. the `unzip_path` arg of `zipapps.create_app`
419-
9. `-cc, --pyc, --compile, --compiled`
420-
1. Compile .py to .pyc for fast import, but zipapp does not work unless you unzip it(so NOT very useful).
421-
2. the `compiled` arg of `zipapps.create_app`
422-
10. ` --cache-path, --source-dir, -cp`
422+
4. the `unzip_path` arg of `zipapps.create_app`
423+
10. `-cc, --pyc, --compile, --compiled`
424+
5. Compile .py to .pyc for fast import, but zipapp does not work unless you unzip it(so NOT very useful).
425+
6. the `compiled` arg of `zipapps.create_app`
426+
11. ` --cache-path, --source-dir, -cp`
423427
1. The cache path of zipapps to store site-packages and `includes` files. If not set, will create and clean-up in TEMP dir automately.
424428
2. the `cache_path` arg of `zipapps.create_app`
425-
11. `--shell, -s`
429+
12. `--shell, -s`
426430
1. Only while `main` is not set, used for shell=True in `subprocess.run`.
427431
1. *very rarely used*, because extra sub-process is not welcome
428432
2. the `shell` arg of `zipapps.create_app`
429-
12. `--main-shell, -ss`
433+
13. `--main-shell, -ss`
430434
1. Only for `main` is not null, call `main` with `subprocess.Popen`: `python -c "import a.b;a.b.c()"`. This is used for `psutil` ImportError of DLL load.
431435
1. *very rarely used* too
432436
2. the `main_shell` arg of `zipapps.create_app`
433-
13. `--strict-python-path, -spp`
437+
14. `--strict-python-path, -spp`
434438
1. `Boolean` value. Ignore global PYTHONPATH, only use `zipapps_cache` and `app.pyz`.
435439
2. the `ignore_system_python_path` arg of `zipapps.create_app`
436-
14. `-b, --build-id`
440+
15. `-b, --build-id`
437441
1. The string to skip duplicate builds, it can be the paths of files/folders which splited by ",", then the modify time will be used as build_id. If build_id contains `*`, will use `glob` function to get paths. For example, you can set requirements.txt as your build_id by `python3 -m zipapps -b requirements.txt -r requirements.txt` when you use pyz as venv.
438442
1. *very rarely used* too too
439443
2. the `build_id` arg of `zipapps.create_app`
440-
15. `--zipapps, --env-paths`
444+
16. `--zipapps, --env-paths`
441445
1. Default `--zipapps` arg if it is not given while running. Support TEMP/HOME/SELF prefix.
442-
16. `--delay, -d, --lazy-pip, --lazy-install, --lazy-pip-install`
446+
17. `--delay, -d, --lazy-pip, --lazy-install, --lazy-pip-install`
443447
1. Install packages with pip while first running, which means requirements will not be install into pyz file.
444-
17. `--ensure-pip`
448+
18. `--ensure-pip`
445449
1. Add the ensurepip package to your pyz file, works for **embed-python**(windows) or other python versions without `pip` installed but `lazy-install` mode is enabled. [EXPERIMENTAL]
446-
18. `--layer-mode`
450+
19. `--layer-mode`
447451
1. Layer mode for the `serverless` use case, `__main__.py / ensure_zipapps.py / activate_zipapps.py` files will not be set in this mode.
448452
2. `--layer-mode-prefix`
449453
1. Only work while `--layer-mode` is set, will move the files in the given prefix folder.
450-
19. `--clear-zipapps-cache, -czc`
454+
20. `--clear-zipapps-cache, -czc`
451455
1. Clear the zipapps cache folder after running, but maybe failed for .pyd/.so files.
452-
20. all the other (or `unknown`) args will be used by `pip install`
456+
21. all the other (or `unknown`) args will be used by `pip install`
453457
1. such as `-r requirements.txt`
454458
2. such as `bottle aiohttp`
455459
3. the `pip_args` arg of `zipapps.create_app`

changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
# Changelogs
33

44

5+
- 2021.02.27
6+
- add `--unzip-exclude, -ue`
7+
- The opposite of `--unzip` / `-u` which will not be unzipped, should be used with `--unzip` / `-u`.
8+
- Can be overwrite with environment variable `ZIPAPPS_UNZIP_EXCLUDE`
59
- 2021.01.17
610
- add runtime arg `--activate-zipapps` to ensure cache folder and do nothing
711
- fix pip install for `-d` (lazy install mode) with `pip.main` function instead of subprocess

test_utils.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ def _clean_paths():
3636

3737
def test_create_app_function():
3838

39+
# test unzip_exclude
40+
_clean_paths()
41+
app_path = create_app(unzip='*', pip_args=['six'], unzip_exclude='')
42+
stdout_output, stderr_output = subprocess.Popen(
43+
[sys.executable, str(app_path), '--activate-zipapps']).communicate()
44+
assert Path('./zipapps_cache/app/six.py').is_file()
45+
_clean_paths()
46+
app_path = create_app(unzip='*', pip_args=['six'], unzip_exclude='six')
47+
stdout_output, stderr_output = subprocess.Popen(
48+
[sys.executable, str(app_path), '--activate-zipapps']).communicate()
49+
assert not Path('./zipapps_cache/app/six.py').is_file()
50+
3951
# test -czc
4052
_clean_paths()
4153
app_path = create_app(clear_zipapps_cache=False, unzip='*')

zipapps/__main__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,15 @@ def main():
9292
'-u',
9393
default='',
9494
help='The names which need to be unzipped while running, splited by "," '
95-
'`without ext`, such as `bottle,aiohttp`, or the complete path like `bin/bottle.py,temp.py`. For `.so/.pyd` files(which can not be loaded by zipimport), or packages with operations of static files. if unzip is set to "*", then will unzip all files and folders. if unzip is set to **AUTO**, then will add the `.pyd` and `.so` files automatically.'
95+
'`without ext`, such as `bottle,aiohttp`, or the complete path like `bin/bottle.py,temp.py`. For `.so/.pyd` files(which can not be loaded by zipimport), or packages with operations of static files. if unzip is set to "*", then will unzip all files and folders. if unzip is set to **AUTO**, then will add the `.pyd` and `.so` files automatically. Can be overwrite with environment variable `ZIPAPPS_UNZIP`'
96+
)
97+
parser.add_argument(
98+
'--unzip-exclude',
99+
'-ue',
100+
default='',
101+
dest='unzip_exclude',
102+
help='The opposite of `--unzip` / `-u` which will not be unzipped, '
103+
'should be used with `--unzip` / `-u`. Can be overwrite with environment variable `ZIPAPPS_UNZIP_EXCLUDE`'
96104
)
97105
parser.add_argument(
98106
'--unzip-path',
@@ -246,6 +254,7 @@ def main():
246254
layer_mode=args.layer_mode,
247255
layer_mode_prefix=args.layer_mode_prefix,
248256
clear_zipapps_cache=args.clear_zipapps_cache,
257+
unzip_exclude=args.unzip_exclude,
249258
)
250259

251260

zipapps/ensure_zipapps_template.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
# const
1111
ignore_system_python_path = {ignore_system_python_path}
1212
unzip = os.environ.get('ZIPAPPS_UNZIP') or r'''{unzip}'''
13+
unzip_exclude = os.environ.get(
14+
'ZIPAPPS_UNZIP_EXCLUDE') or r'''{unzip_exclude}'''
1315
_cache_folder = os.environ.get('ZIPAPPS_CACHE') or os.environ.get(
1416
'UNZIP_PATH') or r'''{unzip_path}'''
1517
ts_file_name = '_zip_time_{ts}'
@@ -85,12 +87,18 @@ def _remove_cache_folder():
8587
# rm the folder
8688
clear_old_cache(_cache_folder_path, LAZY_PIP_DIR_NAME)
8789
_need_unzip_names = unzip.split(',')
90+
if unzip_exclude:
91+
_exclude_unzip_names = set(unzip_exclude.split(','))
92+
else:
93+
_exclude_unzip_names = set()
8894
_need_unzip_names.append(ts_file_name)
8995
with ZipFile(zip_file_path, "r") as zf:
9096
for member in zf.infolist():
9197
file_dir_name = os.path.splitext(
9298
member.filename.split('/')[0])[0]
93-
if unzip == '*' or member.filename in _need_unzip_names or file_dir_name in _need_unzip_names:
99+
allow_unzip = unzip == '*' or member.filename in _need_unzip_names or file_dir_name in _need_unzip_names
100+
exclude_unzip = member.filename in _exclude_unzip_names or file_dir_name in _exclude_unzip_names
101+
if allow_unzip and not exclude_unzip:
94102
zf.extract(member, path=_cache_folder_path_str)
95103
if LAZY_PIP_DIR_NAME:
96104
import platform

zipapps/main.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from pkgutil import get_data
1515
from zipfile import ZIP_DEFLATED, ZIP_STORED, BadZipFile, ZipFile
1616

17-
__version__ = '2021.01.17'
17+
__version__ = '2021.02.27'
1818

1919

2020
class ZipApp(object):
@@ -51,6 +51,7 @@ def __init__(
5151
layer_mode: bool = False,
5252
layer_mode_prefix: str = 'python',
5353
clear_zipapps_cache: bool = False,
54+
unzip_exclude: str = '',
5455
):
5556
"""Zip your code.
5657
@@ -68,7 +69,7 @@ def __init__(
6869
:type compressed: bool, optional
6970
:param shell: whether run python in subprocess, or use runpy if shell is False, defaults to False
7071
:type shell: bool, optional
71-
:param unzip: names to be unzip, using `AUTO` is a better choice, defaults to ''
72+
:param unzip: names to be unzip, using `AUTO` is a better choice, defaults to ''. Can be overwrite with environment variable `ZIPAPPS_UNZIP`
7273
:type unzip: str, optional
7374
:param unzip_path: If `unzip` arg is not null, cache files will be unzipped to the given path while running. Defaults to `zipapps_cache`, support some internal variables: `TEMP/HOME/SELF` as internal variables, for example `HOME/zipapps_cache`. `TEMP` means `tempfile.gettempdir()`, `HOME` means `Path.home()`, `SELF` means `.pyz` file path, defaults to ''
7475
:type unzip_path: str, optional
@@ -98,6 +99,8 @@ def __init__(
9899
:type includes: str, optional
99100
:param clear_zipapps_cache: Clear the zipapps cache folder after running, but maybe failed for .pyd/.so files..
100101
:type includes: bool, optional
102+
:param unzip_exclude: names not to be unzip, defaults to '', should be used with unzip. Can be overwrite with environment variable `ZIPAPPS_UNZIP_EXCLUDE`
103+
:type unzip_exclude: str, optional
101104
"""
102105
self.includes = includes
103106
self.cache_path = cache_path
@@ -108,6 +111,7 @@ def __init__(
108111
self.compressed = compressed
109112
self.shell = shell
110113
self.unzip = unzip
114+
self.unzip_exclude = unzip_exclude
111115
self.unzip_path = unzip_path
112116
self.ignore_system_python_path = ignore_system_python_path
113117
self.main_shell = main_shell
@@ -129,6 +133,10 @@ def __init__(
129133

130134
def ensure_args(self):
131135
if not self.unzip:
136+
if self.unzip_exclude:
137+
self._log(
138+
'[WARN]: The arg `unzip_exclude` should not be with `unzip` but `unzip` is null.'
139+
)
132140
if self.compiled:
133141
self._log(
134142
'[WARN]: The arg `compiled` should not be True while `unzip` is null, because .pyc files of __pycache__ folder may not work in zip file.'
@@ -273,6 +281,7 @@ def prepare_active_zipapps(self):
273281
'shell': self.shell,
274282
'main_shell': self.main_shell,
275283
'unzip': self.unzip,
284+
'unzip_exclude': self.unzip_exclude,
276285
'output_name': output_name,
277286
'unzip_path': self.unzip_path,
278287
'ignore_system_python_path': self.ignore_system_python_path,

0 commit comments

Comments
 (0)