diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index f4bd961017b0ed..032b910a280083 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -1910,6 +1910,18 @@ def test_create(self): self.assertGreater(writer.get_buffer()[0], len(s)) self.assertEqual(writer.finish(), s) + def test_str_subclass(self): + # The read-only optimization must not return a str subclass + class MyStr(str): + def __str__(self): + return self + + writer = self.create_writer(0) + writer.write_str(MyStr('abc')) + result = writer.finish() + self.assertEqual(result, 'abc') + self.assertIs(type(result), str) + def test_repr_null(self): writer = self.create_writer(0) writer.write_utf8(b'var=', -1) diff --git a/Lib/test/test_io/test_memoryio.py b/Lib/test/test_io/test_memoryio.py index b378505aa8f7db..b6f3aa93e7aa43 100644 --- a/Lib/test/test_io/test_memoryio.py +++ b/Lib/test/test_io/test_memoryio.py @@ -1118,7 +1118,11 @@ def __str__(self): s = MyStr("correct") memio = self.ioclass() memio.write(s) - self.assertEqual(memio.getvalue(), "correct") + value = memio.getvalue() + self.assertEqual(value, "correct") + self.assertIs(type(value), str) + memio.write("!") + self.assertEqual(memio.getvalue(), "correct!") # Also test the fast path where pos == string_size (STATE_ACCUMULATING) memio2 = self.ioclass() diff --git a/Objects/unicode_writer.c b/Objects/unicode_writer.c index d6564ce84ed54e..c1a2af4d9ac1fe 100644 --- a/Objects/unicode_writer.c +++ b/Objects/unicode_writer.c @@ -313,7 +313,7 @@ _PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, PyObject *str) Py_UCS4 maxchar = PyUnicode_MAX_CHAR_VALUE(str); if (maxchar > writer->maxchar || len > writer->size - writer->pos) { - if (writer->buffer == NULL) { + if (writer->buffer == NULL && PyUnicode_CheckExact(str)) { assert(_PyUnicode_CheckConsistency(str, 1)); writer->readonly = 1; writer->buffer = Py_NewRef(str);