Skip to content

Commit

Permalink
Add PyType::full_name which is tp_name and has an abi3 fallback.
Browse files Browse the repository at this point in the history
  • Loading branch information
adamreichold committed Dec 18, 2023
1 parent ff50285 commit 532a3a9
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 0 deletions.
1 change: 1 addition & 0 deletions newsfragments/3660.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added `PyType::full_name` which in contrast to `PyType::name` includes the module name.
7 changes: 7 additions & 0 deletions pytests/src/misc.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
use pyo3::prelude::*;
use std::borrow::Cow;

#[pyfunction]
fn issue_219() {
// issue 219: acquiring GIL inside #[pyfunction] deadlocks.
Python::with_gil(|_| {});
}

#[pyfunction]
fn get_type_full_name(obj: &PyAny) -> PyResult<Cow<'_, str>> {
obj.get_type().full_name()
}

#[pymodule]
pub fn misc(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(issue_219, m)?)?;
m.add_function(wrap_pyfunction!(get_type_full_name, m)?)?;
Ok(())
}
6 changes: 6 additions & 0 deletions pytests/tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,9 @@ def test_import_in_subinterpreter_forbidden():
)

_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_"
26 changes: 26 additions & 0 deletions src/types/typeobject.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::err::{self, PyResult};
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`.
#[repr(transparent)]
Expand Down Expand Up @@ -35,6 +38,29 @@ impl PyType {
self.getattr(intern!(self.py(), "__qualname__"))?.extract()
}

/// Gets the full name including 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`.
///
/// Equivalent to the Python expression `issubclass(self, other)`.
Expand Down

0 comments on commit 532a3a9

Please sign in to comment.