[Python-checkins] r77142 - in python/branches/py3k: Doc/library/zipfile.rst Lib/test/test_zipfile.py Lib/zipfile.py Misc/NEWS

ezio.melotti python-checkins at python.org
Wed Dec 30 13:35:00 CET 2009


Author: ezio.melotti
Date: Wed Dec 30 13:34:59 2009
New Revision: 77142

Log:
Merged revisions 77136 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r77136 | ezio.melotti | 2009-12-30 08:14:51 +0200 (Wed, 30 Dec 2009) | 1 line
  
  #5511: Added the ability to use ZipFile as a context manager. Patch by Brian Curtin.
........


Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Doc/library/zipfile.rst
   python/branches/py3k/Lib/test/test_zipfile.py
   python/branches/py3k/Lib/zipfile.py
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Doc/library/zipfile.rst
==============================================================================
--- python/branches/py3k/Doc/library/zipfile.rst	(original)
+++ python/branches/py3k/Doc/library/zipfile.rst	Wed Dec 30 13:34:59 2009
@@ -102,25 +102,32 @@
    Open a ZIP file, where *file* can be either a path to a file (a string) or a
    file-like object.  The *mode* parameter should be ``'r'`` to read an existing
    file, ``'w'`` to truncate and write a new file, or ``'a'`` to append to an
-   existing file.  If *mode* is ``'a'`` and *file* refers to an existing ZIP file,
-   then additional files are added to it.  If *file* does not refer to a ZIP file,
-   then a new ZIP archive is appended to the file.  This is meant for adding a ZIP
-   archive to another file, such as :file:`python.exe`.  Using ::
-
-      cat myzip.zip >> python.exe
-
-   also works, and at least :program:`WinZip` can read such files. If *mode* is
-   ``a`` and the file does not exist at all, it is created. *compression* is the
-   ZIP compression method to use when writing the archive, and should be
-   :const:`ZIP_STORED` or :const:`ZIP_DEFLATED`; unrecognized values will cause
-   :exc:`RuntimeError` to be raised.  If :const:`ZIP_DEFLATED` is specified but the
-   :mod:`zlib` module is not available, :exc:`RuntimeError` is also raised.  The
-   default is :const:`ZIP_STORED`.  If *allowZip64* is ``True`` zipfile will create
-   ZIP files that use the ZIP64 extensions when the zipfile is larger than 2 GB. If
-   it is  false (the default) :mod:`zipfile` will raise an exception when the ZIP
-   file would require ZIP64 extensions. ZIP64 extensions are disabled by default
-   because the default :program:`zip` and :program:`unzip` commands on Unix (the
-   InfoZIP utilities) don't support these extensions.
+   existing file.  If *mode* is ``'a'`` and *file* refers to an existing ZIP
+   file, then additional files are added to it.  If *file* does not refer to a
+   ZIP file, then a new ZIP archive is appended to the file.  This is meant for
+   adding a ZIP archive to another file (such as :file:`python.exe`).  If
+   *mode* is ``a`` and the file does not exist at all, it is created.
+   *compression* is the ZIP compression method to use when writing the archive,
+   and should be :const:`ZIP_STORED` or :const:`ZIP_DEFLATED`; unrecognized
+   values will cause :exc:`RuntimeError` to be raised.  If :const:`ZIP_DEFLATED`
+   is specified but the :mod:`zlib` module is not available, :exc:`RuntimeError`
+   is also raised. The default is :const:`ZIP_STORED`.  If *allowZip64* is
+   ``True`` zipfile will create ZIP files that use the ZIP64 extensions when
+   the zipfile is larger than 2 GB. If it is  false (the default) :mod:`zipfile`
+   will raise an exception when the ZIP file would require ZIP64 extensions.
+   ZIP64 extensions are disabled by default because the default :program:`zip`
+   and :program:`unzip` commands on Unix (the InfoZIP utilities) don't support
+   these extensions.
+
+   ZipFile is also a context manager and therefore supports the
+   :keyword:`with` statement.  In the example, *myzip* is closed after the
+   :keyword:`with` statement's suite is finished---even if an exception occurs::
+
+      with ZipFile('spam.zip', 'w') as myzip:
+          myzip.write('eggs.txt')
+
+   .. versionadded:: 3.2
+      Added the ability to use :class:`ZipFile` as a context manager.
 
 
 .. method:: ZipFile.close()

Modified: python/branches/py3k/Lib/test/test_zipfile.py
==============================================================================
--- python/branches/py3k/Lib/test/test_zipfile.py	(original)
+++ python/branches/py3k/Lib/test/test_zipfile.py	Wed Dec 30 13:34:59 2009
@@ -42,63 +42,61 @@
 
     def make_test_archive(self, f, compression):
         # Create the ZIP archive
-        zipfp = zipfile.ZipFile(f, "w", compression)
-        zipfp.write(TESTFN, "another.name")
-        zipfp.write(TESTFN, TESTFN)
-        zipfp.writestr("strfile", self.data)
-        zipfp.close()
+        with zipfile.ZipFile(f, "w", compression) as zipfp:
+            zipfp.write(TESTFN, "another.name")
+            zipfp.write(TESTFN, TESTFN)
+            zipfp.writestr("strfile", self.data)
 
     def zip_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r", compression)
