Implement is_instance and is_subclass (#27)

* Implement is_instance

* Implement is_subclass

* Move is_instance and is_subclass to Python impl

* Move implementation detail to PyType
This commit is contained in:
messense 2017-06-12 00:41:02 +08:00 committed by GitHub
parent cb68cd23a2
commit 6b18ccb50b
3 changed files with 61 additions and 10 deletions

View file

@ -77,7 +77,6 @@ impl PyByteArray {
mod test {
use exc;
use python::Python;
use typeob::PyTypeObject;
use objects::{PyObject, PyByteArray};
#[test]
@ -100,7 +99,7 @@ mod test {
let none = py.None();
if let Err(mut err) = PyByteArray::from(py, &none) {
assert!(exc::TypeError::type_object(py).is_instance(py, &err.instance(py)))
assert!(py.is_instance::<exc::TypeError>(&err.instance(py)).unwrap())
} else {
panic!("error");
}

View file

@ -9,6 +9,8 @@ use ffi;
use pointers::PyPtr;
use python::{Python, ToPyPointer};
use objects::PyObject;
use err::{PyErr, PyResult};
use typeob::PyTypeObject;
/// Represents a reference to a Python type object.
pub struct PyType(PyPtr);
@ -39,16 +41,34 @@ impl PyType {
}
}
/// Return true if `self` is a subtype of `b`.
#[inline]
pub fn is_subtype_of(&self, _py: Python, b: &PyType) -> bool {
unsafe { ffi::PyType_IsSubtype(self.as_type_ptr(), b.as_type_ptr()) != 0 }
/// Check whether `self` is subclass of type `T` like Python `issubclass` function
pub fn is_subclass<T>(self, py: Python) -> PyResult<bool>
where T: PyTypeObject
{
let result = unsafe {
ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object(py).as_ptr())
};
if result == -1 {
Err(PyErr::fetch(py))
} else if result == 1 {
Ok(true)
} else {
Ok(false)
}
}
/// Return true if `obj` is an instance of `self`.
#[inline]
pub fn is_instance<T: ToPyPointer>(&self, _py: Python, obj: &T) -> bool {
unsafe { ffi::PyObject_TypeCheck(obj.as_ptr(), self.as_type_ptr()) != 0 }
// Check whether `obj` is an instance of `self`
pub fn is_instance<T: ToPyPointer>(self, py: Python, obj: &T) -> PyResult<bool> {
let result = unsafe {
ffi::PyObject_IsInstance(obj.as_ptr(), self.as_ptr())
};
if result == -1 {
Err(PyErr::fetch(py))
} else if result == 1 {
Ok(true)
} else {
Ok(false)
}
}
}

View file

@ -255,11 +255,25 @@ impl<'p> Python<'p> {
Err(e) => e.release(self)
}
}
/// Check whether `obj` is an instance of type `T` like Python `isinstance` function
pub fn is_instance<T: PyTypeObject>(self, obj: &PyObject) -> PyResult<bool> {
T::type_object(self).is_instance(self, obj)
}
/// Check whether type `T` is subclass of type `U` like Python `issubclass` function
pub fn is_subclass<T, U>(self) -> PyResult<bool>
where T: PyTypeObject,
U: PyTypeObject
{
T::type_object(self).is_subclass::<U>(self)
}
}
#[cfg(test)]
mod test {
use {Python, PyDict};
use objects::{PyBool, PyList, PyLong};
#[test]
fn test_eval() {
@ -285,4 +299,22 @@ mod test {
let v: i32 = py.eval("min(foo, 2)", None, Some(&d)).unwrap().extract(py).unwrap();
assert_eq!(v, 2);
}
#[test]
fn test_is_instance() {
let gil = Python::acquire_gil();
let py = gil.python();
assert!(py.is_instance::<PyBool>(py.True().as_ref()).unwrap());
let list = PyList::new(py, &[1, 2, 3, 4]);
assert!(!py.is_instance::<PyBool>(list.as_ref()).unwrap());
assert!(py.is_instance::<PyList>(list.as_ref()).unwrap());
}
#[test]
fn test_is_subclass() {
let gil = Python::acquire_gil();
let py = gil.python();
assert!(py.is_subclass::<PyBool, PyLong>().unwrap());
assert!(!py.is_subclass::<PyBool, PyList>().unwrap());
}
}