Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions Doc/library/zipapp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ The following options are understood:

:option:`--main` cannot be specified when copying an archive.

.. cmdoption:: -c, --compress

Compress files with the deflate method, reducing the size of the output
file. By default, files are stored uncompressed in the archive.

:option:`--compress` has no effect when copying an archive.

.. cmdoption:: --info

Display the interpreter embedded in the archive, for diagnostic purposes. In
Expand All @@ -98,8 +105,7 @@ Python API
The module defines two convenience functions:


.. function:: create_archive(source, target=None, interpreter=None, main=None,
filter=None)
.. function:: create_archive(source, target=None, interpreter=None, main=None, filter=None, compressed=False)

Create an application archive from *source*. The source can be any
of the following:
Expand Down Expand Up @@ -149,6 +155,11 @@ The module defines two convenience functions:
(relative to the source directory). It should return ``True`` if the
file is to be added.

The optional *compressed* argument determines whether files are
compressed. If set to ``True``, files in the archive are compressed
with the deflate method; otherwise, files are stored uncompressed.
This argument has no effect when copying an existing archive.

If a file object is specified for *source* or *target*, it is the
caller's responsibility to close it after calling create_archive.

Expand All @@ -159,7 +170,7 @@ The module defines two convenience functions:
needed by that class.

.. versionadded:: 3.7
Added the *filter* argument.
Added the *filter* and *compressed* arguments.

.. function:: get_interpreter(archive)

Expand Down
6 changes: 5 additions & 1 deletion Doc/whatsnew/3.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,13 @@ zipapp
------

Function :func:`zipapp.create_archive` now accepts an optional *filter*
argument, to allow the user to select which files should be included in the
argument to allow the user to select which files should be included in the
archive, and an optional *compressed* argument to generate a compressed
archive.

A command line option ``--compress`` has also been added to support
compression.


Optimizations
=============
Expand Down
14 changes: 14 additions & 0 deletions Lib/test/test_zipapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ def test_create_archive_default_target(self):
expected_target = self.tmpdir / 'source.pyz'
self.assertTrue(expected_target.is_file())

def test_create_archive_with_compression(self):
# Test packing a directory into a compressed archive.
source = self.tmpdir / 'source'
source.mkdir()
(source / '__main__.py').touch()
(source / 'test.py').touch()
target = self.tmpdir / 'source.pyz'

zipapp.create_archive(source, target, compressed=True)
with zipfile.ZipFile(target, 'r') as z:
for name in ('__main__.py', 'test.py'):
self.assertEqual(z.getinfo(name).compress_type,
zipfile.ZIP_DEFLATED)

def test_no_main(self):
# Test that packing a directory with no __main__.py fails.
source = self.tmpdir / 'source'
Expand Down
12 changes: 9 additions & 3 deletions Lib/zipapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def _copy_archive(archive, new_archive, interpreter=None):


def create_archive(source, target=None, interpreter=None, main=None,
filter=None):
filter=None, compressed=False):
"""Create an application archive from SOURCE.

The SOURCE can be the name of a directory, or a filename or a file-like
Expand Down Expand Up @@ -133,7 +133,9 @@ def create_archive(source, target=None, interpreter=None, main=None,

with _maybe_open(target, 'wb') as fd:
_write_file_prefix(fd, interpreter)
with zipfile.ZipFile(fd, 'w') as z:
compression = (zipfile.ZIP_DEFLATED if compressed else
zipfile.ZIP_STORED)
with zipfile.ZipFile(fd, 'w', compression=compression) as z:
for child in source.rglob('*'):
arcname = child.relative_to(source)
if filter is None or filter(arcname):
Expand Down Expand Up @@ -170,6 +172,9 @@ def main(args=None):
parser.add_argument('--main', '-m', default=None,
help="The main function of the application "
"(default: use an existing __main__.py).")
parser.add_argument('--compress', '-c', action='store_true',
help="Compress files with the deflate method. "
"Files are stored uncompressed by default.")
parser.add_argument('--info', default=False, action='store_true',
help="Display the interpreter from the archive.")
parser.add_argument('source',
Expand All @@ -193,7 +198,8 @@ def main(args=None):
raise SystemExit("Cannot change the main function when copying")

create_archive(args.source, args.output,
interpreter=args.python, main=args.main)
interpreter=args.python, main=args.main,
compressed=args.compress)


if __name__ == '__main__':
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add optional argument ``compressed`` to ``zipapp.create_archive``, and add
option ``--compress`` to the command line interface of ``zipapp``.