33import os
44from pprint import pprint
55
6+
67def validate_shadowing (filepath : str ):
78 """
8- Parses a python file and ensures no local variable (or argument)
9+ Parses a python file and ensures no local variable (or argument)
910 in any function shadows a top-level module import.
1011 """
11- with open (filepath , 'r' , encoding = ' utf-8' ) as f :
12+ with open (filepath , "r" , encoding = " utf-8" ) as f :
1213 source = f .read ()
13-
14+
1415 tree = ast .parse (source , filename = filepath )
15-
16+
1617 # 1. Collect all top-level imports
1718 global_imports = set ()
1819 for node in tree .body :
@@ -31,40 +32,47 @@ def validate_shadowing(filepath: str):
3132 for node in ast .walk (tree ):
3233 if isinstance (node , (ast .FunctionDef , ast .AsyncFunctionDef )):
3334 func_name = node .name
34-
35+
3536 # 2a. Check arguments
3637 args = []
37- if node .args .args : args .extend (node .args .args )
38- if node .args .posonlyargs : args .extend (node .args .posonlyargs )
39- if node .args .kwonlyargs : args .extend (node .args .kwonlyargs )
40- if node .args .vararg : args .append (node .args .vararg )
41- if node .args .kwarg : args .append (node .args .kwarg )
38+ if node .args .args :
39+ args .extend (node .args .args )
40+ if node .args .posonlyargs :
41+ args .extend (node .args .posonlyargs )
42+ if node .args .kwonlyargs :
43+ args .extend (node .args .kwonlyargs )
44+ if node .args .vararg :
45+ args .append (node .args .vararg )
46+ if node .args .kwarg :
47+ args .append (node .args .kwarg )
4248
4349 for arg in args :
4450 if arg .arg in global_imports :
45- shadow_errors .append (f"Function '{ func_name } ' has parameter '{ arg .arg } ' shadowing an import." )
51+ shadow_errors .append (
52+ f"Function '{ func_name } ' has parameter '{ arg .arg } ' shadowing an import."
53+ )
4654
4755 # 2b. Check local assignments (any Name with Store context)
4856 for child in ast .walk (node ):
4957 if isinstance (child , ast .Name ) and isinstance (child .ctx , ast .Store ):
5058 if child .id in global_imports :
51- shadow_errors .append (f"Function '{ func_name } ' has local variable '{ child .id } ' shadowing an import. Line { getattr (child , 'lineno' , '?' )} " )
59+ shadow_errors .append (
60+ f"Function '{ func_name } ' has local variable '{ child .id } ' shadowing an import. Line { getattr (child , 'lineno' , '?' )} "
61+ )
5262
5363 if shadow_errors :
5464 print (f"\n [CRITICAL FATAL] Shadowing detected in { filepath } :" )
5565 for err in shadow_errors :
5666 print (f" - { err } " )
5767 return False
58-
68+
5969 print (f"[{ os .path .basename (filepath )} ] AST Shadowing Check: PASSED \u2705 " )
6070 return True
6171
72+
6273if __name__ == "__main__" :
63- files_to_check = [
64- "src/telegram_mcp/mcp_server.py" ,
65- "src/telegram_mcp/client.py"
66- ]
67-
74+ files_to_check = ["src/telegram_mcp/mcp_server.py" , "src/telegram_mcp/client.py" ]
75+
6876 all_passed = True
6977 for f in files_to_check :
7078 full_path = os .path .join (os .getcwd (), f )
@@ -73,8 +81,8 @@ def validate_shadowing(filepath: str):
7381 all_passed = False
7482 else :
7583 print (f"Warning: File { f } not found." )
76-
84+
7785 if not all_passed :
7886 sys .exit (1 )
79-
87+
8088 sys .exit (0 )
0 commit comments