@@ -101,7 +101,7 @@ def mypy_to_pandas(input_lines: Iterator[str]) -> pandas.DataFrame:
101101 "file" : [],
102102 "line" : [],
103103 "type" : [],
104- "section " : [],
104+ "errorcode " : [],
105105 "message" : [],
106106 }
107107 for line in input_lines :
@@ -120,7 +120,7 @@ def mypy_to_pandas(input_lines: Iterator[str]) -> pandas.DataFrame:
120120 data ["file" ].append (file )
121121 data ["line" ].append (lineno )
122122 data ["type" ].append (message_type )
123- data ["section " ].append (current_section )
123+ data ["errorcode " ].append (current_section )
124124 data ["message" ].append (message )
125125 except Exception as ex :
126126 print (elems )
@@ -154,43 +154,67 @@ def check_no_unexpected_results(mypy_lines: Iterator[str]):
154154 if not unexpected_failing :
155155 print (f"{ len (passing )} /{ len (all_files )} files pass as expected." )
156156 else :
157- print (f"{ len (unexpected_failing )} files unexpectedly failed:" )
157+ print ("!!!!!!!!!" )
158+ print (f"{ len (unexpected_failing )} files unexpectedly failed." )
158159 print ("\n " .join (sorted (map (str , unexpected_failing ))))
160+ print (
161+ "These files did not fail before, so please check the above output"
162+ f" for errors in { unexpected_failing } and fix them."
163+ )
164+ print ("!!!!!!!!!" )
159165 sys .exit (1 )
160166
161167 if unexpected_passing == {"pymc/sampling_jax.py" }:
162168 print ("Letting you know that 'pymc/sampling_jax.py' unexpectedly passed." )
163169 print ("But this file is known to sometimes pass and sometimes not." )
164- print ("Unless tried to resolve problems in sampling_jax.py just ignore this message." )
170+ print ("Unless you tried to resolve problems in sampling_jax.py just ignore this message." )
165171 elif unexpected_passing :
172+ print ("!!!!!!!!!" )
166173 print (f"{ len (unexpected_passing )} files unexpectedly passed the type checks:" )
167174 print ("\n " .join (sorted (map (str , unexpected_passing ))))
168175 print ("This is good news! Go to scripts/run_mypy.py and add them to the list." )
169176 if all_files .issubset (passing ):
170177 print ("WOW! All files are passing the mypy type checks!" )
171178 print ("scripts\\ run_mypy.py may no longer be needed." )
179+ print ("!!!!!!!!!" )
172180 sys .exit (1 )
173181 return
174182
175183
176184if __name__ == "__main__" :
177185 # Enforce PEP 561 for some important dependencies that
178186 # have relevant type hints but don't tell that to mypy.
179- enforce_pep561 ("aesara" )
180187 enforce_pep561 ("aeppl" )
181188
182- parser = argparse .ArgumentParser (description = "Process some integers ." )
189+ parser = argparse .ArgumentParser (description = "Run mypy type checks on PyMC codebase ." )
183190 parser .add_argument (
184191 "--verbose" , action = "count" , default = 0 , help = "Pass this to print mypy output."
185192 )
193+ parser .add_argument (
194+ "--groupby" ,
195+ default = "file" ,
196+ help = "How to group verbose output. One of {file|errorcode|message}." ,
197+ )
186198 args , _ = parser .parse_known_args ()
187199
188200 cp = subprocess .run (
189- ["mypy" , "--exclude" , "pymc/tests" , "pymc" ],
201+ ["mypy" , "--show-error-codes" , "-- exclude" , "pymc/tests" , "pymc" ],
190202 capture_output = True ,
191203 )
192204 output = cp .stdout .decode ()
193205 if args .verbose :
194- print (output )
206+ df = mypy_to_pandas (output .split ("\n " ))
207+ for section , sdf in df .reset_index ().groupby (args .groupby ):
208+ print (f"\n \n [{ section } ]" )
209+ for row in sdf .itertuples ():
210+ print (f"{ row .file } :{ row .line } : { row .type } : { row .message } " )
211+ print ()
212+ else :
213+ print (
214+ "Mypy output hidden."
215+ " Run `python run_mypy.py --verbose` to see the full output,"
216+ " or `python run_mypy.py --help` for other options."
217+ )
218+
195219 check_no_unexpected_results (output .split ("\n " ))
196220 sys .exit (0 )
0 commit comments