33use  crate :: { 
44    attributes:: { 
55        self ,  take_attributes,  take_pyo3_options,  CrateAttribute ,  ModuleAttribute ,  NameAttribute , 
6+         SubmoduleAttribute , 
67    } , 
78    get_doc, 
89    pyclass:: PyClassPyO3Option , 
@@ -27,6 +28,7 @@ pub struct PyModuleOptions {
2728    krate :  Option < CrateAttribute > , 
2829    name :  Option < syn:: Ident > , 
2930    module :  Option < ModuleAttribute > , 
31+     is_submodule :  bool , 
3032} 
3133
3234impl  PyModuleOptions  { 
@@ -38,6 +40,7 @@ impl PyModuleOptions {
3840                PyModulePyO3Option :: Name ( name)  => options. set_name ( name. value . 0 ) ?, 
3941                PyModulePyO3Option :: Crate ( path)  => options. set_crate ( path) ?, 
4042                PyModulePyO3Option :: Module ( module)  => options. set_module ( module) ?, 
43+                 PyModulePyO3Option :: Submodule ( submod)  => options. set_submodule ( submod) ?, 
4144            } 
4245        } 
4346
@@ -73,9 +76,22 @@ impl PyModuleOptions {
7376        self . module  = Some ( name) ; 
7477        Ok ( ( ) ) 
7578    } 
79+ 
80+     fn  set_submodule ( & mut  self ,  submod :  SubmoduleAttribute )  -> Result < ( ) >  { 
81+         ensure_spanned ! ( 
82+             !self . is_submodule, 
83+             submod. span( )  => "`submodule` may only be specified once" 
84+         ) ; 
85+ 
86+         self . is_submodule  = true ; 
87+         Ok ( ( ) ) 
88+     } 
7689} 
7790
78- pub  fn  pymodule_module_impl ( mut  module :  syn:: ItemMod )  -> Result < TokenStream >  { 
91+ pub  fn  pymodule_module_impl ( 
92+     mut  module :  syn:: ItemMod , 
93+     mut  is_submodule :  bool , 
94+ )  -> Result < TokenStream >  { 
7995    let  syn:: ItemMod  { 
8096        attrs, 
8197        vis, 
@@ -100,6 +116,7 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
100116    }  else  { 
101117        name. to_string ( ) 
102118    } ; 
119+     is_submodule = is_submodule || options. is_submodule ; 
103120
104121    let  mut  module_items = Vec :: new ( ) ; 
105122    let  mut  module_items_cfg_attrs = Vec :: new ( ) ; 
@@ -297,7 +314,7 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
297314            ) 
298315        } 
299316    } } ; 
300-     let  initialization = module_initialization ( & name,  ctx,  module_def) ; 
317+     let  initialization = module_initialization ( & name,  ctx,  module_def,  is_submodule ) ; 
301318    Ok ( quote ! ( 
302319        #( #attrs) * 
303320        #vis mod  #ident { 
@@ -331,7 +348,7 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
331348    let  vis = & function. vis ; 
332349    let  doc = get_doc ( & function. attrs ,  None ,  ctx) ; 
333350
334-     let  initialization = module_initialization ( & name,  ctx,  quote !  {  MakeDef :: make_def( )  } ) ; 
351+     let  initialization = module_initialization ( & name,  ctx,  quote !  {  MakeDef :: make_def( )  } ,   false ) ; 
335352
336353    // Module function called with optional Python<'_> marker as first arg, followed by the module. 
337354    let  mut  module_args = Vec :: new ( ) ; 
@@ -396,28 +413,37 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
396413    } ) 
397414} 
398415
399- fn  module_initialization ( name :  & syn:: Ident ,  ctx :  & Ctx ,  module_def :  TokenStream )  -> TokenStream  { 
416+ fn  module_initialization ( 
417+     name :  & syn:: Ident , 
418+     ctx :  & Ctx , 
419+     module_def :  TokenStream , 
420+     is_submodule :  bool , 
421+ )  -> TokenStream  { 
400422    let  Ctx  {  pyo3_path,  .. }  = ctx; 
401423    let  pyinit_symbol = format ! ( "PyInit_{}" ,  name) ; 
402424    let  name = name. to_string ( ) ; 
403425    let  pyo3_name = LitCStr :: new ( CString :: new ( name) . unwrap ( ) ,  Span :: call_site ( ) ,  ctx) ; 
404426
405-     quote !  { 
427+     let   mut  result =  quote !  { 
406428        #[ doc( hidden) ] 
407429        pub  const  __PYO3_NAME:  & ' static  :: std:: ffi:: CStr  = #pyo3_name; 
408430
409431        pub ( super )  struct  MakeDef ; 
410432        #[ doc( hidden) ] 
411433        pub  static  _PYO3_DEF:  #pyo3_path:: impl_:: pymodule:: ModuleDef  = #module_def; 
412- 
413-         /// This autogenerated function is called by the python interpreter when importing 
414- /// the module. 
415- [ doc( hidden) ] 
416-         #[ export_name = #pyinit_symbol] 
417-         pub  unsafe  extern "C"  fn  __pyo3_init( )  -> * mut  #pyo3_path:: ffi:: PyObject  { 
418-             #pyo3_path:: impl_:: trampoline:: module_init( |py| _PYO3_DEF. make_module( py) ) 
419-         } 
434+     } ; 
435+     if  !is_submodule { 
436+         result. extend ( quote !  { 
437+             /// This autogenerated function is called by the python interpreter when importing 
438+ /// the module. 
439+ [ doc( hidden) ] 
440+             #[ export_name = #pyinit_symbol] 
441+             pub  unsafe  extern "C"  fn  __pyo3_init( )  -> * mut  #pyo3_path:: ffi:: PyObject  { 
442+                 #pyo3_path:: impl_:: trampoline:: module_init( |py| _PYO3_DEF. make_module( py) ) 
443+             } 
444+         } ) ; 
420445    } 
446+     result
421447} 
422448
423449/// Finds and takes care of the #[pyfn(...)] in `#[pymodule]` 
@@ -557,6 +583,7 @@ fn has_pyo3_module_declared<T: Parse>(
557583} 
558584
559585enum  PyModulePyO3Option  { 
586+     Submodule ( SubmoduleAttribute ) , 
560587    Crate ( CrateAttribute ) , 
561588    Name ( NameAttribute ) , 
562589    Module ( ModuleAttribute ) , 
@@ -571,6 +598,8 @@ impl Parse for PyModulePyO3Option {
571598            input. parse ( ) . map ( PyModulePyO3Option :: Crate ) 
572599        }  else  if  lookahead. peek ( attributes:: kw:: module)  { 
573600            input. parse ( ) . map ( PyModulePyO3Option :: Module ) 
601+         }  else  if  lookahead. peek ( attributes:: kw:: submodule)  { 
602+             input. parse ( ) . map ( PyModulePyO3Option :: Submodule ) 
574603        }  else  { 
575604            Err ( lookahead. error ( ) ) 
576605        } 
0 commit comments