← index #18942PR #18955
Related · high · value 4.181
QUERY · ISSUE

`repr()` does not preserve `str` subclass type returned by `__repr__`

openby jseop-limopened 2026-03-17updated 2026-03-20
bug

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

CANDIDATE · PULL REQUEST

tests/cpydiff: Add str return type and subclass preservation differences.

openby jseop-limopened 2026-03-20updated 2026-03-21
tests

Summary

Document two str()-related CPython compatibility differences in tests/cpydiff/:

  1. types_str_strrettype.py: __str__/__repr__ returning a non-string type does not raise TypeError. MicroPython silently converts and prints the value.
    Relates to #18941.

  2. types_str_subclassret.py: str() does not preserve str subclass type from __str__/__repr__ return value. MicroPython always returns a plain str instance.
    Relates to #18942.

Testing

Verified that each test produces different output between CPython and MicroPython:

  • types_str_strrettype.py: CPython raises TypeError, MicroPython prints True.
  • 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.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied