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

This commit is contained in:
Christian Tismer 2013-10-21 03:59:23 +02:00
parent 47f1b762fd
commit 59202e5fc7
4 changed files with 204 additions and 159 deletions

View File

@ -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: 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 Search for files :file:`\*.py` and add the corresponding file to the
archive. 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 package directory, then all :file:`\*.py[co]` are added under the package
name as a file path, and if any subdirectories are package directories, name as a file path, and if any subdirectories are package directories,
all of these are added recursively. *basename* is intended for internal 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:: this::
string.pyc # Top level name string.pyc # Top level name

View File

@ -564,6 +564,16 @@ Add an event-driven parser for non-blocking applications,
(Contributed by Antoine Pitrou in :issue:`17741`.) (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 Other improvements
================== ==================

View File

@ -591,6 +591,28 @@ class PyZipFileTests(unittest.TestCase):
self.assertCompiledIn('email/__init__.py', names) self.assertCompiledIn('email/__init__.py', names)
self.assertCompiledIn('email/mime/text.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): def test_write_with_optimization(self):
import email import email
packagedir = os.path.dirname(email.__file__) packagedir = os.path.dirname(email.__file__)

View File

@ -1566,7 +1566,7 @@ class PyZipFile(ZipFile):
allowZip64=allowZip64) allowZip64=allowZip64)
self._optimize = optimize self._optimize = optimize
def writepy(self, pathname, basename=""): def writepy(self, pathname, basename="", filterfunc=None):
"""Add all files from "pathname" to the ZIP archive. """Add all files from "pathname" to the ZIP archive.
If pathname is a package directory, search the directory and 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. archive. Added modules are always module.pyo or module.pyc.
This method will compile the module.py into module.pyc if This method will compile the module.py into module.pyc if
necessary. 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) dir, name = os.path.split(pathname)
if os.path.isdir(pathname): if os.path.isdir(pathname):
initname = os.path.join(pathname, "__init__.py") initname = os.path.join(pathname, "__init__.py")
@ -1602,7 +1608,8 @@ class PyZipFile(ZipFile):
if os.path.isdir(path): if os.path.isdir(path):
if os.path.isfile(os.path.join(path, "__init__.py")): if os.path.isfile(os.path.join(path, "__init__.py")):
# This is a package directory, add it # This is a package directory, add it
self.writepy(path, basename) # Recursive call self.writepy(path, basename,
filterfunc=filterfunc) # Recursive call
elif ext == ".py": elif ext == ".py":
fname, arcname = self._get_codename(path[0:-3], fname, arcname = self._get_codename(path[0:-3],
basename) basename)