@@ -15,7 +15,7 @@ use crate::{
1515 get_doc,
1616 pyclass:: PyClassPyO3Option ,
1717 pyfunction:: { impl_wrap_pyfunction, PyFunctionOptions } ,
18- utils:: { has_attribute, has_attribute_with_namespace, Ctx , IdentOrStr } ,
18+ utils:: { has_attribute, has_attribute_with_namespace, Ctx , IdentOrStr , PythonDoc } ,
1919} ;
2020use proc_macro2:: { Span , TokenStream } ;
2121use quote:: quote;
@@ -389,23 +389,15 @@ pub fn pymodule_module_impl(
389389 #[ cfg( not( feature = "experimental-inspect" ) ) ]
390390 let introspection_id = quote ! { } ;
391391
392- let module_def = quote ! { {
393- use #pyo3_path:: impl_:: pymodule as impl_;
394- const INITIALIZER : impl_:: ModuleInitializer = impl_:: ModuleInitializer ( __pyo3_pymodule) ;
395- unsafe {
396- impl_:: ModuleDef :: new(
397- __PYO3_NAME,
398- #doc,
399- INITIALIZER
400- )
401- }
402- } } ;
392+ let gil_used = options. gil_used . is_some_and ( |op| op. value . value ) ;
393+
403394 let initialization = module_initialization (
404395 & name,
405396 ctx,
406- module_def ,
397+ quote ! { __pyo3_pymodule } ,
407398 options. submodule . is_some ( ) ,
408- options. gil_used . is_none_or ( |op| op. value . value ) ,
399+ gil_used,
400+ doc,
409401 ) ;
410402
411403 let module_consts_names = module_consts. iter ( ) . map ( |i| i. unraw ( ) . to_string ( ) ) ;
@@ -456,12 +448,15 @@ pub fn pymodule_function_impl(
456448 let vis = & function. vis ;
457449 let doc = get_doc ( & function. attrs , None , ctx) ?;
458450
451+ let gil_used = options. gil_used . is_some_and ( |op| op. value . value ) ;
452+
459453 let initialization = module_initialization (
460454 & name,
461455 ctx,
462- quote ! { MakeDef :: make_def ( ) } ,
456+ quote ! { ModuleExec :: __pyo3_module_exec } ,
463457 false ,
464- options. gil_used . is_none_or ( |op| op. value . value ) ,
458+ gil_used,
459+ doc,
465460 ) ;
466461
467462 #[ cfg( feature = "experimental-inspect" ) ]
@@ -495,20 +490,9 @@ pub fn pymodule_function_impl(
495490 // (and `super` doesn't always refer to the outer scope, e.g. if the `#[pymodule] is
496491 // inside a function body)
497492 #[ allow( unknown_lints, non_local_definitions) ]
498- impl #ident:: MakeDef {
499- const fn make_def( ) -> #pyo3_path:: impl_:: pymodule:: ModuleDef {
500- fn __pyo3_pymodule( module: & #pyo3_path:: Bound <' _, #pyo3_path:: types:: PyModule >) -> #pyo3_path:: PyResult <( ) > {
501- #ident( #( #module_args) , * )
502- }
503-
504- const INITIALIZER : #pyo3_path:: impl_:: pymodule:: ModuleInitializer = #pyo3_path:: impl_:: pymodule:: ModuleInitializer ( __pyo3_pymodule) ;
505- unsafe {
506- #pyo3_path:: impl_:: pymodule:: ModuleDef :: new(
507- #ident:: __PYO3_NAME,
508- #doc,
509- INITIALIZER
510- )
511- }
493+ impl #ident:: ModuleExec {
494+ fn __pyo3_module_exec( module: & #pyo3_path:: Bound <' _, #pyo3_path:: types:: PyModule >) -> #pyo3_path:: PyResult <( ) > {
495+ #ident( #( #module_args) , * )
512496 }
513497 }
514498 } )
@@ -517,9 +501,10 @@ pub fn pymodule_function_impl(
517501fn module_initialization (
518502 name : & syn:: Ident ,
519503 ctx : & Ctx ,
520- module_def : TokenStream ,
504+ module_exec : TokenStream ,
521505 is_submodule : bool ,
522506 gil_used : bool ,
507+ doc : PythonDoc ,
523508) -> TokenStream {
524509 let Ctx { pyo3_path, .. } = ctx;
525510 let pyinit_symbol = format ! ( "PyInit_{name}" ) ;
@@ -530,9 +515,27 @@ fn module_initialization(
530515 #[ doc( hidden) ]
531516 pub const __PYO3_NAME: & ' static :: std:: ffi:: CStr = #pyo3_name;
532517
533- pub ( super ) struct MakeDef ;
518+ // This structure exists for `fn` modules declared within `fn` bodies, where due to the hidden
519+ // module (used for importing) the `fn` to initialize the module cannot be seen from the #module_def
520+ // declaration just below.
534521 #[ doc( hidden) ]
535- pub static _PYO3_DEF: #pyo3_path:: impl_:: pymodule:: ModuleDef = #module_def;
522+ pub ( super ) struct ModuleExec ;
523+
524+ #[ doc( hidden) ]
525+ pub static _PYO3_DEF: #pyo3_path:: impl_:: pymodule:: ModuleDef = {
526+ use #pyo3_path:: impl_:: pymodule as impl_;
527+
528+ unsafe extern "C" fn __pyo3_module_exec( module: * mut #pyo3_path:: ffi:: PyObject ) -> :: std:: os:: raw:: c_int {
529+ #pyo3_path:: impl_:: trampoline:: module_exec( module, #module_exec)
530+ }
531+
532+ static SLOTS : impl_:: PyModuleSlots <4 > = impl_:: PyModuleSlotsBuilder :: new( )
533+ . with_mod_exec( __pyo3_module_exec)
534+ . with_gil_used( #gil_used)
535+ . build( ) ;
536+
537+ impl_:: ModuleDef :: new( __PYO3_NAME, #doc, & SLOTS )
538+ } ;
536539 #[ doc( hidden) ]
537540 // so wrapped submodules can see what gil_used is
538541 pub static __PYO3_GIL_USED: bool = #gil_used;
@@ -544,7 +547,10 @@ fn module_initialization(
544547 #[ doc( hidden) ]
545548 #[ export_name = #pyinit_symbol]
546549 pub unsafe extern "C" fn __pyo3_init( ) -> * mut #pyo3_path:: ffi:: PyObject {
547- unsafe { #pyo3_path:: impl_:: trampoline:: module_init( |py| _PYO3_DEF. make_module( py, #gil_used) ) }
550+ _PYO3_DEF. init_multi_phase(
551+ unsafe { #pyo3_path:: Python :: assume_attached( ) } ,
552+ #gil_used
553+ )
548554 }
549555 } ) ;
550556 }
0 commit comments