From dbc2be7c8c35ddbbd8fcb34f1e3ca12ab973a46a Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Wed, 18 Dec 2024 14:10:49 +0100 Subject: [PATCH 1/4] Simplify __new__ --- examples/pure/pure.pyi | 4 +- pyo3-stub-gen-derive/src/gen_stub.rs | 2 - pyo3-stub-gen-derive/src/gen_stub/method.rs | 8 ++- pyo3-stub-gen-derive/src/gen_stub/new.rs | 50 ------------------- .../src/gen_stub/pymethods.rs | 30 ++++++----- pyo3-stub-gen/src/generate.rs | 2 - pyo3-stub-gen/src/generate/class.rs | 2 +- pyo3-stub-gen/src/generate/method.rs | 9 +++- pyo3-stub-gen/src/generate/new.rs | 48 ------------------ pyo3-stub-gen/src/generate/stub_info.rs | 2 +- pyo3-stub-gen/src/type_info.rs | 10 +--- 11 files changed, 38 insertions(+), 129 deletions(-) delete mode 100644 pyo3-stub-gen-derive/src/gen_stub/new.rs delete mode 100644 pyo3-stub-gen/src/generate/new.rs diff --git a/examples/pure/pure.pyi b/examples/pure/pure.pyi index 0e22628..d524802 100644 --- a/examples/pure/pure.pyi +++ b/examples/pure/pure.pyi @@ -9,7 +9,9 @@ from enum import Enum, auto MY_CONSTANT: int class A: x: int - def __new__(cls,x:int): ... + def __new__(cls, x:int) -> A: + ... + def show_x(self) -> None: ... diff --git a/pyo3-stub-gen-derive/src/gen_stub.rs b/pyo3-stub-gen-derive/src/gen_stub.rs index 4e6436f..bf02077 100644 --- a/pyo3-stub-gen-derive/src/gen_stub.rs +++ b/pyo3-stub-gen-derive/src/gen_stub.rs @@ -63,7 +63,6 @@ mod arg; mod attr; mod member; mod method; -mod new; mod pyclass; mod pyclass_enum; mod pyfunction; @@ -76,7 +75,6 @@ use arg::*; use attr::*; use member::*; use method::*; -use new::*; use pyclass::*; use pyclass_enum::*; use pyfunction::*; diff --git a/pyo3-stub-gen-derive/src/gen_stub/method.rs b/pyo3-stub-gen-derive/src/gen_stub/method.rs index 633d9f6..d18414a 100644 --- a/pyo3-stub-gen-derive/src/gen_stub/method.rs +++ b/pyo3-stub-gen-derive/src/gen_stub/method.rs @@ -18,6 +18,7 @@ pub struct MethodInfo { doc: String, is_static: bool, is_class: bool, + pub(crate) is_new: bool, } fn replace_inner(ty: &mut Type, self_: &Type) { @@ -64,16 +65,18 @@ impl TryFrom for MethodInfo { let mut text_sig = Signature::overriding_operator(&sig); let mut is_static = false; let mut is_class = false; + let mut is_new = false; for attr in attrs { match attr { Attr::Name(name) => method_name = Some(name), Attr::Signature(text_sig_) => text_sig = Some(text_sig_), Attr::StaticMethod => is_static = true, Attr::ClassMethod => is_class = true, + Attr::New => {is_new = true; is_class = true}, _ => {} } } - let name = method_name.unwrap_or(sig.ident.to_string()); + let name = if is_new { "__new__".to_string() } else { method_name.unwrap_or(sig.ident.to_string()) }; let r#return = escape_return_type(&sig.output); Ok(MethodInfo { name, @@ -83,6 +86,7 @@ impl TryFrom for MethodInfo { doc, is_static, is_class, + is_new, }) } } @@ -97,6 +101,7 @@ impl ToTokens for MethodInfo { doc, is_class, is_static, + is_new, } = self; let sig_tt = quote_option(sig); let ret_tt = if let Some(ret) = ret { @@ -113,6 +118,7 @@ impl ToTokens for MethodInfo { doc: #doc, is_static: #is_static, is_class: #is_class, + is_new: #is_new } }) } diff --git a/pyo3-stub-gen-derive/src/gen_stub/new.rs b/pyo3-stub-gen-derive/src/gen_stub/new.rs deleted file mode 100644 index 8d01638..0000000 --- a/pyo3-stub-gen-derive/src/gen_stub/new.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::{parse_args, parse_pyo3_attrs, quote_option, ArgInfo, Attr, Signature}; - -use proc_macro2::TokenStream as TokenStream2; -use quote::{quote, ToTokens, TokenStreamExt}; -use syn::{Error, ImplItemFn, Result}; - -#[derive(Debug)] -pub struct NewInfo { - args: Vec, - sig: Option, -} - -impl NewInfo { - pub fn is_candidate(item: &ImplItemFn) -> Result { - let attrs = parse_pyo3_attrs(&item.attrs)?; - Ok(attrs.iter().any(|attr| matches!(attr, Attr::New))) - } -} - -impl TryFrom for NewInfo { - type Error = Error; - fn try_from(item: ImplItemFn) -> Result { - assert!(Self::is_candidate(&item)?); - let ImplItemFn { attrs, sig, .. } = item; - let attrs = parse_pyo3_attrs(&attrs)?; - let mut new_sig = None; - for attr in attrs { - if let Attr::Signature(text_sig) = attr { - new_sig = Some(text_sig); - } - } - Ok(NewInfo { - args: parse_args(sig.inputs)?, - sig: new_sig, - }) - } -} - -impl ToTokens for NewInfo { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let Self { args, sig } = self; - let sig_tt = quote_option(sig); - tokens.append_all(quote! { - ::pyo3_stub_gen::type_info::NewInfo { - args: &[ #(#args),* ], - signature: #sig_tt, - } - }) - } -} diff --git a/pyo3-stub-gen-derive/src/gen_stub/pymethods.rs b/pyo3-stub-gen-derive/src/gen_stub/pymethods.rs index c35e7cc..91a0d9c 100644 --- a/pyo3-stub-gen-derive/src/gen_stub/pymethods.rs +++ b/pyo3-stub-gen-derive/src/gen_stub/pymethods.rs @@ -2,11 +2,11 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{Error, ImplItem, ItemImpl, Result, Type}; -use super::{quote_option, MemberInfo, MethodInfo, NewInfo}; +use super::{quote_option, MemberInfo, MethodInfo}; pub struct PyMethodsInfo { struct_id: Type, - new: Option, + new: Option, getters: Vec, methods: Vec, } @@ -19,17 +19,21 @@ impl TryFrom for PyMethodsInfo { let mut getters = Vec::new(); let mut methods = Vec::new(); - for inner in item.items { - if let ImplItem::Fn(item_fn) = inner { - if NewInfo::is_candidate(&item_fn)? { - new = Some(NewInfo::try_from(item_fn)?); - } else if MemberInfo::is_candidate_item(&item_fn)? { - getters.push(MemberInfo::try_from(item_fn)?); - } else { - let mut method = MethodInfo::try_from(item_fn)?; - method.replace_self(&item.self_ty); - methods.push(method); - } + for inner in item.items.into_iter() { + let ImplItem::Fn(item_fn) = inner else { + continue; + }; + if MemberInfo::is_candidate_item(&item_fn)? { + getters.push(MemberInfo::try_from(item_fn)?); + continue; + } + + let mut method = MethodInfo::try_from(item_fn)?; + method.replace_self(&item.self_ty); + if method.is_new { + new = Some(method) + } else { + methods.push(method); } } Ok(Self { diff --git a/pyo3-stub-gen/src/generate.rs b/pyo3-stub-gen/src/generate.rs index 5e21bbb..ac9cd30 100644 --- a/pyo3-stub-gen/src/generate.rs +++ b/pyo3-stub-gen/src/generate.rs @@ -8,7 +8,6 @@ mod function; mod member; mod method; mod module; -mod new; mod stub_info; mod variable; @@ -20,7 +19,6 @@ pub use function::*; pub use member::*; pub use method::*; pub use module::*; -pub use new::*; pub use stub_info::*; pub use variable::*; diff --git a/pyo3-stub-gen/src/generate/class.rs b/pyo3-stub-gen/src/generate/class.rs index e115ef8..8998656 100644 --- a/pyo3-stub-gen/src/generate/class.rs +++ b/pyo3-stub-gen/src/generate/class.rs @@ -6,7 +6,7 @@ use std::fmt; pub struct ClassDef { pub name: &'static str, pub doc: &'static str, - pub new: Option, + pub new: Option, pub members: Vec, pub methods: Vec, } diff --git a/pyo3-stub-gen/src/generate/method.rs b/pyo3-stub-gen/src/generate/method.rs index 82a20c6..0d90fbe 100644 --- a/pyo3-stub-gen/src/generate/method.rs +++ b/pyo3-stub-gen/src/generate/method.rs @@ -11,6 +11,7 @@ pub struct MethodDef { pub doc: &'static str, pub is_static: bool, pub is_class: bool, + pub is_new: bool, } impl Import for MethodDef { @@ -33,6 +34,7 @@ impl From<&MethodInfo> for MethodDef { doc: info.doc, is_static: info.is_static, is_class: info.is_class, + is_new: info.is_new, } } } @@ -44,8 +46,11 @@ impl fmt::Display for MethodDef { if self.is_static { writeln!(f, "{indent}@staticmethod")?; write!(f, "{indent}def {}(", self.name)?; - } else if self.is_class { - writeln!(f, "{indent}@classmethod")?; + } else if self.is_new || self.is_class { + if !self.is_new { + // new is a classmethod without the decorator + writeln!(f, "{indent}@classmethod")?; + } write!(f, "{indent}def {}(cls", self.name)?; needs_comma = true; } else { diff --git a/pyo3-stub-gen/src/generate/new.rs b/pyo3-stub-gen/src/generate/new.rs deleted file mode 100644 index a3dc6c3..0000000 --- a/pyo3-stub-gen/src/generate/new.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{generate::*, type_info::*}; -use std::fmt; - -/// Definition of `__new__` method. -#[derive(Debug, Clone, PartialEq)] -pub struct NewDef { - pub args: Vec, - pub signature: Option<&'static str>, -} - -impl Import for NewDef { - fn import(&self) -> HashSet { - let mut import = HashSet::new(); - for arg in &self.args { - import.extend(arg.import().into_iter()); - } - import - } -} - -impl From<&NewInfo> for NewDef { - fn from(info: &NewInfo) -> Self { - Self { - args: info.args.iter().map(Arg::from).collect(), - signature: info.signature, - } - } -} - -impl fmt::Display for NewDef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let indent = indent(); - write!(f, "{indent}def __new__(cls,")?; - if let Some(signature) = self.signature { - let joined = signature.replace('\n', " "); - write!(f, "{}", joined)?; - } else { - for (n, arg) in self.args.iter().enumerate() { - write!(f, "{}", arg)?; - if n != self.args.len() - 1 { - write!(f, ", ")?; - } - } - } - writeln!(f, "): ...")?; - Ok(()) - } -} diff --git a/pyo3-stub-gen/src/generate/stub_info.rs b/pyo3-stub-gen/src/generate/stub_info.rs index cbea2cc..90637fb 100644 --- a/pyo3-stub-gen/src/generate/stub_info.rs +++ b/pyo3-stub-gen/src/generate/stub_info.rs @@ -135,7 +135,7 @@ impl StubInfoBuilder { entry.methods.push(MethodDef::from(method)) } if let Some(new) = &info.new { - entry.new = Some(NewDef::from(new)); + entry.new = Some(MethodDef::from(new)); } return; } diff --git a/pyo3-stub-gen/src/type_info.rs b/pyo3-stub-gen/src/type_info.rs index 1ae983a..748ff86 100644 --- a/pyo3-stub-gen/src/type_info.rs +++ b/pyo3-stub-gen/src/type_info.rs @@ -51,6 +51,7 @@ pub struct MethodInfo { pub doc: &'static str, pub is_static: bool, pub is_class: bool, + pub is_new: bool, } /// Info of getter method decorated with `#[getter]` or `#[pyo3(get, set)]` appears in `#[pyclass]` @@ -60,20 +61,13 @@ pub struct MemberInfo { pub r#type: fn() -> TypeInfo, } -/// Info of `#[new]`-attributed methods appears in `#[pymethods]` -#[derive(Debug)] -pub struct NewInfo { - pub args: &'static [ArgInfo], - pub signature: Option<&'static str>, -} - /// Info of `#[pymethod]` #[derive(Debug)] pub struct PyMethodsInfo { // The Rust struct type-id of `impl` block where `#[pymethod]` acts on pub struct_id: fn() -> TypeId, /// Method specified `#[new]` attribute - pub new: Option, + pub new: Option, /// Methods decorated with `#[getter]` pub getters: &'static [MemberInfo], /// Other usual methods From 824113d2f1ba402dd663578a787c937aac7c9c44 Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Wed, 18 Dec 2024 14:13:05 +0100 Subject: [PATCH 2/4] Fix tests --- pyo3-stub-gen/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pyo3-stub-gen/src/lib.rs b/pyo3-stub-gen/src/lib.rs index 176e619..aabfba4 100644 --- a/pyo3-stub-gen/src/lib.rs +++ b/pyo3-stub-gen/src/lib.rs @@ -123,6 +123,7 @@ //! doc: "This is a foo method.", //! is_static: false, //! is_class: false, +//! is_new: false, //! }; //! //! assert_eq!( From a3e3d8374964a573518173ad52aec9eb91efb894 Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Wed, 18 Dec 2024 14:18:51 +0100 Subject: [PATCH 3/4] =?UTF-8?q?Remove=20new=20attr,=20it=E2=80=99s=20just?= =?UTF-8?q?=20a=20method=20now?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyo3-stub-gen-derive/src/gen_stub/pymethods.rs | 14 ++------------ pyo3-stub-gen/src/generate/class.rs | 8 -------- pyo3-stub-gen/src/generate/stub_info.rs | 3 --- pyo3-stub-gen/src/type_info.rs | 2 -- 4 files changed, 2 insertions(+), 25 deletions(-) diff --git a/pyo3-stub-gen-derive/src/gen_stub/pymethods.rs b/pyo3-stub-gen-derive/src/gen_stub/pymethods.rs index 91a0d9c..483f440 100644 --- a/pyo3-stub-gen-derive/src/gen_stub/pymethods.rs +++ b/pyo3-stub-gen-derive/src/gen_stub/pymethods.rs @@ -2,11 +2,10 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{Error, ImplItem, ItemImpl, Result, Type}; -use super::{quote_option, MemberInfo, MethodInfo}; +use super::{MemberInfo, MethodInfo}; pub struct PyMethodsInfo { struct_id: Type, - new: Option, getters: Vec, methods: Vec, } @@ -15,7 +14,6 @@ impl TryFrom for PyMethodsInfo { type Error = Error; fn try_from(item: ItemImpl) -> Result { let struct_id = *item.self_ty.clone(); - let mut new = None; let mut getters = Vec::new(); let mut methods = Vec::new(); @@ -30,15 +28,10 @@ impl TryFrom for PyMethodsInfo { let mut method = MethodInfo::try_from(item_fn)?; method.replace_self(&item.self_ty); - if method.is_new { - new = Some(method) - } else { - methods.push(method); - } + methods.push(method); } Ok(Self { struct_id, - new, getters, methods, }) @@ -49,15 +42,12 @@ impl ToTokens for PyMethodsInfo { fn to_tokens(&self, tokens: &mut TokenStream2) { let Self { struct_id, - new, getters, methods, } = self; - let new_tt = quote_option(new); tokens.append_all(quote! { ::pyo3_stub_gen::type_info::PyMethodsInfo { struct_id: std::any::TypeId::of::<#struct_id>, - new: #new_tt, getters: &[ #(#getters),* ], methods: &[ #(#methods),* ], } diff --git a/pyo3-stub-gen/src/generate/class.rs b/pyo3-stub-gen/src/generate/class.rs index 8998656..7f0f434 100644 --- a/pyo3-stub-gen/src/generate/class.rs +++ b/pyo3-stub-gen/src/generate/class.rs @@ -6,7 +6,6 @@ use std::fmt; pub struct ClassDef { pub name: &'static str, pub doc: &'static str, - pub new: Option, pub members: Vec, pub methods: Vec, } @@ -14,9 +13,6 @@ pub struct ClassDef { impl Import for ClassDef { fn import(&self) -> HashSet { let mut import = HashSet::new(); - if let Some(new) = &self.new { - import.extend(new.import()); - } for member in &self.members { import.extend(member.import()); } @@ -33,7 +29,6 @@ impl From<&PyClassInfo> for ClassDef { // This is only an initializer. See `StubInfo::gather` for the actual merging. Self { name: info.pyclass_name, - new: None, doc: info.doc, members: info.members.iter().map(MemberDef::from).collect(), methods: Vec::new(), @@ -56,9 +51,6 @@ impl fmt::Display for ClassDef { for member in &self.members { member.fmt(f)?; } - if let Some(new) = &self.new { - new.fmt(f)?; - } for method in &self.methods { method.fmt(f)?; } diff --git a/pyo3-stub-gen/src/generate/stub_info.rs b/pyo3-stub-gen/src/generate/stub_info.rs index 90637fb..6656c0b 100644 --- a/pyo3-stub-gen/src/generate/stub_info.rs +++ b/pyo3-stub-gen/src/generate/stub_info.rs @@ -134,9 +134,6 @@ impl StubInfoBuilder { for method in info.methods { entry.methods.push(MethodDef::from(method)) } - if let Some(new) = &info.new { - entry.new = Some(MethodDef::from(new)); - } return; } } diff --git a/pyo3-stub-gen/src/type_info.rs b/pyo3-stub-gen/src/type_info.rs index 748ff86..a4e4152 100644 --- a/pyo3-stub-gen/src/type_info.rs +++ b/pyo3-stub-gen/src/type_info.rs @@ -66,8 +66,6 @@ pub struct MemberInfo { pub struct PyMethodsInfo { // The Rust struct type-id of `impl` block where `#[pymethod]` acts on pub struct_id: fn() -> TypeId, - /// Method specified `#[new]` attribute - pub new: Option, /// Methods decorated with `#[getter]` pub getters: &'static [MemberInfo], /// Other usual methods From 45b6e60ddc82a38cc55e67cf1195002e167820d7 Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Wed, 18 Dec 2024 14:39:03 +0100 Subject: [PATCH 4/4] Improve typing --- pyo3-stub-gen-derive/src/gen_stub/method.rs | 46 ++++++++++++--------- pyo3-stub-gen/src/generate/method.rs | 38 +++++++++-------- pyo3-stub-gen/src/lib.rs | 4 +- pyo3-stub-gen/src/type_info.rs | 13 ++++-- 4 files changed, 58 insertions(+), 43 deletions(-) diff --git a/pyo3-stub-gen-derive/src/gen_stub/method.rs b/pyo3-stub-gen-derive/src/gen_stub/method.rs index d18414a..3b58697 100644 --- a/pyo3-stub-gen-derive/src/gen_stub/method.rs +++ b/pyo3-stub-gen-derive/src/gen_stub/method.rs @@ -9,6 +9,14 @@ use syn::{ Error, GenericArgument, ImplItemFn, PathArguments, Result, Type, TypePath, TypeReference, }; +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum MethodType { + Instance, + Static, + Class, + New, +} + #[derive(Debug)] pub struct MethodInfo { name: String, @@ -16,9 +24,7 @@ pub struct MethodInfo { sig: Option, r#return: Option, doc: String, - is_static: bool, - is_class: bool, - pub(crate) is_new: bool, + r#type: MethodType, } fn replace_inner(ty: &mut Type, self_: &Type) { @@ -63,20 +69,22 @@ impl TryFrom for MethodInfo { let attrs = parse_pyo3_attrs(&attrs)?; let mut method_name = None; let mut text_sig = Signature::overriding_operator(&sig); - let mut is_static = false; - let mut is_class = false; - let mut is_new = false; + let mut method_type = MethodType::Instance; for attr in attrs { match attr { Attr::Name(name) => method_name = Some(name), Attr::Signature(text_sig_) => text_sig = Some(text_sig_), - Attr::StaticMethod => is_static = true, - Attr::ClassMethod => is_class = true, - Attr::New => {is_new = true; is_class = true}, + Attr::StaticMethod => method_type = MethodType::Static, + Attr::ClassMethod => method_type = MethodType::Class, + Attr::New => method_type = MethodType::New, _ => {} } } - let name = if is_new { "__new__".to_string() } else { method_name.unwrap_or(sig.ident.to_string()) }; + let name = if method_type == MethodType::New { + "__new__".to_string() + } else { + method_name.unwrap_or(sig.ident.to_string()) + }; let r#return = escape_return_type(&sig.output); Ok(MethodInfo { name, @@ -84,9 +92,7 @@ impl TryFrom for MethodInfo { args: parse_args(sig.inputs)?, r#return, doc, - is_static, - is_class, - is_new, + r#type: method_type, }) } } @@ -99,9 +105,7 @@ impl ToTokens for MethodInfo { args, sig, doc, - is_class, - is_static, - is_new, + r#type, } = self; let sig_tt = quote_option(sig); let ret_tt = if let Some(ret) = ret { @@ -109,6 +113,12 @@ impl ToTokens for MethodInfo { } else { quote! { ::pyo3_stub_gen::type_info::no_return_type_output } }; + let type_tt = match r#type { + MethodType::Instance => quote! { ::pyo3_stub_gen::type_info::MethodType::Instance }, + MethodType::Static => quote! { ::pyo3_stub_gen::type_info::MethodType::Static }, + MethodType::Class => quote! { ::pyo3_stub_gen::type_info::MethodType::Class }, + MethodType::New => quote! { ::pyo3_stub_gen::type_info::MethodType::New }, + }; tokens.append_all(quote! { ::pyo3_stub_gen::type_info::MethodInfo { name: #name, @@ -116,9 +126,7 @@ impl ToTokens for MethodInfo { r#return: #ret_tt, signature: #sig_tt, doc: #doc, - is_static: #is_static, - is_class: #is_class, - is_new: #is_new + r#type: #type_tt } }) } diff --git a/pyo3-stub-gen/src/generate/method.rs b/pyo3-stub-gen/src/generate/method.rs index 0d90fbe..f018d18 100644 --- a/pyo3-stub-gen/src/generate/method.rs +++ b/pyo3-stub-gen/src/generate/method.rs @@ -1,6 +1,8 @@ use crate::{generate::*, type_info::*, TypeInfo}; use std::{collections::HashSet, fmt}; +pub use crate::type_info::MethodType; + /// Definition of a class method. #[derive(Debug, Clone, PartialEq)] pub struct MethodDef { @@ -9,9 +11,7 @@ pub struct MethodDef { pub signature: Option<&'static str>, pub r#return: TypeInfo, pub doc: &'static str, - pub is_static: bool, - pub is_class: bool, - pub is_new: bool, + pub r#type: MethodType, } impl Import for MethodDef { @@ -32,9 +32,7 @@ impl From<&MethodInfo> for MethodDef { signature: info.signature, r#return: (info.r#return)(), doc: info.doc, - is_static: info.is_static, - is_class: info.is_class, - is_new: info.is_new, + r#type: info.r#type, } } } @@ -43,19 +41,23 @@ impl fmt::Display for MethodDef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let indent = indent(); let mut needs_comma = false; - if self.is_static { - writeln!(f, "{indent}@staticmethod")?; - write!(f, "{indent}def {}(", self.name)?; - } else if self.is_new || self.is_class { - if !self.is_new { - // new is a classmethod without the decorator - writeln!(f, "{indent}@classmethod")?; + match self.r#type { + MethodType::Static => { + writeln!(f, "{indent}@staticmethod")?; + write!(f, "{indent}def {}(", self.name)?; + } + MethodType::Class | MethodType::New => { + if self.r#type == MethodType::Class { + // new is a classmethod without the decorator + writeln!(f, "{indent}@classmethod")?; + } + write!(f, "{indent}def {}(cls", self.name)?; + needs_comma = true; + } + MethodType::Instance => { + write!(f, "{indent}def {}(self", self.name)?; + needs_comma = true; } - write!(f, "{indent}def {}(cls", self.name)?; - needs_comma = true; - } else { - write!(f, "{indent}def {}(self", self.name)?; - needs_comma = true; } if let Some(signature) = self.signature { if needs_comma { diff --git a/pyo3-stub-gen/src/lib.rs b/pyo3-stub-gen/src/lib.rs index aabfba4..13baf8b 100644 --- a/pyo3-stub-gen/src/lib.rs +++ b/pyo3-stub-gen/src/lib.rs @@ -121,9 +121,7 @@ //! signature: None, //! r#return: TypeInfo::builtin("int"), //! doc: "This is a foo method.", -//! is_static: false, -//! is_class: false, -//! is_new: false, +//! r#type: MethodType::Instance, //! }; //! //! assert_eq!( diff --git a/pyo3-stub-gen/src/type_info.rs b/pyo3-stub-gen/src/type_info.rs index a4e4152..ff1644c 100644 --- a/pyo3-stub-gen/src/type_info.rs +++ b/pyo3-stub-gen/src/type_info.rs @@ -41,6 +41,15 @@ pub struct ArgInfo { pub r#type: fn() -> TypeInfo, } +/// Type of a method +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum MethodType { + Instance, + Static, + Class, + New, +} + /// Info of usual method appears in `#[pymethod]` #[derive(Debug)] pub struct MethodInfo { @@ -49,9 +58,7 @@ pub struct MethodInfo { pub r#return: fn() -> TypeInfo, pub signature: Option<&'static str>, pub doc: &'static str, - pub is_static: bool, - pub is_class: bool, - pub is_new: bool, + pub r#type: MethodType, } /// Info of getter method decorated with `#[getter]` or `#[pyo3(get, set)]` appears in `#[pyclass]`