pyo3_stub_gen_derive/
gen_stub.rs1mod arg;
79mod attr;
80mod member;
81mod method;
82mod parameter;
83mod parse_python;
84mod pyclass;
85mod pyclass_complex_enum;
86mod pyclass_enum;
87mod pyfunction;
88mod pymethods;
89mod renaming;
90mod signature;
91mod stub_type;
92mod util;
93mod variant;
94
95use arg::*;
96use attr::*;
97use member::*;
98use method::*;
99use pyclass::*;
100use pyclass_complex_enum::*;
101use pyclass_enum::*;
102use pymethods::*;
103use renaming::*;
104use signature::*;
105use stub_type::*;
106use util::*;
107
108use proc_macro2::TokenStream as TokenStream2;
109use quote::quote;
110use syn::{parse2, ItemEnum, ItemFn, ItemImpl, ItemStruct, LitStr, Result};
111
112pub fn pyclass(attr: TokenStream2, item: TokenStream2) -> Result<TokenStream2> {
113 let attr = parse2::<attr::PyClassAttr>(attr)?;
114 let mut item_struct = parse2::<ItemStruct>(item)?;
115 let inner = PyClassInfo::from_item_with_attr(item_struct.clone(), &attr)?;
116 pyclass::prune_attrs(&mut item_struct);
117
118 if attr.skip_stub_type {
119 Ok(quote! {
120 #item_struct
121 pyo3_stub_gen::inventory::submit! {
122 #inner
123 }
124 })
125 } else {
126 let derive_stub_type = StubType::from(&inner);
127 Ok(quote! {
128 #item_struct
129 #derive_stub_type
130 pyo3_stub_gen::inventory::submit! {
131 #inner
132 }
133 })
134 }
135}
136
137pub fn pyclass_enum(attr: TokenStream2, item: TokenStream2) -> Result<TokenStream2> {
138 let attr = parse2::<attr::PyClassAttr>(attr)?;
139 let inner = PyEnumInfo::from_item_with_attr(parse2::<ItemEnum>(item.clone())?, &attr)?;
140
141 if attr.skip_stub_type {
142 Ok(quote! {
143 #item
144 pyo3_stub_gen::inventory::submit! {
145 #inner
146 }
147 })
148 } else {
149 let derive_stub_type = StubType::from(&inner);
150 Ok(quote! {
151 #item
152 #derive_stub_type
153 pyo3_stub_gen::inventory::submit! {
154 #inner
155 }
156 })
157 }
158}
159
160pub fn pyclass_complex_enum(attr: TokenStream2, item: TokenStream2) -> Result<TokenStream2> {
161 let attr = parse2::<attr::PyClassAttr>(attr)?;
162 let inner = PyComplexEnumInfo::from_item_with_attr(parse2::<ItemEnum>(item.clone())?, &attr)?;
163
164 if attr.skip_stub_type {
165 Ok(quote! {
166 #item
167 pyo3_stub_gen::inventory::submit! {
168 #inner
169 }
170 })
171 } else {
172 let derive_stub_type = StubType::from(&inner);
173 Ok(quote! {
174 #item
175 #derive_stub_type
176 pyo3_stub_gen::inventory::submit! {
177 #inner
178 }
179 })
180 }
181}
182
183pub fn pymethods(item: TokenStream2) -> Result<TokenStream2> {
184 let mut item_impl = parse2::<ItemImpl>(item)?;
185 let inner = PyMethodsInfo::try_from(item_impl.clone())?;
186 pymethods::prune_attrs(&mut item_impl);
187 Ok(quote! {
188 #item_impl
189 #[automatically_derived]
190 pyo3_stub_gen::inventory::submit! {
191 #inner
192 }
193 })
194}
195
196pub fn pyfunction(attr: TokenStream2, item: TokenStream2) -> Result<TokenStream2> {
197 let item_fn = parse2::<ItemFn>(item)?;
199 let attr = parse2::<pyfunction::PyFunctionAttr>(attr)?;
200
201 let infos = pyfunction::PyFunctionInfos::from_parts(item_fn, attr)?;
203
204 Ok(quote! { #infos })
206}
207
208pub fn gen_function_from_python_impl(input: TokenStream2) -> Result<TokenStream2> {
209 let parsed: parse_python::GenFunctionFromPythonInput = parse2(input)?;
210 let inner = parse_python::parse_gen_function_from_python_input(parsed)?;
211 Ok(quote! { #inner })
212}
213
214pub fn gen_methods_from_python_impl(input: TokenStream2) -> Result<TokenStream2> {
215 let stub_str: LitStr = parse2(input)?;
216 let inner = parse_python::parse_python_methods_stub(&stub_str)?;
217 Ok(quote! { #inner })
218}
219
220pub fn gen_type_alias_from_python_impl(input: TokenStream2) -> Result<TokenStream2> {
221 let parsed: parse_python::GenTypeAliasFromPythonInput = parse2(input)?;
222 let inner = parse_python::parse_python_type_alias_stub(&parsed)?;
223 Ok(quote! { #inner })
224}
225
226pub fn prune_gen_stub(item: TokenStream2) -> Result<TokenStream2> {
227 fn prune_attrs<T: syn::parse::Parse + quote::ToTokens>(
228 item: &TokenStream2,
229 fn_prune_attrs: fn(&mut T),
230 ) -> Result<TokenStream2> {
231 parse2::<T>(item.clone()).map(|mut item| {
232 fn_prune_attrs(&mut item);
233 quote! { #item }
234 })
235 }
236 prune_attrs::<ItemStruct>(&item, pyclass::prune_attrs)
237 .or_else(|_| prune_attrs::<ItemImpl>(&item, pymethods::prune_attrs))
238 .or_else(|_| prune_attrs::<ItemFn>(&item, pyfunction::prune_attrs))
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244 use quote::quote;
245
246 fn format_tokens(tokens: TokenStream2) -> String {
247 let formatted = prettyplease::unparse(&syn::parse_file(&tokens.to_string()).unwrap());
248 formatted.trim().to_string()
249 }
250
251 #[test]
252 fn test_overload_example_1_expansion() {
253 let attr = quote! {
258 python_overload = r#"
259 @overload
260 def overload_example_1(x: int) -> int: ...
261 "#
262 };
263
264 let item = quote! {
265 #[pyfunction]
266 pub fn overload_example_1(x: f64) -> f64 {
267 x + 1.0
268 }
269 };
270
271 let result = pyfunction(attr, item).unwrap();
272 let formatted = format_tokens(result);
273
274 insta::assert_snapshot!(formatted);
275 }
276
277 #[test]
278 fn test_overload_example_2_expansion() {
279 let attr = quote! {
285 python_overload = r#"
286 @overload
287 def overload_example_2(ob: int) -> int:
288 """Increments integer by 1"""
289
290 @overload
291 def overload_example_2(ob: float) -> float:
292 """Increments float by 1"""
293 "#,
294 no_default_overload = true
295 };
296
297 let item = quote! {
298 #[pyfunction]
299 pub fn overload_example_2(ob: Bound<PyAny>) -> PyResult<PyObject> {
300 let py = ob.py();
301 Ok(ob.into_py_any(py)?)
302 }
303 };
304
305 let result = pyfunction(attr, item).unwrap();
306 let formatted = format_tokens(result);
307
308 insta::assert_snapshot!(formatted);
309 }
310
311 #[test]
312 fn test_regular_function_no_overload() {
313 let attr = quote! {};
316
317 let item = quote! {
318 #[pyfunction]
319 pub fn regular_function(x: i32) -> i32 {
320 x + 1
321 }
322 };
323
324 let result = pyfunction(attr, item).unwrap();
325 let formatted = format_tokens(result);
326
327 insta::assert_snapshot!(formatted);
328 }
329}