bpo-37330: open() no longer accept 'U' in file mode (GH-16959)
open(), io.open(), codecs.open() and fileinput.FileInput no longer
accept "U" ("universal newline") in the file mode. This flag was
deprecated since Python 3.3.
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index c1bdac7..e819b0a 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -71,7 +71,6 @@
'b' binary mode
't' text mode (default)
'+' open a disk file for updating (reading and writing)
- 'U' universal newline mode (deprecated)
========= ===============================================================
The default mode is 'rt' (open for reading text). For binary random
@@ -87,10 +86,6 @@
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
@@ -176,7 +171,7 @@
if errors is not None and not isinstance(errors, str):
raise TypeError("invalid errors: %r" % errors)
modes = set(mode)
- if modes - set("axrwb+tU") or len(mode) > len(modes):
+ if modes - set("axrwb+t") or len(mode) > len(modes):
raise ValueError("invalid mode: %r" % mode)
creating = "x" in modes
reading = "r" in modes
@@ -185,13 +180,6 @@
updating = "+" in modes
text = "t" in modes
binary = "b" in modes
- if "U" in modes:
- if creating or writing or appending or updating:
- raise ValueError("mode U cannot be combined with 'x', 'w', 'a', or '+'")
- 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")
if creating + reading + writing + appending > 1:
diff --git a/Lib/fileinput.py b/Lib/fileinput.py
index c1b0ec9..166c631 100644
--- a/Lib/fileinput.py
+++ b/Lib/fileinput.py
@@ -209,15 +209,10 @@
self._isstdin = False
self._backupfilename = None
# restrict mode argument to reading modes
- 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("'U' mode is deprecated",
- DeprecationWarning, 2)
+ if mode not in ('r', 'rb'):
+ raise ValueError("FileInput opening mode must be 'r' or 'rb'")
self._mode = mode
- self._write_mode = mode.replace('r', 'w') if 'U' not in mode else 'w'
+ self._write_mode = mode.replace('r', 'w')
if openhook:
if inplace:
raise ValueError("FileInput cannot use an opening hook in inplace mode")
diff --git a/Lib/imp.py b/Lib/imp.py
index 31f8c76..a6f6fc8 100644
--- a/Lib/imp.py
+++ b/Lib/imp.py
@@ -225,7 +225,7 @@
"""
suffix, mode, type_ = details
- if mode and (not mode.startswith(('r', 'U')) or '+' in mode):
+ if mode and (not mode.startswith('r') or '+' in mode):
raise ValueError('invalid file open mode {!r}'.format(mode))
elif file is None and type_ in {PY_SOURCE, PY_COMPILED}:
msg = 'file object required for import (type code {})'.format(type_)
diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
index b37525b..e1638c1 100644
--- a/Lib/test/test_codecs.py
+++ b/Lib/test/test_codecs.py
@@ -712,11 +712,23 @@
self.addCleanup(support.unlink, support.TESTFN)
with open(support.TESTFN, 'wb') as fp:
fp.write(s)
- with support.check_warnings(('', DeprecationWarning)):
- reader = codecs.open(support.TESTFN, 'U', encoding=self.encoding)
- with reader:
+ with codecs.open(support.TESTFN, 'r',
+ encoding=self.encoding) as reader:
self.assertEqual(reader.read(), s1)
+ def test_invalid_modes(self):
+ for mode in ('U', 'rU', 'r+U'):
+ with self.assertRaises(ValueError) as cm:
+ codecs.open(support.TESTFN, mode, encoding=self.encoding)
+ self.assertIn('invalid mode', str(cm.exception))
+
+ for mode in ('rt', 'wt', 'at', 'r+t'):
+ with self.assertRaises(ValueError) as cm:
+ codecs.open(support.TESTFN, mode, encoding=self.encoding)
+ self.assertIn("can't have text and binary mode at once",
+ str(cm.exception))
+
+
class UTF16LETest(ReadTest, unittest.TestCase):
encoding = "utf-16-le"
ill_formed_sequence = b"\x80\xdc"
diff --git a/Lib/test/test_fileinput.py b/Lib/test/test_fileinput.py
index 014f19e..819557d 100644
--- a/Lib/test/test_fileinput.py
+++ b/Lib/test/test_fileinput.py
@@ -226,19 +226,11 @@
self.assertEqual(fi.fileno(), -1)
def test_opening_mode(self):
- try:
- # invalid mode, should raise ValueError
- fi = FileInput(mode="w")
- self.fail("FileInput should reject invalid mode argument")
- except ValueError:
- pass
- # try opening in universal newline mode
- t1 = self.writeTmp(b"A\nB\r\nC\rD", mode="wb")
- with check_warnings(('', DeprecationWarning)):
- fi = FileInput(files=t1, mode="U")
- with check_warnings(('', DeprecationWarning)):
- lines = list(fi)
- self.assertEqual(lines, ["A\n", "B\n", "C\n", "D"])
+ # invalid modes
+ for mode in ('w', 'rU', 'U'):
+ with self.subTest(mode=mode):
+ with self.assertRaises(ValueError):
+ FileInput(mode=mode)
def test_stdin_binary_mode(self):
with mock.patch('sys.stdin') as m_stdin:
@@ -985,10 +977,6 @@
self.assertEqual(lines, expected_lines)
check('r', ['A\n', 'B\n', 'C\n', 'D\u20ac'])
- with self.assertWarns(DeprecationWarning):
- check('rU', ['A\n', 'B\n', 'C\n', 'D\u20ac'])
- with self.assertWarns(DeprecationWarning):
- check('U', ['A\n', 'B\n', 'C\n', 'D\u20ac'])
with self.assertRaises(ValueError):
check('rb', ['A\n', 'B\r\n', 'C\r', 'D\u20ac'])
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 1fe1cba..ad22dfe 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -3886,16 +3886,6 @@
self.assertEqual(f.mode, "wb")
f.close()
- with support.check_warnings(('', DeprecationWarning)):
- f = self.open(support.TESTFN, "U")
- self.assertEqual(f.name, support.TESTFN)
- self.assertEqual(f.buffer.name, support.TESTFN)
- self.assertEqual(f.buffer.raw.name, support.TESTFN)
- self.assertEqual(f.mode, "U")
- self.assertEqual(f.buffer.mode, "rb")
- self.assertEqual(f.buffer.raw.mode, "rb")
- f.close()
-
f = self.open(support.TESTFN, "w+")
self.assertEqual(f.mode, "w+")
self.assertEqual(f.buffer.mode, "rb+") # Does it really matter?
@@ -3909,6 +3899,13 @@
f.close()
g.close()
+ def test_removed_u_mode(self):
+ # "U" mode has been removed in Python 3.9
+ for mode in ("U", "rU", "r+U"):
+ with self.assertRaises(ValueError) as cm:
+ self.open(support.TESTFN, mode)
+ self.assertIn('invalid mode', str(cm.exception))
+
def test_io_after_close(self):
for kwargs in [
{"mode": "w"},