bpo-31072: Rename the new filter argument for zipapp.create_archive. (#3049)
bpo-31072: Rename the new filter argument for zipapp.create_archive (GH-3049) * Rename the new argument to "filter" * Improve tests for the new functionality * Add a "What's New" entry.
This commit is contained in:
parent
a5b4ea15b6
commit
0780bf7578
|
@ -99,7 +99,7 @@ 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)
|
filter=None)
|
||||||
|
|
||||||
Create an application archive from *source*. The source can be any
|
Create an application archive from *source*. The source can be any
|
||||||
of the following:
|
of the following:
|
||||||
|
@ -144,9 +144,10 @@ The module defines two convenience functions:
|
||||||
contain a ``__main__.py`` file, as otherwise the resulting archive
|
contain a ``__main__.py`` file, as otherwise the resulting archive
|
||||||
would not be executable.
|
would not be executable.
|
||||||
|
|
||||||
The *include_file* argument specifies a callback function that is passed the
|
The optional *filter* argument specifies a callback function that
|
||||||
relative path to the file in order to determine which files to store when
|
is passed a Path object representing the path to the file being added
|
||||||
being called against a directory.
|
(relative to the source directory). It should return ``True`` if the
|
||||||
|
file is to be added.
|
||||||
|
|
||||||
If a file object is specified for *source* or *target*, it is the
|
If a file object is specified for *source* or *target*, it is the
|
||||||
caller's responsibility to close it after calling create_archive.
|
caller's responsibility to close it after calling create_archive.
|
||||||
|
@ -157,6 +158,9 @@ The module defines two convenience functions:
|
||||||
passed to the ``zipfile.ZipFile`` class, and must supply the methods
|
passed to the ``zipfile.ZipFile`` class, and must supply the methods
|
||||||
needed by that class.
|
needed by that class.
|
||||||
|
|
||||||
|
.. versionadded:: 3.7
|
||||||
|
Added the *filter* argument.
|
||||||
|
|
||||||
.. function:: get_interpreter(archive)
|
.. function:: get_interpreter(archive)
|
||||||
|
|
||||||
Return the interpreter specified in the ``#!`` line at the start of the
|
Return the interpreter specified in the ``#!`` line at the start of the
|
||||||
|
|
|
@ -258,6 +258,13 @@ Function :func:`~uu.encode` now accepts an optional *backtick*
|
||||||
keyword argument. When it's true, zeros are represented by ``'`'``
|
keyword argument. When it's true, zeros are represented by ``'`'``
|
||||||
instead of spaces. (Contributed by Xiang Zhang in :issue:`30103`.)
|
instead of spaces. (Contributed by Xiang Zhang in :issue:`30103`.)
|
||||||
|
|
||||||
|
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
|
||||||
|
archive.
|
||||||
|
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
=============
|
=============
|
||||||
|
|
|
@ -53,10 +53,11 @@ class ZipAppTest(unittest.TestCase):
|
||||||
self.assertIn('foo/', z.namelist())
|
self.assertIn('foo/', z.namelist())
|
||||||
self.assertIn('bar/', z.namelist())
|
self.assertIn('bar/', z.namelist())
|
||||||
|
|
||||||
def test_create_archive_with_include_file(self):
|
def test_create_archive_with_filter(self):
|
||||||
# Test packing a directory and using include_file to specify which files to include.
|
# Test packing a directory and using filter to specify
|
||||||
def skip_pyc_files(file):
|
# which files to include.
|
||||||
return '.pyc' not in str(file)
|
def skip_pyc_files(path):
|
||||||
|
return path.suffix != '.pyc'
|
||||||
source = self.tmpdir / 'source'
|
source = self.tmpdir / 'source'
|
||||||
source.mkdir()
|
source.mkdir()
|
||||||
(source / '__main__.py').touch()
|
(source / '__main__.py').touch()
|
||||||
|
@ -64,12 +65,32 @@ class ZipAppTest(unittest.TestCase):
|
||||||
(source / 'test.pyc').touch()
|
(source / 'test.pyc').touch()
|
||||||
target = self.tmpdir / 'source.pyz'
|
target = self.tmpdir / 'source.pyz'
|
||||||
|
|
||||||
zipapp.create_archive(source, target, include_file=skip_pyc_files)
|
zipapp.create_archive(source, target, filter=skip_pyc_files)
|
||||||
with zipfile.ZipFile(target, 'r') as z:
|
with zipfile.ZipFile(target, 'r') as z:
|
||||||
self.assertIn('__main__.py', z.namelist())
|
self.assertIn('__main__.py', z.namelist())
|
||||||
self.assertIn('test.py', z.namelist())
|
self.assertIn('test.py', z.namelist())
|
||||||
self.assertNotIn('test.pyc', z.namelist())
|
self.assertNotIn('test.pyc', z.namelist())
|
||||||
|
|
||||||
|
def test_create_archive_filter_exclude_dir(self):
|
||||||
|
# Test packing a directory and using a filter to exclude a
|
||||||
|
# subdirectory (ensures that the path supplied to include
|
||||||
|
# is relative to the source location, as expected).
|
||||||
|
def skip_dummy_dir(path):
|
||||||
|
return path.parts[0] != 'dummy'
|
||||||
|
source = self.tmpdir / 'source'
|
||||||
|
source.mkdir()
|
||||||
|
(source / '__main__.py').touch()
|
||||||
|
(source / 'test.py').touch()
|
||||||
|
(source / 'dummy').mkdir()
|
||||||
|
(source / 'dummy' / 'test2.py').touch()
|
||||||
|
target = self.tmpdir / 'source.pyz'
|
||||||
|
|
||||||
|
zipapp.create_archive(source, target, filter=skip_dummy_dir)
|
||||||
|
with zipfile.ZipFile(target, 'r') as z:
|
||||||
|
self.assertEqual(len(z.namelist()), 2)
|
||||||
|
self.assertIn('__main__.py', z.namelist())
|
||||||
|
self.assertIn('test.py', z.namelist())
|
||||||
|
|
||||||
def test_create_archive_default_target(self):
|
def test_create_archive_default_target(self):
|
||||||
# Test packing a directory to the default name.
|
# Test packing a directory to the default name.
|
||||||
source = self.tmpdir / 'source'
|
source = self.tmpdir / 'source'
|
||||||
|
|
|
@ -74,7 +74,7 @@ def _copy_archive(archive, new_archive, interpreter=None):
|
||||||
|
|
||||||
|
|
||||||
def create_archive(source, target=None, interpreter=None, main=None,
|
def create_archive(source, target=None, interpreter=None, main=None,
|
||||||
include_file=None):
|
filter=None):
|
||||||
"""Create an application archive from SOURCE.
|
"""Create an application archive from SOURCE.
|
||||||
|
|
||||||
The SOURCE can be the name of a directory, or a filename or a file-like
|
The SOURCE can be the name of a directory, or a filename or a file-like
|
||||||
|
@ -135,9 +135,9 @@ def create_archive(source, target=None, interpreter=None, main=None,
|
||||||
_write_file_prefix(fd, interpreter)
|
_write_file_prefix(fd, interpreter)
|
||||||
with zipfile.ZipFile(fd, 'w') as z:
|
with zipfile.ZipFile(fd, 'w') as z:
|
||||||
for child in source.rglob('*'):
|
for child in source.rglob('*'):
|
||||||
arcname = child.relative_to(source).as_posix()
|
arcname = child.relative_to(source)
|
||||||
if include_file is None or include_file(pathlib.Path(arcname)):
|
if filter is None or filter(arcname):
|
||||||
z.write(child, arcname)
|
z.write(child, arcname.as_posix())
|
||||||
if main_py:
|
if main_py:
|
||||||
z.writestr('__main__.py', main_py.encode('utf-8'))
|
z.writestr('__main__.py', main_py.encode('utf-8'))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue