Skip to content

Commit 2163ac6

Browse files
Merge branch 'master' into empty-tuple-constant
2 parents 6ce0c9f + 116b92b commit 2163ac6

File tree

126 files changed

+5289
-1330
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+5289
-1330
lines changed

misc/typeshed_patches/0001-Remove-use-of-LiteralString-in-builtins-13743.patch

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
From e6995c91231e1915eba43a29a22dd4cbfaf9e08e Mon Sep 17 00:00:00 2001
1+
From 805d7fc06a8bee350959512e0908a18a87b7f8c2 Mon Sep 17 00:00:00 2001
22
From: Shantanu <[email protected]>
33
Date: Mon, 26 Sep 2022 12:55:07 -0700
44
Subject: [PATCH] Remove use of LiteralString in builtins (#13743)
@@ -8,7 +8,7 @@ Subject: [PATCH] Remove use of LiteralString in builtins (#13743)
88
1 file changed, 1 insertion(+), 99 deletions(-)
99

1010
diff --git a/mypy/typeshed/stdlib/builtins.pyi b/mypy/typeshed/stdlib/builtins.pyi
11-
index 00728f42d..ea77a730f 100644
11+
index c7ab95482..3e93da36e 100644
1212
--- a/mypy/typeshed/stdlib/builtins.pyi
1313
+++ b/mypy/typeshed/stdlib/builtins.pyi
1414
@@ -63,7 +63,6 @@ from typing import ( # noqa: Y022,UP035
@@ -19,7 +19,7 @@ index 00728f42d..ea77a730f 100644
1919
ParamSpec,
2020
Self,
2121
TypeAlias,
22-
@@ -453,31 +452,16 @@ class str(Sequence[str]):
22+
@@ -468,31 +467,16 @@ class str(Sequence[str]):
2323
def __new__(cls, object: object = ...) -> Self: ...
2424
@overload
2525
def __new__(cls, object: ReadableBuffer, encoding: str = ..., errors: str = ...) -> Self: ...
@@ -51,7 +51,7 @@ index 00728f42d..ea77a730f 100644
5151
def format(self, *args: object, **kwargs: object) -> str: ...
5252
def format_map(self, mapping: _FormatMapMapping, /) -> str: ...
5353
def index(self, sub: str, start: SupportsIndex | None = ..., end: SupportsIndex | None = ..., /) -> int: ...
54-
@@ -493,98 +477,34 @@ class str(Sequence[str]):
54+
@@ -508,98 +492,34 @@ class str(Sequence[str]):
5555
def isspace(self) -> bool: ...
5656
def istitle(self) -> bool: ...
5757
def isupper(self) -> bool: ...
@@ -150,7 +150,7 @@ index 00728f42d..ea77a730f 100644
150150
def zfill(self, width: SupportsIndex, /) -> str: ... # type: ignore[misc]
151151
@staticmethod
152152
@overload
153-
@@ -595,39 +515,21 @@ class str(Sequence[str]):
153+
@@ -610,39 +530,21 @@ class str(Sequence[str]):
154154
@staticmethod
155155
@overload
156156
def maketrans(x: str, y: str, z: str, /) -> dict[int, int | None]: ...
@@ -190,7 +190,7 @@ index 00728f42d..ea77a730f 100644
190190
- @overload
191191
def __rmul__(self, value: SupportsIndex, /) -> str: ... # type: ignore[misc]
192192
def __getnewargs__(self) -> tuple[str]: ...
193-
193+
def __format__(self, format_spec: str, /) -> str: ...
194194
--
195-
2.49.0
195+
2.50.1
196196

mypy/build.py

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from typing_extensions import TypeAlias as _TypeAlias
4141

4242
import mypy.semanal_main
43+
from mypy.cache import Buffer
4344
from mypy.checker import TypeChecker
4445
from mypy.error_formatter import OUTPUT_CHOICES, ErrorFormatter
4546
from mypy.errors import CompileError, ErrorInfo, Errors, report_internal_error
@@ -116,6 +117,8 @@
116117
"abc",
117118
}
118119

120+
# We are careful now, we can increase this in future if safe/useful.
121+
MAX_GC_FREEZE_CYCLES = 1
119122

120123
Graph: _TypeAlias = dict[str, "State"]
121124

@@ -707,6 +710,8 @@ def __init__(
707710
# new file can be processed O(n**2) times. This cache
708711
# avoids most of this redundant work.
709712
self.ast_cache: dict[str, tuple[MypyFile, list[ErrorInfo]]] = {}
713+
# Number of times we used GC optimization hack for fresh SCCs.
714+
self.gc_freeze_cycles = 0
710715

711716
def dump_stats(self) -> None:
712717
if self.options.dump_build_stats:
@@ -1139,6 +1144,17 @@ def read_deps_cache(manager: BuildManager, graph: Graph) -> dict[str, FgDepMeta]
11391144
return module_deps_metas
11401145

11411146

1147+
def _load_ff_file(file: str, manager: BuildManager, log_error: str) -> bytes | None:
1148+
t0 = time.time()
1149+
try:
1150+
data = manager.metastore.read(file)
1151+
except OSError:
1152+
manager.log(log_error + file)
1153+
return None
1154+
manager.add_stats(metastore_read_time=time.time() - t0)
1155+
return data
1156+
1157+
11421158
def _load_json_file(
11431159
file: str, manager: BuildManager, log_success: str, log_error: str
11441160
) -> dict[str, Any] | None:
@@ -1259,7 +1275,11 @@ def get_cache_names(id: str, path: str, options: Options) -> tuple[str, str, str
12591275
deps_json = None
12601276
if options.cache_fine_grained:
12611277
deps_json = prefix + ".deps.json"
1262-
return (prefix + ".meta.json", prefix + ".data.json", deps_json)
1278+
if options.fixed_format_cache:
1279+
data_suffix = ".data.ff"
1280+
else:
1281+
data_suffix = ".data.json"
1282+
return (prefix + ".meta.json", prefix + data_suffix, deps_json)
12631283

12641284

12651285
def find_cache_meta(id: str, path: str, manager: BuildManager) -> CacheMeta | None:
@@ -1559,8 +1579,13 @@ def write_cache(
15591579
tree.path = path
15601580

15611581
# Serialize data and analyze interface
1562-
data = tree.serialize()
1563-
data_bytes = json_dumps(data, manager.options.debug_cache)
1582+
if manager.options.fixed_format_cache:
1583+
data_io = Buffer()
1584+
tree.write(data_io)
1585+
data_bytes = data_io.getvalue()
1586+
else:
1587+
data = tree.serialize()
1588+
data_bytes = json_dumps(data, manager.options.debug_cache)
15641589
interface_hash = hash_digest(data_bytes)
15651590

15661591
plugin_data = manager.plugin.report_config_data(ReportConfigContext(id, path, is_check=False))
@@ -2085,15 +2110,23 @@ def load_tree(self, temporary: bool = False) -> None:
20852110
self.meta is not None
20862111
), "Internal error: this method must be called only for cached modules"
20872112

2088-
data = _load_json_file(
2089-
self.meta.data_json, self.manager, "Load tree ", "Could not load tree: "
2090-
)
2113+
data: bytes | dict[str, Any] | None
2114+
if self.options.fixed_format_cache:
2115+
data = _load_ff_file(self.meta.data_json, self.manager, "Could not load tree: ")
2116+
else:
2117+
data = _load_json_file(
2118+
self.meta.data_json, self.manager, "Load tree ", "Could not load tree: "
2119+
)
20912120
if data is None:
20922121
return
20932122

20942123
t0 = time.time()
20952124
# TODO: Assert data file wasn't changed.
2096-
self.tree = MypyFile.deserialize(data)
2125+
if isinstance(data, bytes):
2126+
data_io = Buffer(data)
2127+
self.tree = MypyFile.read(data_io)
2128+
else:
2129+
self.tree = MypyFile.deserialize(data)
20972130
t1 = time.time()
20982131
self.manager.add_stats(deserialize_time=t1 - t0)
20992132
if not temporary:
@@ -2481,7 +2514,11 @@ def write_cache(self) -> None:
24812514
):
24822515
if self.options.debug_serialize:
24832516
try:
2484-
self.tree.serialize()
2517+
if self.manager.options.fixed_format_cache:
2518+
data = Buffer()
2519+
self.tree.write(data)
2520+
else:
2521+
self.tree.serialize()
24852522
except Exception:
24862523
print(f"Error serializing {self.id}", file=self.manager.stdout)
24872524
raise # Propagate to display traceback
@@ -3326,8 +3363,29 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
33263363
#
33273364
# TODO: see if it's possible to determine if we need to process only a
33283365
# _subset_ of the past SCCs instead of having to process them all.
3366+
if (
3367+
platform.python_implementation() == "CPython"
3368+
and manager.gc_freeze_cycles < MAX_GC_FREEZE_CYCLES
3369+
):
3370+
# When deserializing cache we create huge amount of new objects, so even
3371+
# with our generous GC thresholds, GC is still doing a lot of pointless
3372+
# work searching for garbage. So, we temporarily disable it when
3373+
# processing fresh SCCs, and then move all the new objects to the oldest
3374+
# generation with the freeze()/unfreeze() trick below. This is arguably
3375+
# a hack, but it gives huge performance wins for large third-party
3376+
# libraries, like torch.
3377+
gc.collect()
3378+
gc.disable()
33293379
for prev_scc in fresh_scc_queue:
33303380
process_fresh_modules(graph, prev_scc, manager)
3381+
if (
3382+
platform.python_implementation() == "CPython"
3383+
and manager.gc_freeze_cycles < MAX_GC_FREEZE_CYCLES
3384+
):
3385+
manager.gc_freeze_cycles += 1
3386+
gc.freeze()
3387+
gc.unfreeze()
3388+
gc.enable()
33313389
fresh_scc_queue = []
33323390
size = len(scc)
33333391
if size == 1:

mypy/cache.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Sequence
4+
from typing import TYPE_CHECKING, Final
5+
6+
try:
7+
from native_internal import (
8+
Buffer as Buffer,
9+
read_bool as read_bool,
10+
read_float as read_float,
11+
read_int as read_int,
12+
read_str as read_str,
13+
write_bool as write_bool,
14+
write_float as write_float,
15+
write_int as write_int,
16+
write_str as write_str,
17+
)
18+
except ImportError:
19+
# TODO: temporary, remove this after we publish mypy-native on PyPI.
20+
if not TYPE_CHECKING:
21+
22+
class Buffer:
23+
def __init__(self, source: bytes = b"") -> None:
24+
raise NotImplementedError
25+
26+
def getvalue(self) -> bytes:
27+
raise NotImplementedError
28+
29+
def read_int(data: Buffer) -> int:
30+
raise NotImplementedError
31+
32+
def write_int(data: Buffer, value: int) -> None:
33+
raise NotImplementedError
34+
35+
def read_str(data: Buffer) -> str:
36+
raise NotImplementedError
37+
38+
def write_str(data: Buffer, value: str) -> None:
39+
raise NotImplementedError
40+
41+
def read_bool(data: Buffer) -> bool:
42+
raise NotImplementedError
43+
44+
def write_bool(data: Buffer, value: bool) -> None:
45+
raise NotImplementedError
46+
47+
def read_float(data: Buffer) -> float:
48+
raise NotImplementedError
49+
50+
def write_float(data: Buffer, value: float) -> None:
51+
raise NotImplementedError
52+
53+
54+
LITERAL_INT: Final = 1
55+
LITERAL_STR: Final = 2
56+
LITERAL_BOOL: Final = 3
57+
LITERAL_FLOAT: Final = 4
58+
LITERAL_COMPLEX: Final = 5
59+
LITERAL_NONE: Final = 6
60+
61+
62+
def read_literal(data: Buffer, marker: int) -> int | str | bool | float:
63+
if marker == LITERAL_INT:
64+
return read_int(data)
65+
elif marker == LITERAL_STR:
66+
return read_str(data)
67+
elif marker == LITERAL_BOOL:
68+
return read_bool(data)
69+
elif marker == LITERAL_FLOAT:
70+
return read_float(data)
71+
assert False, f"Unknown literal marker {marker}"
72+
73+
74+
def write_literal(data: Buffer, value: int | str | bool | float | complex | None) -> None:
75+
if isinstance(value, bool):
76+
write_int(data, LITERAL_BOOL)
77+
write_bool(data, value)
78+
elif isinstance(value, int):
79+
write_int(data, LITERAL_INT)
80+
write_int(data, value)
81+
elif isinstance(value, str):
82+
write_int(data, LITERAL_STR)
83+
write_str(data, value)
84+
elif isinstance(value, float):
85+
write_int(data, LITERAL_FLOAT)
86+
write_float(data, value)
87+
elif isinstance(value, complex):
88+
write_int(data, LITERAL_COMPLEX)
89+
write_float(data, value.real)
90+
write_float(data, value.imag)
91+
else:
92+
write_int(data, LITERAL_NONE)
93+
94+
95+
def read_int_opt(data: Buffer) -> int | None:
96+
if read_bool(data):
97+
return read_int(data)
98+
return None
99+
100+
101+
def write_int_opt(data: Buffer, value: int | None) -> None:
102+
if value is not None:
103+
write_bool(data, True)
104+
write_int(data, value)
105+
else:
106+
write_bool(data, False)
107+
108+
109+
def read_str_opt(data: Buffer) -> str | None:
110+
if read_bool(data):
111+
return read_str(data)
112+
return None
113+
114+
115+
def write_str_opt(data: Buffer, value: str | None) -> None:
116+
if value is not None:
117+
write_bool(data, True)
118+
write_str(data, value)
119+
else:
120+
write_bool(data, False)
121+
122+
123+
def read_int_list(data: Buffer) -> list[int]:
124+
size = read_int(data)
125+
return [read_int(data) for _ in range(size)]
126+
127+
128+
def write_int_list(data: Buffer, value: list[int]) -> None:
129+
write_int(data, len(value))
130+
for item in value:
131+
write_int(data, item)
132+
133+
134+
def read_str_list(data: Buffer) -> list[str]:
135+
size = read_int(data)
136+
return [read_str(data) for _ in range(size)]
137+
138+
139+
def write_str_list(data: Buffer, value: Sequence[str]) -> None:
140+
write_int(data, len(value))
141+
for item in value:
142+
write_str(data, item)
143+
144+
145+
def read_str_opt_list(data: Buffer) -> list[str | None]:
146+
size = read_int(data)
147+
return [read_str_opt(data) for _ in range(size)]
148+
149+
150+
def write_str_opt_list(data: Buffer, value: list[str | None]) -> None:
151+
write_int(data, len(value))
152+
for item in value:
153+
write_str_opt(data, item)

mypy/checker.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
from mypy.typeanal import check_for_explicit_any, has_any_from_unimported_type, make_optional_type
172172
from mypy.typeops import (
173173
bind_self,
174+
can_have_shared_disjoint_base,
174175
coerce_to_literal,
175176
custom_special_method,
176177
erase_def_to_union_or_bound,
@@ -2658,6 +2659,8 @@ def visit_class_def(self, defn: ClassDef) -> None:
26582659
for base in typ.mro[1:]:
26592660
if base.is_final:
26602661
self.fail(message_registry.CANNOT_INHERIT_FROM_FINAL.format(base.name), defn)
2662+
if not can_have_shared_disjoint_base(typ.bases):
2663+
self.fail(message_registry.INCOMPATIBLE_DISJOINT_BASES.format(typ.name), defn)
26612664
with self.tscope.class_scope(defn.info), self.enter_partial_types(is_class=True):
26622665
old_binder = self.binder
26632666
self.binder = ConditionalTypeBinder(self.options)
@@ -5502,7 +5505,7 @@ def visit_with_stmt(self, s: WithStmt) -> None:
55025505
self.accept(s.body)
55035506

55045507
def check_untyped_after_decorator(self, typ: Type, func: FuncDef) -> None:
5505-
if not self.options.disallow_any_decorated or self.is_stub:
5508+
if not self.options.disallow_any_decorated or self.is_stub or self.current_node_deferred:
55065509
return
55075510

55085511
if mypy.checkexpr.has_any_type(typ):
@@ -5826,6 +5829,10 @@ def _make_fake_typeinfo_and_full_name(
58265829
format_type_distinctly(*base_classes, options=self.options, bare=True), "and"
58275830
)
58285831

5832+
if not can_have_shared_disjoint_base(base_classes):
5833+
errors.append((pretty_names_list, "have distinct disjoint bases"))
5834+
return None
5835+
58295836
new_errors = []
58305837
for base in base_classes:
58315838
if base.type.is_final:

mypy/checkexpr.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,10 @@ def visit_call_expr_inner(self, e: CallExpr, allow_none_return: bool = False) ->
582582
and not node.node.no_args
583583
and not (
584584
isinstance(union_target := get_proper_type(node.node.target), UnionType)
585-
and union_target.uses_pep604_syntax
585+
and (
586+
union_target.uses_pep604_syntax
587+
or self.chk.options.python_version >= (3, 10)
588+
)
586589
)
587590
):
588591
self.msg.type_arguments_not_allowed(e)

0 commit comments

Comments
 (0)