-        self.assertEqual(zipfp.read(TESTFN), self.data)
-        self.assertEqual(zipfp.read("another.name"), self.data)
-        self.assertEqual(zipfp.read("strfile"), self.data)
-
-        # Print the ZIP directory
-        fp = io.StringIO()
-        zipfp.printdir(file=fp)
-        directory = fp.getvalue()
-        lines = directory.splitlines()
-        self.assertEquals(len(lines), 4) # Number of files + header
-
-        self.assertTrue('File Name' in lines[0])
-        self.assertTrue('Modified' in lines[0])
-        self.assertTrue('Size' in lines[0])
-
-        fn, date, time, size = lines[1].split()
-        self.assertEquals(fn, 'another.name')
-        # XXX: timestamp is not tested
-        self.assertEquals(size, str(len(self.data)))
-
-        # Check the namelist
-        names = zipfp.namelist()
-        self.assertEquals(len(names), 3)
-        self.assertTrue(TESTFN in names)
-        self.assertTrue("another.name" in names)
-        self.assertTrue("strfile" in names)
-
-        # Check infolist
-        infos = zipfp.infolist()
-        names = [ i.filename for i in infos ]
-        self.assertEquals(len(names), 3)
-        self.assertTrue(TESTFN in names)
-        self.assertTrue("another.name" in names)
-        self.assertTrue("strfile" in names)
-        for i in infos:
-            self.assertEquals(i.file_size, len(self.data))
-
-        # check getinfo
-        for nm in (TESTFN, "another.name", "strfile"):
-            info = zipfp.getinfo(nm)
-            self.assertEquals(info.filename, nm)
-            self.assertEquals(info.file_size, len(self.data))
-
-        # Check that testzip doesn't raise an exception
-        zipfp.testzip()
-        zipfp.close()
+        with zipfile.ZipFile(f, "r", compression) as zipfp:
+            self.assertEqual(zipfp.read(TESTFN), self.data)
+            self.assertEqual(zipfp.read("another.name"), self.data)
+            self.assertEqual(zipfp.read("strfile"), self.data)
+
+            # Print the ZIP directory
+            fp = io.StringIO()
+            zipfp.printdir(file=fp)
+            directory = fp.getvalue()
+            lines = directory.splitlines()
+            self.assertEquals(len(lines), 4) # Number of files + header
+
+            self.assertTrue('File Name' in lines[0])
+            self.assertTrue('Modified' in lines[0])
+            self.assertTrue('Size' in lines[0])
+
+            fn, date, time, size = lines[1].split()
+            self.assertEquals(fn, 'another.name')
+            # XXX: timestamp is not tested
+            self.assertEquals(size, str(len(self.data)))
+
+            # Check the namelist
+            names = zipfp.namelist()
+            self.assertEquals(len(names), 3)
+            self.assertTrue(TESTFN in names)
+            self.assertTrue("another.name" in names)
+            self.assertTrue("strfile" in names)
+
+            # Check infolist
+            infos = zipfp.infolist()
+            names = [ i.filename for i in infos ]
+            self.assertEquals(len(names), 3)
+            self.assertTrue(TESTFN in names)
+            self.assertTrue("another.name" in names)
+            self.assertTrue("strfile" in names)
+            for i in infos:
+                self.assertEquals(i.file_size, len(self.data))
+
+            # check getinfo
+            for nm in (TESTFN, "another.name", "strfile"):
+                info = zipfp.getinfo(nm)
+                self.assertEquals(info.filename, nm)
+                self.assertEquals(info.file_size, len(self.data))
+
+            # Check that testzip doesn't raise an exception
+            zipfp.testzip()
 
     def test_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -108,26 +106,25 @@
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r", compression)
-        zipdata1 = []
-        zipopen1 = zipfp.open(TESTFN)
-        while 1:
-            read_data = zipopen1.read(256)
-            if not read_data:
-                break
-            zipdata1.append(read_data)
-
-        zipdata2 = []
-        zipopen2 = zipfp.open("another.name")
-        while 1:
-            read_data = zipopen2.read(256)
-            if not read_data:
-                break
-            zipdata2.append(read_data)
-
-        self.assertEqual(b''.join(zipdata1), self.data)
-        self.assertEqual(b''.join(zipdata2), self.data)
-        zipfp.close()
+        with zipfile.ZipFile(f, "r", compression) as zipfp:
+            zipdata1 = []
+            zipopen1 = zipfp.open(TESTFN)
+            while True:
+                read_data = zipopen1.read(256)
+                if not read_data:
+                    break
+                zipdata1.append(read_data)
+
+            zipdata2 = []
+            zipopen2 = zipfp.open("another.name")
+            while True:
+                read_data = zipopen2.read(256)
+                if not read_data:
+                    break
+                zipdata2.append(read_data)
+
+            self.assertEqual(b''.join(zipdata1), self.data)
+            self.assertEqual(b''.join(zipdata2), self.data)
 
     def test_open_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -135,38 +132,36 @@
 
     def test_open_via_zip_info(self):
         # Create the ZIP archive
-        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
-        zipfp.writestr("name", "foo")
-        zipfp.writestr("name", "bar")
-        zipfp.close()
-
-        zipfp = zipfile.ZipFile(TESTFN2, "r")
-        infos = zipfp.infolist()
-        data = b""
-        for info in infos:
-            data += zipfp.open(info).read()
-        self.assertTrue(data == b"foobar" or data == b"barfoo")
-        data = b""
-        for info in infos:
-            data += zipfp.read(info)
-        self.assertTrue(data == b"foobar" or data == b"barfoo")
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
+            zipfp.writestr("name", "foo")
+            zipfp.writestr("name", "bar")
+
+        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
+            infos = zipfp.infolist()
+            data = b""
+            for info in infos:
+                data += zipfp.open(info).read()
+            self.assertTrue(data == b"foobar" or data == b"barfoo")
+            data = b""
+            for info in infos:
+                data += zipfp.read(info)
+            self.assertTrue(data == b"foobar" or data == b"barfoo")
 
     def zip_random_open_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r", compression)
-        zipdata1 = []
-        zipopen1 = zipfp.open(TESTFN)
-        while 1:
-            read_data = zipopen1.read(randint(1, 1024))
-            if not read_data:
-                break
-            zipdata1.append(read_data)
+        with zipfile.ZipFile(f, "r", compression) as zipfp:
+            zipdata1 = []
+            zipopen1 = zipfp.open(TESTFN)
+            while True:
+                read_data = zipopen1.read(randint(1, 1024))
+                if not read_data:
+                    break
+                zipdata1.append(read_data)
+
+            self.assertEqual(b''.join(zipdata1), self.data)
 
-        self.assertEqual(b''.join(zipdata1), self.data)
-        zipfp.close()
 
     def test_random_open_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -176,34 +171,28 @@
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r")
-        zipopen = zipfp.open(TESTFN)
-        for line in self.line_gen:
-            linedata = zipopen.readline()
-            self.assertEqual(linedata, line + '\n')
-
-        zipfp.close()
+        with zipfile.ZipFile(f, "r") as zipfp:
+            zipopen = zipfp.open(TESTFN)
+            for line in self.line_gen:
+                linedata = zipopen.readline()
+                self.assertEqual(linedata, line + '\n')
 
     def zip_readlines_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r")
