From 864143ac468da5d69ea7a9aca06bd2dc2a53f71b Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 31 Mar 2021 13:57:48 +0900 Subject: [PATCH 1/4] test OpenWrapper() emits EncodingWarning for right place --- Lib/test/test_io.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 6a9ce39f08eb581..db8b0392d735ef1 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -4267,21 +4267,22 @@ def test_check_encoding_warning(self): filename = __file__ code = textwrap.dedent(f'''\ import sys - from {mod} import open, TextIOWrapper + try: + from {mod} import OpenWrapper as open + except ImportError: + from {mod} import open import pathlib - with open({filename!r}) as f: # line 5 + with open({filename!r}) as f: # line 8 pass - pathlib.Path({filename!r}).read_text() # line 8 + pathlib.Path({filename!r}).read_text() # line 11 ''') proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code) warnings = proc.err.splitlines() self.assertEqual(len(warnings), 2) - self.assertTrue( - warnings[0].startswith(b":5: EncodingWarning: ")) - self.assertTrue( - warnings[1].startswith(b":8: EncodingWarning: ")) + self.assertRegex(warnings[0], br"\A:8: EncodingWarning: ") + self.assertRegex(warnings[1], br"\A:11: EncodingWarning: ") class CMiscIOTest(MiscIOTest): From 77ca116457cbda181898361e1d2a6810586e03a7 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 31 Mar 2021 14:35:28 +0900 Subject: [PATCH 2/4] Fix OpenWrapper --- Lib/_pyio.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index ba0b0a29b5013d5..9bc8900270c6b44 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -323,8 +323,12 @@ class OpenWrapper: """ __doc__ = DocDescriptor() - def __new__(cls, *args, **kwargs): - return open(*args, **kwargs) + def __new__(cls, file, mode="r", buffering=-1, encoding=None, + *args, **kwargs): + # Emit the EncodingWarning for the caller. + if "b" not in mode: + encoding = text_encoding(encoding) + return open(file, mode, buffering, encoding, *args, **kwargs) # In normal operation, both `UnsupportedOperation`s should be bound to the From 38863c38fb5746b949db3929d62fa3538687da43 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 31 Mar 2021 19:56:04 +0900 Subject: [PATCH 3/4] Use @staticmethod --- Lib/_pyio.py | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 9bc8900270c6b44..79a9b4707f38e0f 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -63,6 +63,7 @@ def text_encoding(encoding, stacklevel=2): return encoding +@staticmethod def open(file, mode="r", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None): @@ -304,31 +305,8 @@ def _open_code_with_warning(path): open_code = _open_code_with_warning -class DocDescriptor: - """Helper for builtins.open.__doc__ - """ - def __get__(self, obj, typ=None): - return ( - "open(file, mode='r', buffering=-1, encoding=None, " - "errors=None, newline=None, closefd=True)\n\n" + - open.__doc__) - -class OpenWrapper: - """Wrapper for builtins.open - - Trick so that open won't become a bound method when stored - as a class variable (as dbm.dumb does). - - See initstdio() in Python/pylifecycle.c. - """ - __doc__ = DocDescriptor() - - def __new__(cls, file, mode="r", buffering=-1, encoding=None, - *args, **kwargs): - # Emit the EncodingWarning for the caller. - if "b" not in mode: - encoding = text_encoding(encoding) - return open(file, mode, buffering, encoding, *args, **kwargs) +# For backward compatibility +OpenWrapper = open # In normal operation, both `UnsupportedOperation`s should be bound to the From facef8cf29075cf368b7babf5358a83f4f63a97d Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 31 Mar 2021 19:59:57 +0900 Subject: [PATCH 4/4] Remove use of OpenWrapper --- Lib/test/test_io.py | 13 +++++-------- Python/pylifecycle.c | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index e9611db413c28af..0fea7221121e2a3 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -4256,22 +4256,19 @@ def test_check_encoding_warning(self): filename = __file__ code = textwrap.dedent(f'''\ import sys - try: - from {mod} import OpenWrapper as open - except ImportError: - from {mod} import open + from {mod} import open import pathlib - with open({filename!r}) as f: # line 8 + with open({filename!r}) as f: # line 5 pass - pathlib.Path({filename!r}).read_text() # line 11 + pathlib.Path({filename!r}).read_text() # line 8 ''') proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code) warnings = proc.err.splitlines() self.assertEqual(len(warnings), 2) - self.assertRegex(warnings[0], br"\A:8: EncodingWarning: ") - self.assertRegex(warnings[1], br"\A:11: EncodingWarning: ") + self.assertRegex(warnings[0], br"\A:5: EncodingWarning: ") + self.assertRegex(warnings[1], br"\A:8: EncodingWarning: ") class CMiscIOTest(MiscIOTest): diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8309477806f7a3b..8061b33f153904b 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2213,7 +2213,7 @@ create_stdio(const PyConfig *config, PyObject* io, return NULL; } -/* Set builtins.open to io.OpenWrapper */ +/* Set builtins.open to io.open */ static PyStatus init_set_builtins_open(void) { @@ -2229,7 +2229,7 @@ init_set_builtins_open(void) goto error; } - if (!(wrapper = PyObject_GetAttrString(iomod, "OpenWrapper"))) { + if (!(wrapper = PyObject_GetAttrString(iomod, "open"))) { goto error; }