Skip to content

Commit 9d03abf

Browse files
committed
Move __class__ attribute to object to make it work in more situations
1 parent d7f8961 commit 9d03abf

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

tests/snippets/types_snippet.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,14 @@
1515
assert type(cls) is metaclass
1616
assert type(metaclass) is type
1717

18+
assert issubclass(metaclass, type)
19+
assert isinstance(cls, type)
20+
21+
assert inst.__class__ is cls
22+
assert cls.__class__ is metaclass
23+
assert metaclass.__class__ is type
24+
assert type.__class__ is type
25+
assert None.__class__ is type(None)
26+
1827
assert isinstance(type, type)
1928
assert issubclass(type, type)

vm/src/obj/objfunction.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ pub fn init(context: &PyContext) {
2727
context.new_rustfunc(member_get),
2828
);
2929

30+
let data_descriptor_type = &context.data_descriptor_type;
31+
context.set_attr(
32+
&data_descriptor_type,
33+
"__get__",
34+
context.new_rustfunc(data_get),
35+
);
36+
context.set_attr(
37+
&data_descriptor_type,
38+
"__set__",
39+
context.new_rustfunc(data_set),
40+
);
41+
3042
let classmethod_type = &context.classmethod_type;
3143
context.set_attr(
3244
&classmethod_type,
@@ -83,6 +95,28 @@ fn member_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
8395
}
8496
}
8597

98+
fn data_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
99+
match args.shift().get_attr("fget") {
100+
Some(function) => vm.invoke(function, args),
101+
None => {
102+
println!("A");
103+
let attribute_error = vm.context().exceptions.attribute_error.clone();
104+
Err(vm.new_exception(attribute_error, String::from("Attribute Error")))
105+
}
106+
}
107+
}
108+
109+
fn data_set(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
110+
match args.shift().get_attr("fset") {
111+
Some(function) => vm.invoke(function, args),
112+
None => {
113+
println!("B");
114+
let attribute_error = vm.context().exceptions.attribute_error.clone();
115+
Err(vm.new_exception(attribute_error, String::from("Attribute Error")))
116+
}
117+
}
118+
}
119+
86120
// Classmethod type methods:
87121
fn classmethod_get(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
88122
trace!("classmethod.__get__ {:?}", args.args);

vm/src/obj/objobject.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ pub fn init(context: &PyContext) {
161161

162162
context.set_attr(&object, "__new__", context.new_rustfunc(new_instance));
163163
context.set_attr(&object, "__init__", context.new_rustfunc(object_init));
164+
context.set_attr(
165+
&object,
166+
"__class__",
167+
context.new_data_descriptor(object_class, object_class_setter),
168+
);
164169
context.set_attr(&object, "__eq__", context.new_rustfunc(object_eq));
165170
context.set_attr(&object, "__ne__", context.new_rustfunc(object_ne));
166171
context.set_attr(&object, "__lt__", context.new_rustfunc(object_lt));
@@ -190,6 +195,21 @@ fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
190195
Ok(vm.ctx.none())
191196
}
192197

198+
fn object_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
199+
arg_check!(
200+
vm,
201+
args,
202+
required = [(_obj, None), (owner, Some(vm.ctx.type_type()))]
203+
);
204+
Ok(owner.clone())
205+
}
206+
207+
fn object_class_setter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
208+
arg_check!(vm, args, required = [(instance, None), (_value, None)]);
209+
let type_repr = vm.to_pystr(&instance.typ())?;
210+
Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr)))
211+
}
212+
193213
fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
194214
match args.args[0].payload {
195215
PyObjectPayload::Class { ref dict, .. } | PyObjectPayload::Instance { ref dict, .. } => {

vm/src/obj/objtype.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ pub fn init(context: &PyContext) {
3939
"__mro__",
4040
context.new_member_descriptor(type_mro),
4141
);
42-
context.set_attr(
43-
&type_type,
44-
"__class__",
45-
context.new_member_descriptor(type_new),
46-
);
4742
context.set_attr(&type_type, "__repr__", context.new_rustfunc(type_repr));
4843
context.set_attr(
4944
&type_type,

vm/src/pyobject.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ pub struct PyContext {
150150
pub module_type: PyObjectRef,
151151
pub bound_method_type: PyObjectRef,
152152
pub member_descriptor_type: PyObjectRef,
153+
pub data_descriptor_type: PyObjectRef,
153154
pub object: PyObjectRef,
154155
pub exceptions: exceptions::ExceptionZoo,
155156
}
@@ -199,6 +200,8 @@ impl PyContext {
199200
let bound_method_type = create_type("method", &type_type, &object_type, &dict_type);
200201
let member_descriptor_type =
201202
create_type("member_descriptor", &type_type, &object_type, &dict_type);
203+
let data_descriptor_type =
204+
create_type("data_descriptor", &type_type, &object_type, &dict_type);
202205
let str_type = create_type("str", &type_type, &object_type, &dict_type);
203206
let list_type = create_type("list", &type_type, &object_type, &dict_type);
204207
let set_type = create_type("set", &type_type, &object_type, &dict_type);
@@ -285,6 +288,7 @@ impl PyContext {
285288
module_type,
286289
bound_method_type,
287290
member_descriptor_type,
291+
data_descriptor_type,
288292
type_type,
289293
exceptions,
290294
};
@@ -449,6 +453,10 @@ impl PyContext {
449453
pub fn member_descriptor_type(&self) -> PyObjectRef {
450454
self.member_descriptor_type.clone()
451455
}
456+
pub fn data_descriptor_type(&self) -> PyObjectRef {
457+
self.data_descriptor_type.clone()
458+
}
459+
452460
pub fn type_type(&self) -> PyObjectRef {
453461
self.type_type.clone()
454462
}
@@ -658,6 +666,20 @@ impl PyContext {
658666
self.new_instance(self.member_descriptor_type(), Some(dict))
659667
}
660668

669+
pub fn new_data_descriptor<
670+
G: 'static + Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult,
671+
S: 'static + Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult,
672+
>(
673+
&self,
674+
getter: G,
675+
setter: S,
676+
) -> PyObjectRef {
677+
let mut dict = PyAttributes::new();
678+
dict.insert("fget".to_string(), self.new_rustfunc(getter));
679+
dict.insert("fset".to_string(), self.new_rustfunc(setter));
680+
self.new_instance(self.data_descriptor_type(), Some(dict))
681+
}
682+
661683
pub fn new_instance(&self, class: PyObjectRef, dict: Option<PyAttributes>) -> PyObjectRef {
662684
let dict = if let Some(dict) = dict {
663685
dict

0 commit comments

Comments
 (0)