-        ziplines = zipfp.open(TESTFN).readlines()
-        for line, zipline in zip(self.line_gen, ziplines):
-            self.assertEqual(zipline, line + '\n')
-
-        zipfp.close()
+        with zipfile.ZipFile(f, "r") as zipfp:
+            ziplines = zipfp.open(TESTFN).readlines()
+            for line, zipline in zip(self.line_gen, ziplines):
+                self.assertEqual(zipline, line + '\n')
 
     def zip_iterlines_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r")
-        for line, zipline in zip(self.line_gen, zipfp.open(TESTFN)):
-            self.assertEqual(zipline, line + '\n')
-
-        zipfp.close()
+        with zipfile.ZipFile(f, "r") as zipfp:
+            for line, zipline in zip(self.line_gen, zipfp.open(TESTFN)):
+                self.assertEqual(zipline, line + '\n')
 
     def test_readline_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -252,34 +241,30 @@
     def test_low_compression(self):
         # Checks for cases where compressed data is larger than original
         # Create the ZIP archive
-        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED)
-        zipfp.writestr("strfile", '12')
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp:
+            zipfp.writestr("strfile", '12')
 
         # Get an open object for strfile
-        zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED)
-        openobj = zipfp.open("strfile")
-        self.assertEqual(openobj.read(1), b'1')
-        self.assertEqual(openobj.read(1), b'2')
+        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp:
+            openobj = zipfp.open("strfile")
+            self.assertEqual(openobj.read(1), b'1')
+            self.assertEqual(openobj.read(1), b'2')
 
     def test_absolute_arcnames(self):
-        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
-        zipfp.write(TESTFN, "/absolute")
-        zipfp.close()
-
-        zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED)
-        self.assertEqual(zipfp.namelist(), ["absolute"])
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
+            zipfp.write(TESTFN, "/absolute")
+
+        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
+            self.assertEqual(zipfp.namelist(), ["absolute"])
 
     def test_append_to_zip_file(self):
         # Test appending to an existing zipfile
-        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
-        zipfp.write(TESTFN, TESTFN)
-        zipfp.close()
-        zipfp = zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED)
-        zipfp.writestr("strfile", self.data)
-        self.assertEqual(zipfp.namelist(), [TESTFN, "strfile"])
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
+            zipfp.write(TESTFN, TESTFN)
+
+        with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
+            zipfp.writestr("strfile", self.data)
+            self.assertEqual(zipfp.namelist(), [TESTFN, "strfile"])
 
     def test_append_to_non_zip_file(self):
         # Test appending to an existing file that is not a zipfile
@@ -289,94 +274,82 @@
         f = open(TESTFN2, 'wb')
         f.write(d)
         f.close()
-        zipfp = zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED)
-        zipfp.write(TESTFN, TESTFN)
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
+            zipfp.write(TESTFN, TESTFN)
 
         f = open(TESTFN2, 'rb')
         f.seek(len(d))
-        zipfp = zipfile.ZipFile(f, "r")
-        self.assertEqual(zipfp.namelist(), [TESTFN])
-        zipfp.close()
-        f.close()
+        with zipfile.ZipFile(f, "r") as zipfp:
+            self.assertEqual(zipfp.namelist(), [TESTFN])
 
     def test_write_default_name(self):
         # Check that calling ZipFile.write without arcname specified produces the expected result
-        zipfp = zipfile.ZipFile(TESTFN2, "w")
-        zipfp.write(TESTFN)
-        self.assertEqual(zipfp.read(TESTFN), open(TESTFN, "rb").read())
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
+            zipfp.write(TESTFN)
+            self.assertEqual(zipfp.read(TESTFN), open(TESTFN, "rb").read())
 
     @skipUnless(zlib, "requires zlib")
     def test_per_file_compression(self):
         # Check that files within a Zip archive can have different compression options
-        zipfp = zipfile.ZipFile(TESTFN2, "w")
-        zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
-        zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
-        sinfo = zipfp.getinfo('storeme')
-        dinfo = zipfp.getinfo('deflateme')
-        self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
-        self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
+            zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
+            zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
+            sinfo = zipfp.getinfo('storeme')
+            dinfo = zipfp.getinfo('deflateme')
+            self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
+            self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
 
     def test_write_to_readonly(self):
         # Check that trying to call write() on a readonly ZipFile object
         # raises a RuntimeError
-        zipf = zipfile.ZipFile(TESTFN2, mode="w")
-        zipf.writestr("somefile.txt", "bogus")
-        zipf.close()
-        zipf = zipfile.ZipFile(TESTFN2, mode="r")
-        self.assertRaises(RuntimeError, zipf.write, TESTFN)
-        zipf.close()
+        with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
+            zipfp.writestr("somefile.txt", "bogus")
 
-    def test_extract(self):
-        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
-        for fpath, fdata in SMALL_TEST_DATA:
-            zipfp.writestr(fpath, fdata)
-        zipfp.close()
-
-        zipfp = zipfile.ZipFile(TESTFN2, "r")
-        for fpath, fdata in SMALL_TEST_DATA:
-            writtenfile = zipfp.extract(fpath)
-
-            # make sure it was written to the right place
-            if os.path.isabs(fpath):
-                correctfile = os.path.join(os.getcwd(), fpath[1:])
-            else:
-                correctfile = os.path.join(os.getcwd(), fpath)
-            correctfile = os.path.normpath(correctfile)
+        with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
+            self.assertRaises(RuntimeError, zipfp.write, TESTFN)
 
-            self.assertEqual(writtenfile, correctfile)
+    def test_extract(self):
+        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
+            for fpath, fdata in SMALL_TEST_DATA:
+                zipfp.writestr(fpath, fdata)
+
+        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
+            for fpath, fdata in SMALL_TEST_DATA:
+                writtenfile = zipfp.extract(fpath)
+
+                # make sure it was written to the right place
+                if os.path.isabs(fpath):
+                    correctfile = os.path.join(os.getcwd(), fpath[1:])
+                else:
+                    correctfile = os.path.join(os.getcwd(), fpath)
+                correctfile = os.path.normpath(correctfile)
 
-            # make sure correct data is in correct file
-            self.assertEqual(fdata.encode(), open(writtenfile, "rb").read())
+                self.assertEqual(writtenfile, correctfile)
 
-            os.remove(writtenfile)
+                # make sure correct data is in correct file
+                self.assertEqual(fdata.encode(), open(writtenfile, "rb").read())
 
