From b811d664defed085d16951088afb579fb649c58d Mon Sep 17 00:00:00 2001 From: Jeffrey Rackauckas Date: Wed, 9 Aug 2017 06:37:17 -0700 Subject: [PATCH] bpo-31072: Add filter to zipapp (#3021) bpo-31072: Add a filter argument to zipapp.create_archive (GH-3021) * Add an include_file argument to allow callers to decide which files to include * Document the new argument --- Doc/library/zipapp.rst | 7 ++++++- Lib/test/test_zipapp.py | 17 +++++++++++++++++ Lib/zipapp.py | 6 ++++-- Misc/ACKS | 1 + .../2017-08-09-13-45-23.bpo-31072.NLXDPV.rst | 1 + 5 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2017-08-09-13-45-23.bpo-31072.NLXDPV.rst diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index 71753cb9a0d..993c2ccc398 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -98,7 +98,8 @@ Python API The module defines two convenience functions: -.. function:: create_archive(source, target=None, interpreter=None, main=None) +.. function:: create_archive(source, target=None, interpreter=None, main=None, + include_file=None) Create an application archive from *source*. The source can be any of the following: @@ -143,6 +144,10 @@ The module defines two convenience functions: contain a ``__main__.py`` file, as otherwise the resulting archive would not be executable. + The *include_file* argument specifies a callback function that is passed the + relative path to the file in order to determine which files to store when + being called against a directory. + If a file object is specified for *source* or *target*, it is the caller's responsibility to close it after calling create_archive. diff --git a/Lib/test/test_zipapp.py b/Lib/test/test_zipapp.py index d8d44375bdd..47eed5f4a6c 100644 --- a/Lib/test/test_zipapp.py +++ b/Lib/test/test_zipapp.py @@ -53,6 +53,23 @@ def test_create_archive_with_subdirs(self): self.assertIn('foo/', z.namelist()) self.assertIn('bar/', z.namelist()) + def test_create_archive_with_include_file(self): + # Test packing a directory and using include_file to specify which files to include. + def skip_pyc_files(file): + return '.pyc' not in str(file) + source = self.tmpdir / 'source' + source.mkdir() + (source / '__main__.py').touch() + (source / 'test.py').touch() + (source / 'test.pyc').touch() + target = self.tmpdir / 'source.pyz' + + zipapp.create_archive(source, target, include_file=skip_pyc_files) + with zipfile.ZipFile(target, 'r') as z: + self.assertIn('__main__.py', z.namelist()) + self.assertIn('test.py', z.namelist()) + self.assertNotIn('test.pyc', z.namelist()) + def test_create_archive_default_target(self): # Test packing a directory to the default name. source = self.tmpdir / 'source' diff --git a/Lib/zipapp.py b/Lib/zipapp.py index c23b788d1c9..bf15b6806dd 100644 --- a/Lib/zipapp.py +++ b/Lib/zipapp.py @@ -73,7 +73,8 @@ def _copy_archive(archive, new_archive, interpreter=None): os.chmod(new_archive, os.stat(new_archive).st_mode | stat.S_IEXEC) -def create_archive(source, target=None, interpreter=None, main=None): +def create_archive(source, target=None, interpreter=None, main=None, + include_file=None): """Create an application archive from SOURCE. The SOURCE can be the name of a directory, or a filename or a file-like @@ -135,7 +136,8 @@ def create_archive(source, target=None, interpreter=None, main=None): with zipfile.ZipFile(fd, 'w') as z: for child in source.rglob('*'): arcname = child.relative_to(source).as_posix() - z.write(child, arcname) + if include_file is None or include_file(pathlib.Path(arcname)): + z.write(child, arcname) if main_py: z.writestr('__main__.py', main_py.encode('utf-8')) diff --git a/Misc/ACKS b/Misc/ACKS index e340392d8e1..d6088b3f5d9 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1253,6 +1253,7 @@ Brian Quinlan Anders Qvist Thomas Rachel Ram Rachum +Jeffrey Rackauckas Jérôme Radix Burton Radons Abhilash Raj diff --git a/Misc/NEWS.d/next/Library/2017-08-09-13-45-23.bpo-31072.NLXDPV.rst b/Misc/NEWS.d/next/Library/2017-08-09-13-45-23.bpo-31072.NLXDPV.rst new file mode 100644 index 00000000000..8c96201210f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-08-09-13-45-23.bpo-31072.NLXDPV.rst @@ -0,0 +1 @@ +Add an ``include_file`` parameter to ``zipapp.create_archive()``