Skip to content

Commit 406ec46

Browse files
authored
Merge pull request #619 from skinny121/class_property
Fix __class__
2 parents 62a2344 + 4b1cd72 commit 406ec46

File tree

5 files changed

+84
-5
lines changed

5 files changed

+84
-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: 32 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,26 @@ 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+
let attribute_error = vm.context().exceptions.attribute_error.clone();
103+
Err(vm.new_exception(attribute_error, String::from("Attribute Error")))
104+
}
105+
}
106+
}
107+
108+
fn data_set(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
109+
match args.shift().get_attr("fset") {
110+
Some(function) => vm.invoke(function, args),
111+
None => {
112+
let attribute_error = vm.context().exceptions.attribute_error.clone();
113+
Err(vm.new_exception(attribute_error, String::from("Attribute Error")))
114+
}
115+
}
116+
}
117+
86118
// Classmethod type methods:
87119
fn classmethod_get(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
88120
trace!("classmethod.__get__ {:?}", args.args);

vm/src/obj/objobject.rs

Lines changed: 19 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,20 @@ fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
190195
Ok(vm.ctx.none())
191196
}
192197

198+
// TODO Use PyClassRef for owner to enforce type
199+
fn object_class(_obj: PyObjectRef, owner: PyObjectRef, _vm: &mut VirtualMachine) -> PyObjectRef {
200+
owner
201+
}
202+
203+
fn object_class_setter(
204+
instance: PyObjectRef,
205+
_value: PyObjectRef,
206+
vm: &mut VirtualMachine,
207+
) -> PyResult {
208+
let type_repr = vm.to_pystr(&instance.typ())?;
209+
Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr)))
210+
}
211+
193212
fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
194213
match args.args[0].payload {
195214
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: 24 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
}
@@ -201,6 +202,8 @@ impl PyContext {
201202
let bound_method_type = create_type("method", &type_type, &object_type, &dict_type);
202203
let member_descriptor_type =
203204
create_type("member_descriptor", &type_type, &object_type, &dict_type);
205+
let data_descriptor_type =
206+
create_type("data_descriptor", &type_type, &object_type, &dict_type);
204207
let str_type = create_type("str", &type_type, &object_type, &dict_type);
205208
let list_type = create_type("list", &type_type, &object_type, &dict_type);
206209
let set_type = create_type("set", &type_type, &object_type, &dict_type);
@@ -298,6 +301,7 @@ impl PyContext {
298301
module_type,
299302
bound_method_type,
300303
member_descriptor_type,
304+
data_descriptor_type,
301305
type_type,
302306
exceptions,
303307
};
@@ -462,6 +466,10 @@ impl PyContext {
462466
pub fn member_descriptor_type(&self) -> PyObjectRef {
463467
self.member_descriptor_type.clone()
464468
}
469+
pub fn data_descriptor_type(&self) -> PyObjectRef {
470+
self.data_descriptor_type.clone()
471+
}
472+
465473
pub fn type_type(&self) -> PyObjectRef {
466474
self.type_type.clone()
467475
}
@@ -671,6 +679,22 @@ impl PyContext {
671679
self.new_instance(self.member_descriptor_type(), Some(dict))
672680
}
673681

682+
pub fn new_data_descriptor<
683+
G: IntoPyNativeFunc<(I, PyObjectRef), T>,
684+
S: IntoPyNativeFunc<(I, T), PyResult>,
685+
T,
686+
I,
687+
>(
688+
&self,
689+
getter: G,
690+
setter: S,
691+
) -> PyObjectRef {
692+
let mut dict = PyAttributes::new();
693+
dict.insert("fget".to_string(), self.new_rustfunc(getter));
694+
dict.insert("fset".to_string(), self.new_rustfunc(setter));
695+
self.new_instance(self.data_descriptor_type(), Some(dict))
696+
}
697+
674698
pub fn new_instance(&self, class: PyObjectRef, dict: Option<PyAttributes>) -> PyObjectRef {
675699
let dict = if let Some(dict) = dict {
676700
dict

0 commit comments

Comments
 (0)