Skip to content

Commit 5be66db

Browse files
committed
refactor for OOP
1 parent 21c746f commit 5be66db

File tree

5 files changed

+373
-294
lines changed

5 files changed

+373
-294
lines changed

README.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@
33

44
Package your python code (with requirements) into a standalone zip file (like a `jar`).
55

6-
`zipapps` is a `pure-python library`, without any 3rd-party dependencies. Inspired by [shiv](https://github.com/linkedin/shiv) but unlike `shiv`, this lib will not always create new cache folders while running, and easy to combine multiple `venv.pyz` files then let them work well together.
6+
`zipapps` is a `pure-python library`, without any 3rd-party dependencies. Inspired by [shiv](https://github.com/linkedin/shiv) but unlike `shiv`, this lib will not always create new cache folders while running, and easy to combine multiple `venv.pyz` files then let them work well together. The `lazy install` mode will give your code the `cross-platform` and `cross-version` feature.
77

88
# What is the `.pyz`?
99

1010
`.pyz` to **Python** is like `.jar` to **Java**. They are both zip 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.
1111

12-
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](https://www.python.org/dev/peps/pep-0441/), then the apps may be `cross-platform` as long as written with pure python code without any C++ building processes.
12+
PS: The **pyz** ext could be any other suffixes even without ext names, so you can rename `app.pyz` to `app.zip` or `app.py` or others as you wish. Depends on [PEP441](https://www.python.org/dev/peps/pep-0441/) & [zipimport](https://docs.python.org/3/library/zipimport.html), the apps may be `cross-platform` as long as written with pure python code without any C++ building processes.
1313

1414
# When to Use it?
1515
1. Package your code(package or model) into one zipped file.
16-
1. sometimes togather with the requirements.
16+
1. Pure python code without any 3rd-party dependencies.
17+
2. Python code with 3rd-party dependencies installed together.
18+
1. Some dependencies need to unzip them into the cache folder for dynamic modules(`.so/.pyd`) files exist, such as `psutil`.
19+
1. This type of `pyz` is `NOT cross-platform`.
20+
2. Some dependencies need not to unzip them, such as requests / bottle.
21+
3. Python code with requirements but not be installed while building. (**Recommended**)
22+
1. The `lazy install` mode by the arg `-d`.
23+
2. But will need to be install at the first running(only once).
24+
3. This is `cross-platform` and `cross-python-version` because of their installation paths is standalone.
1725
2. Run with python interpreter from the venv path.
1826
1. which means the requirements(need to be unzipped) will be installed to the `venv` folder, not in `pyz` file.
1927
2. **build** your package into one `pyz` file with `-m package.module:function -p /venv/bin/python`.
@@ -406,6 +414,16 @@ Details:
406414

407415
# Changelogs
408416

417+
- 2021.04.24
418+
- remove conflict command args with `pip`
419+
- remove `--compile` arg, it will only work for `pip`
420+
- `-c` will not be removed, `pip install -c` could use `pip install --constraint` instead
421+
- Refactor for OOP(Object-oriented programming)
422+
- Will be used as the **first stable version** and end experimental phase
423+
- remove `Config` class
424+
- show version info and other logs in stderr
425+
- `compiled` should not be True while `unzip` is null
426+
- a successful message has been added to the tail of logs: `Successfully built`
409427
- 2021.04.23
410428
- lazy install mode:
411429
- fix bug: python version conflict

test_utils.py

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -255,28 +255,17 @@ def test_create_app_function():
255255

256256
# test compiled
257257
_clean_paths()
258-
app_path = create_app(compiled=True, pip_args=['bottle'])
258+
app_path = create_app(unzip='six', compiled=True, pip_args=['six'])
259259
output, _ = subprocess.Popen(
260260
[
261261
sys.executable,
262-
str(app_path), '-c', 'import bottle;print(bottle.__cached__)'
262+
str(app_path), '-c', 'import six;print(six.__cached__)'
263263
],
264264
stderr=subprocess.PIPE,
265265
stdout=subprocess.PIPE,
266266
).communicate()
267267
# print(output)
268-
assert b'None' in output
269-
app_path = create_app(unzip='bottle', compiled=True, pip_args=['bottle'])
270-
output, _ = subprocess.Popen(
271-
[
272-
sys.executable,
273-
str(app_path), '-c', 'import bottle;print(bottle.__cached__)'
274-
],
275-
stderr=subprocess.PIPE,
276-
stdout=subprocess.PIPE,
277-
).communicate()
278-
# print(output)
279-
assert b'.pyc' in output
268+
assert b'.pyc' in output, output
280269

281270
# test unzip with HOME / SELF / TEMP
282271
_clean_paths()
@@ -352,15 +341,16 @@ def test_create_app_function():
352341
# test for simple usage
353342
create_app(pip_args=['six'], output='six.pyz')
354343
Path('./entry_test.py').write_text('import six;print(six.__file__)')
355-
_ = subprocess.Popen(
344+
output, error = subprocess.Popen(
356345
[
357346
sys.executable, '-m', 'zipapps', '--zipapps', 'six.pyz', '-m',
358347
'entry_test', '-a', 'entry_test.py'
359348
],
360349
stderr=subprocess.PIPE,
361350
stdout=subprocess.PIPE,
362351
).communicate()
363-
assert not any(_)
352+
assert not output, output
353+
assert b'Successfully built' in error, error
364354
output, error = subprocess.Popen(
365355
[sys.executable, './app.pyz'],
366356
stderr=subprocess.PIPE,
@@ -373,15 +363,15 @@ def test_create_app_function():
373363
# test for SELF arg
374364
create_app(pip_args=['six'], output='six.pyz')
375365
Path('./entry_test.py').write_text('import six;print(six.__file__)')
376-
_ = subprocess.Popen(
366+
_, error = subprocess.Popen(
377367
[
378368
sys.executable, '-m', 'zipapps', '--zipapps', 'SELF/six.pyz', '-m',
379369
'entry_test', '-a', 'entry_test.py'
380370
],
381371
stderr=subprocess.PIPE,
382372
stdout=subprocess.PIPE,
383373
).communicate()
384-
assert not any(_)
374+
assert b'Successfully built' in error
385375
output, error = subprocess.Popen(
386376
[sys.executable, './app.pyz'],
387377
stderr=subprocess.PIPE,
@@ -394,15 +384,15 @@ def test_create_app_function():
394384
# test for without --zipapps
395385
create_app(pip_args=['six'], output='six.pyz')
396386
Path('./entry_test.py').write_text('import six;print(six.__file__)')
397-
_ = subprocess.Popen(
387+
_, error = subprocess.Popen(
398388
[
399389
sys.executable, '-m', 'zipapps', '-m', 'entry_test', '-a',
400390
'entry_test.py'
401391
],
402392
stderr=subprocess.PIPE,
403393
stdout=subprocess.PIPE,
404394
).communicate()
405-
assert not any(_)
395+
assert b'Successfully built' in error
406396
output, error = subprocess.Popen(
407397
[sys.executable, './app.pyz'],
408398
stderr=subprocess.PIPE,
@@ -473,6 +463,9 @@ def main():
473463
test all cases
474464
"""
475465
test_create_app_function()
466+
print('=' * 80)
467+
print('All tests finished.')
468+
print('=' * 80)
476469

477470

478471
if __name__ == "__main__":

zipapps/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
from .main import create_app
2+
from .main import create_app, __version__
33
from .activate_zipapps import activate
4-
__all__ = ['create_app', 'activate']
5-
__version__ = '2021.04.23'
4+
5+
__all__ = ['create_app', 'activate', '__version__']

zipapps/__main__.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import sys
33

44
from . import __version__
5-
from .main import Config, create_app
5+
from .main import ZipApp, create_app
66

77
USAGE = r'''
88
===========================================================================
@@ -56,9 +56,9 @@ def main():
5656
parser.add_argument('--version', action='version', version=__version__)
5757
parser.add_argument('--output',
5858
'-o',
59-
default=Config.DEFAULT_OUTPUT_PATH,
59+
default=ZipApp.DEFAULT_OUTPUT_PATH,
6060
help='The path of the output file, defaults to'
61-
f' "{Config.DEFAULT_OUTPUT_PATH}".')
61+
f' "{ZipApp.DEFAULT_OUTPUT_PATH}".')
6262
parser.add_argument(
6363
'--python',
6464
'-p',
@@ -104,7 +104,6 @@ def main():
104104
parser.add_argument(
105105
'-cc',
106106
'--pyc',
107-
'--compile',
108107
'--compiled',
109108
action='store_true',
110109
dest='compiled',
@@ -144,11 +143,7 @@ def main():
144143
default='',
145144
dest='build_id',
146145
help='a string to skip duplicate builds,'
147-
' it can be the paths of files/folders which splited by ",", '
148-
'then the modify time will be used as build_id. If build_id contains `*`,'
149-
' will use `glob` function to get paths. '
150-
'For example, you can set requirements.txt as your build_id by'
151-
' `python3 -m zipapps -b requirements.txt -r requirements.txt` when you use pyz as venv.'
146+
' 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.'
152147
)
153148
parser.add_argument(
154149
'--zipapps',
@@ -184,9 +179,20 @@ def main():
184179
dest='sys_paths',
185180
help='Paths be insert to sys.path[-1] while running.'
186181
' Support TEMP/HOME/SELF prefix, separated by commas.')
182+
parser.add_argument(
183+
'--activate',
184+
default='',
185+
dest='activate',
186+
help='Activate the given paths of zipapps app, '
187+
'only activate them but not run them, separated by commas.')
187188
if len(sys.argv) == 1:
188189
return parser.print_help()
189190
args, pip_args = parser.parse_known_args()
191+
if args.activate:
192+
from .activate_zipapps import activate
193+
for path in args.activate.split(','):
194+
activate(path)
195+
return
190196
return create_app(
191197
includes=args.includes,
192198
cache_path=args.cache_path,

0 commit comments

Comments
 (0)