Commit 59202e5f authored by Christian Tismer's avatar Christian Tismer

add a filterfunc to zip file.PyZipFile.writepy, issue 19274

parent 47f1b762
......@@ -382,7 +382,10 @@ The :class:`PyZipFile` constructor takes the same parameters as the
Instances have one method in addition to those of :class:`ZipFile` objects:
.. method:: PyZipFile.writepy(pathname, basename='')
.. method:: PyZipFile.writepy(pathname, basename='', filterfunc=None)
.. versionadded:: 3.4
The *filterfunc* parameter.
Search for files :file:`\*.py` and add the corresponding file to the
archive.
......@@ -404,7 +407,10 @@ The :class:`PyZipFile` constructor takes the same parameters as the
package directory, then all :file:`\*.py[co]` are added under the package
name as a file path, and if any subdirectories are package directories,
all of these are added recursively. *basename* is intended for internal
use only. The :meth:`writepy` method makes archives with file names like
use only. When *filterfunc(pathname)* is given, it will be called for every
invocation. When it returns a False value, that path and its subpaths will
be ignored.
The :meth:`writepy` method makes archives with file names like
this::
string.pyc # Top level name
......
......@@ -564,6 +564,16 @@ Add an event-driven parser for non-blocking applications,
(Contributed by Antoine Pitrou in :issue:`17741`.)
zipfile.PyZipfile
-----------------
Add a filter function to ignore some packages (tests for instance),
:meth:`~zipfile.PyZipFile.writepy`.
(Contributed by Christian Tismer in :issue:`19274`.)
Other improvements
==================
......
......@@ -591,6 +591,28 @@ class PyZipFileTests(unittest.TestCase):
self.assertCompiledIn('email/__init__.py', names)
self.assertCompiledIn('email/mime/text.py', names)
def test_write_filtered_python_package(self):
import test
packagedir = os.path.dirname(test.__file__)
with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
stdout = sys.stdout
# first make sure that the test folder gives error messages
sys.stdout = reportSIO = io.StringIO()
zipfp.writepy(packagedir)
reportStr = reportSIO.getvalue()
self.assertTrue('SyntaxError' in reportStr)
# then check that the filter works
sys.stdout = reportSIO = io.StringIO()
zipfp.writepy(packagedir, filterfunc=lambda whatever:False)
reportStr = reportSIO.getvalue()
self.assertTrue('SyntaxError' not in reportStr)
sys.stdout = stdout
def test_write_with_optimization(self):
import email
packagedir = os.path.dirname(email.__file__)
......
......@@ -1566,7 +1566,7 @@ class PyZipFile(ZipFile):
allowZip64=allowZip64)
self._optimize = optimize
def writepy(self, pathname, basename=""):
def writepy(self, pathname, basename="", filterfunc=None):
"""Add all files from "pathname" to the ZIP archive.
If pathname is a package directory, search the directory and
......@@ -1577,7 +1577,13 @@ class PyZipFile(ZipFile):
archive. Added modules are always module.pyo or module.pyc.
This method will compile the module.py into module.pyc if
necessary.
If filterfunc(pathname) is given, it is called with every argument.
When it is False, the file or directory is skipped.
"""
if filterfunc and not filterfunc(pathname):
if self.debug:
print('pathname "%s" skipped by filterfunc' % pathname)
return
dir, name = os.path.split(pathname)
if os.path.isdir(pathname):
initname = os.path.join(pathname, "__init__.py")
......@@ -1602,7 +1608,8 @@ class PyZipFile(ZipFile):
if os.path.isdir(path):
if os.path.isfile(os.path.join(path, "__init__.py")):
# This is a package directory, add it
self.writepy(path, basename) # Recursive call
self.writepy(path, basename,
filterfunc=filterfunc) # Recursive call
elif ext == ".py":
fname, arcname = self._get_codename(path[0:-3],
basename)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment