On behalf of Tarek: Issue #11501: disutils.archive_utils.make_zipfile no
authorAntoine Pitrou <solipsis@pitrou.net>
Tue, 15 Mar 2011 20:02:59 +0000 (21:02 +0100)
committerAntoine Pitrou <solipsis@pitrou.net>
Tue, 15 Mar 2011 20:02:59 +0000 (21:02 +0100)
longer fails if zlib is not installed. Instead, the zipfile.ZIP_STORED
compression is used to create the ZipFile. Patch by Natalia B. Bidart.

Lib/distutils/archive_util.py
Lib/distutils/tests/test_archive_util.py
Lib/distutils/tests/test_bdist_dumb.py
Lib/distutils/tests/test_sdist.py
Lib/test/support.py
Misc/ACKS
Misc/NEWS

index 6dd0445dbe60e76baab9d886cbdb561378b7c531..c06eba351d8e1cab95882eb909755dcb5971835c 100644 (file)
@@ -9,6 +9,12 @@ import os
 from warnings import warn
 import sys
 
+try:
+    import zipfile
+except ImportError:
+    zipfile = None
+
+
 from distutils.errors import DistutilsExecError
 from distutils.spawn import spawn
 from distutils.dir_util import mkpath
@@ -74,11 +80,6 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
     available, raises DistutilsExecError.  Returns the name of the output zip
     file.
     """
-    try:
-        import zipfile
-    except ImportError:
-        zipfile = None
-
     zip_filename = base_name + ".zip"
     mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
 
@@ -105,8 +106,12 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
                  zip_filename, base_dir)
 
         if not dry_run:
-            zip = zipfile.ZipFile(zip_filename, "w",
-                                  compression=zipfile.ZIP_DEFLATED)
+            try:
+                zip = zipfile.ZipFile(zip_filename, "w",
+                                      compression=zipfile.ZIP_DEFLATED)
+            except RuntimeError:
+                zip = zipfile.ZipFile(zip_filename, "w",
+                                      compression=zipfile.ZIP_STORED)
 
             for dirpath, dirnames, filenames in os.walk(base_dir):
                 for name in filenames:
index aff426521d9600eee741a0372823297a2ab62b45..f96984959035b614123a79a2691ab20a76bdcd7b 100644 (file)
@@ -7,12 +7,13 @@ import tarfile
 from os.path import splitdrive
 import warnings
 
+from distutils import archive_util
 from distutils.archive_util import (check_archive_formats, make_tarball,
                                     make_zipfile, make_archive,
                                     ARCHIVE_FORMATS)
 from distutils.spawn import find_executable, spawn
 from distutils.tests import support
-from test.support import check_warnings, run_unittest
+from test.support import check_warnings, run_unittest, patch
 
 try:
     import zipfile
@@ -20,10 +21,18 @@ try:
 except ImportError:
     ZIP_SUPPORT = find_executable('zip')
 
+try:
+    import zlib
+    ZLIB_SUPPORT = True
+except ImportError:
+    ZLIB_SUPPORT = False
+
+
 class ArchiveUtilTestCase(support.TempdirManager,
                           support.LoggingSilencer,
                           unittest.TestCase):
 
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_make_tarball(self):
         # creating something to tar
         tmpdir = self.mkdtemp()
@@ -84,8 +93,9 @@ class ArchiveUtilTestCase(support.TempdirManager,
         base_name = os.path.join(tmpdir2, 'archive')
         return tmpdir, tmpdir2, base_name
 
-    @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
-                         'Need the tar command to run')
+    @unittest.skipUnless(find_executable('tar') and find_executable('gzip')
+                         and ZLIB_SUPPORT,
+                         'Need the tar, gzip and zlib command to run')
     def test_tarfile_vs_tar(self):
         tmpdir, tmpdir2, base_name =  self._create_files()
         old_dir = os.getcwd()
@@ -169,7 +179,8 @@ class ArchiveUtilTestCase(support.TempdirManager,
         self.assertTrue(not os.path.exists(tarball))
         self.assertEqual(len(w.warnings), 1)
 
-    @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
+    @unittest.skipUnless(ZIP_SUPPORT and ZLIB_SUPPORT,
+                         'Need zip and zlib support to run')
     def test_make_zipfile(self):
         # creating something to tar
         tmpdir = self.mkdtemp()
@@ -182,6 +193,29 @@ class ArchiveUtilTestCase(support.TempdirManager,
 
         # check if the compressed tarball was created
         tarball = base_name + '.zip'
+        self.assertTrue(os.path.exists(tarball))
+
+    @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
+    def test_make_zipfile_no_zlib(self):
+        patch(self, archive_util.zipfile, 'zlib', None)  # force zlib ImportError
+
+        called = []
+        zipfile_class = zipfile.ZipFile
+        def fake_zipfile(*a, **kw):
+            if kw.get('compression', None) == zipfile.ZIP_STORED:
+                called.append((a, kw))
+            return zipfile_class(*a, **kw)
+
+        patch(self, archive_util.zipfile, 'ZipFile', fake_zipfile)
+
+        # create something to tar and compress
+        tmpdir, tmpdir2, base_name = self._create_files()
+        make_zipfile(base_name, tmpdir)
+
+        tarball = base_name + '.zip'
+        self.assertEqual(called,
+                         [((tarball, "w"), {'compression': zipfile.ZIP_STORED})])
+        self.assertTrue(os.path.exists(tarball))
 
     def test_check_archive_formats(self):
         self.assertEqual(check_archive_formats(['gztar', 'xxx', 'zip']),
index cc37fef8b0190554e1b9ff706202ecaf4f88b092..55ba58d14fae40306549ddfa57598ac00b22154a 100644 (file)
@@ -18,6 +18,13 @@ setup(name='foo', version='0.1', py_modules=['foo'],
 
 """
 
