diff --git a/Lib/string.py b/Lib/string.py --- a/Lib/string.py +++ b/Lib/string.py @@ -299,3 +299,15 @@ obj = obj[i] return obj, first + +# Control whether str(bytes) raises an exception. Thread local. +from contextlib import contextmanager +@contextmanager +def StrBytesRaises(): + previous = _string.get_strbytes_raises() + _string.set_strbytes_raises(True) + try: + yield + finally: + _string.set_strbytes_raises(previous) + \ No newline at end of file diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1375,6 +1375,19 @@ "str() on a bytes instance", 1)) return NULL; } + { + PyObject *dict = PyThreadState_GetDict(); + if (dict != NULL) { + PyObject *strbytes_raises = PyDict_GetItemString(dict, "strbytes_raises"); + if (PyErr_Occurred() || strbytes_raises == NULL) { + PyErr_Clear(); + } else if (strbytes_raises == Py_True) { + PyErr_SetString(PyExc_BytesWarning, + "str() on a bytes instance"); + return NULL; + } + } + } return bytes_repr(op); } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -15413,6 +15413,52 @@ return copy; } +static PyObject * +sys_get_strbytes_raises(PyObject *self, PyObject *noargs) +{ + PyObject *dict, *strbytes_raises; + + dict = PyThreadState_GetDict(); + if (dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "cannot get thread state"); + return NULL; + } + + strbytes_raises = PyDict_GetItemString(dict, "strbytes_raises"); + + if (PyErr_Occurred() || strbytes_raises == NULL) { + PyErr_Clear(); + Py_INCREF(Py_False); + return Py_False; + } + + return strbytes_raises; +} + +static PyObject * +sys_set_strbytes_raises(PyObject *self, PyObject *value) +{ + PyObject *dict; + + if(!PyBool_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "not a bool"); + return NULL; + } + + dict = PyThreadState_GetDict(); + if (dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "cannot get thread state"); + return NULL; + } + + PyDict_SetItemString(dict, "strbytes_raises", value); + + Py_RETURN_NONE; +} + /* A _string module, to export formatter_parser and formatter_field_name_split to the string.Formatter class implemented in Python. */ @@ -15421,6 +15467,8 @@ METH_O, PyDoc_STR("split the argument as a field name")}, {"formatter_parser", (PyCFunction) formatter_parser, METH_O, PyDoc_STR("parse the argument as a format string")}, + {"get_strbytes_raises", sys_get_strbytes_raises, METH_NOARGS, NULL}, + {"set_strbytes_raises", sys_set_strbytes_raises, METH_O, NULL}, {NULL, NULL} };