Skip to content

Add getset_descriptor #1738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
56 changes: 31 additions & 25 deletions vm/src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl PyBaseException {
}

#[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