1111import os
1212from argparse import Namespace
1313from pathlib import Path
14+ from typing import Any , cast
1415
1516from mesonbuild import mlog
1617from mesonbuild .ast import (
2526 AssignmentNode ,
2627 BaseNode ,
2728 DictNode ,
29+ IdNode ,
2830 SymbolNode ,
2931)
3032from mesonbuild .rewriter import (
4749class AstPython (AstVisitor ):
4850 install_sources_calls : list [MethodNode ] = []
4951 extension_data : list [AssignmentNode ] = []
50- doc_sources : list [MethodNode ] = []
52+ doc_sources : list [AssignmentNode ] = []
5153
5254 def visit_MethodNode (self , node : MethodNode ) -> None :
5355 if node .name .value == "install_sources" :
@@ -63,8 +65,8 @@ def visit_AssignmentNode(self, node: AssignmentNode) -> None:
6365
6466
6567# Utility function to get a list of the sources from a node
66- def arg_list_from_node (n ) :
67- args = []
68+ def arg_list_from_node (n : BaseNode ) -> list [ BaseNode ] :
69+ args : list [ BaseNode ] = []
6870 if isinstance (n , FunctionNode ) or isinstance (n , MethodNode ):
6971 args = list (n .args .arguments )
7072 # if 'func_name' in n and n.func_name.value in BUILD_TARGET_FUNCTIONS:
@@ -76,34 +78,45 @@ def arg_list_from_node(n):
7678 return args
7779
7880
81+ def _token (tid : str , filename : str , value : str ) -> Token [str ]:
82+ return Token (tid , filename , 0 , 0 , 0 , (0 , 0 ), value )
83+
84+
7985def _symbol (val : str ) -> SymbolNode :
80- return SymbolNode (Token ("" , "" , 0 , 0 , 0 , (0 , 0 ), val ))
86+ return SymbolNode (_token ("" , "" , val ))
87+
8188
89+ def _id (val : str ) -> IdNode :
90+ return IdNode (_token ("id" , "" , val ))
8291
83- def update_python_sources (self : Rewriter , visitor : AstPython ):
92+
93+ def update_python_sources (self : Rewriter , visitor : AstPython ) -> None :
8494 for target in visitor .install_sources_calls :
8595 # Generate the current source list
86- src_list : list [str ] = []
96+ python_sources : list [str ] = []
8797 for arg in arg_list_from_node (target ):
8898 if isinstance (arg , StringNode ):
89- src_list += [arg .value ]
99+ python_sources += [arg .value ]
90100
91101 folder = Path (target .filename ).parent
92102 python_files = sorted (
93- list (folder .glob ("*.py" )) + list (folder .glob ('*.pxd' )) + list (folder .glob ('*.pyx' )) + list (folder .glob ('*.pyi' ))
103+ list (folder .glob ("*.py" ))
104+ + list (folder .glob ('*.pxd' ))
105+ + list (folder .glob ('*.pyx' ))
106+ + list (folder .glob ('*.pyi' ))
94107 ) # + list(folder.glob('*.pxd')) + list(folder.glob('*.h')))
95108
96109 to_append : list [StringNode ] = []
97110 for file in python_files :
98111 file_name = file .name
99- if file_name in src_list :
112+ if file_name in python_sources :
100113 continue
101- token = Token ("string" , target .filename , 0 , 0 , 0 , None , file_name )
114+ token = _token ("string" , target .filename , file_name )
102115 to_append += [StringNode (token )]
103116
104117 # Get all deleted files
105118 to_remove = []
106- for src in src_list :
119+ for src in python_sources :
107120 if not folder .joinpath (src ).exists ():
108121 to_remove += [src ]
109122
@@ -118,7 +131,7 @@ def update_python_sources(self: Rewriter, visitor: AstPython):
118131 if not (isinstance (arg , StringNode ) and arg .value in to_remove )
119132 ]
120133 + to_append ,
121- key = lambda x : x .value ,
134+ key = lambda x : cast ( "StringNode" , x ) .value ,
122135 )
123136
124137 # Mark the node as modified
@@ -129,17 +142,24 @@ def update_python_sources(self: Rewriter, visitor: AstPython):
129142 for target in visitor .extension_data :
130143 folder = Path (target .filename ).parent
131144 # Generate the current source dict
132- src_list : dict [str , BaseNode ] = {}
145+ extension_sources_by_name : dict [str , BaseNode ] = {}
133146 if isinstance (target .value , DictNode ):
134- src_list .update ({k .value : v for k , v in target .value .args .kwargs .items ()})
147+ extension_sources_by_name .update (
148+ {
149+ cast ("StringNode" , key ).value : value
150+ for key , value in target .value .args .kwargs .items ()
151+ }
152+ )
135153 ext_data .setdefault (folder , [])
136- ext_data [folder ] += src_list .keys ()
154+ ext_data [folder ] += extension_sources_by_name .keys ()
137155
138156 for target in visitor .extension_data :
139157 if target .var_name .value != "extension_data" :
140158 continue
159+ if not isinstance (target .value , DictNode ):
160+ continue
141161 folder = Path (target .filename ).parent
142- src_list = ext_data [folder ]
162+ extension_sources = ext_data [folder ]
143163
144164 cython_files = sorted (folder .glob ("*.pyx" ))
145165 # Some cython files are compiled in a special way, so we don't want to add them
@@ -152,20 +172,18 @@ def update_python_sources(self: Rewriter, visitor: AstPython):
152172 # Add all cython files that are not in the source list
153173 for file in cython_files :
154174 file_name = file .stem
155- if file_name in src_list :
175+ if file_name in extension_sources :
156176 continue
157- token = Token ("string" , target .filename , 0 , 0 , 0 , None , file_name )
158- arg = ArgumentNode (Token ("" , target .filename , 0 , 0 , 0 , None , "[]" ))
159- arg .append (
160- StringNode (Token ("string" , target .filename , 0 , 0 , 0 , None , file .name ))
161- )
162- func = FunctionNode (_symbol ("files" ), _symbol ("(" ), arg , _symbol (")" ))
177+ token = _token ("string" , target .filename , file_name )
178+ arg = ArgumentNode (_token ("" , target .filename , "[]" ))
179+ arg .append (StringNode (_token ("string" , target .filename , file .name )))
180+ func = FunctionNode (_id ("files" ), _symbol ("(" ), arg , _symbol (")" ))
163181 target .value .args .kwargs .update ({StringNode (token ): func })
164182 if target not in self .modified_nodes :
165183 self .modified_nodes += [target ]
166184
167185
168- def update_doc_sources (self : Rewriter , visitor : AstPython ):
186+ def update_doc_sources (self : Rewriter , visitor : AstPython ) -> None :
169187 doc_sources : dict [Path , list [str ]] = {}
170188 ignored_files = {'bootstrap' , 'Makefile' , 'meson.build' }
171189 ignored_folders = {'__pycache__' , 'sage' }
@@ -176,11 +194,15 @@ def update_doc_sources(self: Rewriter, visitor: AstPython):
176194 if isinstance (target .value , ArrayNode ):
177195 src_list .extend (target .value .args .arguments )
178196 doc_sources .setdefault (folder , [])
179- doc_sources [folder ] += [x .value for x in src_list ]
197+ doc_sources [folder ] += [
198+ source .value for source in src_list if isinstance (source , StringNode )
199+ ]
180200
181201 for target in visitor .doc_sources :
182202 if target .var_name .value != "doc_sources" :
183203 continue
204+ if not isinstance (target .value , ArrayNode ):
205+ continue
184206 folder = Path (target .filename ).parent
185207 existing_sources : list [str ] = doc_sources [folder ]
186208 # Add all files that are not in the source list
@@ -191,15 +213,22 @@ def update_doc_sources(self: Rewriter, visitor: AstPython):
191213 if file_name in ignored_files or file .suffix == ".pyc" :
192214 continue
193215 existing_sources .append (file_name )
194- token = Token ("string" , target .filename , 0 , 0 , 0 , None , file_name )
216+ token = _token ("string" , target .filename , file_name )
195217 target .value .args .arguments .append (StringNode (token ))
196218 if target not in self .modified_nodes :
197219 self .modified_nodes += [target ]
198220 # Remove all files that are no longer existing
199221 for file in existing_sources :
200222 if not (folder / file ).exists ():
201223 existing_sources .remove (file )
202- token = next ((x for x in target .value .args .arguments if getattr (x , "value" , None ) == file ), None )
224+ token = next (
225+ (
226+ x
227+ for x in target .value .args .arguments
228+ if getattr (x , "value" , None ) == file
229+ ),
230+ None ,
231+ )
203232 if token is not None :
204233 target .value .args .arguments .remove (token )
205234 if target not in self .modified_nodes :
@@ -208,7 +237,7 @@ def update_doc_sources(self: Rewriter, visitor: AstPython):
208237 # Add all missing meson files in the src/doc folder
209238 doc_folder = Path (options .sourcedir ) / "src" / "doc"
210239 # Delete all totally empty folders as pre-processing step
211- for folder , dirs , files in doc_folder .walk (top_down = False ):
240+ for folder , dirs , files in doc_folder .walk (top_down = False ):
212241 if not dirs and not files :
213242 folder .rmdir ()
214243
@@ -241,7 +270,8 @@ def update_doc_sources(self: Rewriter, visitor: AstPython):
241270 continue
242271 f .write (f"subdir('{ dir } ')\n " )
243272
244- def apply_changes (self : Rewriter ):
273+
274+ def apply_changes (self : Rewriter ) -> None :
245275 assert all (
246276 hasattr (x , "lineno" ) and hasattr (x , "colno" ) and hasattr (x , "filename" )
247277 for x in self .modified_nodes
@@ -262,7 +292,12 @@ def apply_changes(self: Rewriter):
262292 work_nodes = [{"node" : x , "action" : "modify" } for x in self .modified_nodes ]
263293 work_nodes += [{"node" : x , "action" : "rm" } for x in self .to_remove_nodes ]
264294 work_nodes = sorted (
265- work_nodes , key = lambda x : (x ["node" ].lineno , x ["node" ].colno ), reverse = True
295+ work_nodes ,
296+ key = lambda x : (
297+ cast ("BaseNode" , x ["node" ]).lineno ,
298+ cast ("BaseNode" , x ["node" ]).colno ,
299+ ),
300+ reverse = True ,
266301 )
267302 work_nodes += [{"node" : x , "action" : "add" } for x in self .to_add_nodes ]
268303
@@ -272,19 +307,19 @@ def apply_changes(self: Rewriter):
272307 new_data = ""
273308 if i ["action" ] == "modify" or i ["action" ] == "add" :
274309 printer = AstPrinter ()
275- i ["node" ].accept (printer )
310+ cast ( "BaseNode" , i ["node" ]) .accept (printer )
276311 printer .post_process ()
277312 new_data = printer .result .strip ()
278313 data = {
279- "file" : i ["node" ].filename ,
314+ "file" : cast ( "BaseNode" , i ["node" ]) .filename ,
280315 "str" : new_data ,
281316 "node" : i ["node" ],
282317 "action" : i ["action" ],
283318 }
284319 str_list += [data ]
285320
286321 # Load build files
287- files = {}
322+ files : dict [ str , Any ] = {}
288323 for i in str_list :
289324 if i ["file" ] in files :
290325 continue
@@ -308,7 +343,7 @@ def apply_changes(self: Rewriter):
308343 files [i ["file" ]] = {"path" : fpath , "raw" : fdata , "offsets" : line_offsets }
309344
310345 # Replace in source code
311- def remove_node (i ) :
346+ def remove_node (i : dict [ str , Any ]) -> None :
312347 offsets = files [i ["file" ]]["offsets" ]
313348 raw = files [i ["file" ]]["raw" ]
314349 node = i ["node" ]
@@ -357,15 +392,15 @@ def remove_node(i):
357392# Monkey patch the apply_changes method until https://github.com/mesonbuild/meson/pull/12899 is merged
358393Rewriter .apply_changes = apply_changes
359394# Monkey patch the update_python_sources method until this is upstreamed
360- Rewriter . process_update_python_sources = update_python_sources
361- Rewriter . process_update_doc_sources = update_doc_sources
395+ setattr ( Rewriter , " process_update_python_sources" , update_python_sources )
396+ setattr ( Rewriter , " process_update_doc_sources" , update_doc_sources )
362397
363398rewriter = Rewriter (options .sourcedir )
364399visitor = AstPython ()
365400rewriter .interpreter .visitors += [visitor ]
366401rewriter .analyze_meson ()
367- rewriter . process_update_python_sources ( visitor )
368- rewriter . process_update_doc_sources ( visitor )
402+ update_python_sources ( rewriter , visitor )
403+ update_doc_sources ( rewriter , visitor )
369404rewriter .apply_changes ()
370405rewriter .print_info ()
371406
0 commit comments