diff --git a/newsfragments/5157.added.md b/newsfragments/5157.added.md new file mode 100644 index 00000000000..39b326230c6 --- /dev/null +++ b/newsfragments/5157.added.md @@ -0,0 +1 @@ +- Add support for class associated consts introspection. diff --git a/pyo3-macros-backend/src/pyimpl.rs b/pyo3-macros-backend/src/pyimpl.rs index 90b0d961cd8..b20763aa903 100644 --- a/pyo3-macros-backend/src/pyimpl.rs +++ b/pyo3-macros-backend/src/pyimpl.rs @@ -4,6 +4,8 @@ use std::collections::HashSet; use crate::introspection::function_introspection_code; #[cfg(feature = "experimental-inspect")] use crate::method::{FnSpec, FnType}; +#[cfg(feature = "experimental-inspect")] +use crate::pyfunction::FunctionSignature; use crate::utils::{has_attribute, has_attribute_with_namespace, Ctx, PyO3CratePath}; use crate::{ attributes::{take_pyo3_options, CrateAttribute}, @@ -166,6 +168,8 @@ pub fn impl_methods( attributes, }; let attrs = get_cfg_attributes(&konst.attrs); + #[cfg(feature = "experimental-inspect")] + extra_fragments.push(class_const_introspection_code(&spec, ty, ctx)); let MethodAndMethodDef { associated_method, method_def, @@ -391,3 +395,19 @@ fn method_introspection_code(spec: &FnSpec<'_>, parent: &syn::Type, ctx: &Ctx) - Some(parent), ) } + +#[cfg(feature = "experimental-inspect")] +fn class_const_introspection_code(spec: &ConstSpec, parent: &syn::Type, ctx: &Ctx) -> TokenStream { + let Ctx { pyo3_path, .. } = ctx; + + let name = spec.python_name().to_string(); + function_introspection_code( + pyo3_path, + None, + &name, + &FunctionSignature::from_arguments(vec![]), + Some("cls"), + vec!["classmethod".into(), "property".into()], // TODO: this combination only works with Python 3.9-3.11 https://docs.python.org/3.11/library/functions.html#classmethod + Some(parent), + ) +} diff --git a/pytests/src/pyclasses.rs b/pytests/src/pyclasses.rs index 4e681b2c941..83cd8675890 100644 --- a/pytests/src/pyclasses.rs +++ b/pytests/src/pyclasses.rs @@ -9,6 +9,9 @@ struct EmptyClass {} #[pymethods] impl EmptyClass { + #[classattr] + const CLS_ATTRIBUTE: u32 = 42; + #[new] fn new() -> Self { EmptyClass {} diff --git a/pytests/stubs/pyclasses.pyi b/pytests/stubs/pyclasses.pyi index 13b52f1c4e2..2a6854f5faa 100644 --- a/pytests/stubs/pyclasses.pyi +++ b/pytests/stubs/pyclasses.pyi @@ -18,6 +18,9 @@ class ClassWithDecorators: class ClassWithoutConstructor: ... class EmptyClass: + @classmethod + @property + def CLS_ATTRIBUTE(cls, /): ... def __len__(self, /): ... def __new__(cls, /): ... def method(self, /): ...