@@ -67,59 +67,34 @@ def main(script_path: Optional[str],
67
67
sources , options = process_options (args , stdout = stdout , stderr = stderr ,
68
68
fscache = fscache )
69
69
70
- messages = []
71
70
formatter = util .FancyFormatter (stdout , stderr , options .show_error_codes )
72
71
73
72
if options .install_types and (stdout is not sys .stdout or stderr is not sys .stderr ):
74
73
# 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 )
76
75
77
76
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 )
79
78
80
79
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" ,
82
81
stderr , options )
83
82
84
83
if options .install_types and not sources :
85
84
install_types (options .cache_dir , formatter , non_interactive = options .non_interactive )
86
85
return
87
86
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 )
100
88
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 )
123
98
124
99
if MEM_PROFILE :
125
100
from mypy .memprofile import print_memory_profile
@@ -128,7 +103,7 @@ def flush_errors(new_messages: List[str], serious: bool) -> None:
128
103
code = 0
129
104
if messages :
130
105
code = 2 if blockers else 1
131
- if options .error_summary and not options . non_interactive :
106
+ if options .error_summary :
132
107
if messages :
133
108
n_errors , n_files = util .count_stats (messages )
134
109
if n_errors :
@@ -141,10 +116,13 @@ def flush_errors(new_messages: List[str], serious: bool) -> None:
141
116
stdout .write (formatter .format_success (len (sources ), options .color_output ) + '\n ' )
142
117
stdout .flush ()
143
118
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
148
126
149
127
if options .fast_exit :
150
128
# Exit without freeing objects -- it's faster.
@@ -158,6 +136,62 @@ def flush_errors(new_messages: List[str], serious: bool) -> None:
158
136
list ([res ])
159
137
160
138
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
+
161
195
# Make the help output a little less jarring.
162
196
class AugmentedHelpFormatter (argparse .RawDescriptionHelpFormatter ):
163
197
def __init__ (self , prog : str ) -> None :
@@ -1087,29 +1121,36 @@ def fail(msg: str, stderr: TextIO, options: Options) -> None:
1087
1121
sys .exit (2 )
1088
1122
1089
1123
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 ]:
1096
1125
if not os .path .isdir (cache_dir ):
1097
1126
if not after_run :
1098
1127
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 " +
1100
1129
"(and no cache from previous mypy run)\n "
1101
1130
)
1102
1131
else :
1103
1132
sys .stderr .write (
1104
- "Error : --install-types failed (no mypy cache directory)\n "
1133
+ "error : --install-types failed (no mypy cache directory)\n "
1105
1134
)
1106
1135
sys .exit (2 )
1107
1136
fnam = build .missing_stubs_file (cache_dir )
1108
1137
if not os .path .isfile (fnam ):
1109
- # If there are no missing stubs, generate no output .
1110
- return
1138
+ # No missing stubs.
1139
+ return []
1111
1140
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
1113
1154
if after_run and not non_interactive :
1114
1155
print ()
1115
1156
print ('Installing missing stub packages:' )
@@ -1123,3 +1164,4 @@ def install_types(cache_dir: str,
1123
1164
sys .exit (2 )
1124
1165
print ()
1125
1166
subprocess .run (cmd )
1167
+ return True
0 commit comments