From 117f60bed0f906fed843455b3dd77aa03303fe5f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 8 Sep 2020 08:59:22 -0400 Subject: [PATCH] Make PyType::name abi3 compatible The implementation is more complex, because there's no equivalent to tp_name in the limited API --- guide/src/trait_bounds.md | 8 ++++---- pyo3-derive-backend/src/from_pyobject.rs | 2 +- src/err.rs | 11 +++++++---- src/exceptions.rs | 6 +++--- src/types/typeobject.rs | 6 ++---- tests/test_methods.rs | 4 ++-- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/guide/src/trait_bounds.md b/guide/src/trait_bounds.md index e3aac085..8dde99e0 100644 --- a/guide/src/trait_bounds.md +++ b/guide/src/trait_bounds.md @@ -408,8 +408,8 @@ impl Model for UserModel { .call_method("get_results", (), None) .unwrap(); - if py_result.get_type().name() != "list" { - panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name()); + if py_result.get_type().name().unwrap() != "list" { + panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name().unwrap()); } py_result.extract() }) @@ -536,8 +536,8 @@ impl Model for UserModel { .call_method("get_results", (), None) .unwrap(); - if py_result.get_type().name() != "list" { - panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name()); + if py_result.get_type().name().unwrap() != "list" { + panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name().unwrap()); } py_result.extract() }) diff --git a/pyo3-derive-backend/src/from_pyobject.rs b/pyo3-derive-backend/src/from_pyobject.rs index f7688e2b..c6dbd31a 100644 --- a/pyo3-derive-backend/src/from_pyobject.rs +++ b/pyo3-derive-backend/src/from_pyobject.rs @@ -72,7 +72,7 @@ impl<'a> Enum<'a> { }; quote!( #(#var_extracts)* - let type_name = obj.get_type().name(); + let type_name = obj.get_type().name()?; let from = obj .repr() .map(|s| format!("{} ({})", s.to_string_lossy(), type_name)) diff --git a/src/err.rs b/src/err.rs index e1ade1ee..5fc10fef 100644 --- a/src/err.rs +++ b/src/err.rs @@ -478,10 +478,13 @@ impl<'a> std::fmt::Display for PyDowncastError<'a> { write!( f, "Can't convert {} to {}", - self.from - .repr() - .map(|s| s.to_string_lossy()) - .unwrap_or_else(|_| self.from.get_type().name()), + self.from.repr().map(|s| s.to_string_lossy()).or_else(|_| { + self.from + .get_type() + .name() + .map_err(|_| std::fmt::Error) + .map(|s| s.into()) + })?, self.to ) } diff --git a/src/exceptions.rs b/src/exceptions.rs index be73c5d4..ca0412cc 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -38,8 +38,8 @@ macro_rules! impl_exception_boilerplate { impl std::fmt::Debug for $name { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let type_name = self.get_type().name(); - f.debug_struct(&*type_name) + let type_name = self.get_type().name().map_err(|_| std::fmt::Error)?; + f.debug_struct(type_name) // TODO: print out actual fields! .finish() } @@ -47,7 +47,7 @@ macro_rules! impl_exception_boilerplate { impl std::fmt::Display for $name { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let type_name = self.get_type().name(); + let type_name = self.get_type().name().map_err(|_| std::fmt::Error)?; write!(f, "{}", type_name)?; if let Ok(s) = self.str() { write!(f, ": {}", &s.to_string_lossy()) diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index 7db9d6c3..30037a5c 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -6,8 +6,6 @@ use crate::err::{PyErr, PyResult}; use crate::instance::PyNativeType; use crate::type_object::PyTypeObject; use crate::{ffi, AsPyPointer, PyAny, Python}; -use std::borrow::Cow; -use std::ffi::CStr; /// Represents a reference to a Python `type object`. #[repr(transparent)] @@ -39,8 +37,8 @@ impl PyType { } /// Gets the name of the `PyType`. - pub fn name(&self) -> Cow { - unsafe { CStr::from_ptr((*self.as_type_ptr()).tp_name).to_string_lossy() } + pub fn name(&self) -> PyResult<&str> { + self.getattr("__qualname__")?.extract() } /// Checks whether `self` is subclass of type `T`. diff --git a/tests/test_methods.rs b/tests/test_methods.rs index 40db57ae..b6b8a7f8 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -76,7 +76,7 @@ impl ClassMethod { #[classmethod] /// Test class method. fn method(cls: &PyType) -> PyResult { - Ok(format!("{}.method()!", cls.name())) + Ok(format!("{}.method()!", cls.name()?)) } } @@ -104,7 +104,7 @@ struct ClassMethodWithArgs {} impl ClassMethodWithArgs { #[classmethod] fn method(cls: &PyType, input: &PyString) -> PyResult { - Ok(format!("{}.method({})", cls.name(), input)) + Ok(format!("{}.method({})", cls.name()?, input)) } }