Skip to content

Commit

Permalink
Add PyTypeMethods trait with qualname method
Browse files Browse the repository at this point in the history
This allows calling `Bound<'py, PyType>::qualname()`.
  • Loading branch information
LilyFoote committed Feb 17, 2024
1 parent c33d330 commit 291145f
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 4 deletions.
3 changes: 2 additions & 1 deletion src/err/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,10 +946,11 @@ struct PyDowncastErrorArguments {

impl PyErrArguments for PyDowncastErrorArguments {
fn arguments(self, py: Python<'_>) -> PyObject {
use crate::types::typeobject::PyTypeMethods;
format!(
"'{}' object cannot be converted to '{}'",
self.from
.as_ref(py)
.bind(py)
.qualname()
.as_deref()
.unwrap_or("<failed to extract type name>"),
Expand Down
1 change: 1 addition & 0 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ pub use crate::types::set::PySetMethods;
pub use crate::types::string::PyStringMethods;
pub use crate::types::traceback::PyTracebackMethods;
pub use crate::types::tuple::PyTupleMethods;
pub use crate::types::typeobject::PyTypeMethods;
2 changes: 1 addition & 1 deletion src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,4 @@ mod slice;
pub(crate) mod string;
pub(crate) mod traceback;
pub(crate) mod tuple;
mod typeobject;
pub(crate) mod typeobject;
37 changes: 36 additions & 1 deletion src/types/typeobject.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::err::{self, PyResult};
use crate::{ffi, PyAny, PyTypeInfo, Python};
use crate::{ffi, Bound, PyAny, PyTypeInfo, Python};
use std::borrow::Cow;
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
use std::ffi::CStr;
Expand Down Expand Up @@ -108,6 +108,41 @@ impl PyType {
}
}

/// Implementation of functionality for [`PyType`].
///
/// These methods are defined for the `Bound<'py, PyType>` smart pointer, so to use method call
/// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`.
pub trait PyTypeMethods<'py> {
/// Gets the [qualified name](https://docs.python.org/3/glossary.html#term-qualified-name) of the `PyType`.
fn qualname(&self) -> PyResult<String>;
}

impl<'py> PyTypeMethods<'py> for Bound<'py, PyType> {
fn qualname(&self) -> PyResult<String> {
use crate::types::any::PyAnyMethods;
#[cfg(any(Py_LIMITED_API, PyPy, not(Py_3_11)))]
let name = self
.as_any()
.getattr(intern!(self.py(), "__qualname__"))?
.extract();

#[cfg(not(any(Py_LIMITED_API, PyPy, not(Py_3_11))))]
let name = {
use crate::ffi_ptr_ext::FfiPtrExt;

let obj = unsafe {
ffi::PyType_GetQualName(self.as_ptr() as *mut ffi::PyTypeObject)
.assume_owned_or_err(self.py())?
};

obj.extract()
};

name
}
}

#[cfg(test)]
mod tests {
use crate::types::{PyBool, PyLong};
Expand Down
2 changes: 1 addition & 1 deletion tests/test_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl ClassMethod {
fn method_owned(cls: Py<PyType>) -> PyResult<String> {
Ok(format!(
"{}.method_owned()!",
Python::with_gil(|gil| cls.as_ref(gil).qualname())?
Python::with_gil(|gil| cls.bind(gil).qualname())?
))
}
}
Expand Down

0 comments on commit 291145f

Please sign in to comment.