Patch #1775025: allow opening zipfile members via ZipInfo instances.

Patch by Graham Horler.
This commit is contained in:
Georg Brandl 2008-05-20 08:25:48 +00:00
parent 4dd019fde3
commit 112aa50329
4 changed files with 52 additions and 19 deletions

View File

@ -155,11 +155,11 @@ ZipFile Objects
.. method:: ZipFile.open(name[, mode[, pwd]])
Extract a member from the archive as a file-like object (ZipExtFile). *name* is
the name of the file in the archive. The *mode* parameter, if included, must be
one of the following: ``'r'`` (the default), ``'U'``, or ``'rU'``. Choosing
``'U'`` or ``'rU'`` will enable universal newline support in the read-only
object. *pwd* is the password used for encrypted files. Calling :meth:`open`
on a closed ZipFile will raise a :exc:`RuntimeError`.
the name of the file in the archive, or a :class:`ZipInfo` object. The *mode*
parameter, if included, must be one of the following: ``'r'`` (the default),
``'U'``, or ``'rU'``. Choosing ``'U'`` or ``'rU'`` will enable universal newline
support in the read-only object. *pwd* is the password used for encrypted files.
Calling :meth:`open` on a closed ZipFile will raise a :exc:`RuntimeError`.
.. note::
@ -178,16 +178,22 @@ ZipFile Objects
create a new file object that will be held by the ZipExtFile, allowing it to
operate independently of the ZipFile.
.. note::
The :meth:`open`, :meth:`read` and :meth:`extract` methods can take a filename
or a :class:`ZipInfo` object. You will appreciate this when trying to read a
ZIP file that contains members with duplicate names.
.. versionadded:: 2.6
.. method:: ZipFile.extract(member[, path[, pwd]])
Extract a member from the archive to the current working directory, using its
full name. Its file information is extracted as accurately as possible.
*path* specifies a different directory to extract to. *member* can be a
filename or a :class:`ZipInfo` object. *pwd* is the password used for
encrypted files.
Extract a member from the archive to the current working directory; *member*
must be its full name or a :class:`ZipInfo` object). Its file information is
extracted as accurately as possible. *path* specifies a different directory
to extract to. *member* can be a filename or a :class:`ZipInfo` object.
*pwd* is the password used for encrypted files.
.. versionadded:: 2.6
@ -216,13 +222,14 @@ ZipFile Objects
.. method:: ZipFile.read(name[, pwd])
Return the bytes of the file in the archive. The archive must be open for read
or append. *pwd* is the password used for encrypted files and, if specified, it
will override the default password set with :meth:`setpassword`. Calling
Return the bytes of the file *name* in the archive. *name* is the name of the
file in the archive, or a :class:`ZipInfo` object. The archive must be open for
read or append. *pwd* is the password used for encrypted files and, if specified,
it will override the default password set with :meth:`setpassword`. Calling
:meth:`read` on a closed ZipFile will raise a :exc:`RuntimeError`.
.. versionchanged:: 2.6
*pwd* was added.
*pwd* was added, and *name* can now be a :class:`ZipInfo` object.
.. method:: ZipFile.testzip()

View File

@ -132,6 +132,25 @@ class TestsWithSourceFile(unittest.TestCase):
for f in (TESTFN2, TemporaryFile(), StringIO()):
self.zipOpenTest(f, zipfile.ZIP_STORED)
def testOpenViaZipInfo(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 = ""
for info in infos:
data += zipfp.open(info).read()
self.assert_(data == "foobar" or data == "barfoo")
data = ""
for info in infos:
data += zipfp.read(info)
self.assert_(data == "foobar" or data == "barfoo")
zipfp.close()
def zipRandomOpenTest(self, f, compression):
self.makeTestArchive(f, compression)

View File

@ -776,10 +776,13 @@ class ZipFile:
else:
zef_file = open(self.filename, 'rb')
# Get info object for name
zinfo = self.getinfo(name)
filepos = zef_file.tell()
# Make sure we have an info object
if isinstance(name, ZipInfo):
# 'name' is already an info object
zinfo = name
else:
# Get info object for name
zinfo = self.getinfo(name)
zef_file.seek(zinfo.header_offset, 0)
@ -884,7 +887,7 @@ class ZipFile:
if upperdirs and not os.path.exists(upperdirs):
os.makedirs(upperdirs)
source = self.open(member.filename, pwd=pwd)
source = self.open(member, pwd=pwd)
target = file(targetpath, "wb")
shutil.copyfileobj(source, target)
source.close()

View File

@ -52,6 +52,10 @@ Extension Modules
Library
-------
- Issue #1775025: You can now specify zipfile members to open(),
read() or extract() via a ZipInfo instance. This allows handling
duplicate filenames in zipfiles.
- Issue #961805: Fix Text.edit_modified() in Tkinter.
- Issue #1793: Function ctypes.util.find_msvcrt() added that returns