Skip to content

Commit a86f7e3

Browse files
authored
Microoptimise read buffering, metastore abspath, path joining (#20810)
Removing buffering on file reads can make those reads like 20% faster. This is probably worth a few percent on a warm cache profile I was looking at. Removing abspath in metastore also looks like a percent or two on a warm cache profile. I don't think using the faster path join from #17949 will really help the profiles I was looking at, but if we're microoptimising some of these code paths we might as well. (On a cold profile I do think some of the variadic os.path.join now add up enough that it could be worth making a function for them, but whatever)
1 parent b8b50b1 commit a86f7e3

2 files changed

Lines changed: 18 additions & 15 deletions

File tree

mypy/build.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
is_sub_path_normabs,
120120
is_typeshed_file,
121121
module_prefix,
122+
os_path_join,
122123
read_py_file,
123124
time_ref,
124125
time_spent_us,
@@ -582,7 +583,7 @@ def plugin_error(message: str) -> NoReturn:
582583
plugin_path, func_name = plugin_path.rsplit(":", 1)
583584
if plugin_path.endswith(".py"):
584585
# Plugin paths can be relative to the config file location.
585-
plugin_path = os.path.join(os.path.dirname(options.config_file), plugin_path)
586+
plugin_path = os_path_join(os.path.dirname(options.config_file), plugin_path)
586587
if not os.path.isfile(plugin_path):
587588
plugin_error(f'Can\'t find plugin "{plugin_path}"')
588589
# Use an absolute path to avoid populating the cache entry
@@ -1466,7 +1467,7 @@ def _cache_dir_prefix(options: Options) -> str:
14661467
return os.curdir
14671468
cache_dir = options.cache_dir
14681469
pyversion = options.python_version
1469-
base = os.path.join(cache_dir, "%d.%d" % pyversion)
1470+
base = os_path_join(cache_dir, "%d.%d" % pyversion)
14701471
return base
14711472

14721473

@@ -1475,7 +1476,7 @@ def add_catch_all_gitignore(target_dir: str) -> None:
14751476
14761477
No-op if the .gitignore already exists.
14771478
"""
1478-
gitignore = os.path.join(target_dir, ".gitignore")
1479+
gitignore = os_path_join(target_dir, ".gitignore")
14791480
try:
14801481
with open(gitignore, "x") as f:
14811482
print("# Automatically created by mypy", file=f)
@@ -1489,7 +1490,7 @@ def exclude_from_backups(target_dir: str) -> None:
14891490
14901491
If the CACHEDIR.TAG file exists the function is a no-op.
14911492
"""
1492-
cachedir_tag = os.path.join(target_dir, "CACHEDIR.TAG")
1493+
cachedir_tag = os_path_join(target_dir, "CACHEDIR.TAG")
14931494
try:
14941495
with open(cachedir_tag, "x") as f:
14951496
f.write("""Signature: 8a477f597d28d172789f06886806bc55
@@ -1539,7 +1540,7 @@ def get_cache_names(id: str, path: str, options: Options) -> tuple[str, str, str
15391540
prefix = os.path.join(*id.split("."))
15401541
is_package = os.path.basename(path).startswith("__init__.py")
15411542
if is_package:
1542-
prefix = os.path.join(prefix, "__init__")
1543+
prefix = os_path_join(prefix, "__init__")
15431544

15441545
deps_json = None
15451546
if options.cache_fine_grained:
@@ -2393,7 +2394,7 @@ def __init__(
23932394
if os.path.isabs(path):
23942395
self.abspath = path
23952396
else:
2396-
self.abspath = os.path.normpath(os.path.join(manager.cwd, path))
2397+
self.abspath = os.path.normpath(os_path_join(manager.cwd, path))
23972398
self.xpath = path or "<string>"
23982399
self.source = source
23992400
self.options = options
@@ -4327,7 +4328,7 @@ def transitive_dep_hash(scc: SCC, graph: Graph) -> bytes:
43274328

43284329

43294330
def missing_stubs_file(cache_dir: str) -> str:
4330-
return os.path.join(cache_dir, "missing_stubs")
4331+
return os_path_join(cache_dir, "missing_stubs")
43314332

43324333

43334334
def record_missing_stub_packages(cache_dir: str, missing_stub_packages: set[str]) -> None:

mypy/metastore.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from collections.abc import Iterable
1818
from typing import TYPE_CHECKING, Any
1919

20+
from mypy.util import os_path_join
21+
2022
if TYPE_CHECKING:
2123
# We avoid importing sqlite3 unless we are using it so we can mostly work
2224
# on semi-broken pythons that are missing it.
@@ -85,24 +87,24 @@ def getmtime(self, name: str) -> float:
8587
if not self.cache_dir_prefix:
8688
raise FileNotFoundError()
8789

88-
return int(os.path.getmtime(os.path.join(self.cache_dir_prefix, name)))
90+
return int(os.path.getmtime(os_path_join(self.cache_dir_prefix, name)))
8991

9092
def read(self, name: str) -> bytes:
91-
assert os.path.normpath(name) != os.path.abspath(name), "Don't use absolute paths!"
93+
assert not os.path.isabs(name), "Don't use absolute paths!"
9294

9395
if not self.cache_dir_prefix:
9496
raise FileNotFoundError()
9597

96-
with open(os.path.join(self.cache_dir_prefix, name), "rb") as f:
98+
with open(os_path_join(self.cache_dir_prefix, name), "rb", buffering=0) as f:
9799
return f.read()
98100

99101
def write(self, name: str, data: bytes, mtime: float | None = None) -> bool:
100-
assert os.path.normpath(name) != os.path.abspath(name), "Don't use absolute paths!"
102+
assert not os.path.isabs(name), "Don't use absolute paths!"
101103

102104
if not self.cache_dir_prefix:
103105
return False
104106

105-
path = os.path.join(self.cache_dir_prefix, name)
107+
path = os_path_join(self.cache_dir_prefix, name)
106108
tmp_filename = path + "." + random_string()
107109
try:
108110
os.makedirs(os.path.dirname(path), exist_ok=True)
@@ -120,7 +122,7 @@ def remove(self, name: str) -> None:
120122
if not self.cache_dir_prefix:
121123
raise FileNotFoundError()
122124

123-
os.remove(os.path.join(self.cache_dir_prefix, name))
125+
os.remove(os_path_join(self.cache_dir_prefix, name))
124126

125127
def commit(self) -> None:
126128
pass
@@ -132,7 +134,7 @@ def list_all(self) -> Iterable[str]:
132134
for dir, _, files in os.walk(self.cache_dir_prefix):
133135
dir = os.path.relpath(dir, self.cache_dir_prefix)
134136
for file in files:
135-
yield os.path.normpath(os.path.join(dir, file))
137+
yield os.path.normpath(os_path_join(dir, file))
136138

137139

138140
SCHEMA = """
@@ -168,7 +170,7 @@ def __init__(self, cache_dir_prefix: str, sync_off: bool = False) -> None:
168170
return
169171

170172
os.makedirs(cache_dir_prefix, exist_ok=True)
171-
self.db = connect_db(os.path.join(cache_dir_prefix, "cache.db"), sync_off=sync_off)
173+
self.db = connect_db(os_path_join(cache_dir_prefix, "cache.db"), sync_off=sync_off)
172174

173175
def _query(self, name: str, field: str) -> Any:
174176
# Raises FileNotFound for consistency with the file system version

0 commit comments

Comments
 (0)