Description
ascii() always creates a new plain str from the repr result, even when the repr is already ASCII. CPython's PyObject_ASCII returns the repr object directly when it's already ASCII, preserving str subclass types. This is a CPython compatibility issue.
Root Cause
builtin_ascii() unconditionally converts the repr result to a new AsciiString via to_ascii(), which then becomes a plain str through ToPyObject. The same pattern exists in PyObject::ascii().
CPython reference: object.c#L848-L849
// Key branch: return repr directly when it's already ASCII
if (PyUnicode_IS_ASCII(repr))
return repr;
Fix
Add an ASCII check before to_ascii() — if the repr is already ASCII, return the repr object directly instead of creating a new string.
Reproduction
class MyStr(str):
pass
class Foo:
def __repr__(self):
return MyStr('hello')
result = ascii(Foo())
print(type(result))
Output
RustPython:
CPython:
Environment
- RustPython d248a04 (Python 3.14.0)
- CPython 3.14.3
- OS: Debian 12
Description
ascii()always creates a new plainstrfrom the repr result, even when the repr is already ASCII. CPython'sPyObject_ASCIIreturns the repr object directly when it's already ASCII, preserving str subclass types. This is a CPython compatibility issue.Root Cause
builtin_ascii()unconditionally converts the repr result to a newAsciiStringviato_ascii(), which then becomes a plainstrthroughToPyObject. The same pattern exists inPyObject::ascii().Fix
Add an ASCII check before
to_ascii()— if the repr is already ASCII, return the repr object directly instead of creating a new string.Reproduction
Output
RustPython:
CPython:
Environment