__contains__: if extraction fails with TypeError, return False instead.
This commit is contained in:
parent
9eafaebfa2
commit
04081bc8de
|
@ -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
|
For mapping types, this should consider the keys of the mapping rather than the values
|
||||||
or the key-item pairs.
|
or the key-item pairs.
|
||||||
|
|
||||||
|
If extraction of the `item` parameter fails with `TypeError`,
|
||||||
|
`__contains__` will return `Ok(false)`.
|
||||||
|
|
||||||
## Other Special Methods
|
## Other Special Methods
|
||||||
|
|
||||||
* `def __bool__(&self) -> PyResult<bool>`
|
* `def __bool__(&self) -> PyResult<bool>`
|
||||||
|
|
|
@ -506,6 +506,10 @@ def special_class_method(special_name, *args, **kwargs):
|
||||||
generate_class_method(special_name=special_name, *args, **kwargs)
|
generate_class_method(special_name=special_name, *args, **kwargs)
|
||||||
|
|
||||||
Argument = namedtuple('Argument', ['name', 'default_type'])
|
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
|
@special_method
|
||||||
def operator(special_name, slot,
|
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)'
|
new_slots = [(slot, 'py_class_unary_slot!($class::%s, %s, %s)'
|
||||||
% (special_name, res_ffi_type, res_conv))]
|
% (special_name, res_ffi_type, res_conv))]
|
||||||
elif len(args) == 1:
|
elif len(args) == 1:
|
||||||
new_slots = [(slot, 'py_class_binary_slot!($class::%s, $%s_type, %s, %s)'
|
new_slots = [(slot, 'py_class_binary_slot!($class::%s, $%s_type, %s, %s, %s)'
|
||||||
% (special_name, args[0].name, res_ffi_type, res_conv))]
|
% (special_name, args[0].name, args[0].extract_err, res_ffi_type, res_conv))]
|
||||||
elif len(args) == 2:
|
elif len(args) == 2:
|
||||||
new_slots = [(slot, 'py_class_ternary_slot!($class::%s, $%s_type, $%s_type, %s, %s)'
|
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))]
|
% (special_name, args[0].name, args[1].name, res_ffi_type, res_conv))]
|
||||||
|
@ -615,23 +619,23 @@ special_names = {
|
||||||
]),
|
]),
|
||||||
'__length_hint__': normal_method(),
|
'__length_hint__': normal_method(),
|
||||||
'__getitem__': operator('mp_subscript',
|
'__getitem__': operator('mp_subscript',
|
||||||
args=[Argument('key', '&PyObject')],
|
args=[Argument('key')],
|
||||||
additional_slots=[
|
additional_slots=[
|
||||||
('sq_item', 'Some($crate::py_class::slots::sq_item)')
|
('sq_item', 'Some($crate::py_class::slots::sq_item)')
|
||||||
]),
|
]),
|
||||||
'__missing__': normal_method(),
|
'__missing__': normal_method(),
|
||||||
'__setitem__': operator('sdi_setitem',
|
'__setitem__': operator('sdi_setitem',
|
||||||
args=[Argument('key', '&PyObject'), Argument('value', '&PyObject')],
|
args=[Argument('key'), Argument('value')],
|
||||||
res_type='()'),
|
res_type='()'),
|
||||||
'__delitem__': operator('sdi_delitem',
|
'__delitem__': operator('sdi_delitem',
|
||||||
args=[Argument('key', '&PyObject')],
|
args=[Argument('key')],
|
||||||
res_type='()'),
|
res_type='()'),
|
||||||
'__iter__': operator('tp_iter'),
|
'__iter__': operator('tp_iter'),
|
||||||
'__next__': operator('tp_iternext',
|
'__next__': operator('tp_iternext',
|
||||||
res_conv='$crate::py_class::slots::IterNextResultConverter'),
|
res_conv='$crate::py_class::slots::IterNextResultConverter'),
|
||||||
'__reversed__': normal_method(),
|
'__reversed__': normal_method(),
|
||||||
'__contains__': operator('sq_contains',
|
'__contains__': operator('sq_contains',
|
||||||
args=[Argument('item', '&PyObject')],
|
args=[Argument('item', extract_err='false')],
|
||||||
res_type='bool'),
|
res_type='bool'),
|
||||||
|
|
||||||
# Emulating numeric types
|
# Emulating numeric types
|
||||||
|
|
|
@ -430,7 +430,7 @@ macro_rules! py_class_impl {
|
||||||
$type_slots $as_number
|
$type_slots $as_number
|
||||||
/* as_sequence */ [
|
/* as_sequence */ [
|
||||||
$( $sq_slot_name : $sq_slot_value, )*
|
$( $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
|
$as_mapping $setdelitem
|
||||||
}
|
}
|
||||||
|
@ -474,7 +474,7 @@ macro_rules! py_class_impl {
|
||||||
$type_slots $as_number $as_sequence $as_mapping
|
$type_slots $as_number $as_sequence $as_mapping
|
||||||
/* setdelitem */ [
|
/* setdelitem */ [
|
||||||
sdi_setitem: $sdi_setitem_slot_value,
|
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: */ {
|
/* impl: */ {
|
||||||
|
@ -556,7 +556,7 @@ macro_rules! py_class_impl {
|
||||||
]
|
]
|
||||||
/* as_mapping */ [
|
/* as_mapping */ [
|
||||||
$( $mp_slot_name : $mp_slot_value, )*
|
$( $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
|
$setdelitem
|
||||||
}
|
}
|
||||||
|
|
|
@ -430,7 +430,7 @@ macro_rules! py_class_impl {
|
||||||
$type_slots $as_number
|
$type_slots $as_number
|
||||||
/* as_sequence */ [
|
/* as_sequence */ [
|
||||||
$( $sq_slot_name : $sq_slot_value, )*
|
$( $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
|
$as_mapping $setdelitem
|
||||||
}
|
}
|
||||||
|
@ -474,7 +474,7 @@ macro_rules! py_class_impl {
|
||||||
$type_slots $as_number $as_sequence $as_mapping
|
$type_slots $as_number $as_sequence $as_mapping
|
||||||
/* setdelitem */ [
|
/* setdelitem */ [
|
||||||
sdi_setitem: $sdi_setitem_slot_value,
|
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: */ {
|
/* impl: */ {
|
||||||
|
@ -556,7 +556,7 @@ macro_rules! py_class_impl {
|
||||||
]
|
]
|
||||||
/* as_mapping */ [
|
/* as_mapping */ [
|
||||||
$( $mp_slot_name : $mp_slot_value, )*
|
$( $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
|
$setdelitem
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,7 +253,7 @@ macro_rules! py_class_unary_slot {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
macro_rules! py_class_binary_slot {
|
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>(
|
unsafe extern "C" fn wrap_binary<DUMMY>(
|
||||||
slf: *mut $crate::_detail::ffi::PyObject,
|
slf: *mut $crate::_detail::ffi::PyObject,
|
||||||
arg: *mut $crate::_detail::ffi::PyObject)
|
arg: *mut $crate::_detail::ffi::PyObject)
|
||||||
|
@ -269,10 +269,10 @@ macro_rules! py_class_binary_slot {
|
||||||
Ok(prepared) => {
|
Ok(prepared) => {
|
||||||
match <$arg_type as $crate::ExtractPyObject>::extract(py, &prepared) {
|
match <$arg_type as $crate::ExtractPyObject>::extract(py, &prepared) {
|
||||||
Ok(arg) => slf.$f(py, arg),
|
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(arg, py);
|
||||||
$crate::PyDrop::release_ref(slf, 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;
|
pub struct UnitCallbackConverter;
|
||||||
|
|
||||||
impl CallbackConverter<()> for UnitCallbackConverter {
|
impl CallbackConverter<()> for UnitCallbackConverter {
|
||||||
|
|
|
@ -569,5 +569,6 @@ fn contains() {
|
||||||
let c = Contains::create_instance(py).unwrap();
|
let c = Contains::create_instance(py).unwrap();
|
||||||
py_run!(py, c, "assert 1 in c");
|
py_run!(py, c, "assert 1 in c");
|
||||||
py_run!(py, c, "assert -1 not in c");
|
py_run!(py, c, "assert -1 not in c");
|
||||||
|
py_run!(py, c, "assert 'wrong type' not in c");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue