Add PyType::full_name which is tp_name and has an abi3 fallback.

This commit is contained in:
Adam Reichold 2023-12-18 09:57:37 +01:00
parent 1dca87972a
commit 2fdd52003e
4 changed files with 40 additions and 0 deletions

View File

@ -0,0 +1 @@
Added `PyType::full_name` which in contrast to `PyType::name` includes the module name.

View File

@ -1,4 +1,5 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use std::borrow::Cow;
#[pyfunction] #[pyfunction]
fn issue_219() { fn issue_219() {
@ -6,8 +7,14 @@ fn issue_219() {
Python::with_gil(|_| {}); Python::with_gil(|_| {});
} }
#[pyfunction]
fn get_type_full_name(obj: &PyAny) -> PyResult<Cow<'_, str>> {
obj.get_type().full_name()
}
#[pymodule] #[pymodule]
pub fn misc(_py: Python<'_>, m: &PyModule) -> PyResult<()> { pub fn misc(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(issue_219, m)?)?; m.add_function(wrap_pyfunction!(issue_219, m)?)?;
m.add_function(wrap_pyfunction!(get_type_full_name, m)?)?;
Ok(()) Ok(())
} }

View File

@ -48,3 +48,9 @@ def test_import_in_subinterpreter_forbidden():
) )
_xxsubinterpreters.destroy(sub_interpreter) _xxsubinterpreters.destroy(sub_interpreter)
def test_type_full_name_includes_module():
numpy = pytest.importorskip("numpy")
assert pyo3_pytests.misc.get_type_full_name(numpy.bool_(True)) == "numpy.bool_"

View File

@ -1,5 +1,8 @@
use crate::err::{self, PyResult}; use crate::err::{self, PyResult};
use crate::{ffi, PyAny, PyTypeInfo, Python}; use crate::{ffi, PyAny, PyTypeInfo, Python};
use std::borrow::Cow;
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
use std::ffi::CStr;
/// Represents a reference to a Python `type object`. /// Represents a reference to a Python `type object`.
#[repr(transparent)] #[repr(transparent)]
@ -35,6 +38,29 @@ impl PyType {
self.getattr(intern!(self.py(), "__qualname__"))?.extract() self.getattr(intern!(self.py(), "__qualname__"))?.extract()
} }
/// Gets the full name, which includes the module, of the `PyType`.
pub fn full_name(&self) -> PyResult<Cow<'_, str>> {
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
{
let name = unsafe { CStr::from_ptr((*self.as_type_ptr()).tp_name) }.to_str()?;
Ok(Cow::Borrowed(name))
}
#[cfg(any(Py_LIMITED_API, PyPy))]
{
let module = self
.getattr(intern!(self.py(), "__module__"))?
.extract::<&str>()?;
let name = self
.getattr(intern!(self.py(), "__name__"))?
.extract::<&str>()?;
Ok(Cow::Owned(format!("{}.{}", module, name)))
}
}
/// Checks whether `self` is a subclass of `other`. /// Checks whether `self` is a subclass of `other`.
/// ///
/// Equivalent to the Python expression `issubclass(self, other)`. /// Equivalent to the Python expression `issubclass(self, other)`.