Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/5579.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `PyClass::NAME`.
1 change: 1 addition & 0 deletions newsfragments/5579.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deprecate `PyTypeInfo::NAME` and `PyTypeInfo::MODULE`.
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ impl<'a> FnSpec<'a> {
};
let python_name = &self.python_name;
let qualname_prefix = match cls {
Some(cls) => quote!(Some(<#cls as #pyo3_path::PyTypeInfo>::NAME)),
Some(cls) => quote!(Some(<#cls as #pyo3_path::PyClass>::NAME)),
None => quote!(None),
};
let arg_names = (0..args.len())
Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub fn impl_arg_params(
};

let cls_name = if let Some(cls) = self_ {
quote! { ::std::option::Option::Some(<#cls as #pyo3_path::type_object::PyTypeInfo>::NAME) }
quote! { ::std::option::Option::Some(<#cls as #pyo3_path::PyClass>::NAME) }
} else {
quote! { ::std::option::Option::None }
};
Expand Down
27 changes: 17 additions & 10 deletions pyo3-macros-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1951,13 +1951,6 @@ fn descriptors_to_items(

fn impl_pytypeinfo(cls: &syn::Ident, attr: &PyClassArgs, ctx: &Ctx) -> TokenStream {
let Ctx { pyo3_path, .. } = ctx;
let cls_name = get_class_python_name(cls, attr).to_string();

let module = if let Some(ModuleAttribute { value, .. }) = &attr.options.module {
quote! { ::core::option::Option::Some(#value) }
} else {
quote! { ::core::option::Option::None }
};

#[cfg(feature = "experimental-inspect")]
let type_hint = {
Expand All @@ -1966,11 +1959,14 @@ fn impl_pytypeinfo(cls: &syn::Ident, attr: &PyClassArgs, ctx: &Ctx) -> TokenStre
};
#[cfg(not(feature = "experimental-inspect"))]
let type_hint = quote! {};
#[cfg(not(feature = "experimental-inspect"))]
let _ = attr;

quote! {
unsafe impl #pyo3_path::type_object::PyTypeInfo for #cls {
const NAME: &'static str = #cls_name;
const MODULE: ::std::option::Option<&'static str> = #module;

const NAME: &str = <Self as #pyo3_path::PyClass>::NAME;
const MODULE: ::std::option::Option<&str> = <Self as #pyo3_path::impl_::pyclass::PyClassImpl>::MODULE;

#type_hint

Expand All @@ -1982,7 +1978,7 @@ fn impl_pytypeinfo(cls: &syn::Ident, attr: &PyClassArgs, ctx: &Ctx) -> TokenStre
.unwrap_or_else(|e| #pyo3_path::impl_::pyclass::type_object_init_failed(
py,
e,
<Self as #pyo3_path::type_object::PyTypeInfo>::NAME
<Self as #pyo3_path::PyClass>::NAME
))
.as_type_ptr()
}
Expand Down Expand Up @@ -2329,6 +2325,8 @@ impl<'a> PyClassImplsBuilder<'a> {
let Ctx { pyo3_path, .. } = ctx;
let cls = self.cls;

let cls_name = get_class_python_name(cls, self.attr).to_string();

let frozen = if self.attr.options.frozen.is_some() {
quote! { #pyo3_path::pyclass::boolean_struct::True }
} else {
Expand All @@ -2337,6 +2335,7 @@ impl<'a> PyClassImplsBuilder<'a> {

quote! {
impl #pyo3_path::PyClass for #cls {
const NAME: &str = #cls_name;
type Frozen = #frozen;
}
}
Expand Down Expand Up @@ -2379,6 +2378,13 @@ impl<'a> PyClassImplsBuilder<'a> {
.doc
.as_ref()
.map_or(c"".to_token_stream(), PythonDoc::to_token_stream);

let module = if let Some(ModuleAttribute { value, .. }) = &self.attr.options.module {
quote! { ::core::option::Option::Some(#value) }
} else {
quote! { ::core::option::Option::None }
};

let is_basetype = self.attr.options.subclass.is_some();
let base = match &self.attr.options.extends {
Some(extends_attr) => extends_attr.value.clone(),
Expand Down Expand Up @@ -2563,6 +2569,7 @@ impl<'a> PyClassImplsBuilder<'a> {
#pyclass_base_type_impl

impl #pyo3_path::impl_::pyclass::PyClassImpl for #cls {
const MODULE: ::std::option::Option<&str> = #module;
const IS_BASETYPE: bool = #is_basetype;
const IS_SUBCLASS: bool = #is_subclass;
const IS_MAPPING: bool = #is_mapping;
Expand Down
6 changes: 6 additions & 0 deletions src/impl_/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ unsafe impl Sync for PyClassItems {}
/// Users are discouraged from implementing this trait manually; it is a PyO3 implementation detail
/// and may be changed at any time.
pub trait PyClassImpl: Sized + 'static {
/// Module which the class will be associated with.
///
/// (Currently defaults to `builtins` if unset, this will likely be improved in the future, it
/// may also be removed when passing module objects in class init.)
const MODULE: Option<&'static str>;

/// #[pyclass(subclass)]
const IS_BASETYPE: bool = false;

Expand Down
4 changes: 2 additions & 2 deletions src/impl_/pyclass/doc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{ffi::CStr, marker::PhantomData};

use crate::{impl_::pyclass::PyClassImpl, PyClass, PyTypeInfo};
use crate::{impl_::pyclass::PyClassImpl, PyClass};

/// Trait implemented by classes with a known text signature for instantiation.
///
Expand All @@ -26,7 +26,7 @@ pub struct PyClassDocGenerator<

impl<ClassT: PyClass + PyClassNewTextSignature> PyClassDocGenerator<ClassT, true> {
pub const DOC_PIECES: &'static [&'static [u8]] = &[
<ClassT as PyTypeInfo>::NAME.as_bytes(),
<ClassT as PyClass>::NAME.as_bytes(),
ClassT::TEXT_SIGNATURE.as_bytes(),
b"\n--\n\n",
<ClassT as PyClassImpl>::RAW_DOC.to_bytes_with_nul(),
Expand Down
8 changes: 6 additions & 2 deletions src/impl_/pyclass/lazy_type_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,12 @@ impl<T: PyClass> LazyTypeObject<T> {

#[cold]
fn try_init<'py>(&self, py: Python<'py>) -> PyResult<&Bound<'py, PyType>> {
self.0
.get_or_try_init(py, create_type_object::<T>, T::NAME, T::items_iter())
self.0.get_or_try_init(
py,
create_type_object::<T>,
<T as PyClass>::NAME,
T::items_iter(),
)
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ pub use self::guard::{
/// The `#[pyclass]` attribute implements this trait for your Rust struct -
/// you shouldn't implement this trait directly.
pub trait PyClass: PyTypeInfo + PyClassImpl {
/// Name of the class.
///
/// This can be set via `#[pyclass(name = "...")]`, otherwise it defaults to the Rust type name.
const NAME: &'static str;

/// Whether the pyclass is frozen.
///
/// This can be enabled via `#[pyclass(frozen)]`.
Expand Down
6 changes: 3 additions & 3 deletions src/pyclass/create_type_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
pycell::PyClassObject,
pyclass::{
assign_sequence_item_from_mapping, get_sequence_item_from_mapping, tp_dealloc,
tp_dealloc_with_gc, PyClassItemsIter,
tp_dealloc_with_gc, PyClassImpl, PyClassItemsIter,
},
pymethods::{Getter, PyGetterDef, PyMethodDefType, PySetterDef, Setter, _call_clear},
trampoline::trampoline,
Expand Down Expand Up @@ -96,8 +96,8 @@ where
T::weaklist_offset(),
T::IS_BASETYPE,
T::items_iter(),
T::NAME,
T::MODULE,
<T as PyClass>::NAME,
<T as PyClassImpl>::MODULE,
std::mem::size_of::<PyClassObject<T>>(),
)
}
Expand Down
9 changes: 9 additions & 0 deletions src/type_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,17 @@ pub trait PySizedLayout<T>: PyLayout<T> + Sized {}
/// `is_exact_type_of` must only return true for objects whose type is exactly `Self`.
pub unsafe trait PyTypeInfo: Sized {
/// Class name.
#[deprecated(
since = "0.28.0",
note = "prefer using `::type_object(py).name()` to get the correct runtime value"
)]
const NAME: &'static str;

/// Module name, if any.
#[deprecated(
since = "0.28.0",
note = "prefer using `::type_object(py).module()` to get the correct runtime value"
)]
const MODULE: Option<&'static str>;

/// Provides the full python type as a type hint.
Expand Down Expand Up @@ -124,6 +132,7 @@ unsafe impl<T> PyTypeCheck for T
where
T: PyTypeInfo,
{
#[allow(deprecated)]
const NAME: &'static str = T::NAME;

#[cfg(feature = "experimental-inspect")]
Expand Down
5 changes: 4 additions & 1 deletion src/types/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,10 @@ impl<'py> PyModuleMethods<'py> for Bound<'py, PyModule> {
T: PyClass,
{
let py = self.py();
self.add(T::NAME, T::lazy_type_object().get_or_try_init(py)?)
self.add(
<T as PyClass>::NAME,
T::lazy_type_object().get_or_try_init(py)?,
)
}

fn add_wrapped<T>(&self, wrapper: &impl Fn(Python<'py>) -> T) -> PyResult<()>
Expand Down
Loading