diff -r 816e1fe72c1e Doc/library/zipfile.rst --- a/Doc/library/zipfile.rst Sun May 15 13:21:25 2016 +0000 +++ b/Doc/library/zipfile.rst Sun May 15 21:16:39 2016 +0300 @@ -204,18 +204,13 @@ ZipFile Objects Return a list of archive members by name. -.. index:: - single: universal newlines; zipfile.ZipFile.open method - .. method:: ZipFile.open(name, mode='r', pwd=None, *, force_zip64=False) Access a member of the archive as a file-like object. *name* is 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'``, ``'rU'`` or ``'w'``. Choosing ``'U'`` or ``'rU'`` will - enable :term:`universal newlines` support in the read-only object. *pwd* is - the password used to decrypt encrypted ZIP files. Calling :meth:`.open` on - a closed ZipFile will raise a :exc:`RuntimeError`. + *mode* parameter, if included, must be ``'r'`` (the default) or ``'w'``. + *pwd* is the password used to decrypt encrypted ZIP files. Calling + :meth:`.open` on a closed ZipFile will raise a :exc:`RuntimeError`. :meth:`~ZipFile.open` is also a context manager and therefore supports the :keyword:`with` statement:: @@ -224,7 +219,7 @@ ZipFile Objects with myzip.open('eggs.txt') as myfile: print(myfile.read()) - With *mode* ``'r'``, ``'U'`` or ``'rU'``, the file-like object + With *mode* ``'r'`` the file-like object (``ZipExtFile``) is read-only and provides the following methods: :meth:`~io.BufferedIOBase.read`, :meth:`~io.IOBase.readline`, :meth:`~io.IOBase.readlines`, :meth:`__iter__`, @@ -248,9 +243,8 @@ ZipFile Objects or a :class:`ZipInfo` object. You will appreciate this when trying to read a ZIP file that contains members with duplicate names. - .. deprecated-removed:: 3.4 3.6 - The ``'U'`` or ``'rU'`` mode. Use :class:`io.TextIOWrapper` for reading - compressed text files in :term:`universal newlines` mode. + .. versionchanged:: 3.6 + Removed support of ``mode='U'``. .. versionchanged:: 3.6 :meth:`open` can now be used to write files into the archive with the diff -r 816e1fe72c1e Doc/whatsnew/3.6.rst --- a/Doc/whatsnew/3.6.rst Sun May 15 13:21:25 2016 +0000 +++ b/Doc/whatsnew/3.6.rst Sun May 15 21:16:39 2016 +0300 @@ -489,6 +489,11 @@ API and Feature Removals :mod:`traceback` module. They were undocumented methods deprecated since Python 3.2 and equivalent functionality is available from private methods. +* The :meth:`~zipfile.ZipFile.open` method of the :class:`zipfile.ZipFile` + class no longer supports the ``'U'`` mode (was deprecated since Python 3.4). + Use :class:`io.TextIOWrapper` for reading compressed text files in + :term:`universal newlines` mode. + Porting to Python 3.6 ===================== diff -r 816e1fe72c1e Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py Sun May 15 13:21:25 2016 +0000 +++ b/Lib/test/test_zipfile.py Sun May 15 21:16:39 2016 +0300 @@ -38,10 +38,6 @@ def get_files(test): yield f test.assertFalse(f.closed) -def openU(zipfp, fn): - with check_warnings(('', DeprecationWarning)): - return zipfp.open(fn, 'rU') - class AbstractTestsWithSourceFile: @classmethod def setUpClass(cls): @@ -1035,32 +1031,6 @@ class OtherTests(unittest.TestCase): data += zipfp.read(info) self.assertIn(data, {b"foobar", b"barfoo"}) - def test_universal_deprecation(self): - f = io.BytesIO() - with zipfile.ZipFile(f, "w") as zipfp: - zipfp.writestr('spam.txt', b'ababagalamaga') - - with zipfile.ZipFile(f, "r") as zipfp: - for mode in 'U', 'rU': - with self.assertWarns(DeprecationWarning): - zipopen = zipfp.open('spam.txt', mode) - zipopen.close() - - def test_universal_readaheads(self): - f = io.BytesIO() - - data = b'a\r\n' * 16 * 1024 - with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as zipfp: - zipfp.writestr(TESTFN, data) - - data2 = b'' - with zipfile.ZipFile(f, 'r') as zipfp, \ - openU(zipfp, TESTFN) as zipopen: - for line in zipopen: - data2 += line - - self.assertEqual(data, data2.replace(b'\n', b'\r\n')) - def test_writestr_extended_local_header_issue1202(self): with zipfile.ZipFile(TESTFN2, 'w') as orig_zip: for data in 'abcdefghijklmnop': @@ -1268,9 +1238,12 @@ class OtherTests(unittest.TestCase): 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 + # read the data to make sure the file is there zipf.read("foo.txt") self.assertRaises(RuntimeError, zipf.open, "foo.txt", "q") + # universal newlines support is removed + self.assertRaises(RuntimeError, zipf.open, "foo.txt", "U") + self.assertRaises(RuntimeError, zipf.open, "foo.txt", "rU") def test_read0(self): """Check that calling read(0) on a ZipExtFile object returns an empty @@ -2011,138 +1984,6 @@ class TestWithDirectory(unittest.TestCas unlink(TESTFN) -class AbstractUniversalNewlineTests: - @classmethod - def setUpClass(cls): - cls.line_gen = [bytes("Test of zipfile line %d." % i, "ascii") - for i in range(FIXEDTEST_SIZE)] - cls.seps = (b'\r', b'\r\n', b'\n') - cls.arcdata = {} - for n, s in enumerate(cls.seps): - cls.arcdata[s] = s.join(cls.line_gen) + s - - def setUp(self): - self.arcfiles = {} - for n, s in enumerate(self.seps): - self.arcfiles[s] = '%s-%d' % (TESTFN, n) - with open(self.arcfiles[s], "wb") as f: - f.write(self.arcdata[s]) - - def make_test_archive(self, f, compression): - # Create the ZIP archive - 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 - with zipfile.ZipFile(f, "r") as zipfp: - for sep, fn in self.arcfiles.items(): - with openU(zipfp, fn) as fp: - zipdata = fp.read() - self.assertEqual(self.arcdata[sep], zipdata) - - def test_read(self): - for f in get_files(self): - self.read_test(f, self.compression) - - def readline_read_test(self, f, compression): - self.make_test_archive(f, compression) - - # Read the ZIP archive - with zipfile.ZipFile(f, "r") as zipfp: - for sep, fn in self.arcfiles.items(): - with openU(zipfp, fn) as zipopen: - data = b'' - while True: - read = zipopen.readline() - if not read: - break - data += read - - read = zipopen.read(5) - if not read: - break - data += read - - self.assertEqual(data, self.arcdata[b'\n']) - - def test_readline_read(self): - for f in get_files(self): - self.readline_read_test(f, self.compression) - - def readline_test(self, f, compression): - self.make_test_archive(f, compression) - - # Read the ZIP archive - with zipfile.ZipFile(f, "r") as zipfp: - for sep, fn in self.arcfiles.items(): - with openU(zipfp, fn) as zipopen: - for line in self.line_gen: - linedata = zipopen.readline() - self.assertEqual(linedata, line + b'\n') - - def test_readline(self): - for f in get_files(self): - self.readline_test(f, self.compression) - - def readlines_test(self, f, compression): - self.make_test_archive(f, compression) - - # Read the ZIP archive - with zipfile.ZipFile(f, "r") as zipfp: - for sep, fn in self.arcfiles.items(): - with openU(zipfp, fn) as fp: - ziplines = fp.readlines() - for line, zipline in zip(self.line_gen, ziplines): - self.assertEqual(zipline, line + b'\n') - - def test_readlines(self): - for f in get_files(self): - self.readlines_test(f, self.compression) - - def iterlines_test(self, f, compression): - self.make_test_archive(f, compression) - - # Read the ZIP archive - with zipfile.ZipFile(f, "r") as zipfp: - for sep, fn in self.arcfiles.items(): - with openU(zipfp, fn) as fp: - for line, zipline in zip(self.line_gen, fp): - self.assertEqual(zipline, line + b'\n') - - def test_iterlines(self): - for f in get_files(self): - self.iterlines_test(f, self.compression) - - def tearDown(self): - for sep, fn in self.arcfiles.items(): - unlink(fn) - unlink(TESTFN) - unlink(TESTFN2) - - -class StoredUniversalNewlineTests(AbstractUniversalNewlineTests, - unittest.TestCase): - compression = zipfile.ZIP_STORED - -@requires_zlib -class DeflateUniversalNewlineTests(AbstractUniversalNewlineTests, - unittest.TestCase): - compression = zipfile.ZIP_DEFLATED - -@requires_bz2 -class Bzip2UniversalNewlineTests(AbstractUniversalNewlineTests, - unittest.TestCase): - compression = zipfile.ZIP_BZIP2 - -@requires_lzma -class LzmaUniversalNewlineTests(AbstractUniversalNewlineTests, - unittest.TestCase): - compression = zipfile.ZIP_LZMA - class ZipInfoTests(unittest.TestCase): def test_from_file(self): zi = zipfile.ZipInfo.from_file(__file__) diff -r 816e1fe72c1e Lib/zipfile.py --- a/Lib/zipfile.py Sun May 15 13:21:25 2016 +0000 +++ b/Lib/zipfile.py Sun May 15 21:16:39 2016 +0300 @@ -743,9 +743,6 @@ class ZipExtFile(io.BufferedIOBase): # Read from compressed files in 4k blocks. MIN_READ_SIZE = 4096 - # Search for universal newlines or line chunks. - PATTERN = re.compile(br'^(?P[^\r\n]+)|(?P\n|\r\n?)') - def __init__(self, fileobj, mode, zipinfo, decrypter=None, close_fileobj=False): self._fileobj = fileobj @@ -762,7 +759,6 @@ class ZipExtFile(io.BufferedIOBase): self._readbuffer = b'' self._offset = 0 - self._universal = 'U' in mode self.newlines = None # Adjust read size for encrypted files since the first 12 bytes @@ -799,7 +795,7 @@ class ZipExtFile(io.BufferedIOBase): If limit is specified, at most limit bytes will be read. """ - if not self._universal and limit < 0: + if limit < 0: # Shortcut common case - newline found in buffer. i = self._readbuffer.find(b'\n', self._offset) + 1 if i > 0: @@ -807,41 +803,7 @@ class ZipExtFile(io.BufferedIOBase): self._offset = i return line - if not self._universal: - return io.BufferedIOBase.readline(self, limit) - - line = b'' - while limit < 0 or len(line) < limit: - readahead = self.peek(2) - if readahead == b'': - return line - - # - # Search for universal newlines or line chunks. - # - # The pattern returns either a line chunk or a newline, but not - # both. Combined with peek(2), we are assured that the sequence - # '\r\n' is always retrieved completely and never split into - # separate newlines - '\r', '\n' due to coincidental readaheads. - # - match = self.PATTERN.search(readahead) - newline = match.group('newline') - if newline is not None: - if self.newlines is None: - self.newlines = [] - if newline not in self.newlines: - self.newlines.append(newline) - self._offset += len(newline) - return line + b'\n' - - chunk = match.group('chunk') - if limit >= 0: - chunk = chunk[: limit - len(line)] - - self._offset += len(chunk) - line += chunk - - return line + return io.BufferedIOBase.readline(self, limit) def peek(self, n=1): """Returns buffered bytes without advancing the position.""" @@ -1360,12 +1322,8 @@ class ZipFile: files. If the size is known in advance, it is best to pass a ZipInfo instance for name, with zinfo.file_size set. """ - if mode not in {"r", "w", "U", "rU"}: - raise RuntimeError('open() requires mode "r", "w", "U", or "rU"') - if 'U' in mode: - import warnings - warnings.warn("'U' mode is deprecated", - DeprecationWarning, 2) + if mode not in {"r", "w"}: + raise RuntimeError('open() requires mode "r" or "w"') if pwd and not isinstance(pwd, bytes): raise TypeError("pwd: expected bytes, got %s" % type(pwd)) if pwd and (mode == "w"):