mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Preserve str subclass type returned by __str__ / __repr__ (#7701)
Closes #7450. CPython's unicode_new_impl returns the PyObject_Str result as-is when type == &PyUnicode_Type, only invoking unicode_subtype_new for actual str subclasses. RustPython's PyStr::Constructor stripped the result via Self::from(s.as_wtf8().to_owned()) and re-materialized through into_ref_with_type, dropping the subclass type even when cls is exactly str. Add a slot_new branch that returns input.str(vm)? directly when cls is str_type with no encoding. Subtype construction and the bytes-decoding path are unchanged. Unmasks test_str.StrTest.test_conversion (11 assertTypedEqual cases).
This commit is contained in:
1
Lib/test/test_str.py
vendored
1
Lib/test/test_str.py
vendored
@@ -2414,7 +2414,6 @@ class StrTest(string_tests.StringLikeTest,
|
||||
else:
|
||||
self.fail("Should have raised UnicodeDecodeError")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: <class 'str'> is not <class 'test.test_str.StrSubclass'>
|
||||
def test_conversion(self):
|
||||
# Make sure __str__() works properly
|
||||
class StrWithStr(str):
|
||||
|
||||
@@ -406,6 +406,18 @@ impl Constructor for PyStr {
|
||||
}
|
||||
|
||||
let args: Self::Args = func_args.bind(vm)?;
|
||||
|
||||
// CPython parity: when cls is exactly str, return the __str__ / __repr__
|
||||
// result as-is so any str subclass type the user returned is preserved
|
||||
// (matches unicode_new_impl which only invokes unicode_subtype_new when
|
||||
// type != &PyUnicode_Type).
|
||||
if cls.is(vm.ctx.types.str_type)
|
||||
&& args.encoding.is_missing()
|
||||
&& let OptionalArg::Present(input) = &args.object
|
||||
{
|
||||
return Ok(input.str(vm)?.into());
|
||||
}
|
||||
|
||||
let payload = Self::py_new(&cls, args, vm)?;
|
||||
payload.into_ref_with_type(vm, cls).map(Into::into)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user