1414import subprocess
1515import sys
1616
17- def display_warning_summary (warnings ):
18- print ("\n Warnings:" )
19- unused_count = sum (1 for e in warnings if e .startswith ('F401:' ))
20- if unused_count > 0 :
21- print (f" - Unused imports: { unused_count } " )
22-
23- print (" Consider addressing warnings in future updates." )
24-
25- def run_analysis ():
26- print ("Running static analysis..." )
27- print ("=" * 60 )
28-
29- all_critical_errors = []
30- all_warnings = []
31-
32- # Check for missing arguments with mypy - CRITICAL
33- print ("\n 1. Checking for missing function arguments..." )
34- print ("-" * 40 )
35-
17+ MYPY_IGNORE_PATTERNS = [
18+ 'click.' , 'subprocess.' , 'Module "' ,
19+ 'has incompatible type "Optional' ,
20+ 'validator' , 'pydantic' , '__call__' ,
21+ 'OnlyValueValidator' , 'V1Validator' ,
22+ 'QCParameter' , 'QCBacktest'
23+ ]
24+
25+ def run_mypy_check ():
3626 result = subprocess .run (
3727 ["python" , "-m" , "mypy" , "lean/" ,
3828 "--show-error-codes" ,
@@ -43,119 +33,97 @@ def run_analysis():
4333 text = True
4434 )
4535
46- # Filter for critical call argument mismatches
47- call_arg_errors = []
36+ errors = []
37+ for line in result .stdout .splitlines () + result .stderr .splitlines ():
38+ if not line .strip () or '[call-arg]' not in line :
39+ continue
4840
49- for line in ( result . stdout + result . stderr ). split ( ' \n ' ):
50- if not line . strip ( ):
41+ # Skip false positives
42+ if any ( pattern in line for pattern in MYPY_IGNORE_PATTERNS ):
5143 continue
5244
53- # Look for call-arg errors (this covers both "too many" and "missing" arguments)
54- if '[call-arg]' in line :
55- # Skip false positives
56- if any (pattern in line for pattern in
57- ['click.' , 'subprocess.' , 'Module "' , 'has incompatible type "Optional' ,
58- 'validator' , 'pydantic' , '__call__' , 'OnlyValueValidator' , 'V1Validator' ,
59- 'QCParameter' , 'QCBacktest' ]):
60- continue
61- call_arg_errors .append (line .strip ())
62-
63- # Display call argument mismatches
64- if call_arg_errors :
65- print ("CRITICAL: Missing function arguments found:" )
66- for error in call_arg_errors :
67- # Clean path for better display
68- clean_error = error .replace ('/home/runner/work/lean-cli/lean-cli/' , '' )
69- print (f" { clean_error } " )
45+ errors .append (line .strip ())
7046
71- all_critical_errors .extend (call_arg_errors )
72- else :
73- print ("No argument mismatch errors found" )
74-
75- # Check for undefined variables with flake8 - CRITICAL
76- print ("\n 2. Checking for undefined variables..." )
77- print ("-" * 40 )
47+ return errors
7848
49+ def run_flake8_check (select_code ):
7950 result = subprocess .run (
8051 ["python" , "-m" , "flake8" , "lean/" ,
81- "--select=F821 " ,
52+ f "--select={ select_code } " ,
8253 "--ignore=ALL" ,
83- "--count " ],
54+ "--exit-zero " ],
8455 capture_output = True ,
8556 text = True
8657 )
8758
88- if result .stdout .strip () and result .stdout .strip () != "0" :
89- detail = subprocess .run (
90- ["python" , "-m" , "flake8" , "lean/" , "--select=F821" , "--ignore=ALL" ],
91- capture_output = True ,
92- text = True
93- )
59+ errors = [line .strip () for line in result .stdout .splitlines () if line .strip ()]
60+ return errors , len (errors )
9461
95- undefined_errors = [e .strip () for e in detail .stdout .split ('\n ' ) if e .strip ()]
96- print (f"CRITICAL: { len (undefined_errors )} undefined variable(s) found:" )
62+ def display_errors (title , errors , is_critical = True ):
63+ level = "CRITICAL" if is_critical else "WARNING"
64+ if errors :
65+ print (f"{ level } : { len (errors )} { title } found:" )
66+ for error in errors :
67+ # Clean path for better display
68+ clean_error = error .replace ('/home/runner/work/lean-cli/lean-cli/' , '' )
69+ print (f" { clean_error } " )
70+ else :
71+ print (f"No { title } found" )
9772
98- for error in undefined_errors :
99- print (f" { error } " )
73+ def display_warning_summary (unused_count ):
74+ print ("\n Warnings:" )
75+ if unused_count > 0 :
76+ print (f" - Unused imports: { unused_count } " )
77+ print (" Consider addressing warnings in future updates." )
10078
101- all_critical_errors . extend ([ f"F821: { e } " for e in undefined_errors ])
102- else :
103- print ("No undefined variables found" )
79+ def run_analysis () -> int :
80+ print ( "Running static analysis..." )
81+ print ("=" * 60 )
10482
105- # Check for unused imports with flake8 - WARNING
106- print ("\n 3. Checking for unused imports..." )
107- print ("-" * 40 )
83+ critical_error_count = 0
84+ warning_count = 0
10885
109- result = subprocess .run (
110- ["python" , "-m" , "flake8" , "lean/" ,
111- "--select=F401" ,
112- "--ignore=ALL" ,
113- "--count" ,
114- "--exit-zero" ],
115- capture_output = True ,
116- text = True
117- )
86+ # Check for missing function arguments with mypy
87+ print ("\n 1. Checking for missing function arguments..." )
88+ print ("-" * 40 )
11889
119- if result .stdout .strip () and result .stdout .strip () != "0" :
120- detail = subprocess .run (
121- ["python" , "-m" , "flake8" , "lean/" , "--select=F401" , "--ignore=ALL" , "--exit-zero" ],
122- capture_output = True ,
123- text = True
124- )
90+ call_arg_errors = run_mypy_check ()
91+ display_errors ("function call argument mismatch(es)" , call_arg_errors )
92+ critical_error_count += len (call_arg_errors )
12593
126- unused_imports = [ e . strip () for e in detail . stdout . split ( ' \n ' ) if e . strip ()]
127- if unused_imports :
128- print (f"WARNING: { len ( unused_imports ) } unused import(s) found:" )
94+ # Check for undefined variables with flake8
95+ print ( " \n 2. Checking for undefined variables..." )
96+ print ("-" * 40 )
12997
130- for error in unused_imports :
131- print (f" { error } " )
98+ undefined_errors , undefined_count = run_flake8_check ("F821" )
99+ display_errors ("undefined variable(s)" , undefined_errors )
100+ critical_error_count += undefined_count
132101
133- all_warnings .extend ([f"F401: { e } " for e in unused_imports ])
134- else :
135- print ("No unused imports found" )
136- else :
137- print ("No unused imports found" )
102+ # Check for unused imports with flake8
103+ print ("\n 3. Checking for unused imports..." )
104+ print ("-" * 40 )
138105
139- print ("\n " + "=" * 60 )
106+ unused_imports , unused_count = run_flake8_check ("F401" )
107+ display_errors ("unused import(s)" , unused_imports , is_critical = False )
108+ warning_count += unused_count
140109
141110 # Summary
142- if all_critical_errors :
143- total_errors = len (all_critical_errors )
144- print (f"BUILD FAILED: Found { total_errors } critical error(s)" )
111+ print ("\n " + "=" * 60 )
145112
113+ if critical_error_count > 0 :
114+ print (f"BUILD FAILED: Found { critical_error_count } critical error(s)" )
146115 print ("\n Summary of critical errors:" )
147116 print (f" - Function call argument mismatches: { len (call_arg_errors )} " )
148- undefined_count = sum (1 for e in all_critical_errors if e .startswith ('F821:' ))
149117 print (f" - Undefined variables: { undefined_count } " )
150118
151- if all_warnings :
152- display_warning_summary (all_warnings )
119+ if warning_count > 0 :
120+ display_warning_summary (unused_count )
153121
154122 return 1
155123
156- if all_warnings :
157- print (f"BUILD PASSED with { len ( all_warnings ) } warning(s)" )
158- display_warning_summary (all_warnings )
124+ if warning_count > 0 :
125+ print (f"BUILD PASSED with { warning_count } warning(s)" )
126+ display_warning_summary (unused_count )
159127 return 0
160128
161129 print ("SUCCESS: All checks passed with no warnings" )
0 commit comments