Skip to content

Commit 3facd78

Browse files
committed
Fix over eager types-google-cloud-ndb suggestion
Fixes #15343
1 parent c0af000 commit 3facd78

File tree

5 files changed

+26
-38
lines changed

5 files changed

+26
-38
lines changed

mypy/build.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
DecodeError,
5858
decode_python_encoding,
5959
get_mypy_comments,
60-
get_top_two_prefixes,
6160
hash_digest,
6261
is_stub_package_file,
6362
is_sub_path,
@@ -97,7 +96,7 @@
9796
is_legacy_bundled_package,
9897
legacy_bundled_packages,
9998
non_bundled_packages,
100-
stub_package_name,
99+
stub_distribution_name,
101100
)
102101
from mypy.types import Type
103102
from mypy.typestate import reset_global_state, type_state
@@ -2664,14 +2663,15 @@ def find_module_and_diagnose(
26642663
# search path or the module has not been installed.
26652664

26662665
ignore_missing_imports = options.ignore_missing_imports
2667-
top_level, second_level = get_top_two_prefixes(id)
2666+
2667+
id_components = id.split(".")
26682668
# Don't honor a global (not per-module) ignore_missing_imports
26692669
# setting for modules that used to have bundled stubs, as
26702670
# otherwise updating mypy can silently result in new false
26712671
# negatives. (Unless there are stubs but they are incomplete.)
26722672
global_ignore_missing_imports = manager.options.ignore_missing_imports
26732673
if (
2674-
(is_legacy_bundled_package(top_level) or is_legacy_bundled_package(second_level))
2674+
any(".".join(id_components[:i]) in legacy_bundled_packages for i in range(len(id_components), 0, -1))
26752675
and global_ignore_missing_imports
26762676
and not options.ignore_missing_imports_per_module
26772677
and result is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED
@@ -2780,15 +2780,19 @@ def module_not_found(
27802780
daemon = manager.options.fine_grained_incremental
27812781
msg, notes = reason.error_message_templates(daemon)
27822782
errors.report(line, 0, msg.format(module=target), code=codes.IMPORT)
2783-
top_level, second_level = get_top_two_prefixes(target)
2784-
if second_level in legacy_bundled_packages or second_level in non_bundled_packages:
2785-
top_level = second_level
2783+
2784+
components = target.split(".")
2785+
for i in range(len(components), 0, -1):
2786+
module = ".".join(components[:i])
2787+
if module in legacy_bundled_packages or module in non_bundled_packages:
2788+
break
2789+
27862790
for note in notes:
27872791
if "{stub_dist}" in note:
2788-
note = note.format(stub_dist=stub_package_name(top_level))
2792+
note = note.format(stub_dist=stub_distribution_name(module))
27892793
errors.report(line, 0, note, severity="note", only_once=True, code=codes.IMPORT)
27902794
if reason is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED:
2791-
manager.missing_stub_packages.add(stub_package_name(top_level))
2795+
manager.missing_stub_packages.add(stub_distribution_name(module))
27922796
errors.set_import_context(save_import_context)
27932797

27942798

mypy/modulefinder.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -337,14 +337,9 @@ def _find_module_non_stub_helper(
337337
# If this is not a directory then we can't traverse further into it
338338
if not self.fscache.isdir(dir_path):
339339
break
340-
if approved_stub_package_exists(components[0]):
341-
if len(components) == 1 or (
342-
self.find_module(components[0])
343-
is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED
344-
):
340+
for i in range(len(components), 0, -1):
341+
if approved_stub_package_exists(".".join(components[:i])):
345342
return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED
346-
if approved_stub_package_exists(".".join(components[:2])):
347-
return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED
348343
if plausible_match:
349344
return ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS
350345
else:

mypy/stubinfo.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def approved_stub_package_exists(prefix: str) -> bool:
99
return is_legacy_bundled_package(prefix) or prefix in non_bundled_packages
1010

1111

12-
def stub_package_name(prefix: str) -> str:
12+
def stub_distribution_name(prefix: str) -> str:
1313
return legacy_bundled_packages.get(prefix) or non_bundled_packages[prefix]
1414

1515

@@ -116,7 +116,7 @@ def stub_package_name(prefix: str) -> str:
116116
"flask_sqlalchemy": "types-Flask-SQLAlchemy",
117117
"fpdf": "types-fpdf2",
118118
"gdb": "types-gdb",
119-
"google.cloud": "types-google-cloud-ndb",
119+
"google.cloud.ndb": "types-google-cloud-ndb",
120120
"hdbcli": "types-hdbcli",
121121
"html5lib": "types-html5lib",
122122
"httplib2": "types-httplib2",

mypy/util.py

-11
Original file line numberDiff line numberDiff line change
@@ -308,17 +308,6 @@ def get_prefix(fullname: str) -> str:
308308
return fullname.rsplit(".", 1)[0]
309309

310310

311-
def get_top_two_prefixes(fullname: str) -> tuple[str, str]:
312-
"""Return one and two component prefixes of a fully qualified name.
313-
314-
Given 'a.b.c.d', return ('a', 'a.b').
315-
316-
If fullname has only one component, return (fullname, fullname).
317-
"""
318-
components = fullname.split(".", 3)
319-
return components[0], ".".join(components[:2])
320-
321-
322311
def correct_relative_import(
323312
cur_mod_id: str, relative: int, target: str, is_cur_package_init_file: bool
324313
) -> tuple[str, bool]:

test-data/unit/check-modules.test

+9-9
Original file line numberDiff line numberDiff line change
@@ -3134,17 +3134,17 @@ import google.cloud
31343134
from google.cloud import x
31353135

31363136
[case testErrorFromGoogleCloud]
3137-
import google.cloud
3137+
import google.cloud # E: Cannot find implementation or library stub for module named "google.cloud" \
3138+
# E: Cannot find implementation or library stub for module named "google"
31383139
from google.cloud import x
3139-
import google.non_existent
3140+
import google.non_existent # E: Cannot find implementation or library stub for module named "google.non_existent"
31403141
from google.non_existent import x
3141-
[out]
3142-
main:1: error: Library stubs not installed for "google.cloud"
3143-
main:1: note: Hint: "python3 -m pip install types-google-cloud-ndb"
3144-
main:1: note: (or run "mypy --install-types" to install all missing stub packages)
3145-
main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
3146-
main:1: error: Cannot find implementation or library stub for module named "google"
3147-
main:3: error: Cannot find implementation or library stub for module named "google.non_existent"
3142+
3143+
import google.cloud.ndb # E: Library stubs not installed for "google.cloud.ndb" \
3144+
# N: Hint: "python3 -m pip install types-google-cloud-ndb" \
3145+
# N: (or run "mypy --install-types" to install all missing stub packages) \
3146+
# N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
3147+
from google.cloud import ndb
31483148

31493149
[case testMissingSubmoduleOfInstalledStubPackage]
31503150
import bleach.xyz

0 commit comments

Comments
 (0)