pyo3_stub_gen/generate/
method.rs

1use crate::{generate::*, type_info::*, TypeInfo};
2use std::{collections::HashSet, fmt};
3
4pub use crate::type_info::MethodType;
5
6/// Definition of a class method.
7#[derive(Debug, Clone, PartialEq)]
8pub struct MethodDef {
9    pub name: &'static str,
10    pub args: Vec<Arg>,
11    pub r#return: TypeInfo,
12    pub doc: &'static str,
13    pub r#type: MethodType,
14    pub is_async: bool,
15    pub deprecated: Option<DeprecatedInfo>,
16}
17
18impl Import for MethodDef {
19    fn import(&self) -> HashSet<ModuleRef> {
20        let mut import = self.r#return.import.clone();
21        for arg in &self.args {
22            import.extend(arg.import().into_iter());
23        }
24        // Add typing_extensions import if deprecated
25        if self.deprecated.is_some() {
26            import.insert("typing_extensions".into());
27        }
28        import
29    }
30}
31
32impl From<&MethodInfo> for MethodDef {
33    fn from(info: &MethodInfo) -> Self {
34        Self {
35            name: info.name,
36            args: info.args.iter().map(Arg::from).collect(),
37            r#return: (info.r#return)(),
38            doc: info.doc,
39            r#type: info.r#type,
40            is_async: info.is_async,
41            deprecated: info.deprecated.clone(),
42        }
43    }
44}
45
46impl fmt::Display for MethodDef {
47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48        let indent = indent();
49        let mut needs_comma = false;
50        let async_ = if self.is_async { "async " } else { "" };
51
52        // Add deprecated decorator if present
53        if let Some(deprecated) = &self.deprecated {
54            writeln!(f, "{indent}{deprecated}")?;
55        }
56
57        match self.r#type {
58            MethodType::Static => {
59                writeln!(f, "{indent}@staticmethod")?;
60                write!(f, "{indent}{async_}def {}(", self.name)?;
61            }
62            MethodType::Class | MethodType::New => {
63                if self.r#type == MethodType::Class {
64                    // new is a classmethod without the decorator
65                    writeln!(f, "{indent}@classmethod")?;
66                }
67                write!(f, "{indent}{async_}def {}(cls", self.name)?;
68                needs_comma = true;
69            }
70            MethodType::Instance => {
71                write!(f, "{indent}{async_}def {}(self", self.name)?;
72                needs_comma = true;
73            }
74        }
75        for arg in &self.args {
76            if needs_comma {
77                write!(f, ", ")?;
78            }
79            write!(f, "{arg}")?;
80            needs_comma = true;
81        }
82        write!(f, ") -> {}:", self.r#return)?;
83
84        let doc = self.doc;
85        if !doc.is_empty() {
86            writeln!(f)?;
87            let double_indent = format!("{indent}{indent}");
88            docstring::write_docstring(f, self.doc, &double_indent)?;
89        } else {
90            writeln!(f, " ...")?;
91        }
92        Ok(())
93    }
94}