Skip to content

Commit e7ea486

Browse files
authored
Merge pull request RustPython#1738 from youknowone/getset
Add getset_descriptor
2 parents 0f12db1 + c0b235e commit e7ea486

26 files changed

+549
-376
lines changed

derive/src/pyclass.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -337,17 +337,16 @@ impl Class {
337337
};
338338
if name == "pymethod" {
339339
self.add_item(Self::extract_method(sig, meta)?, meta_span)?;
340-
attr_idxs.push(i);
341340
} else if name == "pyclassmethod" {
342341
self.add_item(Self::extract_classmethod(sig, meta)?, meta_span)?;
343-
attr_idxs.push(i);
344342
} else if name == "pyproperty" {
345343
self.add_item(Self::extract_property(sig, meta)?, meta_span)?;
346-
attr_idxs.push(i);
347344
} else if name == "pyslot" {
348345
self.add_item(Self::extract_slot(sig, meta)?, meta_span)?;
349-
attr_idxs.push(i);
346+
} else {
347+
continue;
350348
}
349+
attr_idxs.push(i);
351350
}
352351
let mut i = 0;
353352
let mut attr_idxs = &*attr_idxs;
@@ -406,8 +405,8 @@ fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnosti
406405
let properties = properties
407406
.into_iter()
408407
.map(|(name, prop)| {
409-
let getter = match prop.0 {
410-
Some(getter) => getter,
408+
let getter_func = match prop.0 {
409+
Some(func) => func,
411410
None => {
412411
push_err_span!(
413412
diagnostics,
@@ -418,14 +417,17 @@ fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnosti
418417
return TokenStream2::new();
419418
}
420419
};
421-
let add_setter = prop.1.map(|setter| quote!(.add_setter(Self::#setter)));
420+
let (new, setter) = match prop.1 {
421+
Some(func) => (quote! { with_get_set }, quote! { , &Self::#func }),
422+
None => (quote! { with_get }, quote! { }),
423+
};
424+
let str_name = name.to_string();
422425
quote! {
423426
class.set_str_attr(
424427
#name,
425-
::rustpython_vm::obj::objproperty::PropertyBuilder::new(ctx)
426-
.add_getter(Self::#getter)
427-
#add_setter
428-
.create(),
428+
::rustpython_vm::pyobject::PyObject::new(
429+
::rustpython_vm::obj::objgetset::PyGetSet::#new(#str_name.into(), &Self::#getter_func #setter),
430+
ctx.getset_type(), None)
429431
);
430432
}
431433
})
@@ -453,8 +455,13 @@ fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnosti
453455
slot_ident,
454456
item_ident,
455457
} => {
458+
let transform = if vec!["new", "call"].contains(&slot_ident.to_string().as_str()) {
459+
quote! { ::rustpython_vm::function::IntoPyNativeFunc::into_func }
460+
} else {
461+
quote! { Box::new }
462+
};
456463
let into_func = quote_spanned! {item_ident.span()=>
457-
::rustpython_vm::function::IntoPyNativeFunc::into_func(Self::#item_ident)
464+
#transform(Self::#item_ident)
458465
};
459466
Some(quote! {
460467
(*class.slots.borrow_mut()).#slot_ident = Some(#into_func);
@@ -685,7 +692,8 @@ pub fn impl_pystruct_sequence(attr: AttributeArgs, item: Item) -> Result<TokenSt
685692
let property = quote! {
686693
class.set_str_attr(
687694
#field_name_str,
688-
ctx.new_property(
695+
ctx.new_readonly_getset(
696+
#field_name_str,
689697
|zelf: &::rustpython_vm::obj::objtuple::PyTuple,
690698
_vm: &::rustpython_vm::VirtualMachine| {
691699
zelf.fast_getitem(#idx)

tests/snippets/types_snippet.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,7 @@ class C(B, BB):
8686
pass
8787

8888
assert C.mro() == [C, B, A, BB, AA, object]
89+
90+
91+
assert type(Exception.args).__name__ == 'getset_descriptor'
92+
assert type(None).__bool__(None) is False

vm/src/exceptions.rs

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl PyBaseException {
8080
}
8181

8282
#[pyproperty(name = "__traceback__")]
83-
fn get_traceback(&self, _vm: &VirtualMachine) -> Option<PyTracebackRef> {
83+
fn get_traceback(&self) -> Option<PyTracebackRef> {
8484
self.traceback.borrow().clone()
8585
}
8686

@@ -95,8 +95,13 @@ impl PyBaseException {
9595
}
9696

9797
#[pyproperty(name = "__cause__", setter)]
98-
fn setter_cause(&self, cause: Option<PyBaseExceptionRef>, _vm: &VirtualMachine) {
98+
fn setter_cause(
99+
&self,
100+
cause: Option<PyBaseExceptionRef>,
101+
_vm: &VirtualMachine,
102+
) -> PyResult<()> {
99103
self.cause.replace(cause);
104+
Ok(())
100105
}
101106

102107
#[pyproperty(name = "__context__")]
@@ -105,8 +110,13 @@ impl PyBaseException {
105110
}
106111

107112
#[pyproperty(name = "__context__", setter)]
108-
fn setter_context(&self, context: Option<PyBaseExceptionRef>, _vm: &VirtualMachine) {
113+
fn setter_context(
114+
&self,
115+
context: Option<PyBaseExceptionRef>,
116+
_vm: &VirtualMachine,
117+
) -> PyResult<()> {
109118
self.context.replace(context);
119+
Ok(())
110120
}
111121

112122
#[pyproperty(name = "__suppress_context__")]
@@ -634,48 +644,44 @@ pub fn init(ctx: &PyContext) {
634644
PyBaseException::extend_class(ctx, &excs.base_exception_type);
635645

636646
extend_class!(ctx, &excs.syntax_error, {
637-
"msg" => ctx.new_property(make_arg_getter(0)),
638-
"filename" => ctx.new_property(make_arg_getter(1)),
639-
"lineno" => ctx.new_property(make_arg_getter(2)),
640-
"offset" => ctx.new_property(make_arg_getter(3)),
641-
"text" => ctx.new_property(make_arg_getter(4)),
647+
"msg" => ctx.new_readonly_getset("msg", make_arg_getter(0)),
642648
});
643649

644650
extend_class!(ctx, &excs.import_error, {
645651
"__init__" => ctx.new_method(import_error_init),
646-
"msg" => ctx.new_property(make_arg_getter(0)),
652+
"msg" => ctx.new_readonly_getset("msg", make_arg_getter(0)),
647653
});
648654

649655
extend_class!(ctx, &excs.stop_iteration, {
650-
"value" => ctx.new_property(make_arg_getter(0)),
656+
"value" => ctx.new_readonly_getset("value", make_arg_getter(0)),
651657
});
652658

653659
extend_class!(ctx, &excs.key_error, {
654660
"__str__" => ctx.new_method(key_error_str),
655661
});
656662

657663
extend_class!(ctx, &excs.unicode_decode_error, {
658-
"encoding" => ctx.new_property(make_arg_getter(0)),
659-
"object" => ctx.new_property(make_arg_getter(1)),
660-
"start" => ctx.new_property(make_arg_getter(2)),
661-
"end" => ctx.new_property(make_arg_getter(3)),
662-
"reason" => ctx.new_property(make_arg_getter(4)),
664+
"encoding" => ctx.new_readonly_getset("encoding", make_arg_getter(0)),
665+
"object" => ctx.new_readonly_getset("object", make_arg_getter(1)),
666+
"start" => ctx.new_readonly_getset("start", make_arg_getter(2)),
667+
"end" => ctx.new_readonly_getset("end", make_arg_getter(3)),
668+
"reason" => ctx.new_readonly_getset("reason", make_arg_getter(4)),
663669
});
664670

665671
extend_class!(ctx, &excs.unicode_encode_error, {
666-
"encoding" => ctx.new_property(make_arg_getter(0)),
667-
"object" => ctx.new_property(make_arg_getter(1)),
668-
"start" => ctx.new_property(make_arg_getter(2)),
669-
"end" => ctx.new_property(make_arg_getter(3)),
670-
"reason" => ctx.new_property(make_arg_getter(4)),
672+
"encoding" => ctx.new_readonly_getset("encoding", make_arg_getter(0)),
673+
"object" => ctx.new_readonly_getset("object", make_arg_getter(1)),
674+
"start" => ctx.new_readonly_getset("start", make_arg_getter(2)),
675+
"end" => ctx.new_readonly_getset("end", make_arg_getter(3)),
676+
"reason" => ctx.new_readonly_getset("reason", make_arg_getter(4)),
671677
});
672678

673679
extend_class!(ctx, &excs.unicode_translate_error, {
674-
"encoding" => ctx.new_property(none_getter),
675-
"object" => ctx.new_property(make_arg_getter(0)),
676-
"start" => ctx.new_property(make_arg_getter(1)),
677-
"end" => ctx.new_property(make_arg_getter(2)),
678-
"reason" => ctx.new_property(make_arg_getter(3)),
680+
"encoding" => ctx.new_readonly_getset("encoding", none_getter),
681+
"object" => ctx.new_readonly_getset("object", make_arg_getter(0)),
682+
"start" => ctx.new_readonly_getset("start", make_arg_getter(1)),
683+
"end" => ctx.new_readonly_getset("end", make_arg_getter(2)),
684+
"reason" => ctx.new_readonly_getset("reason", make_arg_getter(3)),
679685
});
680686
}
681687

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod objfloat;
1717
pub mod objframe;
1818
pub mod objfunction;
1919
pub mod objgenerator;
20+
pub mod objgetset;
2021
pub mod objint;
2122
pub mod objiter;
2223
pub mod objlist;

vm/src/obj/objbuiltinfunc.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use std::fmt;
33
use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
44
use crate::obj::objtype::PyClassRef;
55
use crate::pyobject::{
6-
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
6+
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue, TypeProtocol,
77
};
8-
use crate::slots::{PyBuiltinCallable, PyBuiltinDescriptor};
8+
use crate::slots::{SlotCall, SlotDescriptor};
99
use crate::vm::VirtualMachine;
1010

1111
#[pyclass]
@@ -35,13 +35,13 @@ impl PyBuiltinFunction {
3535
}
3636
}
3737

38-
impl PyBuiltinCallable for PyBuiltinFunction {
38+
impl SlotCall for PyBuiltinFunction {
3939
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
4040
(self.value)(vm, args)
4141
}
4242
}
4343

44-
#[pyimpl(with(PyBuiltinCallable))]
44+
#[pyimpl(with(SlotCall))]
4545
impl PyBuiltinFunction {}
4646

4747
#[pyclass]
@@ -73,13 +73,17 @@ impl PyBuiltinMethod {
7373
}
7474
}
7575

76-
impl PyBuiltinDescriptor for PyBuiltinMethod {
77-
fn get(
78-
zelf: PyRef<Self>,
79-
obj: PyObjectRef,
80-
cls: OptionalArg<PyObjectRef>,
76+
impl SlotDescriptor for PyBuiltinMethod {
77+
fn descr_get(
8178
vm: &VirtualMachine,
79+
zelf: PyObjectRef,
80+
obj: Option<PyObjectRef>,
81+
cls: OptionalArg<PyObjectRef>,
8282
) -> PyResult {
83+
let (zelf, obj) = match Self::_check(zelf, obj, vm) {
84+
Ok(obj) => obj,
85+
Err(result) => return result,
86+
};
8387
if obj.is(&vm.get_none()) && !Self::_cls_is(&cls, &obj.class()) {
8488
Ok(zelf.into_object())
8589
} else {
@@ -88,13 +92,13 @@ impl PyBuiltinDescriptor for PyBuiltinMethod {
8892
}
8993
}
9094

91-
impl PyBuiltinCallable for PyBuiltinMethod {
95+
impl SlotCall for PyBuiltinMethod {
9296
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
9397
(self.function.value)(vm, args)
9498
}
9599
}
96100

97-
#[pyimpl(with(PyBuiltinDescriptor, PyBuiltinCallable))]
101+
#[pyimpl(with(SlotDescriptor, SlotCall))]
98102
impl PyBuiltinMethod {}
99103

100104
pub fn init(context: &PyContext) {

vm/src/obj/objclassmethod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::function::OptionalArg;
33
use crate::pyobject::{
44
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
55
};
6-
use crate::slots::PyBuiltinDescriptor;
6+
use crate::slots::SlotDescriptor;
77
use crate::vm::VirtualMachine;
88

99
/// classmethod(function) -> method
@@ -47,19 +47,20 @@ impl PyValue for PyClassMethod {
4747
}
4848
}
4949

50-
impl PyBuiltinDescriptor for PyClassMethod {
51-
fn get(
52-
zelf: PyRef<Self>,
53-
obj: PyObjectRef,
54-
cls: OptionalArg<PyObjectRef>,
50+
impl SlotDescriptor for PyClassMethod {
51+
fn descr_get(
5552
vm: &VirtualMachine,
53+
zelf: PyObjectRef,
54+
obj: Option<PyObjectRef>,
55+
cls: OptionalArg<PyObjectRef>,
5656
) -> PyResult {
57+
let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?;
5758
let cls = cls.unwrap_or_else(|| obj.class().into_object());
5859
Ok(vm.ctx.new_bound_method(zelf.callable.clone(), cls))
5960
}
6061
}
6162

62-
#[pyimpl(with(PyBuiltinDescriptor), flags(BASETYPE))]
63+
#[pyimpl(with(SlotDescriptor), flags(BASETYPE))]
6364
impl PyClassMethod {
6465
#[pyslot]
6566
fn tp_new(

vm/src/obj/objcode.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,17 @@ impl PyCodeRef {
9292
}
9393
}
9494

95-
pub fn init(context: &PyContext) {
96-
extend_class!(context, &context.types.code_type, {
95+
pub fn init(ctx: &PyContext) {
96+
extend_class!(ctx, &ctx.types.code_type, {
9797
(slot new) => PyCodeRef::new,
98-
"__repr__" => context.new_method(PyCodeRef::repr),
99-
100-
"co_argcount" => context.new_property(PyCodeRef::co_argcount),
101-
"co_consts" => context.new_property(PyCodeRef::co_consts),
102-
"co_filename" => context.new_property(PyCodeRef::co_filename),
103-
"co_firstlineno" => context.new_property(PyCodeRef::co_firstlineno),
104-
"co_kwonlyargcount" => context.new_property(PyCodeRef::co_kwonlyargcount),
105-
"co_name" => context.new_property(PyCodeRef::co_name),
106-
"co_flags" => context.new_property(PyCodeRef::co_flags),
98+
"__repr__" => ctx.new_method(PyCodeRef::repr),
99+
100+
"co_argcount" => ctx.new_readonly_getset("co_argcount", PyCodeRef::co_argcount),
101+
"co_consts" => ctx.new_readonly_getset("co_consts", PyCodeRef::co_consts),
102+
"co_filename" => ctx.new_readonly_getset("co_filename", PyCodeRef::co_filename),
103+
"co_firstlineno" => ctx.new_readonly_getset("co_firstlineno", PyCodeRef::co_firstlineno),
104+
"co_kwonlyargcount" => ctx.new_readonly_getset("co_kwonlyargcount", PyCodeRef::co_kwonlyargcount),
105+
"co_name" => ctx.new_readonly_getset("co_name", PyCodeRef::co_name),
106+
"co_flags" => ctx.new_readonly_getset("co_flags", PyCodeRef::co_flags),
107107
});
108108
}

vm/src/obj/objfloat.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,12 +498,12 @@ impl PyFloat {
498498
pyhash::hash_float(self.value)
499499
}
500500

501-
#[pyproperty(name = "real")]
501+
#[pyproperty]
502502
fn real(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyFloatRef {
503503
zelf
504504
}
505505

506-
#[pyproperty(name = "imag")]
506+
#[pyproperty]
507507
fn imag(&self, _vm: &VirtualMachine) -> f64 {
508508
0.0f64
509509
}

0 commit comments

Comments
 (0)