@@ -62,8 +62,8 @@ def stat_proxy(path: str) -> os.stat_result:
6262def main (
6363 * ,
6464 args : list [str ] | None = None ,
65- stdout : TextIO = sys . stdout ,
66- stderr : TextIO = sys . stderr ,
65+ stdout : TextIO | None = None ,
66+ stderr : TextIO | None = None ,
6767 clean_exit : bool = False ,
6868) -> None :
6969 """Main entry point to the type checker.
@@ -74,6 +74,15 @@ def main(
7474 clean_exit: Don't hard kill the process on exit. This allows catching
7575 SystemExit.
7676 """
77+ # As a common pattern around the codebase, we tend to do this instead of
78+ # using default arguments that are mutable objects (due to Python's
79+ # famously counterintuitive behavior about those): use a sentinel, then
80+ # set.
81+ stdout = stdout if stdout is not None else sys .stdout
82+ stderr = stderr if stderr is not None else sys .stderr
83+ # sys.stdout and sys.stderr might technically be None, but this fact isn't
84+ # currently enforced by the stubs (they are marked as MaybeNone (=Any)).
85+
7786 util .check_python_version ("mypy" )
7887 t0 = time .time ()
7988 # To log stat() calls: os.stat = stat_proxy
@@ -150,11 +159,10 @@ def main(
150159 summary = formatter .format_error (
151160 n_errors , n_files , len (sources ), blockers = blockers , use_color = options .color_output
152161 )
153- stdout . write (summary + " \n " )
162+ print (summary , file = stdout , flush = True )
154163 # Only notes should also output success
155164 elif not messages or n_notes == len (messages ):
156- stdout .write (formatter .format_success (len (sources ), options .color_output ) + "\n " )
157- stdout .flush ()
165+ print (formatter .format_success (len (sources ), options .color_output ), file = stdout , flush = True )
158166
159167 if options .install_types and not options .non_interactive :
160168 result = install_types (formatter , options , after_run = True , non_interactive = False )
@@ -180,13 +188,14 @@ def run_build(
180188 options : Options ,
181189 fscache : FileSystemCache ,
182190 t0 : float ,
183- stdout : TextIO ,
184- stderr : TextIO ,
191+ stdout : TextIO | None = None ,
192+ stderr : TextIO | None = None ,
185193) -> tuple [build .BuildResult | None , list [str ], bool ]:
186194 formatter = util .FancyFormatter (
187195 stdout , stderr , options .hide_error_codes , hide_success = bool (options .output )
188196 )
189-
197+ stdout = stdout if stdout is not None else sys .stdout
198+ stderr = stderr if stderr is not None else sys .stderr
190199 messages = []
191200 messages_by_file = defaultdict (list )
192201
@@ -238,14 +247,12 @@ def flush_errors(filename: str | None, new_messages: list[str], serious: bool) -
238247
239248
240249def show_messages (
241- messages : list [str ], f : TextIO , formatter : util .FancyFormatter , options : Options
250+ messages : list [str ], f : TextIO | None , formatter : util .FancyFormatter , options : Options
242251) -> None :
243252 for msg in messages :
244253 if options .color_output :
245254 msg = formatter .colorize (msg )
246- f .write (msg + "\n " )
247- f .flush ()
248-
255+ print (msg , file = f , flush = True )
249256
250257# Make the help output a little less jarring.
251258class AugmentedHelpFormatter (argparse .RawDescriptionHelpFormatter ):
@@ -399,7 +406,7 @@ def _print_message(self, message: str, file: SupportsWrite[str] | None = None) -
399406 if message :
400407 if file is None :
401408 file = self .stderr
402- file . write (message )
409+ print (message , file = file )
403410
404411 # ===============
405412 # Exiting methods
@@ -465,8 +472,8 @@ def __call__(
465472def define_options (
466473 program : str = "mypy" ,
467474 header : str = HEADER ,
468- stdout : TextIO | None ,
469- stderr : TextIO | None ,
475+ stdout : TextIO | None = None ,
476+ stderr : TextIO | None = None ,
470477 server_options : bool = False ,
471478) -> tuple [CapturableArgumentParser , list [str ], list [tuple [str , bool ]]]:
472479 """Define the options in the parser (by calling a bunch of methods that express/build our desired command-line flags).
0 commit comments