pyo3_stub_gen/generate/
member.rs1use crate::generate::docstring::normalize_docstring;
2use crate::{generate::*, type_info::*, TypeInfo};
3use std::{
4 borrow::Cow,
5 collections::HashSet,
6 fmt::{self},
7};
8
9#[derive(Debug, Clone, PartialEq)]
11pub struct MemberDef {
12 pub name: &'static str,
13 pub r#type: TypeInfo,
14 pub doc: &'static str,
15 pub default: Option<String>,
16 pub deprecated: Option<DeprecatedInfo>,
17}
18
19impl Import for MemberDef {
20 fn import(&self) -> HashSet<ImportRef> {
21 let mut import = self.r#type.import.clone();
22 if self.deprecated.is_some() {
24 import.insert("typing_extensions".into());
25 }
26 import
27 }
28}
29
30impl From<&MemberInfo> for MemberDef {
31 fn from(info: &MemberInfo) -> Self {
32 let doc = if info.doc.is_empty() {
33 ""
34 } else {
35 Box::leak(normalize_docstring(info.doc).into_boxed_str())
36 };
37
38 Self {
39 name: info.name,
40 r#type: (info.r#type)(),
41 doc,
42 default: info.default.map(|f| f()),
43 deprecated: info.deprecated.clone(),
44 }
45 }
46}
47
48impl fmt::Display for MemberDef {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 let indent = indent();
51 if let Some(_deprecated) = &self.deprecated {
54 log::warn!(
55 "Ignoring #[deprecated] on constant '{}': Python constants cannot have decorators. \
56 Consider using a function instead if deprecation is needed.",
57 self.name
58 );
59 }
60 write!(f, "{indent}{}: {}", self.name, self.r#type)?;
61 if let Some(default) = &self.default {
62 write!(f, " = {default}")?;
63 }
64 writeln!(f)?;
65 docstring::write_docstring(f, self.doc, indent)?;
66 Ok(())
67 }
68}
69
70impl MemberDef {
71 pub fn fmt_for_module(
76 &self,
77 target_module: &str,
78 f: &mut fmt::Formatter,
79 indent: &str,
80 ) -> fmt::Result {
81 if let Some(_deprecated) = &self.deprecated {
84 log::warn!(
85 "Ignoring #[deprecated] on constant '{}': Python constants cannot have decorators. \
86 Consider using a function instead if deprecation is needed.",
87 self.name
88 );
89 }
90 let qualified_type = self.r#type.qualified_for_module(target_module);
91 write!(f, "{indent}{}: {}", self.name, qualified_type)?;
92 if let Some(default) = &self.default {
93 write!(f, " = {default}")?;
94 }
95 writeln!(f)?;
96 docstring::write_docstring(f, self.doc, indent)?;
97 Ok(())
98 }
99}
100
101pub struct GetterDisplay<'a> {
102 pub member: &'a MemberDef,
103 pub target_module: &'a str,
104}
105
106pub struct SetterDisplay<'a> {
107 pub member: &'a MemberDef,
108 pub target_module: &'a str,
109}
110
111impl fmt::Display for GetterDisplay<'_> {
112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113 let indent = indent();
114 let qualified_type = self.member.r#type.qualified_for_module(self.target_module);
115 if let Some(deprecated) = &self.member.deprecated {
117 writeln!(f, "{indent}{deprecated}")?;
118 }
119 write!(
120 f,
121 "{indent}@property\n{indent}def {}(self) -> {}:",
122 self.member.name, qualified_type
123 )?;
124 let doc = if let Some(default) = &self.member.default {
125 if default == "..." {
126 Cow::Borrowed(self.member.doc)
127 } else {
128 Cow::Owned(format!(
129 "{}\n```python\ndefault = {default}\n```",
130 self.member.doc
131 ))
132 }
133 } else {
134 Cow::Borrowed(self.member.doc)
135 };
136 if !doc.is_empty() {
137 writeln!(f)?;
138 let double_indent = format!("{indent}{indent}");
139 docstring::write_docstring(f, &doc, &double_indent)
140 } else {
141 writeln!(f, " ...")
142 }
143 }
144}
145
146impl fmt::Display for SetterDisplay<'_> {
147 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148 let indent = indent();
149 let qualified_type = self.member.r#type.qualified_for_module(self.target_module);
150 writeln!(f, "{indent}@{}.setter", self.member.name)?;
152 if let Some(deprecated) = &self.member.deprecated {
153 writeln!(f, "{indent}{deprecated}")?;
154 }
155 write!(
156 f,
157 "{indent}def {}(self, value: {}) -> None:",
158 self.member.name, qualified_type
159 )?;
160 let doc = if let Some(default) = &self.member.default {
161 if default == "..." {
162 Cow::Borrowed(self.member.doc)
163 } else {
164 Cow::Owned(format!(
165 "{}\n```python\ndefault = {default}\n```",
166 self.member.doc
167 ))
168 }
169 } else {
170 Cow::Borrowed(self.member.doc)
171 };
172 if !doc.is_empty() {
173 writeln!(f)?;
174 let double_indent = format!("{indent}{indent}");
175 docstring::write_docstring(f, &doc, &double_indent)
176 } else {
177 writeln!(f, " ...")
178 }
179 }
180}