-        zipfp.close()
+                os.remove(writtenfile)
 
         # remove the test file subdirectories
         shutil.rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
 
     def test_extract_all(self):
-        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
-        for fpath, fdata in SMALL_TEST_DATA:
-            zipfp.writestr(fpath, fdata)
-        zipfp.close()
-
-        zipfp = zipfile.ZipFile(TESTFN2, "r")
-        zipfp.extractall()
-        for fpath, fdata in SMALL_TEST_DATA:
-            if os.path.isabs(fpath):
-                outfile = os.path.join(os.getcwd(), fpath[1:])
-            else:
-                outfile = os.path.join(os.getcwd(), fpath)
-
-            self.assertEqual(fdata.encode(), open(outfile, "rb").read())
+        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
+            for fpath, fdata in SMALL_TEST_DATA:
+                zipfp.writestr(fpath, fdata)
+
+        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
+            zipfp.extractall()
+            for fpath, fdata in SMALL_TEST_DATA:
+                if os.path.isabs(fpath):
+                    outfile = os.path.join(os.getcwd(), fpath[1:])
+                else:
+                    outfile = os.path.join(os.getcwd(), fpath)
 
-            os.remove(outfile)
+                self.assertEqual(fdata.encode(), open(outfile, "rb").read())
 
-        zipfp.close()
+                os.remove(outfile)
 
         # remove the test file subdirectories
         shutil.rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
@@ -386,21 +359,45 @@
         # when it is passed a name rather than a ZipInfo instance.
 
         self.make_test_archive(f, compression)
-        zipfp = zipfile.ZipFile(f, "r")
-        zinfo = zipfp.getinfo('strfile')
-        self.assertEqual(zinfo.external_attr, 0o600 << 16)
+        with zipfile.ZipFile(f, "r") as zipfp:
+            zinfo = zipfp.getinfo('strfile')
+            self.assertEqual(zinfo.external_attr, 0o600 << 16)
 
     def test_writestr_permissions(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED)
 
     def test_writestr_extended_local_header_issue1202(self):
-        orig_zip = zipfile.ZipFile(TESTFN2, 'w')
-        for data in 'abcdefghijklmnop':
-            zinfo = zipfile.ZipInfo(data)
-            zinfo.flag_bits |= 0x08  # Include an extended local header.
-            orig_zip.writestr(zinfo, data)
-        orig_zip.close()
+        with zipfile.ZipFile(TESTFN2, 'w') as orig_zip:
+            for data in 'abcdefghijklmnop':
+                zinfo = zipfile.ZipInfo(data)
+                zinfo.flag_bits |= 0x08  # Include an extended local header.
+                orig_zip.writestr(zinfo, data)
+
+    def test_close(self):
+        """Check that the zipfile is closed after the 'with' block."""
+        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
+            for fpath, fdata in SMALL_TEST_DATA:
+                zipfp.writestr(fpath, fdata)
+                self.assertTrue(zipfp.fp is not None, 'zipfp is not open')
+        self.assertTrue(zipfp.fp is None, 'zipfp is not closed')
+
+        with zipfile.ZipFile(TESTFN2, "r") as zipfp:
+            self.assertTrue(zipfp.fp is not None, 'zipfp is not open')
+        self.assertTrue(zipfp.fp is None, 'zipfp is not closed')
+
+    def test_close_on_exception(self):
+        """Check that the zipfile is closed if an exception is raised in the
+        'with' block."""
+        with zipfile.ZipFile(TESTFN2, "w") as zipfp:
+            for fpath, fdata in SMALL_TEST_DATA:
+                zipfp.writestr(fpath, fdata)
+
+        try:
+            with zipfile.ZipFile(TESTFN2, "r") as zipfp2:
+                raise zipfile.BadZipfile()
+        except zipfile.BadZipfile:
+            self.assertTrue(zipfp2.fp is None, 'zipfp is not closed')
 
     def tearDown(self):
         unlink(TESTFN)
@@ -425,16 +422,14 @@
         fp.close()
 
     def large_file_exception_test(self, f, compression):
-        zipfp = zipfile.ZipFile(f, "w", compression)
-        self.assertRaises(zipfile.LargeZipFile,
-                zipfp.write, TESTFN, "another.name")
-        zipfp.close()
+        with zipfile.ZipFile(f, "w", compression) as zipfp:
+            self.assertRaises(zipfile.LargeZipFile,
+                    zipfp.write, TESTFN, "another.name")
 
     def large_file_exception_test2(self, f, compression):
