diff --git a/CHANGELOG.md b/CHANGELOG.md index 07453a53..8b214040 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Change formatting of `PyDowncastError` messages to be closer to Python's builtin error messages. [#1212](https://github.com/PyO3/pyo3/pull/1212) - Change `Debug` and `Display` impls for `PyException` to be consistent with `PyAny`. [#1275](https://github.com/PyO3/pyo3/pull/1275) - Change `Debug` impl of `PyErr` to output more helpful information (acquiring the GIL if necessary). [#1275](https://github.com/PyO3/pyo3/pull/1275) +- Rename `PyTypeInfo::is_instance` and `PyTypeInfo::is_exact_instance` to `PyTypeInfo::is_type_of` and `PyTypeInfo::is_exact_type_of`. [#1278](https://github.com/PyO3/pyo3/pull/1278) ### Removed - Remove deprecated ffi definitions `PyUnicode_AsUnicodeCopy`, `PyUnicode_GetMax`, `_Py_CheckRecursionLimit`, `PyObject_AsCharBuffer`, `PyObject_AsReadBuffer`, `PyObject_CheckReadBuffer` and `PyObject_AsWriteBuffer`, which will be removed in Python 3.10. [#1217](https://github.com/PyO3/pyo3/pull/1217) diff --git a/src/conversion.rs b/src/conversion.rs index 0efce47c..e5716429 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -326,7 +326,7 @@ where fn try_from>(value: V) -> Result<&'v Self, PyDowncastError<'v>> { let value = value.into(); unsafe { - if T::is_instance(value) { + if T::is_type_of(value) { Ok(Self::try_from_unchecked(value)) } else { Err(PyDowncastError::new(value, T::NAME)) @@ -337,7 +337,7 @@ where fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError<'v>> { let value = value.into(); unsafe { - if T::is_exact_instance(value) { + if T::is_exact_type_of(value) { Ok(Self::try_from_unchecked(value)) } else { Err(PyDowncastError::new(value, T::NAME)) @@ -358,7 +358,7 @@ where fn try_from>(value: V) -> Result<&'v Self, PyDowncastError<'v>> { let value = value.into(); unsafe { - if T::is_instance(value) { + if T::is_type_of(value) { Ok(Self::try_from_unchecked(value)) } else { Err(PyDowncastError::new(value, T::NAME)) @@ -368,7 +368,7 @@ where fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError<'v>> { let value = value.into(); unsafe { - if T::is_exact_instance(value) { + if T::is_exact_type_of(value) { Ok(Self::try_from_unchecked(value)) } else { Err(PyDowncastError::new(value, T::NAME)) @@ -434,11 +434,39 @@ where #[cfg(test)] mod test { - use crate::types::PyList; - use crate::Python; + use crate::types::{IntoPyDict, PyAny, PyDict, PyList}; + use crate::{Python, ToPyObject}; use super::PyTryFrom; + #[test] + fn test_try_from() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py); + let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref(); + + assert!(PyList::try_from(list).is_ok()); + assert!(PyDict::try_from(dict).is_ok()); + + assert!(PyAny::try_from(list).is_ok()); + assert!(PyAny::try_from(dict).is_ok()); + } + + #[test] + fn test_try_from_exact() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py); + let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref(); + + assert!(PyList::try_from_exact(list).is_ok()); + assert!(PyDict::try_from_exact(dict).is_ok()); + + assert!(PyAny::try_from_exact(list).is_err()); + assert!(PyAny::try_from_exact(dict).is_err()); + } + #[test] fn test_try_from_unchecked() { let gil = Python::acquire_gil(); diff --git a/src/type_object.rs b/src/type_object.rs index 0c687072..17d67973 100644 --- a/src/type_object.rs +++ b/src/type_object.rs @@ -104,13 +104,13 @@ pub unsafe trait PyTypeInfo: Sized { /// PyTypeObject instance for this type. fn type_object_raw(py: Python) -> *mut ffi::PyTypeObject; - /// Check if `*mut ffi::PyObject` is instance of this type - fn is_instance(object: &PyAny) -> bool { + /// Checks if `object` is an instance of this type or a subclass of this type. + fn is_type_of(object: &PyAny) -> bool { unsafe { ffi::PyObject_TypeCheck(object.as_ptr(), Self::type_object_raw(object.py())) != 0 } } - /// Check if `*mut ffi::PyObject` is exact instance of this type - fn is_exact_instance(object: &PyAny) -> bool { + /// Checks if `object` is an instance of this type. + fn is_exact_type_of(object: &PyAny) -> bool { unsafe { ffi::Py_TYPE(object.as_ptr()) == Self::type_object_raw(object.py()) } } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 7e532645..fbd01e41 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -184,7 +184,7 @@ macro_rules! pyobject_native_type_convert( } #[allow(unused_unsafe)] - fn is_instance(ptr: &$crate::PyAny) -> bool { + fn is_type_of(ptr: &$crate::PyAny) -> bool { use $crate::AsPyPointer; unsafe { $checkfunction(ptr.as_ptr()) > 0 } }