Speed up stubs suggestions (#17965) · python/mypy@50aa4ca · GitHub
Skip to content

Commit 50aa4ca

Browse files
committed
Speed up stubs suggestions (#17965)
See #17948 This is starting to show up on profiles - 1.01x faster on clean (below noise) - 1.02x faster on long - 1.02x faster on openai - 1.01x faster on openai incremental I had a dumb bug that was preventing the optimisation for a while, I'll see if I can make it even faster. Currently it's a small improvement We could also get rid of the legacy stuff in mypy 2.0
1 parent 7c27808 commit 50aa4ca

4 files changed

Lines changed: 93 additions & 35 deletions

File tree

mypy/build.py

Lines changed: 7 additions & 14 deletions

mypy/modulefinder.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,8 @@ def _find_module_non_stub_helper(
331331
# If this is not a directory then we can't traverse further into it
332332
if not self.fscache.isdir(dir_path):
333333
break
334-
for i in range(len(components), 0, -1):
335-
if approved_stub_package_exists(".".join(components[:i])):
336-
return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED
334+
if approved_stub_package_exists(".".join(components)):
335+
return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED
337336
if plausible_match:
338337
return ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS
339338
else:

mypy/stubinfo.py

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,53 @@
11
from __future__ import annotations
22

33

4-
def is_legacy_bundled_package(prefix: str) -> bool:
5-
return prefix in legacy_bundled_packages
4+
def is_module_from_legacy_bundled_package(module: str) -> bool:
5+
top_level = module.split(".", 1)[0]
6+
return top_level in legacy_bundled_packages
67

78

8-
def approved_stub_package_exists(prefix: str) -> bool:
9-
return is_legacy_bundled_package(prefix) or prefix in non_bundled_packages
9+
def approved_stub_package_exists(module: str) -> bool:
10+
top_level = module.split(".", 1)[0]
11+
if top_level in legacy_bundled_packages:
12+
return True
13+
if top_level in non_bundled_packages_flat:
14+
return True
15+
if top_level in non_bundled_packages_namespace:
16+
namespace = non_bundled_packages_namespace[top_level]
17+
components = module.split(".")
18+
for i in range(len(components), 0, -1):
19+
module = ".".join(components[:i])
20+
if module in namespace:
21+
return True
22+
return False
1023

1124

12-
def stub_distribution_name(prefix: str) -> str:
13-
return legacy_bundled_packages.get(prefix) or non_bundled_packages[prefix]
25+
def stub_distribution_name(module: str) -> str | None:
26+
top_level = module.split(".", 1)[0]
27+
28+
dist = legacy_bundled_packages.get(top_level)
29+
if dist:
30+
return dist
31+
dist = non_bundled_packages_flat.get(top_level)
32+
if dist:
33+
return dist
34+
35+
if top_level in non_bundled_packages_namespace:
36+
namespace = non_bundled_packages_namespace[top_level]
37+
components = module.split(".")
38+
for i in range(len(components), 0, -1):
39+
module = ".".join(components[:i])
40+
dist = namespace.get(module)
41+
if dist:
42+
return dist
43+
44+
return None
1445

1546

1647
# Stubs for these third-party packages used to be shipped with mypy.
1748
#
1849
# Map package name to PyPI stub distribution name.
19-
legacy_bundled_packages = {
50+
legacy_bundled_packages: dict[str, str] = {
2051
"aiofiles": "types-aiofiles",
2152
"bleach": "types-bleach",
2253
"boto": "types-boto",
@@ -32,7 +63,6 @@ def stub_distribution_name(prefix: str) -> str:
3263
"docutils": "types-docutils",
3364
"first": "types-first",
3465
"gflags": "types-python-gflags",
35-
"google.protobuf": "types-protobuf",
3666
"markdown": "types-Markdown",
3767
"mock": "types-mock",
3868
"OpenSSL": "types-pyOpenSSL",
@@ -66,20 +96,17 @@ def stub_distribution_name(prefix: str) -> str:
6696
# include packages that have a release that includes PEP 561 type
6797
# information.
6898
#
69-
# Package name can have one or two components ('a' or 'a.b').
70-
#
7199
# Note that these packages are omitted for now:
72100
# pika: typeshed's stubs are on PyPI as types-pika-ts.
73101
# types-pika already exists on PyPI, and is more complete in many ways,
74102
# but is a non-typeshed stubs package.
75-
non_bundled_packages = {
103+
non_bundled_packages_flat: dict[str, str] = {
76104
"MySQLdb": "types-mysqlclient",
77105
"PIL": "types-Pillow",
78106
"PyInstaller": "types-pyinstaller",
79107
"Xlib": "types-python-xlib",
80108
"aws_xray_sdk": "types-aws-xray-sdk",
81109
"babel": "types-babel",
82-
"backports.ssl_match_hostname": "types-backports.ssl_match_hostname",
83110
"braintree": "types-braintree",
84111
"bs4": "types-beautifulsoup4",
85112
"bugbear": "types-flake8-bugbear",
@@ -107,7 +134,6 @@ def stub_distribution_name(prefix: str) -> str:
107134
"flask_migrate": "types-Flask-Migrate",
108135
"fpdf": "types-fpdf2",
109136
"gdb": "types-gdb",
110-
"google.cloud.ndb": "types-google-cloud-ndb",
111137
"hdbcli": "types-hdbcli",
112138
"html5lib": "types-html5lib",
113139
"httplib2": "types-httplib2",
@@ -123,7 +149,6 @@ def stub_distribution_name(prefix: str) -> str:
123149
"oauthlib": "types-oauthlib",
124150
"openpyxl": "types-openpyxl",
125151
"opentracing": "types-opentracing",
126-
"paho.mqtt": "types-paho-mqtt",
127152
"parsimonious": "types-parsimonious",
128153
"passlib": "types-passlib",
129154
"passpy": "types-passpy",
@@ -171,3 +196,10 @@ def stub_distribution_name(prefix: str) -> str:
171196
"pandas": "pandas-stubs", # https://github.com/pandas-dev/pandas-stubs
172197
"lxml": "lxml-stubs", # https://github.com/lxml/lxml-stubs
173198
}
199+
200+
201+
non_bundled_packages_namespace: dict[str, dict[str, str]] = {
202+
"backports": {"backports.ssl_match_hostname": "types-backports.ssl_match_hostname"},
203+
"google": {"google.cloud.ndb": "types-google-cloud-ndb", "google.protobuf": "types-protobuf"},
204+
"paho": {"paho.mqtt": "types-paho-mqtt"},
205+
}

mypy/test/teststubinfo.py

Lines changed: 38 additions & 4 deletions

0 commit comments

Comments
 (0)