-        zipfp = zipfile.ZipFile(f, "w", compression)
-        self.assertRaises(zipfile.LargeZipFile,
-                zipfp.writestr, "another.name", self.data)
-        zipfp.close()
+        with zipfile.ZipFile(f, "w", compression) as zipfp:
+            self.assertRaises(zipfile.LargeZipFile,
+                    zipfp.writestr, "another.name", self.data)
 
     def test_large_file_exception(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -443,62 +438,59 @@
 
     def zip_test(self, f, compression):
         # Create the ZIP archive
-        zipfp = zipfile.ZipFile(f, "w", compression, allowZip64=True)
-        zipfp.write(TESTFN, "another.name")
-        zipfp.write(TESTFN, TESTFN)
-        zipfp.writestr("strfile", self.data)
-        zipfp.close()
+        with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
+            zipfp.write(TESTFN, "another.name")
+            zipfp.write(TESTFN, TESTFN)
+            zipfp.writestr("strfile", self.data)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r", compression)
-        self.assertEqual(zipfp.read(TESTFN), self.data)
-        self.assertEqual(zipfp.read("another.name"), self.data)
-        self.assertEqual(zipfp.read("strfile"), self.data)
-
-        # Print the ZIP directory
-        fp = io.StringIO()
-        zipfp.printdir(fp)
-
-        directory = fp.getvalue()
-        lines = directory.splitlines()
-        self.assertEquals(len(lines), 4) # Number of files + header
-
-        self.assertTrue('File Name' in lines[0])
-        self.assertTrue('Modified' in lines[0])
-        self.assertTrue('Size' in lines[0])
-
-        fn, date, time, size = lines[1].split()
-        self.assertEquals(fn, 'another.name')
-        # XXX: timestamp is not tested
-        self.assertEquals(size, str(len(self.data)))
-
-        # Check the namelist
-        names = zipfp.namelist()
-        self.assertEquals(len(names), 3)
-        self.assertTrue(TESTFN in names)
-        self.assertTrue("another.name" in names)
-        self.assertTrue("strfile" in names)
-
-        # Check infolist
-        infos = zipfp.infolist()
-        names = [ i.filename for i in infos ]
-        self.assertEquals(len(names), 3)
-        self.assertTrue(TESTFN in names)
-        self.assertTrue("another.name" in names)
-        self.assertTrue("strfile" in names)
-        for i in infos:
-            self.assertEquals(i.file_size, len(self.data))
-
-        # check getinfo
-        for nm in (TESTFN, "another.name", "strfile"):
-            info = zipfp.getinfo(nm)
-            self.assertEquals(info.filename, nm)
-            self.assertEquals(info.file_size, len(self.data))
+        with zipfile.ZipFile(f, "r", compression) as zipfp:
+            self.assertEqual(zipfp.read(TESTFN), self.data)
+            self.assertEqual(zipfp.read("another.name"), self.data)
+            self.assertEqual(zipfp.read("strfile"), self.data)
+
+            # Print the ZIP directory
+            fp = io.StringIO()
+            zipfp.printdir(fp)
+
+            directory = fp.getvalue()
+            lines = directory.splitlines()
+            self.assertEquals(len(lines), 4) # Number of files + header
+
+            self.assertTrue('File Name' in lines[0])
+            self.assertTrue('Modified' in lines[0])
+            self.assertTrue('Size' in lines[0])
+
+            fn, date, time, size = lines[1].split()
+            self.assertEquals(fn, 'another.name')
+            # XXX: timestamp is not tested
+            self.assertEquals(size, str(len(self.data)))
 
-        # Check that testzip doesn't raise an exception
-        zipfp.testzip()
+            # Check the namelist
+            names = zipfp.namelist()
+            self.assertEquals(len(names), 3)
+            self.assertTrue(TESTFN in names)
+            self.assertTrue("another.name" in names)
+            self.assertTrue("strfile" in names)
+
+            # Check infolist
+            infos = zipfp.infolist()
+            names = [ i.filename for i in infos ]
+            self.assertEquals(len(names), 3)
+            self.assertTrue(TESTFN in names)
+            self.assertTrue("another.name" in names)
+            self.assertTrue("strfile" in names)
+            for i in infos:
+                self.assertEquals(i.file_size, len(self.data))
+
+            # check getinfo
+            for nm in (TESTFN, "another.name", "strfile"):
+                info = zipfp.getinfo(nm)
+                self.assertEquals(info.filename, nm)
+                self.assertEquals(info.file_size, len(self.data))
 
-        zipfp.close()
+            # Check that testzip doesn't raise an exception
+            zipfp.testzip()
 
     def test_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -510,13 +502,12 @@
             self.zip_test(f, zipfile.ZIP_DEFLATED)
 
     def test_absolute_arcnames(self):
-        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, allowZip64=True)
-        zipfp.write(TESTFN, "/absolute")
-        zipfp.close()
-
-        zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED)
-        self.assertEqual(zipfp.namelist(), ["absolute"])
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
+                             allowZip64=True) as zipfp:
+            zipfp.write(TESTFN, "/absolute")
+
+        with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
+            self.assertEqual(zipfp.namelist(), ["absolute"])
 
     def tearDown(self):
         zipfile.ZIP64_LIMIT = self._limit
@@ -526,41 +517,43 @@
 
 class PyZipFileTests(unittest.TestCase):
     def test_write_pyfile(self):
-        zipfp  = zipfile.PyZipFile(TemporaryFile(), "w")
-        fn = __file__
-        if fn.endswith('.pyc') or fn.endswith('.pyo'):
-            fn = fn[:-1]
-
-        zipfp.writepy(fn)
-
-        bn = os.path.basename(fn)
-        self.assertTrue(bn not in zipfp.namelist())
-        self.assertTrue(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist())
-        zipfp.close()
-
-        zipfp  = zipfile.PyZipFile(TemporaryFile(), "w")
-        fn = __file__
-        if fn.endswith('.pyc') or fn.endswith('.pyo'):
-            fn = fn[:-1]
-
-        zipfp.writepy(fn, "testpackage")
-
-        bn = "%s/%s"%("testpackage", os.path.basename(fn))
-        self.assertTrue(bn not in zipfp.namelist())
-        self.assertTrue(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist())
-        zipfp.close()
+        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
+            fn = __file__
+            if fn.endswith('.pyc') or fn.endswith('.pyo'):
+                fn = fn[:-1]
+
+            zipfp.writepy(fn)
+
+            bn = os.path.basename(fn)
+            self.assertTrue(bn not in zipfp.namelist())
+            self.assertTrue(bn + 'o' in zipfp.namelist() or
+                            bn + 'c' in zipfp.namelist())
+
+        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
+            fn = __file__
+            if fn.endswith('.pyc') or fn.endswith('.pyo'):
+                fn = fn[:-1]
+
+            zipfp.writepy(fn, "testpackage")
+
+            bn = "%s/%s"%("testpackage", os.path.basename(fn))
+            self.assertTrue(bn not in zipfp.namelist())
+            self.assertTrue(bn + 'o' in zipfp.namelist() or
+                            bn + 'c' in zipfp.namelist())
 
     def test_write_python_package(self):
         import email
         packagedir = os.path.dirname(email.__file__)
 
-        zipfp  = zipfile.PyZipFile(TemporaryFile(), "w")
-        zipfp.writepy(packagedir)
+        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
+            zipfp.writepy(packagedir)
 
-        # Check for a couple of modules at different levels of the hieararchy
-        names = zipfp.namelist()
-        self.assertTrue('email/__init__.pyo' in names or 'email/__init__.pyc' in names)
-        self.assertTrue('email/mime/text.pyo' in names or 'email/mime/text.pyc' in names)
+            # Check for a couple of modules at different levels of the hieararchy
+            names = zipfp.namelist()
+            self.assertTrue('email/__init__.pyo' in names or
+                            'email/__init__.pyc' in names)
+            self.assertTrue('email/mime/text.pyo' in names or
+                            'email/mime/text.pyc' in names)
 
     def test_write_python_directory(self):
         os.mkdir(TESTFN2)
@@ -589,22 +582,22 @@
             shutil.rmtree(TESTFN2)
 
     def test_write_non_pyfile(self):
