]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-31638: Add compression support to zipapp (GH-3819)
authorZhiming Wang <zmwangx@gmail.com>
Fri, 29 Sep 2017 17:31:52 +0000 (13:31 -0400)
committerPaul Moore <p.f.moore@gmail.com>
Fri, 29 Sep 2017 17:31:52 +0000 (18:31 +0100)
Add optional argument `compressed` to `zipapp.create_archive`, and add
option `--compress` to the command line interface of `zipapp`.

Doc/library/zipapp.rst
Doc/whatsnew/3.7.rst
Lib/test/test_zipapp.py
Lib/zipapp.py
Misc/NEWS.d/next/Library/2017-09-29-07-14-28.bpo-31638.jElfhl.rst [new file with mode: 0644]

index 120bbbb66201f6415e29491e23b1e6ea925289ff..2bd65cba42e20d53f7e0179958903e195fd99ace 100644 (file)
@@ -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
@@ -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:
@@ -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.
 
@@ -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)
 
index a19a2895828116d84956659becccac94fa50afa6..a474e767529f46740d6ed6ead299c6e59272c5c3 100644 (file)
@@ -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
 =============
index 56cf37c9afa03b457b8194403994333501f64202..3602b9989aebba3e442022e7482046a619f8bb5f 100644 (file)
@@ -100,6 +100,20 @@ class ZipAppTest(unittest.TestCase):
         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'
index 51d0290a901ba8b9baf14b0f3d9d4fff760add4c..ce77632516c646ecc11e231a1d855e3a48670a71 100644 (file)
@@ -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
@@ -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):
@@ -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',
@@ -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__':
diff --git a/Misc/NEWS.d/next/Library/2017-09-29-07-14-28.bpo-31638.jElfhl.rst b/Misc/NEWS.d/next/Library/2017-09-29-07-14-28.bpo-31638.jElfhl.rst
new file mode 100644 (file)
index 0000000..29e504e
--- /dev/null
@@ -0,0 +1,2 @@
+Add optional argument ``compressed`` to ``zipapp.create_archive``, and add
+option ``--compress`` to the command line interface of ``zipapp``.