Skip to content

Commit 242873a

Browse files
authored
Implement flag to allow typechecking of untyped modules (#17712)
Add a flag and config ini options `"follow_untyped_imports"`. Setting it to `True` instructs mypy to typecheck also modules that do not have stubs or a `py.typed` marker. Fixes #8545
1 parent 411e1f1 commit 242873a

File tree

7 files changed

+44
-2
lines changed

7 files changed

+44
-2
lines changed

docs/source/command_line.rst

+4
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ imports.
166166
167167
For more details, see :ref:`ignore-missing-imports`.
168168

169+
.. option:: --follow-untyped-imports
170+
171+
This flag makes mypy analyze imports without stubs or a py.typed marker.
172+
169173
.. option:: --follow-imports {normal,silent,skip,error}
170174

171175
This flag adjusts how mypy follows imported modules that were not

docs/source/config_file.rst

+12
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,18 @@ section of the command line docs.
315315
match the name of the *imported* module, not the module containing the
316316
import statement.
317317

318+
.. confval:: follow_untyped_imports
319+
320+
:type: boolean
321+
:default: False
322+
323+
Typechecks imports from modules that do not have stubs or a py.typed marker.
324+
325+
If this option is used in a per-module section, the module name should
326+
match the name of the *imported* module, not the module containing the
327+
import statement. Note that scanning all unannotated modules might
328+
significantly increase the runtime of your mypy calls.
329+
318330
.. confval:: follow_imports
319331

320332
:type: string

docs/source/running_mypy.rst

+6
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,12 @@ not catch errors in its use.
321321
recommend avoiding ``--ignore-missing-imports`` if possible: it's equivalent
322322
to adding a ``# type: ignore`` to all unresolved imports in your codebase.
323323

324+
4. To make mypy typecheck imports from modules without stubs or a py.typed
325+
marker, you can set the :option:`--follow-untyped-imports <mypy --follow-untyped-imports>`
326+
command line flag or set the :confval:`follow_untyped_imports` config file option to True,
327+
either in the global section of your mypy config file, or individually on a
328+
per-module basis.
329+
324330

325331
Library stubs not installed
326332
---------------------------

mypy/main.py

+5
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,11 @@ def add_invertible_flag(
580580
action="store_true",
581581
help="Silently ignore imports of missing modules",
582582
)
583+
imports_group.add_argument(
584+
"--follow-untyped-imports",
585+
action="store_true",
586+
help="Typecheck modules without stubs or py.typed marker",
587+
)
583588
imports_group.add_argument(
584589
"--follow-imports",
585590
choices=["normal", "silent", "skip", "error"],

mypy/modulefinder.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,11 @@ def _typeshed_has_version(self, module: str) -> bool:
334334
return version >= min_version and (max_version is None or version <= max_version)
335335

336336
def _find_module_non_stub_helper(
337-
self, components: list[str], pkg_dir: str
337+
self, id: str, pkg_dir: str
338338
) -> OnePackageDir | ModuleNotFoundReason:
339339
plausible_match = False
340340
dir_path = pkg_dir
341+
components = id.split(".")
341342
for index, component in enumerate(components):
342343
dir_path = os_path_join(dir_path, component)
343344
if self.fscache.isfile(os_path_join(dir_path, "py.typed")):
@@ -350,6 +351,10 @@ def _find_module_non_stub_helper(
350351
if not self.fscache.isdir(dir_path):
351352
break
352353
if plausible_match:
354+
if self.options:
355+
module_specific_options = self.options.clone_for_module(id)
356+
if module_specific_options.follow_untyped_imports:
357+
return os.path.join(pkg_dir, *components[:-1]), False
353358
return ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS
354359
else:
355360
return ModuleNotFoundReason.NOT_FOUND
@@ -463,7 +468,7 @@ def _find_module(self, id: str, use_typeshed: bool) -> ModuleSearchResult:
463468
third_party_stubs_dirs.append((path, True))
464469
else:
465470
third_party_stubs_dirs.append((path, True))
466-
non_stub_match = self._find_module_non_stub_helper(components, pkg_dir)
471+
non_stub_match = self._find_module_non_stub_helper(id, pkg_dir)
467472
if isinstance(non_stub_match, ModuleNotFoundReason):
468473
if non_stub_match is ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS:
469474
found_possible_third_party_missing_type_hints = True

mypy/options.py

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class BuildType:
4242
"extra_checks",
4343
"follow_imports_for_stubs",
4444
"follow_imports",
45+
"follow_untyped_imports",
4546
"ignore_errors",
4647
"ignore_missing_imports",
4748
"implicit_optional",
@@ -113,6 +114,8 @@ def __init__(self) -> None:
113114
self.ignore_missing_imports = False
114115
# Is ignore_missing_imports set in a per-module section
115116
self.ignore_missing_imports_per_module = False
117+
# Typecheck modules without stubs or py.typed marker
118+
self.follow_untyped_imports = False
116119
self.follow_imports = "normal" # normal|silent|skip|error
117120
# Whether to respect the follow_imports setting even for stub files.
118121
# Intended to be used for disabling specific stubs.

test-data/unit/pep561.test

+7
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ b.bf(1)
187187
testNamespacePkgWStubsWithNamespacePackagesFlag.py:7: error: Argument 1 to "bf" has incompatible type "int"; expected "bool"
188188
testNamespacePkgWStubsWithNamespacePackagesFlag.py:8: error: Argument 1 to "bf" has incompatible type "int"; expected "bool"
189189

190+
[case testMissingPytypedFlag]
191+
# pkgs: typedpkg_ns_b
192+
# flags: --namespace-packages --follow-untyped-imports
193+
import typedpkg_ns.b.bbb as b
194+
b.bf("foo", "bar")
195+
[out]
196+
testMissingPytypedFlag.py:4: error: Too many arguments for "bf"
190197

191198
[case testTypedPkgNamespaceRegFromImportTwiceMissing]
192199
# pkgs: typedpkg_ns_a

0 commit comments

Comments
 (0)