-        zipfp  = zipfile.PyZipFile(TemporaryFile(), "w")
-        open(TESTFN, 'w').write('most definitely not a python file')
-        self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
-        os.remove(TESTFN)
+        with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
+            open(TESTFN, 'w').write('most definitely not a python file')
+            self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
+            os.remove(TESTFN)
+
 
 
 class OtherTests(unittest.TestCase):
     def test_unicode_filenames(self):
-        zf = zipfile.ZipFile(TESTFN, "w")
-        zf.writestr("foo.txt", "Test for unicode filename")
-        zf.writestr("\xf6.txt", "Test for unicode filename")
-        zf.close()
-        zf = zipfile.ZipFile(TESTFN, "r")
-        self.assertEqual(zf.filelist[0].filename, "foo.txt")
-        self.assertEqual(zf.filelist[1].filename, "\xf6.txt")
-        zf.close()
+        with zipfile.ZipFile(TESTFN, "w") as zf:
+            zf.writestr("foo.txt", "Test for unicode filename")
+            zf.writestr("\xf6.txt", "Test for unicode filename")
+
+        with zipfile.ZipFile(TESTFN, "r") as zf:
+            self.assertEqual(zf.filelist[0].filename, "foo.txt")
+            self.assertEqual(zf.filelist[1].filename, "\xf6.txt")
 
     def test_create_non_existent_file_for_append(self):
         if os.path.exists(TESTFN):
@@ -614,17 +607,15 @@
         content = b'hello, world. this is some content.'
 
         try:
-            zf = zipfile.ZipFile(TESTFN, 'a')
-            zf.writestr(filename, content)
-            zf.close()
+            with zipfile.ZipFile(TESTFN, 'a') as zf:
+                zf.writestr(filename, content)
         except IOError:
             self.fail('Could not append data to a non-existent zip file.')
 
         self.assertTrue(os.path.exists(TESTFN))
 
-        zf = zipfile.ZipFile(TESTFN, 'r')
-        self.assertEqual(zf.read(filename), content)
-        zf.close()
+        with zipfile.ZipFile(TESTFN, 'r') as zf:
+            self.assertEqual(zf.read(filename), content)
 
     def test_close_erroneous_file(self):
         # This test checks that the ZipFile constructor closes the file object
@@ -668,9 +659,9 @@
         # a file that is a zip file
 
         # - passing a filename
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
-        zipf.close()
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
+
         chk = zipfile.is_zipfile(TESTFN)
         self.assertTrue(chk)
         # - passing a file object
@@ -715,9 +706,8 @@
     def test_closed_zip_raises_RuntimeError(self):
         # Verify that testzip() doesn't swallow inappropriate exceptions.
         data = io.BytesIO()
-        zipf = zipfile.ZipFile(data, mode="w")
-        zipf.writestr("foo.txt", "O, for a Muse of Fire!")
-        zipf.close()
+        with zipfile.ZipFile(data, mode="w") as zipf:
+            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
 
         # This is correct; calling .read on a closed ZipFile should throw
         # a RuntimeError, and so should calling .testzip.  An earlier
@@ -736,33 +726,31 @@
 
     def test_bad_open_mode(self):
         # Check that bad modes passed to ZipFile.open are caught
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        zipf.writestr("foo.txt", "O, for a Muse of Fire!")
-        zipf.close()
-        zipf = zipfile.ZipFile(TESTFN, mode="r")
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+
+        with zipfile.ZipFile(TESTFN, mode="r") as zipf:
         # read the data to make sure the file is there
-        zipf.read("foo.txt")
-        self.assertRaises(RuntimeError, zipf.open, "foo.txt", "q")
-        zipf.close()
+            zipf.read("foo.txt")
+            self.assertRaises(RuntimeError, zipf.open, "foo.txt", "q")
 
     def test_read0(self):
         # Check that calling read(0) on a ZipExtFile object returns an empty
         # string and doesn't advance file pointer
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        zipf.writestr("foo.txt", "O, for a Muse of Fire!")
-        # read the data to make sure the file is there
-        f = zipf.open("foo.txt")
-        for i in range(FIXEDTEST_SIZE):
-            self.assertEqual(f.read(0), b'')
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+            # read the data to make sure the file is there
+            f = zipf.open("foo.txt")
+            for i in range(FIXEDTEST_SIZE):
+                self.assertEqual(f.read(0), b'')
 
-        self.assertEqual(f.read(), b"O, for a Muse of Fire!")
-        zipf.close()
+            self.assertEqual(f.read(), b"O, for a Muse of Fire!")
 
     def test_open_non_existent_item(self):
         # Check that attempting to call open() for an item that doesn't
         # exist in the archive raises a RuntimeError
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
 
     def test_bad_compression_mode(self):
         # Check that bad compression methods passed to ZipFile.open are caught
@@ -770,9 +758,9 @@
 
     def test_null_byte_in_filename(self):
         # Check that a filename containing a null byte is properly terminated
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        zipf.writestr("foo.txt\x00qqq", b"O, for a Muse of Fire!")
-        self.assertEqual(zipf.namelist(), ['foo.txt'])
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            zipf.writestr("foo.txt\x00qqq", b"O, for a Muse of Fire!")
+            self.assertEqual(zipf.namelist(), ['foo.txt'])
 
     def test_struct_sizes(self):
         # check that ZIP internal structure sizes are calculated correctly
@@ -785,43 +773,37 @@
         # This test checks that comments on the archive are handled properly
 
         # check default comment is empty
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        self.assertEqual(zipf.comment, b'')
-        zipf.writestr("foo.txt", "O, for a Muse of Fire!")
-        zipf.close()
-        zipfr = zipfile.ZipFile(TESTFN, mode="r")
-        self.assertEqual(zipfr.comment, b'')
-        zipfr.close()
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            self.assertEqual(zipf.comment, b'')
+            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+
+        with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
+            self.assertEqual(zipfr.comment, b'')
 
         # check a simple short comment
         comment = b'Bravely taking to his feet, he beat a very brave retreat.'
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        zipf.comment = comment
-        zipf.writestr("foo.txt", "O, for a Muse of Fire!")
-        zipf.close()
-        zipfr = zipfile.ZipFile(TESTFN, mode="r")
-        self.assertEqual(zipfr.comment, comment)
-        zipfr.close()
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            zipf.comment = comment
+            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+        with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
+            self.assertEqual(zipf.comment, comment)
 
         # check a comment of max length
         comment2 = ''.join(['%d' % (i**3 % 10) for i in range((1 << 16)-1)])
         comment2 = comment2.encode("ascii")
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        zipf.comment = comment2
-        zipf.writestr("foo.txt", "O, for a Muse of Fire!")
-        zipf.close()
-        zipfr = zipfile.ZipFile(TESTFN, mode="r")
-        self.assertEqual(zipfr.comment, comment2)
-        zipfr.close()
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            zipf.comment = comment2
+            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+
+        with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
+            self.assertEqual(zipfr.comment, comment2)
 
         # check a comment that is too long is truncated
