__contains__: if extraction fails with TypeError, return False instead.

This commit is contained in:
Daniel Grunwald 2016-05-07 23:31:46 +02:00
parent 9eafaebfa2
commit 04081bc8de
6 changed files with 41 additions and 15 deletions

View file

@ -321,6 +321,9 @@ TODO: implement support for `__cmp__`, `__lt__`, `__le__`, `__gt__`, `__ge__`, `
For mapping types, this should consider the keys of the mapping rather than the values
or the key-item pairs.
If extraction of the `item` parameter fails with `TypeError`,
`__contains__` will return `Ok(false)`.
## Other Special Methods
* `def __bool__(&self) -> PyResult<bool>`

View file

@ -506,6 +506,10 @@ def special_class_method(special_name, *args, **kwargs):
generate_class_method(special_name=special_name, *args, **kwargs)
Argument = namedtuple('Argument', ['name', 'default_type'])
class Argument(object):
def __init__(self, name, extract_err='passthrough'):
self.name = name
self.extract_err = 'py_class_extract_error_%s' % extract_err
@special_method
def operator(special_name, slot,
@ -535,8 +539,8 @@ def operator(special_name, slot,
new_slots = [(slot, 'py_class_unary_slot!($class::%s, %s, %s)'
% (special_name, res_ffi_type, res_conv))]
elif len(args) == 1:
new_slots = [(slot, 'py_class_binary_slot!($class::%s, $%s_type, %s, %s)'
% (special_name, args[0].name, res_ffi_type, res_conv))]
new_slots = [(slot, 'py_class_binary_slot!($class::%s, $%s_type, %s, %s, %s)'
% (special_name, args[0].name, args[0].extract_err, res_ffi_type, res_conv))]
elif len(args) == 2:
new_slots = [(slot, 'py_class_ternary_slot!($class::%s, $%s_type, $%s_type, %s, %s)'
% (special_name, args[0].name, args[1].name, res_ffi_type, res_conv))]
@ -615,23 +619,23 @@ special_names = {
]),
'__length_hint__': normal_method(),
'__getitem__': operator('mp_subscript',
args=[Argument('key', '&PyObject')],
args=[Argument('key')],
additional_slots=[
('sq_item', 'Some($crate::py_class::slots::sq_item)')
]),
'__missing__': normal_method(),
'__setitem__': operator('sdi_setitem',
args=[Argument('key', '&PyObject'), Argument('value', '&PyObject')],
args=[Argument('key'), Argument('value')],
res_type='()'),
'__delitem__': operator('sdi_delitem',
args=[Argument('key', '&PyObject')],
args=[Argument('key')],
res_type='()'),
'__iter__': operator('tp_iter'),
'__next__': operator('tp_iternext',
res_conv='$crate::py_class::slots::IterNextResultConverter'),
'__reversed__': normal_method(),
'__contains__': operator('sq_contains',
args=[Argument('item', '&PyObject')],
args=[Argument('item', extract_err='false')],
res_type='bool'),
# Emulating numeric types

View file

@ -430,7 +430,7 @@ macro_rules! py_class_impl {
$type_slots $as_number
/* as_sequence */ [
$( $sq_slot_name : $sq_slot_value, )*
sq_contains: py_class_binary_slot!($class::__contains__, $item_type, $crate::_detail::libc::c_int, $crate::py_class::slots::BoolConverter),
sq_contains: py_class_binary_slot!($class::__contains__, $item_type, py_class_extract_error_false, $crate::_detail::libc::c_int, $crate::py_class::slots::BoolConverter),
]
$as_mapping $setdelitem
}
@ -474,7 +474,7 @@ macro_rules! py_class_impl {
$type_slots $as_number $as_sequence $as_mapping
/* setdelitem */ [
sdi_setitem: $sdi_setitem_slot_value,
sdi_delitem: { py_class_binary_slot!($class::__delitem__, $key_type, $crate::_detail::libc::c_int, $crate::py_class::slots::UnitCallbackConverter) },
sdi_delitem: { py_class_binary_slot!($class::__delitem__, $key_type, py_class_extract_error_passthrough, $crate::_detail::libc::c_int, $crate::py_class::slots::UnitCallbackConverter) },
]
}
/* impl: */ {
@ -556,7 +556,7 @@ macro_rules! py_class_impl {
]
/* as_mapping */ [
$( $mp_slot_name : $mp_slot_value, )*
mp_subscript: py_class_binary_slot!($class::__getitem__, $key_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
mp_subscript: py_class_binary_slot!($class::__getitem__, $key_type, py_class_extract_error_passthrough, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$setdelitem
}

View file

@ -430,7 +430,7 @@ macro_rules! py_class_impl {
$type_slots $as_number
/* as_sequence */ [
$( $sq_slot_name : $sq_slot_value, )*
sq_contains: py_class_binary_slot!($class::__contains__, $item_type, $crate::_detail::libc::c_int, $crate::py_class::slots::BoolConverter),
sq_contains: py_class_binary_slot!($class::__contains__, $item_type, py_class_extract_error_false, $crate::_detail::libc::c_int, $crate::py_class::slots::BoolConverter),
]
$as_mapping $setdelitem
}
@ -474,7 +474,7 @@ macro_rules! py_class_impl {
$type_slots $as_number $as_sequence $as_mapping
/* setdelitem */ [
sdi_setitem: $sdi_setitem_slot_value,
sdi_delitem: { py_class_binary_slot!($class::__delitem__, $key_type, $crate::_detail::libc::c_int, $crate::py_class::slots::UnitCallbackConverter) },
sdi_delitem: { py_class_binary_slot!($class::__delitem__, $key_type, py_class_extract_error_passthrough, $crate::_detail::libc::c_int, $crate::py_class::slots::UnitCallbackConverter) },
]
}
/* impl: */ {
@ -556,7 +556,7 @@ macro_rules! py_class_impl {
]
/* as_mapping */ [
$( $mp_slot_name : $mp_slot_value, )*
mp_subscript: py_class_binary_slot!($class::__getitem__, $key_type, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
mp_subscript: py_class_binary_slot!($class::__getitem__, $key_type, py_class_extract_error_passthrough, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PyObjectCallbackConverter),
]
$setdelitem
}

View file

@ -253,7 +253,7 @@ macro_rules! py_class_unary_slot {
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_binary_slot {
($class:ident :: $f:ident, $arg_type:ty, $res_type:ty, $conv:expr) => {{
($class:ident :: $f:ident, $arg_type:ty, $extract_err:ident, $res_type:ty, $conv:expr) => {{
unsafe extern "C" fn wrap_binary<DUMMY>(
slf: *mut $crate::_detail::ffi::PyObject,
arg: *mut $crate::_detail::ffi::PyObject)
@ -269,10 +269,10 @@ macro_rules! py_class_binary_slot {
Ok(prepared) => {
match <$arg_type as $crate::ExtractPyObject>::extract(py, &prepared) {
Ok(arg) => slf.$f(py, arg),
Err(e) => Err(e)
Err(e) => $extract_err!(py, e)
}
},
Err(e) => Err(e)
Err(e) => $extract_err!(py, e)
};
$crate::PyDrop::release_ref(arg, py);
$crate::PyDrop::release_ref(slf, py);
@ -329,6 +329,24 @@ macro_rules! py_class_ternary_slot {
}}
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_extract_error_passthrough {
($py: ident, $e:ident) => (Err($e));
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_extract_error_false {
($py: ident, $e:ident) => {
if $e.matches($py, $py.get_type::<$crate::exc::TypeError>()) {
Ok(false)
} else {
Err($e)
}
};
}
pub struct UnitCallbackConverter;
impl CallbackConverter<()> for UnitCallbackConverter {

View file

@ -569,5 +569,6 @@ fn contains() {
let c = Contains::create_instance(py).unwrap();
py_run!(py, c, "assert 1 in c");
py_run!(py, c, "assert -1 not in c");
py_run!(py, c, "assert 'wrong type' not in c");
}