Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Lib/test/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,7 @@ def __bytes__(self):
self.assertEqual(BytesSubclass(StrWithBytes(OtherBytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
# Issue #24731
self.assertTypedEqual(bytes(WithBytes(BytesSubclass(b'abc'))), BytesSubclass(b'abc'))
self.assertTypedEqual(bytes(WithBytes(BytesSubclass(b'abc'))), b'abc')
self.assertTypedEqual(BytesSubclass(WithBytes(BytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
self.assertTypedEqual(BytesSubclass(WithBytes(OtherBytesSubclass(b'abc'))),
Expand All @@ -1078,8 +1078,7 @@ def __bytes__(self):
self.assertTypedEqual(bytes(BytesWithBytes(b'abc')), b'abc')
self.assertTypedEqual(BytesSubclass(BytesWithBytes(b'abc')),
BytesSubclass(b'abc'))
self.assertTypedEqual(bytes(BytesWithBytes(BytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
self.assertTypedEqual(bytes(BytesWithBytes(BytesSubclass(b'abc'))), b'abc')
self.assertTypedEqual(BytesSubclass(BytesWithBytes(BytesSubclass(b'abc'))),
BytesSubclass(b'abc'))
self.assertTypedEqual(BytesSubclass(BytesWithBytes(OtherBytesSubclass(b'abc'))),
Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_capi/test_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ def test_object_str(self):
self.assertTypedEqual(object_str('\U0001f40d'), '\U0001f40d')
self.assertTypedEqual(object_str(StrSubclass('abc')), 'abc')
self.assertTypedEqual(object_str(WithStr('abc')), 'abc')
self.assertTypedEqual(object_str(WithStr(StrSubclass('abc'))), StrSubclass('abc'))
self.assertTypedEqual(object_str(WithStr(StrSubclass('abc'))), 'abc')
self.assertTypedEqual(object_str(WithRepr('<abc>')), '<abc>')
self.assertTypedEqual(object_str(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(object_str(WithRepr(StrSubclass('<abc>'))), '<abc>')
self.assertTypedEqual(object_str(NULL), '<NULL>')

def test_object_repr(self):
Expand All @@ -93,9 +93,9 @@ def test_object_repr(self):
self.assertTypedEqual(object_repr('\U0001f40d'), "'\U0001f40d'")
self.assertTypedEqual(object_repr(StrSubclass('abc')), "'abc'")
self.assertTypedEqual(object_repr(WithRepr('<abc>')), '<abc>')
self.assertTypedEqual(object_repr(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(object_repr(WithRepr(StrSubclass('<abc>'))), '<abc>')
self.assertTypedEqual(object_repr(WithRepr('<\U0001f40d>')), '<\U0001f40d>')
self.assertTypedEqual(object_repr(WithRepr(StrSubclass('<\U0001f40d>'))), StrSubclass('<\U0001f40d>'))
self.assertTypedEqual(object_repr(WithRepr(StrSubclass('<\U0001f40d>'))), '<\U0001f40d>')
self.assertTypedEqual(object_repr(NULL), '<NULL>')

def test_object_ascii(self):
Expand All @@ -106,7 +106,7 @@ def test_object_ascii(self):
self.assertTypedEqual(object_ascii('\U0001f40d'), r"'\U0001f40d'")
self.assertTypedEqual(object_ascii(StrSubclass('abc')), "'abc'")
self.assertTypedEqual(object_ascii(WithRepr('<abc>')), '<abc>')
self.assertTypedEqual(object_ascii(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(object_ascii(WithRepr(StrSubclass('<abc>'))), '<abc>')
self.assertTypedEqual(object_ascii(WithRepr('<\U0001f40d>')), r'<\U0001f40d>')
self.assertTypedEqual(object_ascii(WithRepr(StrSubclass('<\U0001f40d>'))), r'<\U0001f40d>')
self.assertTypedEqual(object_ascii(NULL), '<NULL>')
Expand All @@ -118,7 +118,7 @@ def test_object_bytes(self):
self.assertTypedEqual(object_bytes(b'abc'), b'abc')
self.assertTypedEqual(object_bytes(BytesSubclass(b'abc')), b'abc')
self.assertTypedEqual(object_bytes(WithBytes(b'abc')), b'abc')
self.assertTypedEqual(object_bytes(WithBytes(BytesSubclass(b'abc'))), BytesSubclass(b'abc'))
self.assertTypedEqual(object_bytes(WithBytes(BytesSubclass(b'abc'))), b'abc')
self.assertTypedEqual(object_bytes(bytearray(b'abc')), b'abc')
self.assertTypedEqual(object_bytes(memoryview(b'abc')), b'abc')
self.assertTypedEqual(object_bytes([97, 98, 99]), b'abc')
Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_str.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def test_ascii(self):
self.assertTypedEqual(ascii('\U0001f40d'), r"'\U0001f40d'")
self.assertTypedEqual(ascii(StrSubclass('abc')), "'abc'")
self.assertTypedEqual(ascii(WithRepr('<abc>')), '<abc>')
self.assertTypedEqual(ascii(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(ascii(WithRepr(StrSubclass('<abc>'))), '<abc>')
self.assertTypedEqual(ascii(WithRepr('<\U0001f40d>')), r'<\U0001f40d>')
self.assertTypedEqual(ascii(WithRepr(StrSubclass('<\U0001f40d>'))), r'<\U0001f40d>')
self.assertRaises(TypeError, ascii, WithRepr(b'byte-repr'))
Expand Down Expand Up @@ -193,9 +193,9 @@ def test_repr(self):
self.assertTypedEqual(repr('\U0001f40d'), "'\U0001f40d'")
self.assertTypedEqual(repr(StrSubclass('abc')), "'abc'")
self.assertTypedEqual(repr(WithRepr('<abc>')), '<abc>')
self.assertTypedEqual(repr(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(repr(WithRepr(StrSubclass('<abc>'))), '<abc>')
self.assertTypedEqual(repr(WithRepr('<\U0001f40d>')), '<\U0001f40d>')
self.assertTypedEqual(repr(WithRepr(StrSubclass('<\U0001f40d>'))), StrSubclass('<\U0001f40d>'))
self.assertTypedEqual(repr(WithRepr(StrSubclass('<\U0001f40d>'))), '<\U0001f40d>')
self.assertRaises(TypeError, repr, WithRepr(b'byte-repr'))

def test_iterators(self):
Expand Down Expand Up @@ -2401,23 +2401,23 @@ def __str__(self):
return self.value

self.assertTypedEqual(str(WithStr('abc')), 'abc')
self.assertTypedEqual(str(WithStr(StrSubclass('abc'))), StrSubclass('abc'))
self.assertTypedEqual(str(WithStr(StrSubclass('abc'))), 'abc')
self.assertTypedEqual(StrSubclass(WithStr('abc')), StrSubclass('abc'))
self.assertTypedEqual(StrSubclass(WithStr(StrSubclass('abc'))),
StrSubclass('abc'))
self.assertTypedEqual(StrSubclass(WithStr(OtherStrSubclass('abc'))),
StrSubclass('abc'))

self.assertTypedEqual(str(StrWithStr('abc')), 'abc')
self.assertTypedEqual(str(StrWithStr(StrSubclass('abc'))), StrSubclass('abc'))
self.assertTypedEqual(str(StrWithStr(StrSubclass('abc'))), 'abc')
self.assertTypedEqual(StrSubclass(StrWithStr('abc')), StrSubclass('abc'))
self.assertTypedEqual(StrSubclass(StrWithStr(StrSubclass('abc'))),
StrSubclass('abc'))
self.assertTypedEqual(StrSubclass(StrWithStr(OtherStrSubclass('abc'))),
StrSubclass('abc'))

self.assertTypedEqual(str(WithRepr('<abc>')), '<abc>')
self.assertTypedEqual(str(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
self.assertTypedEqual(str(WithRepr(StrSubclass('<abc>'))), '<abc>')
self.assertTypedEqual(StrSubclass(WithRepr('<abc>')), StrSubclass('<abc>'))
self.assertTypedEqual(StrSubclass(WithRepr(StrSubclass('<abc>'))),
StrSubclass('<abc>'))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:c:func:`PyObject_Str`, :c:func:`PyObject_Repr` and :func:`PyObject_ASCII`
now always return an instance of :class:`str`, even if ``__str__()`` or
``__repr__()`` return an instance of :class:`!str` subclass.
:func:`PyObject_Bytes` now always returns an instance of :class:`bytes`,
even if ``__bytes__()`` returns an instance of :class:`!bytes` subclass.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:func:`str`, :func:`repr` and :func:`ascii` now always return an instance of
:class:`str`, even if ``__str__()`` or ``__repr__()`` return an instance of
:class:`!str` subclass. :func:`bytes` now always returns an instance of
:class:`bytes`, even if ``__bytes__()`` returns an instance of
:class:`!bytes` subclass.
19 changes: 13 additions & 6 deletions Objects/bytesobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2617,12 +2617,19 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding,
Py_DECREF(func);
if (bytes == NULL)
return NULL;
if (!PyBytes_Check(bytes)) {
PyErr_Format(PyExc_TypeError,
"__bytes__ returned non-bytes (type %.200s)",
Py_TYPE(bytes)->tp_name);
Py_DECREF(bytes);
return NULL;
if (!PyBytes_CheckExact(bytes)) {
if (!PyBytes_Check(bytes)) {
PyErr_Format(PyExc_TypeError,
"__bytes__ returned non-bytes (type %.200s)",
Py_TYPE(bytes)->tp_name);
Py_DECREF(bytes);
return NULL;
}
Py_SETREF(bytes, PyBytes_FromStringAndSize(PyBytes_AS_STRING(bytes),
PyBytes_GET_SIZE(bytes)));
if (bytes == NULL) {
return NULL;
}
}
}
else if (PyErr_Occurred())
Expand Down
15 changes: 13 additions & 2 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -674,8 +674,8 @@ PyObject_Repr(PyObject *v)
res = (*Py_TYPE(v)->tp_repr)(v);
_Py_LeaveRecursiveCallTstate(tstate);

if (res == NULL) {
return NULL;
if (res == NULL || PyUnicode_CheckExact(res)) {
return res;
}
if (!PyUnicode_Check(res)) {
_PyErr_Format(tstate, PyExc_TypeError,
Expand All @@ -684,6 +684,7 @@ PyObject_Repr(PyObject *v)
Py_DECREF(res);
return NULL;
}
Py_SETREF(res, _PyUnicode_Copy(res));
return res;
}

Expand Down Expand Up @@ -726,6 +727,10 @@ PyObject_Str(PyObject *v)
if (res == NULL) {
return NULL;
}
if (PyUnicode_CheckExact(res)) {
assert(_PyUnicode_CheckConsistency(res, 1));
return res;
}
if (!PyUnicode_Check(res)) {
_PyErr_Format(tstate, PyExc_TypeError,
"__str__ returned non-string (type %.200s)",
Expand All @@ -734,6 +739,7 @@ PyObject_Str(PyObject *v)
return NULL;
}
assert(_PyUnicode_CheckConsistency(res, 1));
Py_SETREF(res, _PyUnicode_Copy(res));
return res;
}

Expand Down Expand Up @@ -782,13 +788,18 @@ PyObject_Bytes(PyObject *v)
Py_DECREF(func);
if (result == NULL)
return NULL;
if (PyBytes_CheckExact(result)) {
return result;
}
if (!PyBytes_Check(result)) {
PyErr_Format(PyExc_TypeError,
"__bytes__ returned non-bytes (type %.200s)",
Py_TYPE(result)->tp_name);
Py_DECREF(result);
return NULL;
}
Py_SETREF(result, PyBytes_FromStringAndSize(PyBytes_AS_STRING(result),
PyBytes_GET_SIZE(result)));
return result;
}
else if (PyErr_Occurred())
Expand Down