This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author llllllllll
Recipients llllllllll
Date 2017-02-07.03:14:02
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1486437245.45.0.651838453816.issue29468@psf.upfronthosting.co.za>
In-reply-to
Content
In zipfile.py only OSError is checked to see if seek fails:

```
def _EndRecData64(fpin, offset, endrec):
    """
    Read the ZIP64 end-of-archive records and use that to update endrec
    """
    try:
        fpin.seek(offset - sizeEndCentDir64Locator, 2)
    except OSError:
        # If the seek fails, the file is not large enough to contain a ZIP64
        # end-of-archive record, so just return the end record we were given.
        return endrec
```

I belive that this should also catch ValueError so that other file-like objects may be passed to ZipFile. The particular case I ran into was passing an mmap object:

```
"""
$ python p.py
sys.version_info(major=3, minor=6, micro=0, releaselevel='final', serial=0)
[]
Traceback (most recent call last):
  File "p.py", line 34, in <module>
    with mmap_shared_raw_zipfile(f.name) as zf:
  File "/usr/lib64/python3.6/contextlib.py", line 82, in __enter__
    return next(self.gen)
  File "p.py", line 23, in mmap_shared_raw_zipfile
    ZipFile(mm) as zf:
  File "/usr/lib64/python3.6/zipfile.py", line 1100, in __init__
    self._RealGetContents()
  File "/usr/lib64/python3.6/zipfile.py", line 1163, in _RealGetContents
    endrec = _EndRecData(fp)
  File "/usr/lib64/python3.6/zipfile.py", line 264, in _EndRecData
    return _EndRecData64(fpin, -sizeEndCentDir, endrec)
  File "/usr/lib64/python3.6/zipfile.py", line 196, in _EndRecData64
    fpin.seek(offset - sizeEndCentDir64Locator, 2)
ValueError: seek out of range
"""
from contextlib import contextmanager
import mmap
import sys
from tempfile import NamedTemporaryFile
from zipfile import ZipFile


print(sys.version_info)


@contextmanager
def mmap_shared_raw_zipfile(path):
    """Open a zipfile with mmap shared so the data can be shared in multiple
    processes.

    Parameters
    ----------
    path : str
        The path the zipfile to open.

    Notes
    -----
    The context manager returns a :class:`zipfile.ZipFile` on enter.
    """
    with open(path) as f, \
            mmap.mmap(f.fileno(), 0, mmap.MAP_SHARED, mmap.PROT_READ) as mm, \
            ZipFile(mm) as zf:
        yield zf


with NamedTemporaryFile() as f:
    ZipFile(f, mode='w').close()
    print(ZipFile(f.name).infolist())


with NamedTemporaryFile() as f:
    ZipFile(f, mode='w').close()
    with mmap_shared_raw_zipfile(f.name) as zf:
        print(zf.infolist())
```
History
Date User Action Args
2017-02-07 03:14:05llllllllllsetrecipients: + llllllllll
2017-02-07 03:14:05llllllllllsetmessageid: <1486437245.45.0.651838453816.issue29468@psf.upfronthosting.co.za>
2017-02-07 03:14:05lllllllllllinkissue29468 messages
2017-02-07 03:14:03llllllllllcreate