Skip to content

Commit 5b41cc4

Browse files
committed
Fix subclasses of string. (Fixes RustPython#130)
1 parent 964a041 commit 5b41cc4

File tree

2 files changed

+39
-12
lines changed

2 files changed

+39
-12
lines changed

tests/snippets/subclass_str.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from testutils import assertRaises
2+
3+
x = "An interesting piece of text"
4+
assert x is str(x)
5+
6+
class Stringy(str):
7+
def __new__(cls, value=""):
8+
return str.__new__(cls, value)
9+
10+
def __init__(self, value):
11+
self.x = "substr"
12+
13+
y = Stringy(1)
14+
assert type(y) is Stringy, "Type of Stringy should be stringy"
15+
assert type(str(y)) is str, "Str of a str-subtype should be a str."
16+
17+
assert y + " other" == "1 other"
18+
assert y.x == "substr"
19+
20+
## Base strings currently get an attribute dict, but shouldn't.
21+
# with assertRaises(AttributeError):
22+
# "hello".x = 5

vm/src/obj/objstr.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ use unicode_segmentation::UnicodeSegmentation;
77

88
use crate::format::{FormatParseError, FormatPart, FormatString};
99
use crate::pyobject::{
10-
IntoPyObject, OptionalArg, PyContext, PyFuncArgs, PyIterable, PyObjectRef, PyRef, PyResult,
11-
PyValue, TypeProtocol,
10+
IdProtocol, IntoPyObject, OptionalArg, PyContext, PyFuncArgs, PyIterable, PyObjectRef, PyRef,
11+
PyResult, PyValue, TryFromObject, TypeProtocol,
1212
};
1313
use crate::vm::VirtualMachine;
1414

1515
use super::objint;
1616
use super::objsequence::PySliceableSequence;
1717
use super::objslice::PySlice;
18-
use super::objtype;
18+
use super::objtype::{self, PyClassRef};
1919

2020
#[derive(Clone, Debug)]
2121
pub struct PyString {
@@ -788,16 +788,21 @@ fn perform_format(
788788
// TODO: should with following format
789789
// class str(object='')
790790
// class str(object=b'', encoding='utf-8', errors='strict')
791-
fn str_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
792-
if args.args.len() == 1 {
793-
return Ok(vm.new_str("".to_string()));
794-
}
795-
796-
if args.args.len() > 2 {
797-
panic!("str expects exactly one parameter");
791+
fn str_new(
792+
cls: PyClassRef,
793+
object: OptionalArg<PyObjectRef>,
794+
vm: &mut VirtualMachine,
795+
) -> PyResult<PyStringRef> {
796+
let string = match object {
797+
OptionalArg::Present(ref input) => vm.to_str(input)?,
798+
OptionalArg::Missing => vm.new_str("".to_string()),
798799
};
799-
800-
vm.to_str(&args.args[1])
800+
if string.typ().is(&cls) {
801+
TryFromObject::try_from_object(vm, string)
802+
} else {
803+
let payload = string.payload::<PyString>().unwrap();
804+
PyRef::new_with_type(vm, payload.clone(), cls)
805+
}
801806
}
802807

803808
impl PySliceableSequence for String {

0 commit comments

Comments
 (0)