diff --git a/Doc/library/fileinput.rst b/Doc/library/fileinput.rst index d5a48756fe8..ee06830ad8e 100644 --- a/Doc/library/fileinput.rst +++ b/Doc/library/fileinput.rst @@ -160,6 +160,9 @@ available for subclassing as well: .. versionchanged:: 3.2 Can be used as a context manager. + .. deprecated:: 3.4 + The ``'rU'`` and ``'U'`` modes. + **Optional in-place filtering:** if the keyword argument ``inplace=True`` is passed to :func:`fileinput.input` or to the :class:`FileInput` constructor, the diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index ffee09efce9..474bb1dfa02 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -872,8 +872,7 @@ are always available. They are listed here in alphabetical order. ``'b'`` binary mode ``'t'`` text mode (default) ``'+'`` open a disk file for updating (reading and writing) - ``'U'`` universal newlines mode (for backwards compatibility; should - not be used in new code) + ``'U'`` :term:`universal newlines` mode (deprecated) ========= =============================================================== The default mode is ``'r'`` (open for reading text, synonym of ``'rt'``). @@ -1029,6 +1028,9 @@ are always available. They are listed here in alphabetical order. .. versionchanged:: 3.4 The file is now non-inheritable. + .. deprecated-removed:: 3.4 4.0 + The ``'U'`` mode. + .. XXX works for bytes too, but should it? .. function:: ord(c) diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 72b76a09d39..1966713ed00 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -234,6 +234,9 @@ 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. .. method:: ZipFile.extract(member, path=None, pwd=None) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 78c6dfb4cd8..d6eee79e016 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -62,8 +62,7 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, 'b' binary mode 't' text mode (default) '+' open a disk file for updating (reading and writing) - 'U' universal newline mode (for backwards compatibility; unneeded - for new code) + 'U' universal newline mode (deprecated) ========= =============================================================== The default mode is 'rt' (open for reading text). For binary random @@ -79,6 +78,10 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, returned as strings, the bytes having been first decoded using a platform-dependent encoding or using the specified encoding if given. + 'U' mode is deprecated and will raise an exception in future versions + of Python. It has no effect in Python 3. Use newline to control + universal newlines mode. + buffering is an optional integer used to set the buffering policy. Pass 0 to switch buffering off (only allowed in binary mode), 1 to select line buffering (only usable in text mode), and an integer > 1 to indicate @@ -174,6 +177,9 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, if "U" in modes: if creating or writing or appending: raise ValueError("can't use U and writing mode at once") + import warnings + warnings.warn("'U' mode is deprecated", + DeprecationWarning, 2) reading = True if text and binary: raise ValueError("can't have text and binary mode at once") diff --git a/Lib/fileinput.py b/Lib/fileinput.py index 3215154e88d..11ba82df875 100644 --- a/Lib/fileinput.py +++ b/Lib/fileinput.py @@ -222,6 +222,10 @@ class FileInput: if mode not in ('r', 'rU', 'U', 'rb'): raise ValueError("FileInput opening mode must be one of " "'r', 'rU', 'U' and 'rb'") + if 'U' in mode: + import warnings + warnings.warn("Use of 'U' mode is deprecated", + DeprecationWarning, 2) self._mode = mode if openhook: if inplace: diff --git a/Lib/imp.py b/Lib/imp.py index 1144cd1f64c..c8449c61554 100644 --- a/Lib/imp.py +++ b/Lib/imp.py @@ -103,7 +103,7 @@ def source_from_cache(path): def get_suffixes(): """**DEPRECATED**""" extensions = [(s, 'rb', C_EXTENSION) for s in machinery.EXTENSION_SUFFIXES] - source = [(s, 'U', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES] + source = [(s, 'r', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES] bytecode = [(s, 'rb', PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES] return extensions + source + bytecode @@ -297,7 +297,7 @@ def find_module(name, path=None): raise ImportError(_ERR_MSG.format(name), name=name) encoding = None - if mode == 'U': + if 'b' not in mode: with open(file_path, 'rb') as file: encoding = tokenize.detect_encoding(file.readline)[0] file = open(file_path, mode, encoding=encoding) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py index cf27a712d51..78f573407c7 100644 --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -165,7 +165,7 @@ class ImportTests(unittest.TestCase): self.assertIsNotNone(file) self.assertTrue(filename[:-3].endswith(temp_mod_name)) self.assertEqual(info[0], '.py') - self.assertEqual(info[1], 'U') + self.assertEqual(info[1], 'r') self.assertEqual(info[2], imp.PY_SOURCE) mod = imp.load_module(temp_mod_name, file, filename, info) diff --git a/Lib/zipfile.py b/Lib/zipfile.py index ae65b42f70f..fad52a246d5 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1117,6 +1117,10 @@ class ZipFile: """Return file-like object for 'name'.""" if mode not in ("r", "U", "rU"): raise RuntimeError('open() requires mode "r", "U", or "rU"') + if 'U' in mode: + import warnings + warnings.warn("'U' mode is deprecated", + DeprecationWarning, 2) if pwd and not isinstance(pwd, bytes): raise TypeError("pwd: expected bytes, got %s" % type(pwd)) if not self.fp: diff --git a/Misc/NEWS b/Misc/NEWS index 9cfecb5564c..5185efef3f8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -68,6 +68,8 @@ Core and Builtins Library ------- +- Issue #15204: Deprecated the 'U' mode in file-like objects. + - Issue #17810: Implement PEP 3154, pickle protocol 4. - Issue #19668: Added support for the cp1125 encoding. diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index eb701d4400f..9866fbe82be 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -126,8 +126,7 @@ PyDoc_STRVAR(open_doc, "'b' binary mode\n" "'t' text mode (default)\n" "'+' open a disk file for updating (reading and writing)\n" -"'U' universal newline mode (for backwards compatibility; unneeded\n" -" for new code)\n" +"'U' universal newline mode (deprecated)\n" "========= ===============================================================\n" "\n" "The default mode is 'rt' (open for reading text). For binary random\n" @@ -143,6 +142,10 @@ PyDoc_STRVAR(open_doc, "returned as strings, the bytes having been first decoded using a\n" "platform-dependent encoding or using the specified encoding if given.\n" "\n" +"'U' mode is deprecated and will raise an exception in future versions\n" +"of Python. It has no effect in Python 3. Use newline to control\n" +"universal newlines mode.\n" +"\n" "buffering is an optional integer used to set the buffering policy.\n" "Pass 0 to switch buffering off (only allowed in binary mode), 1 to select\n" "line buffering (only usable in text mode), and an integer > 1 to indicate\n" @@ -310,6 +313,9 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) "can't use U and writing mode at once"); return NULL; } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "'U' mode is deprecated", 1) < 0) + return NULL; reading = 1; } diff --git a/Tools/iobench/iobench.py b/Tools/iobench/iobench.py index 530bc79d5c8..712e58472ed 100644 --- a/Tools/iobench/iobench.py +++ b/Tools/iobench/iobench.py @@ -24,6 +24,8 @@ def text_open(fn, mode, encoding=None): try: return open(fn, mode, encoding=encoding or TEXT_ENCODING) except TypeError: + if 'r' in mode: + mode += 'U' # 'U' mode is needed only in Python 2.x return open(fn, mode) def get_file_sizes(): @@ -380,7 +382,7 @@ def prepare_files(): f.write(os.urandom(size)) # Text files chunk = [] - with text_open(__file__, "rU", encoding='utf8') as f: + with text_open(__file__, "r", encoding='utf8') as f: for line in f: if line.startswith("# "): break diff --git a/Tools/scripts/diff.py b/Tools/scripts/diff.py index f9b14bf5e51..8be527fd627 100755 --- a/Tools/scripts/diff.py +++ b/Tools/scripts/diff.py @@ -38,9 +38,9 @@ def main(): fromdate = file_mtime(fromfile) todate = file_mtime(tofile) - with open(fromfile, 'U') as ff: + with open(fromfile) as ff: fromlines = ff.readlines() - with open(tofile, 'U') as tf: + with open(tofile) as tf: tolines = tf.readlines() if options.u: diff --git a/Tools/scripts/ndiff.py b/Tools/scripts/ndiff.py index 2422091dccb..c6d09b8f242 100755 --- a/Tools/scripts/ndiff.py +++ b/Tools/scripts/ndiff.py @@ -60,7 +60,7 @@ def fail(msg): # couldn't be opened def fopen(fname): try: - return open(fname, 'U') + return open(fname) except IOError as detail: return fail("couldn't open " + fname + ": " + str(detail))