22
33use crate :: {
44 attributes:: { self , take_attributes, take_pyo3_options, CrateAttribute , NameAttribute } ,
5+ get_doc,
56 pyfunction:: { impl_wrap_pyfunction, PyFunctionOptions } ,
67 utils:: { get_pyo3_crate, PythonDoc } ,
78} ;
@@ -56,9 +57,156 @@ impl PyModuleOptions {
5657 }
5758}
5859
60+ pub fn pymodule_module_impl ( mut module : syn:: ItemMod ) -> Result < TokenStream > {
61+ let syn:: ItemMod {
62+ attrs,
63+ vis,
64+ unsafety : _,
65+ ident,
66+ mod_token,
67+ content,
68+ semi : _,
69+ } = & mut module;
70+ let items = if let Some ( ( _, items) ) = content {
71+ items
72+ } else {
73+ bail_spanned ! ( module. span( ) => "`#[pymodule]` can only be used on inline modules" )
74+ } ;
75+ let options = PyModuleOptions :: from_attrs ( attrs) ?;
76+ let doc = get_doc ( attrs, None ) ;
77+
78+ let name = options. name . unwrap_or_else ( || ident. unraw ( ) ) ;
79+ let krate = get_pyo3_crate ( & options. krate ) ;
80+ let pyinit_symbol = format ! ( "PyInit_{}" , name) ;
81+
82+ let mut module_items = Vec :: new ( ) ;
83+ let mut module_items_cfg_attrs = Vec :: new ( ) ;
84+
85+ fn extract_use_items (
86+ source : & syn:: UseTree ,
87+ cfg_attrs : & [ syn:: Attribute ] ,
88+ target_items : & mut Vec < syn:: Ident > ,
89+ target_cfg_attrs : & mut Vec < Vec < syn:: Attribute > > ,
90+ ) -> Result < ( ) > {
91+ match source {
92+ syn:: UseTree :: Name ( name) => {
93+ target_items. push ( name. ident . clone ( ) ) ;
94+ target_cfg_attrs. push ( cfg_attrs. to_vec ( ) ) ;
95+ }
96+ syn:: UseTree :: Path ( path) => {
97+ extract_use_items ( & path. tree , cfg_attrs, target_items, target_cfg_attrs) ?
98+ }
99+ syn:: UseTree :: Group ( group) => {
100+ for tree in & group. items {
101+ extract_use_items ( tree, cfg_attrs, target_items, target_cfg_attrs) ?
102+ }
103+ }
104+ syn:: UseTree :: Glob ( glob) => {
105+ bail_spanned ! ( glob. span( ) => "#[pymodule] cannot import glob statements" )
106+ }
107+ syn:: UseTree :: Rename ( rename) => {
108+ target_items. push ( rename. rename . clone ( ) ) ;
109+ target_cfg_attrs. push ( cfg_attrs. to_vec ( ) ) ;
110+ }
111+ }
112+ Ok ( ( ) )
113+ }
114+
115+ let mut pymodule_init = None ;
116+
117+ for item in & mut * items {
118+ match item {
119+ syn:: Item :: Use ( item_use) => {
120+ let mut is_pyo3 = false ;
121+ item_use. attrs . retain ( |attr| {
122+ let found = attr. path ( ) . is_ident ( "pyo3" ) ;
123+ is_pyo3 |= found;
124+ !found
125+ } ) ;
126+ if is_pyo3 {
127+ let cfg_attrs = item_use
128+ . attrs
129+ . iter ( )
130+ . filter ( |attr| attr. path ( ) . is_ident ( "cfg" ) )
131+ . cloned ( )
132+ . collect :: < Vec < _ > > ( ) ;
133+ extract_use_items (
134+ & item_use. tree ,
135+ & cfg_attrs,
136+ & mut module_items,
137+ & mut module_items_cfg_attrs,
138+ ) ?;
139+ }
140+ }
141+ syn:: Item :: Fn ( item_fn) => {
142+ let mut is_module_init = false ;
143+ item_fn. attrs . retain ( |attr| {
144+ let found = attr. path ( ) . is_ident ( "pymodule_init" ) ;
145+ is_module_init |= found;
146+ !found
147+ } ) ;
148+ if is_module_init {
149+ ensure_spanned ! ( pymodule_init. is_none( ) , item_fn. span( ) => "only one pymodule_init may be specified" ) ;
150+ let ident = & item_fn. sig . ident ;
151+ pymodule_init = Some ( quote ! { #ident( module) ?; } ) ;
152+ }
153+ }
154+ item => {
155+ bail_spanned ! ( item. span( ) => "only 'use' statements and and pymodule_init functions are allowed in #[pymodule]" )
156+ }
157+ }
158+ }
159+
160+ Ok ( quote ! {
161+ #vis #mod_token #ident {
162+ #( #items) *
163+
164+ pub const __PYO3_NAME: & ' static str = concat!( stringify!( #name) , "\0 " ) ;
165+
166+ pub ( crate ) struct MakeDef ;
167+ impl MakeDef {
168+ const fn make_def( ) -> #krate:: impl_:: pymodule:: ModuleDef {
169+ use #krate:: impl_:: pymodule as impl_;
170+
171+ const INITIALIZER : impl_:: ModuleInitializer = impl_:: ModuleInitializer ( __pyo3_pymodule) ;
172+ unsafe {
173+ impl_:: ModuleDef :: new( __PYO3_NAME, #doc, INITIALIZER )
174+ }
175+ }
176+ }
177+
178+ pub static DEF : #krate:: impl_:: pymodule:: ModuleDef = unsafe {
179+ use #krate:: impl_:: pymodule as impl_;
180+ impl_:: ModuleDef :: new( concat!( stringify!( #name) , "\0 " ) , #doc, impl_:: ModuleInitializer ( __pyo3_pymodule) )
181+ } ;
182+
183+ pub fn add_to_module( module: & #krate:: types:: PyModule ) -> #krate:: PyResult <( ) > {
184+ module. add_submodule( DEF . make_module( module. py( ) ) ?. into_ref( module. py( ) ) )
185+ }
186+
187+ pub fn __pyo3_pymodule( _py: #krate:: Python , module: & #krate:: types:: PyModule ) -> #krate:: PyResult <( ) > {
188+ use #krate:: impl_:: pymodule:: PyAddToModule ;
189+ #(
190+ #( #module_items_cfg_attrs) *
191+ #module_items:: add_to_module( module) ?;
192+ ) *
193+ #pymodule_init
194+ Ok ( ( ) )
195+ }
196+
197+ /// This autogenerated function is called by the python interpreter when importing
198+ /// the module.
199+ #[ export_name = #pyinit_symbol]
200+ pub unsafe extern "C" fn __pyo3_init( ) -> * mut #krate:: ffi:: PyObject {
201+ #krate:: impl_:: trampoline:: module_init( |py| DEF . make_module( py) )
202+ }
203+ }
204+ } )
205+ }
206+
59207/// Generates the function that is called by the python interpreter to initialize the native
60208/// module
61- pub fn pymodule_impl (
209+ pub fn pymodule_function_impl (
62210 fnname : & Ident ,
63211 options : PyModuleOptions ,
64212 doc : PythonDoc ,
@@ -75,14 +223,18 @@ pub fn pymodule_impl(
75223 #visibility mod #fnname {
76224 pub ( crate ) struct MakeDef ;
77225 pub static DEF : #krate:: impl_:: pymodule:: ModuleDef = MakeDef :: make_def( ) ;
78- pub const NAME : & ' static str = concat!( stringify!( #name) , "\0 " ) ;
226+ pub const __PYO3_NAME : & ' static str = concat!( stringify!( #name) , "\0 " ) ;
79227
80228 /// This autogenerated function is called by the python interpreter when importing
81229 /// the module.
82230 #[ export_name = #pyinit_symbol]
83- pub unsafe extern "C" fn init ( ) -> * mut #krate:: ffi:: PyObject {
231+ pub unsafe extern "C" fn __pyo3_init ( ) -> * mut #krate:: ffi:: PyObject {
84232 #krate:: impl_:: trampoline:: module_init( |py| DEF . make_module( py) )
85233 }
234+
235+ pub fn add_to_module( module: & #krate:: types:: PyModule ) -> #krate:: PyResult <( ) > {
236+ module. add_submodule( DEF . make_module( module. py( ) ) ?. into_ref( module. py( ) ) )
237+ }
86238 }
87239
88240 // Generate the definition inside an anonymous function in the same scope as the original function -
@@ -95,7 +247,7 @@ pub fn pymodule_impl(
95247 const fn make_def( ) -> impl_:: ModuleDef {
96248 const INITIALIZER : impl_:: ModuleInitializer = impl_:: ModuleInitializer ( #fnname) ;
97249 unsafe {
98- impl_:: ModuleDef :: new( #fnname:: NAME , #doc, INITIALIZER )
250+ impl_:: ModuleDef :: new( #fnname:: __PYO3_NAME , #doc, INITIALIZER )
99251 }
100252 }
101253 }
0 commit comments