pyany: add is_instance

This commit is contained in:
David Hewitt 2020-11-15 14:30:21 +00:00
parent db78cd76c8
commit fc34e41163
3 changed files with 31 additions and 11 deletions

View File

@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add FFI definitions for PEP 587 "Python Initialization Configuration". [#1247](https://github.com/PyO3/pyo3/pull/1247)
- Add `PyEval_SetProfile` and `PyEval_SetTrace` to FFI. [#1255](https://github.com/PyO3/pyo3/pull/1255)
- Add context.h functions (`PyContext_New`, etc) to FFI. [#1259](https://github.com/PyO3/pyo3/pull/1259)
- Add `PyAny::is_instance()` method. [#1276](https://github.com/PyO3/pyo3/pull/1276)
- Add support for conversion between `char` and `PyString`. [#1282](https://github.com/PyO3/pyo3/pull/1282)
### Changed

View File

@ -96,8 +96,8 @@ fn my_func(arg: PyObject) -> PyResult<()> {
## Checking exception types
Python has an [`isinstance`](https://docs.python.org/3/library/functions.html#isinstance) method to check an object's type,
in PyO3 there is a [`Python::is_instance`] method which does the same thing.
Python has an [`isinstance`](https://docs.python.org/3/library/functions.html#isinstance) method to check an object's type.
In PyO3 every native type has access to the [`PyAny::is_instance`] method which does the same thing.
```rust
use pyo3::Python;
@ -106,13 +106,13 @@ use pyo3::types::{PyBool, PyList};
fn main() {
let gil = Python::acquire_gil();
let py = gil.python();
assert!(py.is_instance::<PyBool, _>(PyBool::new(py, true)).unwrap());
assert!(PyBool::new(py, true).is_instance::<PyBool>().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());
assert!(!list.is_instance::<PyBool>().unwrap());
assert!(list.is_instance::<PyList>().unwrap());
}
```
[`Python::is_instance`] calls the underlying [`PyType::is_instance`](https://docs.rs/pyo3/latest/pyo3/types/struct.PyType.html#method.is_instance)
[`PyAny::is_instance`] calls the underlying [`PyType::is_instance`](https://docs.rs/pyo3/latest/pyo3/types/struct.PyType.html#method.is_instance)
method to do the actual work.
To check the type of an exception, you can similarly do:

View File

@ -4,6 +4,7 @@ use crate::conversion::{
};
use crate::err::{PyDowncastError, PyErr, PyResult};
use crate::exceptions::PyTypeError;
use crate::type_object::PyTypeObject;
use crate::types::{PyDict, PyIterator, PyList, PyString, PyTuple, PyType};
use crate::{err, ffi, Py, PyNativeType, PyObject};
use libc::c_int;
@ -29,8 +30,8 @@ use std::cmp::Ordering;
/// use pyo3::types::{PyAny, PyDict, PyList};
/// let gil = Python::acquire_gil();
/// let dict = PyDict::new(gil.python());
/// assert!(gil.python().is_instance::<PyAny, _>(dict).unwrap());
/// let any = dict.as_ref();
/// assert!(dict.is_instance::<PyAny>().unwrap());
/// let any: &PyAny = dict.as_ref();
/// assert!(any.downcast::<PyDict>().is_ok());
/// assert!(any.downcast::<PyList>().is_err());
/// ```
@ -452,13 +453,19 @@ impl PyAny {
pub fn dir(&self) -> &PyList {
unsafe { self.py().from_owned_ptr(ffi::PyObject_Dir(self.as_ptr())) }
}
/// Checks whether this object is an instance of type `T`.
///
/// This is equivalent to the Python expression `isinstance(self, T)`.
pub fn is_instance<T: PyTypeObject>(&self) -> PyResult<bool> {
T::type_object(self.py()).is_instance(self)
}
}
#[cfg(test)]
mod test {
use crate::types::{IntoPyDict, PyList};
use crate::Python;
use crate::ToPyObject;
use crate::types::{IntoPyDict, PyList, PyLong};
use crate::{Python, ToPyObject};
#[test]
fn test_call_for_non_existing_method() {
@ -514,4 +521,16 @@ mod test {
let nan = py.eval("float('nan')", None, None).unwrap();
assert!(nan.compare(nan).is_err());
}
#[test]
fn test_any_isinstance() {
let gil = Python::acquire_gil();
let py = gil.python();
let x = 5.to_object(py).into_ref(py);
assert!(x.is_instance::<PyLong>().unwrap());
let l = vec![x, x].to_object(py).into_ref(py);
assert!(l.is_instance::<PyList>().unwrap());
}
}