Skip to content

bpo-31072: Add filter to zipapp #3021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 9, 2017
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
7 changes: 6 additions & 1 deletion Doc/library/zipapp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.

Expand Down
17 changes: 17 additions & 0 deletions Lib/test/test_zipapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
6 changes: 4 additions & 2 deletions Lib/zipapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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'))

Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,7 @@ Brian Quinlan
Anders Qvist
Thomas Rachel
Ram Rachum
Jeffrey Rackauckas
Jérôme Radix
Burton Radons
Abhilash Raj
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add an ``include_file`` parameter to ``zipapp.create_archive()``