mirror of
https://github.com/python/cpython.git
synced 2025-11-03 03:22:27 +00:00
#5511: Added the ability to use ZipFile as a context manager. Patch by Brian Curtin.
This commit is contained in:
parent
eb74da8e67
commit
569e61f351
4 changed files with 465 additions and 486 deletions
|
|
@ -105,28 +105,35 @@ ZipFile Objects
|
|||
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`).
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
If the file does not exist, it is created if the mode is 'a'.
|
||||
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:: 2.7
|
||||
Added the ability to use :class:`ZipFile` as a context manager.
|
||||
|
||||
|
||||
.. method:: ZipFile.close()
|
||||
|
|
|
|||
|
|
@ -41,17 +41,16 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
|
||||
def make_test_archive(self, f, compression):
|
||||
# Create the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "w", compression)
|
||||
with zipfile.ZipFile(f, "w", compression) as zipfp:
|
||||
zipfp.write(TESTFN, "another"+os.extsep+"name")
|
||||
zipfp.write(TESTFN, TESTFN)
|
||||
zipfp.writestr("strfile", self.data)
|
||||
zipfp.close()
|
||||
|
||||
def zip_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r", compression)
|
||||
with zipfile.ZipFile(f, "r", compression) as zipfp:
|
||||
self.assertEqual(zipfp.read(TESTFN), self.data)
|
||||
self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
|
||||
self.assertEqual(zipfp.read("strfile"), self.data)
|
||||
|
|
@ -103,7 +102,6 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
|
||||
# Check that testzip doesn't raise an exception
|
||||
zipfp.testzip()
|
||||
zipfp.close()
|
||||
|
||||
def test_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
|
|
@ -113,10 +111,10 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r", compression)
|
||||
with zipfile.ZipFile(f, "r", compression) as zipfp:
|
||||
zipdata1 = []
|
||||
zipopen1 = zipfp.open(TESTFN)
|
||||
while 1:
|
||||
while True:
|
||||
read_data = zipopen1.read(256)
|
||||
if not read_data:
|
||||
break
|
||||
|
|
@ -124,7 +122,7 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
|
||||
zipdata2 = []
|
||||
zipopen2 = zipfp.open("another"+os.extsep+"name")
|
||||
while 1:
|
||||
while True:
|
||||
read_data = zipopen2.read(256)
|
||||
if not read_data:
|
||||
break
|
||||
|
|
@ -132,7 +130,6 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
|
||||
self.assertEqual(''.join(zipdata1), self.data)
|
||||
self.assertEqual(''.join(zipdata2), self.data)
|
||||
zipfp.close()
|
||||
|
||||
def test_open_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
|
|
@ -140,12 +137,11 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
|
||||
def test_open_via_zip_info(self):
|
||||
# Create the ZIP archive
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
|
||||
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
|
||||
zipfp.writestr("name", "foo")
|
||||
zipfp.writestr("name", "bar")
|
||||
zipfp.close()
|
||||
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "r")
|
||||
with zipfile.ZipFile(TESTFN2, "r") as zipfp:
|
||||
infos = zipfp.infolist()
|
||||
data = ""
|
||||
for info in infos:
|
||||
|
|
@ -155,23 +151,21 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
for info in infos:
|
||||
data += zipfp.read(info)
|
||||
self.assertTrue(data == "foobar" or data == "barfoo")
|
||||
zipfp.close()
|
||||
|
||||
def zip_random_open_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r", compression)
|
||||
with zipfile.ZipFile(f, "r", compression) as zipfp:
|
||||
zipdata1 = []
|
||||
zipopen1 = zipfp.open(TESTFN)
|
||||
while 1:
|
||||
while True:
|
||||
read_data = zipopen1.read(randint(1, 1024))
|
||||
if not read_data:
|
||||
break
|
||||
zipdata1.append(read_data)
|
||||
|
||||
self.assertEqual(''.join(zipdata1), self.data)
|
||||
zipfp.close()
|
||||
|
||||
def test_random_open_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
|
|
@ -181,35 +175,29 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
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')
|
||||
|
||||
zipfp.close()
|
||||
|
||||
def zip_readlines_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
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')
|
||||
|
||||
zipfp.close()
|
||||
|
||||
def zip_iterlines_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
with zipfile.ZipFile(f, "r") as zipfp:
|
||||
for line, zipline in zip(self.line_gen, zipfp.open(TESTFN)):
|
||||
self.assertEqual(zipline, line + '\n')
|
||||
|
||||
zipfp.close()
|
||||
|
||||
def test_readline_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
self.zip_readline_test(f, zipfile.ZIP_STORED)
|
||||
|
|
@ -256,34 +244,30 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
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)
|
||||
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp:
|
||||
zipfp.writestr("strfile", '12')
|
||||
zipfp.close()
|
||||
|
||||
# Get an open object for strfile
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED)
|
||||
with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp:
|
||||
openobj = zipfp.open("strfile")
|
||||
self.assertEqual(openobj.read(1), '1')
|
||||
self.assertEqual(openobj.read(1), '2')
|
||||
|
||||
def test_absolute_arcnames(self):
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
|
||||
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
|
||||
zipfp.write(TESTFN, "/absolute")
|
||||
zipfp.close()
|
||||
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED)
|
||||
with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
|
||||
self.assertEqual(zipfp.namelist(), ["absolute"])
|
||||
zipfp.close()
|
||||
|
||||
def test_append_to_zip_file(self):
|
||||
# Test appending to an existing zipfile
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
|
||||
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
|
||||
zipfp.write(TESTFN, TESTFN)
|
||||
zipfp.close()
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED)
|
||||
|
||||
with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
|
||||
zipfp.writestr("strfile", self.data)
|
||||
self.assertEqual(zipfp.namelist(), [TESTFN, "strfile"])
|
||||
zipfp.close()
|
||||
|
||||
def test_append_to_non_zip_file(self):
|
||||
# Test appending to an existing file that is not a zipfile
|
||||
|
|
@ -293,53 +277,47 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
f = file(TESTFN2, 'wb')
|
||||
f.write(d)
|
||||
f.close()
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED)
|
||||
with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
|
||||
zipfp.write(TESTFN, TESTFN)
|
||||
zipfp.close()
|
||||
|
||||
f = file(TESTFN2, 'rb')
|
||||
f.seek(len(d))
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
with zipfile.ZipFile(f, "r") as zipfp:
|
||||
self.assertEqual(zipfp.namelist(), [TESTFN])
|
||||
zipfp.close()
|
||||
f.close()
|
||||
|
||||
def test_write_default_name(self):
|
||||
# Check that calling ZipFile.write without arcname specified produces the expected result
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "w")
|
||||
with zipfile.ZipFile(TESTFN2, "w") as zipfp:
|
||||
zipfp.write(TESTFN)
|
||||
self.assertEqual(zipfp.read(TESTFN), file(TESTFN).read())
|
||||
zipfp.close()
|
||||
|
||||
@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")
|
||||
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)
|
||||
zipfp.close()
|
||||
|
||||
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")
|
||||
|
||||
with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
|
||||
self.assertRaises(RuntimeError, zipfp.write, TESTFN)
|
||||
|
||||
def test_extract(self):
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
|
||||
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
|
||||
for fpath, fdata in SMALL_TEST_DATA:
|
||||
zipfp.writestr(fpath, fdata)
|
||||
zipfp.close()
|
||||
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "r")
|
||||
with zipfile.ZipFile(TESTFN2, "r") as zipfp:
|
||||
for fpath, fdata in SMALL_TEST_DATA:
|
||||
writtenfile = zipfp.extract(fpath)
|
||||
|
||||
|
|
@ -357,18 +335,15 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
|
||||
os.remove(writtenfile)
|
||||
|
||||
zipfp.close()
|
||||
|
||||
# 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)
|
||||
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
|
||||
for fpath, fdata in SMALL_TEST_DATA:
|
||||
zipfp.writestr(fpath, fdata)
|
||||
zipfp.close()
|
||||
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "r")
|
||||
with zipfile.ZipFile(TESTFN2, "r") as zipfp:
|
||||
zipfp.extractall()
|
||||
for fpath, fdata in SMALL_TEST_DATA:
|
||||
if os.path.isabs(fpath):
|
||||
|
|
@ -380,8 +355,6 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
|
||||
os.remove(outfile)
|
||||
|
||||
zipfp.close()
|
||||
|
||||
# remove the test file subdirectories
|
||||
shutil.rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
|
||||
|
||||
|
|
@ -390,7 +363,7 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
# when it is passed a name rather than a ZipInfo instance.
|
||||
|
||||
self.make_test_archive(f, compression)
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
with zipfile.ZipFile(f, "r") as zipfp:
|
||||
zinfo = zipfp.getinfo('strfile')
|
||||
self.assertEqual(zinfo.external_attr, 0600 << 16)
|
||||
|
||||
|
|
@ -398,6 +371,31 @@ class TestsWithSourceFile(unittest.TestCase):
|
|||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED)
|
||||
|
||||
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)
|
||||
unlink(TESTFN2)
|
||||
|
|
@ -420,16 +418,14 @@ class TestZip64InSmallFiles(unittest.TestCase):
|
|||
fp.close()
|
||||
|
||||
def large_file_exception_test(self, f, compression):
|
||||
zipfp = zipfile.ZipFile(f, "w", compression)
|
||||
with zipfile.ZipFile(f, "w", compression) as zipfp:
|
||||
self.assertRaises(zipfile.LargeZipFile,
|
||||
zipfp.write, TESTFN, "another"+os.extsep+"name")
|
||||
zipfp.close()
|
||||
|
||||
def large_file_exception_test2(self, f, compression):
|
||||
zipfp = zipfile.ZipFile(f, "w", compression)
|
||||
with zipfile.ZipFile(f, "w", compression) as zipfp:
|
||||
self.assertRaises(zipfile.LargeZipFile,
|
||||
zipfp.writestr, "another"+os.extsep+"name", self.data)
|
||||
zipfp.close()
|
||||
|
||||
def test_large_file_exception(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
|
|
@ -438,14 +434,13 @@ class TestZip64InSmallFiles(unittest.TestCase):
|
|||
|
||||
def zip_test(self, f, compression):
|
||||
# Create the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "w", compression, allowZip64=True)
|
||||
with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
|
||||
zipfp.write(TESTFN, "another"+os.extsep+"name")
|
||||
zipfp.write(TESTFN, TESTFN)
|
||||
zipfp.writestr("strfile", self.data)
|
||||
zipfp.close()
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r", compression)
|
||||
with zipfile.ZipFile(f, "r", compression) as zipfp:
|
||||
self.assertEqual(zipfp.read(TESTFN), self.data)
|
||||
self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data)
|
||||
self.assertEqual(zipfp.read("strfile"), self.data)
|
||||
|
|
@ -455,7 +450,6 @@ class TestZip64InSmallFiles(unittest.TestCase):
|
|||
stdout = sys.stdout
|
||||
try:
|
||||
sys.stdout = fp
|
||||
|
||||
zipfp.printdir()
|
||||
finally:
|
||||
sys.stdout = stdout
|
||||
|
|
@ -499,8 +493,6 @@ class TestZip64InSmallFiles(unittest.TestCase):
|
|||
# Check that testzip doesn't raise an exception
|
||||
zipfp.testzip()
|
||||
|
||||
zipfp.close()
|
||||
|
||||
def test_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
self.zip_test(f, zipfile.ZIP_STORED)
|
||||
|
|
@ -511,13 +503,12 @@ class TestZip64InSmallFiles(unittest.TestCase):
|
|||
self.zip_test(f, zipfile.ZIP_DEFLATED)
|
||||
|
||||
def test_absolute_arcnames(self):
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, allowZip64=True)
|
||||
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
|
||||
allowZip64=True) as zipfp:
|
||||
zipfp.write(TESTFN, "/absolute")
|
||||
zipfp.close()
|
||||
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED)
|
||||
with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
|
||||
self.assertEqual(zipfp.namelist(), ["absolute"])
|
||||
zipfp.close()
|
||||
|
||||
def tearDown(self):
|
||||
zipfile.ZIP64_LIMIT = self._limit
|
||||
|
|
@ -527,7 +518,7 @@ class TestZip64InSmallFiles(unittest.TestCase):
|
|||
|
||||
class PyZipFileTests(unittest.TestCase):
|
||||
def test_write_pyfile(self):
|
||||
zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
|
||||
with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
|
||||
fn = __file__
|
||||
if fn.endswith('.pyc') or fn.endswith('.pyo'):
|
||||
fn = fn[:-1]
|
||||
|
|
@ -536,10 +527,10 @@ class PyZipFileTests(unittest.TestCase):
|
|||
|
||||
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()
|
||||
self.assertTrue(bn + 'o' in zipfp.namelist() or
|
||||
bn + 'c' in zipfp.namelist())
|
||||
|
||||
zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
|
||||
with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
|
||||
fn = __file__
|
||||
if fn.endswith('.pyc') or fn.endswith('.pyo'):
|
||||
fn = fn[:-1]
|
||||
|
|
@ -548,20 +539,22 @@ class PyZipFileTests(unittest.TestCase):
|
|||
|
||||
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()
|
||||
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")
|
||||
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)
|
||||
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)
|
||||
|
|
@ -590,7 +583,7 @@ class PyZipFileTests(unittest.TestCase):
|
|||
shutil.rmtree(TESTFN2)
|
||||
|
||||
def test_write_non_pyfile(self):
|
||||
zipfp = zipfile.PyZipFile(TemporaryFile(), "w")
|
||||
with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp:
|
||||
file(TESTFN, 'w').write('most definitely not a python file')
|
||||
self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
|
||||
os.remove(TESTFN)
|
||||
|
|
@ -598,15 +591,14 @@ class PyZipFileTests(unittest.TestCase):
|
|||
|
||||
class OtherTests(unittest.TestCase):
|
||||
def test_unicode_filenames(self):
|
||||
zf = zipfile.ZipFile(TESTFN, "w")
|
||||
with zipfile.ZipFile(TESTFN, "w") as zf:
|
||||
zf.writestr(u"foo.txt", "Test for unicode filename")
|
||||
zf.writestr(u"\xf6.txt", "Test for unicode filename")
|
||||
self.assertTrue(isinstance(zf.infolist()[0].filename, unicode))
|
||||
zf.close()
|
||||
zf = zipfile.ZipFile(TESTFN, "r")
|
||||
|
||||
with zipfile.ZipFile(TESTFN, "r") as zf:
|
||||
self.assertEqual(zf.filelist[0].filename, "foo.txt")
|
||||
self.assertEqual(zf.filelist[1].filename, u"\xf6.txt")
|
||||
zf.close()
|
||||
|
||||
def test_create_non_existent_file_for_append(self):
|
||||
if os.path.exists(TESTFN):
|
||||
|
|
@ -616,17 +608,15 @@ class OtherTests(unittest.TestCase):
|
|||
content = 'hello, world. this is some content.'
|
||||
|
||||
try:
|
||||
zf = zipfile.ZipFile(TESTFN, 'a')
|
||||
with zipfile.ZipFile(TESTFN, 'a') as zf:
|
||||
zf.writestr(filename, content)
|
||||
zf.close()
|
||||
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')
|
||||
with zipfile.ZipFile(TESTFN, 'r') as zf:
|
||||
self.assertEqual(zf.read(filename), content)
|
||||
zf.close()
|
||||
|
||||
def test_close_erroneous_file(self):
|
||||
# This test checks that the ZipFile constructor closes the file object
|
||||
|
|
@ -670,9 +660,8 @@ class OtherTests(unittest.TestCase):
|
|||
# a file that is a zip file
|
||||
|
||||
# - passing a filename
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w")
|
||||
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
|
||||
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
|
||||
zipf.close()
|
||||
chk = zipfile.is_zipfile(TESTFN)
|
||||
self.assertTrue(chk)
|
||||
# - passing a file object
|
||||
|
|
@ -717,9 +706,8 @@ class OtherTests(unittest.TestCase):
|
|||
def test_closed_zip_raises_RuntimeError(self):
|
||||
# Verify that testzip() doesn't swallow inappropriate exceptions.
|
||||
data = StringIO()
|
||||
zipf = zipfile.ZipFile(data, mode="w")
|
||||
with zipfile.ZipFile(data, mode="w") as zipf:
|
||||
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
|
||||
zipf.close()
|
||||
|
||||
# This is correct; calling .read on a closed ZipFile should throw
|
||||
# a RuntimeError, and so should calling .testzip. An earlier
|
||||
|
|
@ -738,19 +726,18 @@ class OtherTests(unittest.TestCase):
|
|||
|
||||
def test_bad_open_mode(self):
|
||||
# Check that bad modes passed to ZipFile.open are caught
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w")
|
||||
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
|
||||
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
|
||||
zipf.close()
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="r")
|
||||
|
||||
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()
|
||||
|
||||
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")
|
||||
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")
|
||||
|
|
@ -758,12 +745,11 @@ class OtherTests(unittest.TestCase):
|
|||
self.assertEqual(f.read(0), '')
|
||||
|
||||
self.assertEqual(f.read(), "O, for a Muse of Fire!")
|
||||
zipf.close()
|
||||
|
||||
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")
|
||||
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
|
||||
self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
|
||||
|
||||
def test_bad_compression_mode(self):
|
||||
|
|
@ -772,7 +758,7 @@ class OtherTests(unittest.TestCase):
|
|||
|
||||
def test_null_byte_in_filename(self):
|
||||
# Check that a filename containing a null byte is properly terminated
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w")
|
||||
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
|
||||
zipf.writestr("foo.txt\x00qqq", "O, for a Muse of Fire!")
|
||||
self.assertEqual(zipf.namelist(), ['foo.txt'])
|
||||
|
||||
|
|
@ -787,42 +773,36 @@ class OtherTests(unittest.TestCase):
|
|||
# This test checks that comments on the archive are handled properly
|
||||
|
||||
# check default comment is empty
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w")
|
||||
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
|
||||
self.assertEqual(zipf.comment, '')
|
||||
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
|
||||
zipf.close()
|
||||
zipfr = zipfile.ZipFile(TESTFN, mode="r")
|
||||
self.assertEqual(zipfr.comment, '')
|
||||
zipfr.close()
|
||||
|
||||
with zipfile.ZipFile(TESTFN, mode="r") as zipf:
|
||||
self.assertEqual(zipf.comment, '')
|
||||
|
||||
# check a simple short comment
|
||||
comment = 'Bravely taking to his feet, he beat a very brave retreat.'
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w")
|
||||
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
|
||||
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="r") as zipf:
|
||||
self.assertEqual(zipf.comment, comment)
|
||||
|
||||
# check a comment of max length
|
||||
comment2 = ''.join(['%d' % (i**3 % 10) for i in xrange((1 << 16)-1)])
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w")
|
||||
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
|
||||
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="r") as zipf:
|
||||
self.assertEqual(zipf.comment, comment2)
|
||||
|
||||
# check a comment that is too long is truncated
|
||||
zipf = zipfile.ZipFile(TESTFN, mode="w")
|
||||
with zipfile.ZipFile(TESTFN, mode="w") as zipf:
|
||||
zipf.comment = comment2 + '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="r") as zipf:
|
||||
self.assertEqual(zipf.comment, comment2)
|
||||
|
||||
def tearDown(self):
|
||||
unlink(TESTFN)
|
||||
|
|
@ -907,21 +887,19 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
|
|||
|
||||
def make_test_archive(self, f, compression):
|
||||
# Create the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "w", compression)
|
||||
with zipfile.ZipFile(f, "w", compression) as zipfp:
|
||||
zipfp.write(TESTFN, "another"+os.extsep+"name")
|
||||
zipfp.write(TESTFN, TESTFN)
|
||||
zipfp.close()
|
||||
|
||||
def zip_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r", compression)
|
||||
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"+os.extsep+"name"), self.data)
|
||||
zipfp.close()
|
||||
|
||||
def test_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
|
|
@ -931,10 +909,10 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
|
|||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r", compression)
|
||||
with zipfile.ZipFile(f, "r", compression) as zipfp:
|
||||
zipdata1 = []
|
||||
zipopen1 = zipfp.open(TESTFN)
|
||||
while 1:
|
||||
while True:
|
||||
read_data = zipopen1.read(256)
|
||||
if not read_data:
|
||||
break
|
||||
|
|
@ -942,7 +920,7 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
|
|||
|
||||
zipdata2 = []
|
||||
zipopen2 = zipfp.open("another"+os.extsep+"name")
|
||||
while 1:
|
||||
while True:
|
||||
read_data = zipopen2.read(256)
|
||||
if not read_data:
|
||||
break
|
||||
|
|
@ -955,7 +933,6 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
|
|||
testdata2 = ''.join(zipdata2)
|
||||
self.assertEqual(len(testdata1), len(self.data))
|
||||
self.assertEqual(testdata1, self.data)
|
||||
zipfp.close()
|
||||
|
||||
def test_open_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
|
|
@ -965,10 +942,10 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
|
|||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r", compression)
|
||||
with zipfile.ZipFile(f, "r", compression) as zipfp:
|
||||
zipdata1 = []
|
||||
zipopen1 = zipfp.open(TESTFN)
|
||||
while 1:
|
||||
while True:
|
||||
read_data = zipopen1.read(randint(1, 1024))
|
||||
if not read_data:
|
||||
break
|
||||
|
|
@ -977,7 +954,6 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
|
|||
testdata = ''.join(zipdata1)
|
||||
self.assertEqual(len(testdata), len(self.data))
|
||||
self.assertEqual(testdata, self.data)
|
||||
zipfp.close()
|
||||
|
||||
def test_random_open_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
|
|
@ -988,15 +964,14 @@ class TestsWithRandomBinaryFiles(unittest.TestCase):
|
|||
class TestsWithMultipleOpens(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Create the ZIP archive
|
||||
zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED)
|
||||
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) as zipfp:
|
||||
zipfp.writestr('ones', '1'*FIXEDTEST_SIZE)
|
||||
zipfp.writestr('twos', '2'*FIXEDTEST_SIZE)
|
||||
zipfp.close()
|
||||
|
||||
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")
|
||||
with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
|
||||
zopen1 = zipf.open('ones')
|
||||
zopen2 = zipf.open('ones')
|
||||
data1 = zopen1.read(500)
|
||||
|
|
@ -1004,12 +979,11 @@ class TestsWithMultipleOpens(unittest.TestCase):
|
|||
data1 += zopen1.read(500)
|
||||
data2 += zopen2.read(500)
|
||||
self.assertEqual(data1, data2)
|
||||
zipf.close()
|
||||
|
||||
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")
|
||||
with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
|
||||
zopen1 = zipf.open('ones')
|
||||
zopen2 = zipf.open('twos')
|
||||
data1 = zopen1.read(500)
|
||||
|
|
@ -1018,12 +992,11 @@ class TestsWithMultipleOpens(unittest.TestCase):
|
|||
data2 += zopen2.read(500)
|
||||
self.assertEqual(data1, '1'*FIXEDTEST_SIZE)
|
||||
self.assertEqual(data2, '2'*FIXEDTEST_SIZE)
|
||||
zipf.close()
|
||||
|
||||
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")
|
||||
with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
|
||||
zopen1 = zipf.open('ones')
|
||||
data1 = zopen1.read(500)
|
||||
zopen2 = zipf.open('twos')
|
||||
|
|
@ -1032,7 +1005,6 @@ class TestsWithMultipleOpens(unittest.TestCase):
|
|||
data2 += zopen2.read(500)
|
||||
self.assertEqual(data1, '1'*FIXEDTEST_SIZE)
|
||||
self.assertEqual(data2, '2'*FIXEDTEST_SIZE)
|
||||
zipf.close()
|
||||
|
||||
def tearDown(self):
|
||||
unlink(TESTFN2)
|
||||
|
|
@ -1043,7 +1015,7 @@ class TestWithDirectory(unittest.TestCase):
|
|||
os.mkdir(TESTFN2)
|
||||
|
||||
def test_extract_dir(self):
|
||||
zipf = zipfile.ZipFile(findfile("zipdir.zip"))
|
||||
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")))
|
||||
|
|
@ -1078,58 +1050,49 @@ class UniversalNewlineTests(unittest.TestCase):
|
|||
|
||||
def make_test_archive(self, f, compression):
|
||||
# Create the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "w", compression)
|
||||
with zipfile.ZipFile(f, "w", compression) as zipfp:
|
||||
for fn in self.arcfiles.values():
|
||||
zipfp.write(fn, fn)
|
||||
zipfp.close()
|
||||
|
||||
def read_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
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)
|
||||
|
||||
zipfp.close()
|
||||
|
||||
def readline_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
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 + '\n')
|
||||
|
||||
zipfp.close()
|
||||
|
||||
def readlines_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
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 + '\n')
|
||||
|
||||
zipfp.close()
|
||||
|
||||
def iterlines_test(self, f, compression):
|
||||
self.make_test_archive(f, compression)
|
||||
|
||||
# Read the ZIP archive
|
||||
zipfp = zipfile.ZipFile(f, "r")
|
||||
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 + '\n')
|
||||
|
||||
zipfp.close()
|
||||
|
||||
def test_read_stored(self):
|
||||
for f in (TESTFN2, TemporaryFile(), StringIO()):
|
||||
self.read_test(f, zipfile.ZIP_STORED)
|
||||
|
|
|
|||
|
|
@ -721,6 +721,12 @@ class ZipFile:
|
|||
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."""
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #5511: now zipfile.ZipFile can be used as a context manager.
|
||||
Initial patch by Brian Curtin.
|
||||
|
||||
- Distutils now correctly identifies the build architecture as "x86_64"
|
||||
when building on OSX 10.6 without "-arch" flags.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue