`repr()` does not raise TypeError when `__repr__` returns a non-string
Port, board and/or hardware
Unix port, Linux
MicroPython version
v1.27.0
Reproduction
class Foo:
def __repr__(self):
return True
print(repr(Foo()))
Expected behaviour
CPython v3.11.15:
TypeError: __repr__ returned non-string (type bool)
Observed behaviour
MicroPython v1.27.0:
True
Additional Information
repr() does not raise TypeError when a user-defined __repr__ method returns a non-string value. Instead, MicroPython silently converts and returns the value as a string. This is a CPython compatibility issue.
Root Cause
instance_print in objtype.c calls the user-defined __repr__ method via mp_call_function_1 and passes the result directly to mp_obj_print_helper without validating that the return value is a string.
CPython reference:
Objects/object.c#L439-L445// CPython validates that __repr__ returns a string, raises TypeError otherwise if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, "__repr__ returned non-string (type %.200s)", Py_TYPE(res)->tp_name); Py_DECREF(res); return NULL; }
Fix
Add a mp_obj_is_str(r) check after calling the __repr__ method in instance_print, and raise TypeError if the return value is not a string.
Code of Conduct
Yes, I agree
`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