+try:
+    import zlib
+    ZLIB_SUPPORT = True
+except ImportError:
+    ZLIB_SUPPORT = False
+
+
 class BuildDumbTestCase(support.TempdirManager,
                         support.LoggingSilencer,
                         support.EnvironGuard,
@@ -34,6 +41,7 @@ class BuildDumbTestCase(support.TempdirManager,
         sys.argv[:] = self.old_sys_argv[1]
         super(BuildDumbTestCase, self).tearDown()
 
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_simple_built(self):
 
         # let's create a simple package
index 655e50dcfc2f84dc76b2fa83f9bf1e16cc2a281b..eaf39a45baecc5b8a08fdcb79599f6e5776a820f 100644 (file)
@@ -40,6 +40,13 @@ somecode%(sep)sdoc.dat
 somecode%(sep)sdoc.txt
 """
 
+try:
+    import zlib
+    ZLIB_SUPPORT = True
+except ImportError:
+    ZLIB_SUPPORT = False
+
+
 class SDistTestCase(PyPIRCCommandTestCase):
 
     def setUp(self):
@@ -78,6 +85,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
         cmd.warn = _warn
         return dist, cmd
 
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_prune_file_list(self):
         # this test creates a package with some vcs dirs in it
         # and launch sdist to make sure they get pruned
@@ -119,6 +127,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
         # making sure everything has been pruned correctly
         self.assertEqual(len(content), 4)
 
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_make_distribution(self):
 
         # check if tar and gzip are installed
@@ -153,6 +162,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
         result.sort()
         self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'])
 
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_add_defaults(self):
 
         # http://bugs.python.org/issue2279
@@ -218,6 +228,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
         finally:
             f.close()
 
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_metadata_check_option(self):
         # testing the `medata-check` option
         dist, cmd = self.get_cmd(metadata={})
@@ -277,7 +288,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
         cmd.formats = 'supazipa'
         self.assertRaises(DistutilsOptionError, cmd.finalize_options)
 
-
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_get_file_list(self):
         # make sure MANIFEST is recalculated
         dist, cmd = self.get_cmd()
@@ -318,6 +329,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
         self.assertEqual(len(manifest2), 6)
         self.assertIn('doc2.txt', manifest2[-1])
 
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_manifest_marker(self):
         # check that autogenerated MANIFESTs have a marker
         dist, cmd = self.get_cmd()
@@ -334,6 +346,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
         self.assertEqual(manifest[0],
                          '# file GENERATED by distutils, do NOT edit')
 
+    @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     def test_manual_manifest(self):
         # check that a MANIFEST without a marker is left alone
         dist, cmd = self.get_cmd()
index 9fb3ee00c10a077796fa4f0ac72c3dd377b4fb22..bef7161e9a1a229c5d272c88bfa45a9f0b0e6624 100644 (file)
@@ -1096,3 +1096,36 @@ def strip_python_stderr(stderr):
     """
     stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip()
     return stderr
+
+def patch(test_instance, object_to_patch, attr_name, new_value):
+    """Override 'object_to_patch'.'attr_name' with 'new_value'.
+
+    Also, add a cleanup procedure to 'test_instance' to restore
+    'object_to_patch' value for 'attr_name'.
+    The 'attr_name' should be a valid attribute for 'object_to_patch'.
+
+    """
+    # check that 'attr_name' is a real attribute for 'object_to_patch'
+    # will raise AttributeError if it does not exist
+    getattr(object_to_patch, attr_name)
+
+    # keep a copy of the old value
+    attr_is_local = False
+    try:
+        old_value = object_to_patch.__dict__[attr_name]
+    except (AttributeError, KeyError):
+        old_value = getattr(object_to_patch, attr_name, None)
+    else:
+        attr_is_local = True
+
+    # restore the value when the test is done
+    def cleanup():
+        if attr_is_local:
+            setattr(object_to_patch, attr_name, old_value)
+        else:
+            delattr(object_to_patch, attr_name)
+
+    test_instance.addCleanup(cleanup)
+
+    # actually override the attribute
+    setattr(object_to_patch, attr_name, new_value)
index fe80c8bbdfeb2e5facbfb8d012a86d3b2d70e162..c7fd2ff9a037aac1bb2fd3d2b0a984a1498c462a 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -72,6 +72,7 @@ Eric Beser
 Steven Bethard
 Stephen Bevan
 Ron Bickers
+Natalia B. Bidart
 David Binger
 Dominic Binks
 Philippe Biondi
index d4ce939119fd230178cdc05bcc10dc92bac1bb74..c4627fac66ace8d960b87fa05c26cbc8b9662983 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -40,6 +40,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #11501: disutils.archive_utils.make_zipfile no longer fails if zlib is
+  not installed. Instead, the zipfile.ZIP_STORED compression is used to create
+  the ZipFile. Patch by Natalia B. Bidart.
+
 - Issue #11491: dbm.error is no longer raised when dbm.open is called with
   the "n" as the flag argument and the file exists. The behavior matches
   the documentation and general logic.