From 0dd5d5218e151df4c9271bc4d537618bd40109b7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 10 Jun 2019 12:39:30 +0200 Subject: [PATCH] bpo-37214: Add a new EncodingWarning warning category open() now emits an EncodingWarning if called with encoding=None. --- Doc/library/exceptions.rst | 8 ++++++++ Include/pyerrors.h | 1 + Lib/_pyio.py | 6 ++++++ Lib/test/test_io.py | 5 +++++ .../2019-06-10-12-50-34.bpo-37214.5J2UJ3.rst | 3 +++ Modules/_io/textio.c | 4 ++++ Objects/exceptions.c | 9 +++++++++ 7 files changed, 36 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-06-10-12-50-34.bpo-37214.5J2UJ3.rst diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 52a505e0a0ff8f..11c9950f77615e 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -683,6 +683,14 @@ The following exceptions are used as warning categories; see the Base class for warnings generated by user code. +.. exception:: EncodingWarning + + Base class for warnings about encodings when those warnings are intended for + other Python developers. + + .. versionadded:: 3.9 + + .. exception:: DeprecationWarning Base class for warnings about deprecated features when those warnings are diff --git a/Include/pyerrors.h b/Include/pyerrors.h index 94af3cb3420ec6..cdf015cffc1d09 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -139,6 +139,7 @@ PyAPI_DATA(PyObject *) PyExc_WindowsError; /* Predefined warning categories */ PyAPI_DATA(PyObject *) PyExc_Warning; PyAPI_DATA(PyObject *) PyExc_UserWarning; +PyAPI_DATA(PyObject *) PyExc_EncodingWarning; PyAPI_DATA(PyObject *) PyExc_DeprecationWarning; PyAPI_DATA(PyObject *) PyExc_PendingDeprecationWarning; PyAPI_DATA(PyObject *) PyExc_SyntaxWarning; diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 43c24342ad6162..93857f5610a854 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -1986,6 +1986,12 @@ def __init__(self, buffer, encoding=None, errors=None, newline=None, line_buffering=False, write_through=False): self._check_newline(newline) if encoding is None: + import warnings + stack_level = 2 + if sys._getframe(1).f_code.co_name == "open": + # open(encoding=None): report the caller frame + stack_level += 1 + warnings.warn("encoding=None", EncodingWarning, stack_level) try: encoding = os.device_encoding(buffer.fileno()) except (AttributeError, UnsupportedOperation): diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 3a1f5ba5b6663d..395fb77daf6a34 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -3642,6 +3642,11 @@ def test_issue25862(self): t.write('x') t.tell() + def test_encoding_warning(self): + with support.check_warnings(('encoding=None', EncodingWarning)): + t = self.TextIOWrapper(self.BytesIO(b'test'), encoding=None) + t.close() + class MemviewBytesIO(io.BytesIO): '''A BytesIO object whose read method returns memoryviews diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-06-10-12-50-34.bpo-37214.5J2UJ3.rst b/Misc/NEWS.d/next/Core and Builtins/2019-06-10-12-50-34.bpo-37214.5J2UJ3.rst new file mode 100644 index 00000000000000..5f9260e7098837 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-06-10-12-50-34.bpo-37214.5J2UJ3.rst @@ -0,0 +1,3 @@ +Add a new :exc:`EncodingWarning` warning category. :func:`open` +(:func:`io.open`) now emits an :exc:`EncodingWarning` if called with +``encoding=None``. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 73b2756afce5e6..fa23a808a72dd6 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1109,6 +1109,10 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, } } if (encoding == NULL && self->encoding == NULL) { + if (PyErr_WarnEx(PyExc_EncodingWarning, "encoding=None", 0)) { + goto error; + } + PyObject *locale_module = _PyIO_get_locale_module(state); if (locale_module == NULL) goto catch_ImportError; diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 568d4959e3a0af..f0394c4664d932 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2375,6 +2375,13 @@ SimpleExtendsException(PyExc_Warning, UserWarning, "Base class for warnings generated by user code."); +/* + * EncodingWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, EncodingWarning, + "Base class for warnings about encodings."); + + /* * DeprecationWarning extends Warning */ @@ -2560,6 +2567,7 @@ _PyExc_Init(void) PRE_INIT(BufferError); PRE_INIT(Warning); PRE_INIT(UserWarning); + PRE_INIT(EncodingWarning); PRE_INIT(DeprecationWarning); PRE_INIT(PendingDeprecationWarning); PRE_INIT(SyntaxWarning); @@ -2701,6 +2709,7 @@ _PyBuiltins_AddExceptions(PyObject *bltinmod) POST_INIT(BufferError); POST_INIT(Warning); POST_INIT(UserWarning); + POST_INIT(EncodingWarning); POST_INIT(DeprecationWarning); POST_INIT(PendingDeprecationWarning); POST_INIT(SyntaxWarning);