@@ -117,6 +117,13 @@ def main(
117117 options ,
118118 )
119119
120+ if options .install_types and options .list_install_types :
121+ fail (
122+ "error: --install-types and --list-install-types cannot be used together" ,
123+ stderr ,
124+ options ,
125+ )
126+
120127 if options .install_types and (stdout is not sys .stdout or stderr is not sys .stderr ):
121128 # Since --install-types performs user input, we want regular stdout and stderr.
122129 fail ("error: --install-types not supported in this mode of running mypy" , stderr , options )
@@ -136,11 +143,26 @@ def main(
136143 options ,
137144 )
138145
146+ if options .list_install_types and not options .incremental :
147+ fail (
148+ "error: --list-install-types not supported with incremental mode disabled" ,
149+ stderr ,
150+ options ,
151+ )
152+
139153 if options .install_types and not sources :
140154 install_types (formatter , options , non_interactive = options .non_interactive )
141155 return
142156
143- res , messages , blockers = run_build (sources , options , fscache , t0 , stdout , stderr )
157+ if options .list_install_types and not sources :
158+ list_install_types (options , out = stdout )
159+ return
160+
161+ # When --list-install-types is active, route all mypy diagnostic output to
162+ # stderr so that only the package names end up on stdout (enabling pipe usage
163+ # like: mypy --list-install-types src/ | xargs uv pip install).
164+ build_stdout = stderr if options .list_install_types else stdout
165+ res , messages , blockers = run_build (sources , options , fscache , t0 , build_stdout , stderr )
144166
145167 if options .non_interactive :
146168 missing_pkgs = read_types_packages_to_install (options .cache_dir , after_run = True )
@@ -166,11 +188,14 @@ def main(
166188 summary = formatter .format_error (
167189 n_errors , n_files , len (sources ), blockers = blockers , use_color = options .color_output
168190 )
169- stdout .write (summary + "\n " )
191+ build_stdout .write (summary + "\n " )
170192 # Only notes should also output success
171193 elif not messages or n_notes == len (messages ):
172- stdout .write (formatter .format_success (len (sources ), options .color_output ) + "\n " )
173- stdout .flush ()
194+ build_stdout .write (formatter .format_success (len (sources ), options .color_output ) + "\n " )
195+ build_stdout .flush ()
196+
197+ if options .list_install_types :
198+ list_install_types (options , after_run = True , out = stdout )
174199
175200 if options .install_types and not options .non_interactive :
176201 result = install_types (formatter , options , after_run = True , non_interactive = False )
@@ -1228,6 +1253,13 @@ def add_invertible_flag(
12281253 group = misc_group ,
12291254 inverse = "--interactive" ,
12301255 )
1256+ add_invertible_flag (
1257+ "--list-install-types" ,
1258+ default = False ,
1259+ strict_flag = False ,
1260+ help = "Print detected missing library stub packages (one per line) without installing" ,
1261+ group = misc_group ,
1262+ )
12311263
12321264 if server_options :
12331265 misc_group .add_argument (
@@ -1479,7 +1511,7 @@ def set_strict_flags() -> None:
14791511 special_opts .files ,
14801512 ]
14811513 )
1482- if code_methods == 0 and not options .install_types :
1514+ if code_methods == 0 and not options .install_types and not options . list_install_types :
14831515 parser .error ("Missing target module, package, files, or command." )
14841516 elif code_methods > 1 :
14851517 parser .error ("May only specify one of: module/package, files, or command." )
@@ -1705,6 +1737,19 @@ def read_types_packages_to_install(cache_dir: str, after_run: bool) -> list[str]
17051737 return [line .strip () for line in f ]
17061738
17071739
1740+ def list_install_types (options : Options , * , after_run : bool = False , out : TextIO ) -> None :
1741+ """Print missing stub packages one per line to *out*.
1742+
1743+ Callers should pass stdout here; mypy diagnostic output is routed to stderr
1744+ by the caller so that only package names reach stdout, making pipe usage
1745+ possible: mypy --list-install-types src/ | xargs uv pip install
1746+ """
1747+ packages = read_types_packages_to_install (options .cache_dir , after_run )
1748+ for pkg in packages :
1749+ out .write (pkg + "\n " )
1750+ out .flush ()
1751+
1752+
17081753def install_types (
17091754 formatter : util .FancyFormatter ,
17101755 options : Options ,
0 commit comments