@@ -67,59 +67,34 @@ def main(script_path: Optional[str],
6767 sources , options = process_options (args , stdout = stdout , stderr = stderr ,
6868 fscache = fscache )
6969
70- messages = []
7170 formatter = util .FancyFormatter (stdout , stderr , options .show_error_codes )
7271
7372 if options .install_types and (stdout is not sys .stdout or stderr is not sys .stderr ):
7473 # Since --install-types performs user input, we want regular stdout and stderr.
75- fail ("Error : --install-types not supported in this mode of running mypy" , stderr , options )
74+ fail ("error : --install-types not supported in this mode of running mypy" , stderr , options )
7675
7776 if options .non_interactive and not options .install_types :
78- fail ("Error : --non-interactive is only supported with --install-types" , stderr , options )
77+ fail ("error : --non-interactive is only supported with --install-types" , stderr , options )
7978
8079 if options .install_types and not options .incremental :
81- fail ("Error : --install-types not supported with incremental mode disabled" ,
80+ fail ("error : --install-types not supported with incremental mode disabled" ,
8281 stderr , options )
8382
8483 if options .install_types and not sources :
8584 install_types (options .cache_dir , formatter , non_interactive = options .non_interactive )
8685 return
8786
88- def flush_errors (new_messages : List [str ], serious : bool ) -> None :
89- if options .non_interactive :
90- return
91- if options .pretty :
92- new_messages = formatter .fit_in_terminal (new_messages )
93- messages .extend (new_messages )
94- f = stderr if serious else stdout
95- for msg in new_messages :
96- if options .color_output :
97- msg = formatter .colorize (msg )
98- f .write (msg + '\n ' )
99- f .flush ()
87+ res , messages , blockers = run_build (sources , options , fscache , t0 , stdout , stderr )
10088
101- serious = False
102- blockers = False
103- res = None
104- try :
105- # Keep a dummy reference (res) for memory profiling below, as otherwise
106- # the result could be freed.
107- res = build .build (sources , options , None , flush_errors , fscache , stdout , stderr )
108- except CompileError as e :
109- blockers = True
110- if not e .use_stdout :
111- serious = True
112- if (options .warn_unused_configs
113- and options .unused_configs
114- and not options .incremental
115- and not options .non_interactive ):
116- print ("Warning: unused section(s) in %s: %s" %
117- (options .config_file ,
118- get_config_module_names (options .config_file ,
119- [glob for glob in options .per_module_options .keys ()
120- if glob in options .unused_configs ])),
121- file = stderr )
122- maybe_write_junit_xml (time .time () - t0 , serious , messages , options )
89+ if options .non_interactive :
90+ missing_pkgs = read_types_packages_to_install (options .cache_dir , after_run = True )
91+ if missing_pkgs :
92+ # Install missing type packages and rerun build.
93+ install_types (options .cache_dir , formatter , after_run = True , non_interactive = True )
94+ fscache .flush ()
95+ print ()
96+ res , messages , blockers = run_build (sources , options , fscache , t0 , stdout , stderr )
97+ show_messages (messages , stderr , formatter , options )
12398
12499 if MEM_PROFILE :
125100 from mypy .memprofile import print_memory_profile
@@ -128,7 +103,7 @@ def flush_errors(new_messages: List[str], serious: bool) -> None:
128103 code = 0
129104 if messages :
130105 code = 2 if blockers else 1
131- if options .error_summary and not options . non_interactive :
106+ if options .error_summary :
132107 if messages :
133108 n_errors , n_files = util .count_stats (messages )
134109 if n_errors :
@@ -141,10 +116,13 @@ def flush_errors(new_messages: List[str], serious: bool) -> None:
141116 stdout .write (formatter .format_success (len (sources ), options .color_output ) + '\n ' )
142117 stdout .flush ()
143118
144- if options .install_types :
145- install_types (options .cache_dir , formatter , after_run = True ,
146- non_interactive = options .non_interactive )
147- return
119+ if options .install_types and not options .non_interactive :
120+ result = install_types (options .cache_dir , formatter , after_run = True ,
121+ non_interactive = False )
122+ if result :
123+ print ()
124+ print ("note: Run mypy again for up-to-date results with installed types" )
125+ code = 2
148126
149127 if options .fast_exit :
150128 # Exit without freeing objects -- it's faster.
@@ -158,6 +136,62 @@ def flush_errors(new_messages: List[str], serious: bool) -> None:
158136 list ([res ])
159137
160138
139+ def run_build (sources : List [BuildSource ],
140+ options : Options ,
141+ fscache : FileSystemCache ,
142+ t0 : float ,
143+ stdout : TextIO ,
144+ stderr : TextIO ) -> Tuple [Optional [build .BuildResult ], List [str ], bool ]:
145+ formatter = util .FancyFormatter (stdout , stderr , options .show_error_codes )
146+
147+ messages = []
148+
149+ def flush_errors (new_messages : List [str ], serious : bool ) -> None :
150+ if options .pretty :
151+ new_messages = formatter .fit_in_terminal (new_messages )
152+ messages .extend (new_messages )
153+ if options .non_interactive :
154+ # Collect messages and possibly show them later.
155+ return
156+ f = stderr if serious else stdout
157+ show_messages (new_messages , f , formatter , options )
158+
159+ serious = False
160+ blockers = False
161+ res = None
162+ try :
163+ # Keep a dummy reference (res) for memory profiling afterwards, as otherwise
164+ # the result could be freed.
165+ res = build .build (sources , options , None , flush_errors , fscache , stdout , stderr )
166+ except CompileError as e :
167+ blockers = True
168+ if not e .use_stdout :
169+ serious = True
170+ if (options .warn_unused_configs
171+ and options .unused_configs
172+ and not options .incremental
173+ and not options .non_interactive ):
174+ print ("Warning: unused section(s) in %s: %s" %
175+ (options .config_file ,
176+ get_config_module_names (options .config_file ,
177+ [glob for glob in options .per_module_options .keys ()
178+ if glob in options .unused_configs ])),
179+ file = stderr )
180+ maybe_write_junit_xml (time .time () - t0 , serious , messages , options )
181+ return res , messages , blockers
182+
183+
184+ def show_messages (messages : List [str ],
185+ f : TextIO ,
186+ formatter : util .FancyFormatter ,
187+ options : Options ) -> None :
188+ for msg in messages :
189+ if options .color_output :
190+ msg = formatter .colorize (msg )
191+ f .write (msg + '\n ' )
192+ f .flush ()
193+
194+
161195# Make the help output a little less jarring.
162196class AugmentedHelpFormatter (argparse .RawDescriptionHelpFormatter ):
163197 def __init__ (self , prog : str ) -> None :
@@ -1087,29 +1121,36 @@ def fail(msg: str, stderr: TextIO, options: Options) -> None:
10871121 sys .exit (2 )
10881122
10891123
1090- def install_types (cache_dir : str ,
1091- formatter : util .FancyFormatter ,
1092- * ,
1093- after_run : bool = False ,
1094- non_interactive : bool = False ) -> None :
1095- """Install stub packages using pip if some missing stubs were detected."""
1124+ def read_types_packages_to_install (cache_dir : str , after_run : bool ) -> List [str ]:
10961125 if not os .path .isdir (cache_dir ):
10971126 if not after_run :
10981127 sys .stderr .write (
1099- "Error : Can't determine which types to install with no files to check " +
1128+ "error : Can't determine which types to install with no files to check " +
11001129 "(and no cache from previous mypy run)\n "
11011130 )
11021131 else :
11031132 sys .stderr .write (
1104- "Error : --install-types failed (no mypy cache directory)\n "
1133+ "error : --install-types failed (no mypy cache directory)\n "
11051134 )
11061135 sys .exit (2 )
11071136 fnam = build .missing_stubs_file (cache_dir )
11081137 if not os .path .isfile (fnam ):
1109- # If there are no missing stubs, generate no output .
1110- return
1138+ # No missing stubs.
1139+ return []
11111140 with open (fnam ) as f :
1112- packages = [line .strip () for line in f .readlines ()]
1141+ return [line .strip () for line in f .readlines ()]
1142+
1143+
1144+ def install_types (cache_dir : str ,
1145+ formatter : util .FancyFormatter ,
1146+ * ,
1147+ after_run : bool = False ,
1148+ non_interactive : bool = False ) -> bool :
1149+ """Install stub packages using pip if some missing stubs were detected."""
1150+ packages = read_types_packages_to_install (cache_dir , after_run )
1151+ if not packages :
1152+ # If there are no missing stubs, generate no output.
1153+ return False
11131154 if after_run and not non_interactive :
11141155 print ()
11151156 print ('Installing missing stub packages:' )
@@ -1123,3 +1164,4 @@ def install_types(cache_dir: str,
11231164 sys .exit (2 )
11241165 print ()
11251166 subprocess .run (cmd )
1167+ return True
0 commit comments