`repr()` does not preserve `str` subclass type returned by `__repr__`
Port, board and/or hardware
Unix port, Linux
MicroPython version
MicroPython v1.27.0 on 2026-03-12
Reproduction
class MyStr(str):
pass
class Foo:
def __repr__(self):
return MyStr("hello")
result = repr(Foo())
print(type(result))
Expected behaviour
CPython 3.11.15:
<class '__main__.MyStr'>
Observed behaviour
MicroPython v1.27.0:
<class 'str'>
Additional Information
When __repr__ returns an instance of a str subclass, repr() discards the subclass type and returns a plain str. CPython preserves the original subclass type. This is a CPython compatibility issue.
Root Cause
mp_builtin_repr() serializes the __repr__ result into a text buffer (vstr) via mp_obj_print_helper(), then constructs a new plain str from that buffer using mp_obj_new_str_from_utf8_vstr(), which hardcodes &mp_type_str as the type. This discards the original str subclass type.
CPython reference: object.c#L402-L451
// CPython returns the __repr__ result directly, preserving str subclass type res = (*Py_TYPE(v)->tp_repr)(v); if (!PyUnicode_Check(res)) { // PyUnicode_Check accepts str subclasses // raise TypeError... } return res; // original object returned as-is
Fix
Document this as a known difference in tests/cpydiff/ (similar to the existing int subclass entry "No int conversion for int-derived types available"), or change mp_builtin_repr() to return the __repr__ result object directly when it is a str (or subclass) instead of serializing through a buffer.
Code of Conduct
Yes, I agree
tests/cpydiff: Add str return type and subclass preservation differences.
Summary
Document two str()-related CPython compatibility differences in tests/cpydiff/:
-
types_str_strrettype.py:__str__/__repr__returning a non-string type does not raiseTypeError. MicroPython silently converts and prints the value.
Relates to #18941. -
types_str_subclassret.py:str()does not preservestrsubclass type from__str__/__repr__return value. MicroPython always returns a plainstrinstance.
Relates to #18942.
Testing
Verified that each test produces different output between CPython and MicroPython:
types_str_strrettype.py: CPython raisesTypeError, MicroPython printsTrue.types_str_subclassret.py: CPython prints<class '__main__.MyStr'>, MicroPython prints<class 'str'>.
Tested on unix port, Linux.
Generative AI
I used generative AI tools when creating this PR, but a human has checked the code and is responsible for the code and the description above.