Skip to content
34 changes: 21 additions & 13 deletions derive/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,17 +337,16 @@ impl Class {
};
if name == "pymethod" {
self.add_item(Self::extract_method(sig, meta)?, meta_span)?;
attr_idxs.push(i);
} else if name == "pyclassmethod" {
self.add_item(Self::extract_classmethod(sig, meta)?, meta_span)?;
attr_idxs.push(i);
} else if name == "pyproperty" {
self.add_item(Self::extract_property(sig, meta)?, meta_span)?;
attr_idxs.push(i);
} else if name == "pyslot" {
self.add_item(Self::extract_slot(sig, meta)?, meta_span)?;
attr_idxs.push(i);
} else {
continue;
}
attr_idxs.push(i);
}
let mut i = 0;
let mut attr_idxs = &*attr_idxs;
Expand Down Expand Up @@ -406,8 +405,8 @@ fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnosti
let properties = properties
.into_iter()
.map(|(name, prop)| {
let getter = match prop.0 {
Some(getter) => getter,
let getter_func = match prop.0 {
Some(func) => func,
None => {
push_err_span!(
diagnostics,
Expand All @@ -418,14 +417,17 @@ fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnosti
return TokenStream2::new();
}
};
let add_setter = prop.1.map(|setter| quote!(.add_setter(Self::#setter)));
let (new, setter) = match prop.1 {
Some(func) => (quote! { with_get_set }, quote! { , &Self::#func }),
None => (quote! { with_get }, quote! { }),
};
let str_name = name.to_string();
quote! {
class.set_str_attr(
#name,
::rustpython_vm::obj::objproperty::PropertyBuilder::new(ctx)
.add_getter(Self::#getter)
#add_setter
.create(),
::rustpython_vm::pyobject::PyObject::new(
::rustpython_vm::obj::objgetset::PyGetSet::#new(#str_name.into(), &Self::#getter_func #setter),
ctx.getset_type(), None)
);
}
})
Expand Down Expand Up @@ -453,8 +455,13 @@ fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnosti
slot_ident,
item_ident,
} => {
let transform = if vec!["new", "call"].contains(&slot_ident.to_string().as_str()) {
quote! { ::rustpython_vm::function::IntoPyNativeFunc::into_func }
} else {
quote! { Box::new }
};
let into_func = quote_spanned! {item_ident.span()=>
::rustpython_vm::function::IntoPyNativeFunc::into_func(Self::#item_ident)
#transform(Self::#item_ident)
};
Some(quote! {
(*class.slots.borrow_mut()).#slot_ident = Some(#into_func);
Expand Down Expand Up @@ -685,7 +692,8 @@ pub fn impl_pystruct_sequence(attr: AttributeArgs, item: Item) -> Result<TokenSt
let property = quote! {
class.set_str_attr(
#field_name_str,
ctx.new_property(
ctx.new_readonly_getset(
#field_name_str,
|zelf: &::rustpython_vm::obj::objtuple::PyTuple,
_vm: &::rustpython_vm::VirtualMachine| {
zelf.fast_getitem(#idx)
Expand Down
4 changes: 4 additions & 0 deletions tests/snippets/types_snippet.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,7 @@ class C(B, BB):
pass

assert C.mro() == [C, B, A, BB, AA, object]


assert type(Exception.args).__name__ == 'getset_descriptor'
assert type(None).__bool__(None) is False
62 changes: 34 additions & 28 deletions vm/src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use crate::obj::objtuple::{PyTuple, PyTupleRef};
use crate::obj::objtype::{self, PyClass, PyClassRef};
use crate::py_serde;
use crate::pyobject::{
PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
TypeProtocol,
PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PySetResult, PyValue,
TryFromObject, TypeProtocol,
};
use crate::slots::PyTpFlags;
use crate::types::create_type;
Expand Down Expand Up @@ -73,14 +73,14 @@ impl PyBaseException {
}

#[pyproperty(setter)]
fn set_args(&self, args: PyIterable, vm: &VirtualMachine) -> PyResult<()> {
fn set_args(&self, args: PyIterable, vm: &VirtualMachine) -> PySetResult {
let args = args.iter(vm)?.collect::<PyResult<Vec<_>>>()?;
self.args.replace(PyTuple::from(args).into_ref(vm));
Ok(())
}

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

Expand All @@ -95,8 +95,13 @@ impl PyBaseException {
}

#[pyproperty(name = "__cause__", setter)]
fn setter_cause(&self, cause: Option<PyBaseExceptionRef>, _vm: &VirtualMachine) {
fn setter_cause(
&self,
cause: Option<PyBaseExceptionRef>,
_vm: &VirtualMachine,
) -> PyResult<()> {
self.cause.replace(cause);
Ok(())
}

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

#[pyproperty(name = "__context__", setter)]
fn setter_context(&self, context: Option<PyBaseExceptionRef>, _vm: &VirtualMachine) {
fn setter_context(
&self,
context: Option<PyBaseExceptionRef>,
_vm: &VirtualMachine,
) -> PyResult<()> {
self.context.replace(context);
Ok(())
}

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

extend_class!(ctx, &excs.syntax_error, {
"msg" => ctx.new_property(make_arg_getter(0)),
"filename" => ctx.new_property(make_arg_getter(1)),
"lineno" => ctx.new_property(make_arg_getter(2)),
"offset" => ctx.new_property(make_arg_getter(3)),
"text" => ctx.new_property(make_arg_getter(4)),
"msg" => ctx.new_readonly_getset("msg", make_arg_getter(0)),
});

extend_class!(ctx, &excs.import_error, {
"__init__" => ctx.new_method(import_error_init),
"msg" => ctx.new_property(make_arg_getter(0)),
"msg" => ctx.new_readonly_getset("msg", make_arg_getter(0)),
});

extend_class!(ctx, &excs.stop_iteration, {
"value" => ctx.new_property(make_arg_getter(0)),
"value" => ctx.new_readonly_getset("value", make_arg_getter(0)),
});

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

extend_class!(ctx, &excs.unicode_decode_error, {
"encoding" => ctx.new_property(make_arg_getter(0)),
"object" => ctx.new_property(make_arg_getter(1)),
"start" => ctx.new_property(make_arg_getter(2)),
"end" => ctx.new_property(make_arg_getter(3)),
"reason" => ctx.new_property(make_arg_getter(4)),
"encoding" => ctx.new_readonly_getset("encoding", make_arg_getter(0)),
"object" => ctx.new_readonly_getset("object", make_arg_getter(1)),
"start" => ctx.new_readonly_getset("start", make_arg_getter(2)),
"end" => ctx.new_readonly_getset("end", make_arg_getter(3)),
"reason" => ctx.new_readonly_getset("reason", make_arg_getter(4)),
});

extend_class!(ctx, &excs.unicode_encode_error, {
"encoding" => ctx.new_property(make_arg_getter(0)),
"object" => ctx.new_property(make_arg_getter(1)),
"start" => ctx.new_property(make_arg_getter(2)),
"end" => ctx.new_property(make_arg_getter(3)),
"reason" => ctx.new_property(make_arg_getter(4)),
"encoding" => ctx.new_readonly_getset("encoding", make_arg_getter(0)),
"object" => ctx.new_readonly_getset("object", make_arg_getter(1)),
"start" => ctx.new_readonly_getset("start", make_arg_getter(2)),
"end" => ctx.new_readonly_getset("end", make_arg_getter(3)),
"reason" => ctx.new_readonly_getset("reason", make_arg_getter(4)),
});

extend_class!(ctx, &excs.unicode_translate_error, {
"encoding" => ctx.new_property(none_getter),
"object" => ctx.new_property(make_arg_getter(0)),
"start" => ctx.new_property(make_arg_getter(1)),
"end" => ctx.new_property(make_arg_getter(2)),
"reason" => ctx.new_property(make_arg_getter(3)),
"encoding" => ctx.new_readonly_getset("encoding", none_getter),
"object" => ctx.new_readonly_getset("object", make_arg_getter(0)),
"start" => ctx.new_readonly_getset("start", make_arg_getter(1)),
"end" => ctx.new_readonly_getset("end", make_arg_getter(2)),
"reason" => ctx.new_readonly_getset("reason", make_arg_getter(3)),
});
}

Expand Down
1 change: 1 addition & 0 deletions vm/src/obj/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod objfloat;
pub mod objframe;
pub mod objfunction;
pub mod objgenerator;
pub mod objgetset;
pub mod objint;
pub mod objiter;
pub mod objlist;
Expand Down
26 changes: 15 additions & 11 deletions vm/src/obj/objbuiltinfunc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::fmt;
use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
use crate::obj::objtype::PyClassRef;
use crate::pyobject::{
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue, TypeProtocol,
};
use crate::slots::{PyBuiltinCallable, PyBuiltinDescriptor};
use crate::slots::{SlotCall, SlotDescriptor};
use crate::vm::VirtualMachine;

#[pyclass]
Expand Down Expand Up @@ -35,13 +35,13 @@ impl PyBuiltinFunction {
}
}

impl PyBuiltinCallable for PyBuiltinFunction {
impl SlotCall for PyBuiltinFunction {
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
(self.value)(vm, args)
}
}

#[pyimpl(with(PyBuiltinCallable))]
#[pyimpl(with(SlotCall))]
impl PyBuiltinFunction {}

#[pyclass]
Expand Down Expand Up @@ -73,13 +73,17 @@ impl PyBuiltinMethod {
}
}

impl PyBuiltinDescriptor for PyBuiltinMethod {
fn get(
zelf: PyRef<Self>,
obj: PyObjectRef,
cls: OptionalArg<PyObjectRef>,
impl SlotDescriptor for PyBuiltinMethod {
fn descr_get(
vm: &VirtualMachine,
zelf: PyObjectRef,
obj: Option<PyObjectRef>,
cls: OptionalArg<PyObjectRef>,
) -> PyResult {
let (zelf, obj) = match Self::_check(zelf, obj, vm) {
Ok(obj) => obj,
Err(result) => return result,
};
if obj.is(&vm.get_none()) && !Self::_cls_is(&cls, &obj.class()) {
Ok(zelf.into_object())
} else {
Expand All @@ -88,13 +92,13 @@ impl PyBuiltinDescriptor for PyBuiltinMethod {
}
}

impl PyBuiltinCallable for PyBuiltinMethod {
impl SlotCall for PyBuiltinMethod {
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
(self.function.value)(vm, args)
}
}

#[pyimpl(with(PyBuiltinDescriptor, PyBuiltinCallable))]
#[pyimpl(with(SlotDescriptor, SlotCall))]
impl PyBuiltinMethod {}

pub fn init(context: &PyContext) {
Expand Down
15 changes: 8 additions & 7 deletions vm/src/obj/objclassmethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::function::OptionalArg;
use crate::pyobject::{
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
use crate::slots::PyBuiltinDescriptor;
use crate::slots::SlotDescriptor;
use crate::vm::VirtualMachine;

/// classmethod(function) -> method
Expand Down Expand Up @@ -47,19 +47,20 @@ impl PyValue for PyClassMethod {
}
}

impl PyBuiltinDescriptor for PyClassMethod {
fn get(
zelf: PyRef<Self>,
obj: PyObjectRef,
cls: OptionalArg<PyObjectRef>,
impl SlotDescriptor for PyClassMethod {
fn descr_get(
vm: &VirtualMachine,
zelf: PyObjectRef,
obj: Option<PyObjectRef>,
cls: OptionalArg<PyObjectRef>,
) -> PyResult {
let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?;
let cls = cls.unwrap_or_else(|| obj.class().into_object());
Ok(vm.ctx.new_bound_method(zelf.callable.clone(), cls))
}
}

#[pyimpl(with(PyBuiltinDescriptor), flags(BASETYPE))]
#[pyimpl(with(SlotDescriptor), flags(BASETYPE))]
impl PyClassMethod {
#[pyslot]
fn tp_new(
Expand Down
22 changes: 11 additions & 11 deletions vm/src/obj/objcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,17 @@ impl PyCodeRef {
}
}

pub fn init(context: &PyContext) {
extend_class!(context, &context.types.code_type, {
pub fn init(ctx: &PyContext) {
extend_class!(ctx, &ctx.types.code_type, {
(slot new) => PyCodeRef::new,
"__repr__" => context.new_method(PyCodeRef::repr),

"co_argcount" => context.new_property(PyCodeRef::co_argcount),
"co_consts" => context.new_property(PyCodeRef::co_consts),
"co_filename" => context.new_property(PyCodeRef::co_filename),
"co_firstlineno" => context.new_property(PyCodeRef::co_firstlineno),
"co_kwonlyargcount" => context.new_property(PyCodeRef::co_kwonlyargcount),
"co_name" => context.new_property(PyCodeRef::co_name),
"co_flags" => context.new_property(PyCodeRef::co_flags),
"__repr__" => ctx.new_method(PyCodeRef::repr),

"co_argcount" => ctx.new_readonly_getset("co_argcount", PyCodeRef::co_argcount),
"co_consts" => ctx.new_readonly_getset("co_consts", PyCodeRef::co_consts),
"co_filename" => ctx.new_readonly_getset("co_filename", PyCodeRef::co_filename),
"co_firstlineno" => ctx.new_readonly_getset("co_firstlineno", PyCodeRef::co_firstlineno),
"co_kwonlyargcount" => ctx.new_readonly_getset("co_kwonlyargcount", PyCodeRef::co_kwonlyargcount),
"co_name" => ctx.new_readonly_getset("co_name", PyCodeRef::co_name),
"co_flags" => ctx.new_readonly_getset("co_flags", PyCodeRef::co_flags),
});
}
4 changes: 2 additions & 2 deletions vm/src/obj/objfloat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,12 +498,12 @@ impl PyFloat {
pyhash::hash_float(self.value)
}

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

#[pyproperty(name = "imag")]
#[pyproperty]
fn imag(&self, _vm: &VirtualMachine) -> f64 {
0.0f64
}
Expand Down
Loading