-        zipf = zipfile.ZipFile(TESTFN, mode="w")
-        zipf.comment = comment2 + b'oops'
-        zipf.writestr("foo.txt", "O, for a Muse of Fire!")
-        zipf.close()
-        zipfr = zipfile.ZipFile(TESTFN, mode="r")
-        self.assertEqual(zipfr.comment, comment2)
-        zipfr.close()
+        with zipfile.ZipFile(TESTFN, mode="w") as zipf:
+            zipf.comment = comment2 + b'oops'
+            zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+        with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
+            self.assertEqual(zipfr.comment, comment2)
 
     def tearDown(self):
         unlink(TESTFN)
@@ -907,21 +889,19 @@
 
     def make_test_archive(self, f, compression):
         # Create the ZIP archive
-        zipfp = zipfile.ZipFile(f, "w", compression)
-        zipfp.write(TESTFN, "another.name")
-        zipfp.write(TESTFN, TESTFN)
-        zipfp.close()
+        with zipfile.ZipFile(f, "w", compression) as zipfp:
+            zipfp.write(TESTFN, "another.name")
+            zipfp.write(TESTFN, TESTFN)
 
     def zip_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r", compression)
-        testdata = zipfp.read(TESTFN)
-        self.assertEqual(len(testdata), len(self.data))
-        self.assertEqual(testdata, self.data)
-        self.assertEqual(zipfp.read("another.name"), self.data)
-        zipfp.close()
+        with zipfile.ZipFile(f, "r", compression) as zipfp:
+            testdata = zipfp.read(TESTFN)
+            self.assertEqual(len(testdata), len(self.data))
+            self.assertEqual(testdata, self.data)
+            self.assertEqual(zipfp.read("another.name"), self.data)
 
     def test_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -931,31 +911,30 @@
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r", compression)
-        zipdata1 = []
-        zipopen1 = zipfp.open(TESTFN)
-        while 1:
-            read_data = zipopen1.read(256)
-            if not read_data:
-                break
-            zipdata1.append(read_data)
-
-        zipdata2 = []
-        zipopen2 = zipfp.open("another.name")
-        while 1:
-            read_data = zipopen2.read(256)
-            if not read_data:
-                break
-            zipdata2.append(read_data)
-
-        testdata1 = b''.join(zipdata1)
-        self.assertEqual(len(testdata1), len(self.data))
-        self.assertEqual(testdata1, self.data)
-
-        testdata2 = b''.join(zipdata2)
-        self.assertEqual(len(testdata1), len(self.data))
-        self.assertEqual(testdata1, self.data)
-        zipfp.close()
+        with zipfile.ZipFile(f, "r", compression) as zipfp:
+            zipdata1 = []
+            zipopen1 = zipfp.open(TESTFN)
+            while True:
+                read_data = zipopen1.read(256)
+                if not read_data:
+                    break
+                zipdata1.append(read_data)
+
+            zipdata2 = []
+            zipopen2 = zipfp.open("another.name")
+            while True:
+                read_data = zipopen2.read(256)
+                if not read_data:
+                    break
+                zipdata2.append(read_data)
+
+            testdata1 = b''.join(zipdata1)
+            self.assertEqual(len(testdata1), len(self.data))
+            self.assertEqual(testdata1, self.data)
+
+            testdata2 = b''.join(zipdata2)
+            self.assertEqual(len(testdata1), len(self.data))
+            self.assertEqual(testdata1, self.data)
 
     def test_open_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -965,19 +944,18 @@
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r", compression)
-        zipdata1 = []
-        zipopen1 = zipfp.open(TESTFN)
-        while 1:
-            read_data = zipopen1.read(randint(1, 1024))
-            if not read_data:
-                break
-            zipdata1.append(read_data)
-
-        testdata = b''.join(zipdata1)
-        self.assertEqual(len(testdata), len(self.data))
-        self.assertEqual(testdata, self.data)
-        zipfp.close()
+        with zipfile.ZipFile(f, "r", compression) as zipfp:
+            zipdata1 = []
+            zipopen1 = zipfp.open(TESTFN)
+            while True:
+                read_data = zipopen1.read(randint(1, 1024))
+                if not read_data:
+                    break
+                zipdata1.append(read_data)
+
+            testdata = b''.join(zipdata1)
+            self.assertEqual(len(testdata), len(self.data))
+            self.assertEqual(testdata, self.data)
 
     def test_random_open_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
@@ -988,51 +966,47 @@
 class TestsWithMultipleOpens(unittest.TestCase):
     def setUp(self):
         # Create the ZIP archive
-        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED)
-        zipfp.writestr('ones', '1'*FIXEDTEST_SIZE)
-        zipfp.writestr('twos', '2'*FIXEDTEST_SIZE)
-        zipfp.close()
+        with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp:
+            zipfp.writestr('ones', '1'*FIXEDTEST_SIZE)
+            zipfp.writestr('twos', '2'*FIXEDTEST_SIZE)
 
     def test_same_file(self):
         # Verify that (when the ZipFile is in control of creating file objects)
         # multiple open() calls can be made without interfering with each other.
-        zipf = zipfile.ZipFile(TESTFN2, mode="r")
-        zopen1 = zipf.open('ones')
-        zopen2 = zipf.open('ones')
-        data1 = zopen1.read(500)
-        data2 = zopen2.read(500)
-        data1 += zopen1.read(500)
-        data2 += zopen2.read(500)
-        self.assertEqual(data1, data2)
-        zipf.close()
+        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
+            zopen1 = zipf.open('ones')
+            zopen2 = zipf.open('ones')
+            data1 = zopen1.read(500)
+            data2 = zopen2.read(500)
+            data1 += zopen1.read(500)
+            data2 += zopen2.read(500)
+            self.assertEqual(data1, data2)
 
     def test_different_file(self):
         # Verify that (when the ZipFile is in control of creating file objects)
         # multiple open() calls can be made without interfering with each other.
