Skip to content

Commit 72d94d2

Browse files
authored
Merge pull request RustPython#7203 from youknowone/pymodule
#[pymodule] submodule support and implicit module_name inheritance
2 parents d0e7fd9 + 53dccae commit 72d94d2

1 file changed

Lines changed: 63 additions & 1 deletion

File tree

crates/derive-impl/src/pymodule.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,59 @@ pub fn impl_pymodule(args: PyModuleArgs, module_item: Item) -> Result<TokenStrea
194194
context.errors.ok_or_push(r);
195195
}
196196

197+
// Detect nested #[pymodule] items (non-sub) and generate submodule init code
198+
let mut submodule_inits: Vec<TokenStream> = Vec::new();
199+
for item in items.iter() {
200+
if let Item::Mod(item_mod) = item {
201+
let r = (|| -> Result<()> {
202+
let attr = match item_mod
203+
.attrs
204+
.iter()
205+
.find(|a| a.path().is_ident("pymodule"))
206+
{
207+
Some(attr) => attr,
208+
None => return Ok(()),
209+
};
210+
let args_tokens = match &attr.meta {
211+
syn::Meta::Path(_) => TokenStream::new(),
212+
syn::Meta::List(list) => list.tokens.clone(),
213+
_ => return Ok(()),
214+
};
215+
let mod_args: PyModuleArgs = syn::parse2(args_tokens)?;
216+
let fake_ident = Ident::new("pymodule", attr.span());
217+
let mod_meta = ModuleItemMeta::from_nested(
218+
item_mod.ident.clone(),
219+
fake_ident,
220+
mod_args.metas.into_iter(),
221+
)?;
222+
if mod_meta.sub()? {
223+
return Ok(());
224+
}
225+
let py_name = mod_meta.simple_name()?;
226+
let mod_ident = &item_mod.ident;
227+
let cfgs: Vec<_> = item_mod
228+
.attrs
229+
.iter()
230+
.filter(|a| a.path().is_ident("cfg"))
231+
.cloned()
232+
.collect();
233+
submodule_inits.push(quote! {
234+
#(#cfgs)*
235+
{
236+
let child_def = #mod_ident::module_def(ctx);
237+
let child = child_def.create_module(vm).expect("submodule create_module failed");
238+
child.__init_methods(vm).expect("submodule __init_methods failed");
239+
#mod_ident::module_exec(vm, &child).expect("submodule module_exec failed");
240+
let child: ::rustpython_vm::PyObjectRef = child.into();
241+
vm.__module_set_attr(module, ctx.intern_str(#py_name), child).expect("module set_attr submodule failed");
242+
}
243+
});
244+
Ok(())
245+
})();
246+
context.errors.ok_or_push(r);
247+
}
248+
}
249+
197250
// append additional items
198251
let module_name = context.name.as_str();
199252
let function_items = context.function_items.validate()?;
@@ -316,6 +369,7 @@ pub fn impl_pymodule(args: PyModuleArgs, module_item: Item) -> Result<TokenStrea
316369
#(#init_with_calls)*
317370
let ctx = &vm.ctx;
318371
#attribute_items
372+
#(#submodule_inits)*
319373
}
320374
},
321375
parse_quote! {
@@ -783,7 +837,15 @@ impl ModuleItem for StructSequenceItem {
783837
"#[pystruct_sequence] requires name parameter",
784838
)
785839
})?;
786-
let module_name = meta.module()?.unwrap_or_else(|| args.context.name.clone());
840+
let module_opt = meta.module()?;
841+
let has_module = module_opt.is_some();
842+
let module_name = module_opt.unwrap_or_else(|| args.context.name.clone());
843+
if !has_module {
844+
let structseq_attr = &mut args.attrs[self.inner.index];
845+
structseq_attr.fill_nested_meta("module", || {
846+
parse_quote! {module = #module_name}
847+
})?;
848+
}
787849
let no_attr = meta.no_attr()?;
788850

789851
// Generate the class creation code

0 commit comments

Comments
 (0)