-        zipf = zipfile.ZipFile(TESTFN2, mode="r")
-        zopen1 = zipf.open('ones')
-        zopen2 = zipf.open('twos')
-        data1 = zopen1.read(500)
-        data2 = zopen2.read(500)
-        data1 += zopen1.read(500)
-        data2 += zopen2.read(500)
-        self.assertEqual(data1, b'1'*FIXEDTEST_SIZE)
-        self.assertEqual(data2, b'2'*FIXEDTEST_SIZE)
-        zipf.close()
+        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
+            zopen1 = zipf.open('ones')
+            zopen2 = zipf.open('twos')
+            data1 = zopen1.read(500)
+            data2 = zopen2.read(500)
+            data1 += zopen1.read(500)
+            data2 += zopen2.read(500)
+            self.assertEqual(data1, b'1'*FIXEDTEST_SIZE)
+            self.assertEqual(data2, b'2'*FIXEDTEST_SIZE)
 
     def test_interleaved(self):
         # Verify that (when the ZipFile is in control of creating file objects)
         # multiple open() calls can be made without interfering with each other.
-        zipf = zipfile.ZipFile(TESTFN2, mode="r")
-        zopen1 = zipf.open('ones')
-        data1 = zopen1.read(500)
-        zopen2 = zipf.open('twos')
-        data2 = zopen2.read(500)
-        data1 += zopen1.read(500)
-        data2 += zopen2.read(500)
-        self.assertEqual(data1, b'1'*FIXEDTEST_SIZE)
-        self.assertEqual(data2, b'2'*FIXEDTEST_SIZE)
-        zipf.close()
+        with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
+            zopen1 = zipf.open('ones')
+            data1 = zopen1.read(500)
+            zopen2 = zipf.open('twos')
+            data2 = zopen2.read(500)
+            data1 += zopen1.read(500)
+            data2 += zopen2.read(500)
+            self.assertEqual(data1, b'1'*FIXEDTEST_SIZE)
+            self.assertEqual(data2, b'2'*FIXEDTEST_SIZE)
 
     def tearDown(self):
         unlink(TESTFN2)
@@ -1043,8 +1017,8 @@
         os.mkdir(TESTFN2)
 
     def test_extract_dir(self):
-        zipf = zipfile.ZipFile(findfile("zipdir.zip"))
-        zipf.extractall(TESTFN2)
+        with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
+            zipf.extractall(TESTFN2)
         self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
         self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
         self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
@@ -1084,57 +1058,48 @@
 
     def make_test_archive(self, f, compression):
         # Create the ZIP archive
-        zipfp = zipfile.ZipFile(f, "w", compression)
-        for fn in self.arcfiles.values():
-            zipfp.write(fn, fn)
-        zipfp.close()
+        with zipfile.ZipFile(f, "w", compression) as zipfp:
+            for fn in self.arcfiles.values():
+                zipfp.write(fn, fn)
 
     def read_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r")
-        for sep, fn in self.arcfiles.items():
-            zipdata = zipfp.open(fn, "rU").read()
-            self.assertEqual(self.arcdata[sep], zipdata)
-
-        zipfp.close()
+        with zipfile.ZipFile(f, "r") as zipfp:
+            for sep, fn in self.arcfiles.items():
+                zipdata = zipfp.open(fn, "rU").read()
+                self.assertEqual(self.arcdata[sep], zipdata)
 
     def readline_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r")
-        for sep, fn in self.arcfiles.items():
-            zipopen = zipfp.open(fn, "rU")
-            for line in self.line_gen:
-                linedata = zipopen.readline()
-                self.assertEqual(linedata, line + b'\n')
-
-        zipfp.close()
+        with zipfile.ZipFile(f, "r") as zipfp:
+            for sep, fn in self.arcfiles.items():
+                zipopen = zipfp.open(fn, "rU")
+                for line in self.line_gen:
+                    linedata = zipopen.readline()
+                    self.assertEqual(linedata, line + b'\n')
 
     def readlines_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r")
-        for sep, fn in self.arcfiles.items():
-            ziplines = zipfp.open(fn, "rU").readlines()
-            for line, zipline in zip(self.line_gen, ziplines):
-                self.assertEqual(zipline, line + b'\n')
-
-        zipfp.close()
+        with zipfile.ZipFile(f, "r") as zipfp:
+            for sep, fn in self.arcfiles.items():
+                ziplines = zipfp.open(fn, "rU").readlines()
+                for line, zipline in zip(self.line_gen, ziplines):
+                    self.assertEqual(zipline, line + b'\n')
 
     def iterlines_test(self, f, compression):
         self.make_test_archive(f, compression)
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r")
-        for sep, fn in self.arcfiles.items():
-            for line, zipline in zip(self.line_gen, zipfp.open(fn, "rU")):
-                self.assertEqual(zipline, line + b'\n')
-
-        zipfp.close()
+        with zipfile.ZipFile(f, "r") as zipfp:
+            for sep, fn in self.arcfiles.items():
+                for line, zipline in zip(self.line_gen, zipfp.open(fn, "rU")):
+                    self.assertEqual(zipline, line + b'\n')
 
     def test_read_stored(self):
         for f in (TESTFN2, TemporaryFile(), io.BytesIO()):

Modified: python/branches/py3k/Lib/zipfile.py
==============================================================================
--- python/branches/py3k/Lib/zipfile.py	(original)
+++ python/branches/py3k/Lib/zipfile.py	Wed Dec 30 13:34:59 2009
@@ -719,6 +719,12 @@
                 self.fp = None
             raise RuntimeError('Mode must be "r", "w" or "a"')
 
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        self.close()
+
     def _GetContents(self):
         """Read the directory, making sure we close the file if the format
         is bad."""

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Wed Dec 30 13:34:59 2009
@@ -171,6 +171,9 @@
 Library
 -------
 
+- Issue #5511: now zipfile.ZipFile can be used as a context manager.
+  Initial patch by Brian Curtin.
+
 - Issue #7556: Make sure Distutils' msvc9compile reads and writes the
   MSVC XML Manifest file in text mode so string patterns can be used 
   in regular expressions.


More information about the Python-checkins mailing list