Skip to content

Commit c3aaefa

Browse files
Merge branch 'master' into to-bytes
2 parents 7cce1e7 + c32b0a5 commit c3aaefa

Some content is hidden

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

59 files changed

+1869
-449
lines changed

docs/requirements-docs.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
-r ../mypy-requirements.txt
12
sphinx>=8.1.0
23
furo>=2022.3.4
34
myst-parser>=4.0.0

mypy/cache.py

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@
33
from collections.abc import Sequence
44
from typing import TYPE_CHECKING, Final
55

6+
from mypy_extensions import u8
7+
68
try:
79
from native_internal import (
810
Buffer as Buffer,
911
read_bool as read_bool,
1012
read_float as read_float,
1113
read_int as read_int,
1214
read_str as read_str,
15+
read_tag as read_tag,
1316
write_bool as write_bool,
1417
write_float as write_float,
1518
write_int as write_int,
1619
write_str as write_str,
20+
write_tag as write_tag,
1721
)
1822
except ImportError:
1923
# TODO: temporary, remove this after we publish mypy-native on PyPI.
@@ -32,6 +36,12 @@ def read_int(data: Buffer) -> int:
3236
def write_int(data: Buffer, value: int) -> None:
3337
raise NotImplementedError
3438

39+
def read_tag(data: Buffer) -> u8:
40+
raise NotImplementedError
41+
42+
def write_tag(data: Buffer, value: u8) -> None:
43+
raise NotImplementedError
44+
3545
def read_str(data: Buffer) -> str:
3646
raise NotImplementedError
3747

@@ -51,45 +61,48 @@ def write_float(data: Buffer, value: float) -> None:
5161
raise NotImplementedError
5262

5363

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
64+
# Always use this type alias to refer to type tags.
65+
Tag = u8
66+
67+
LITERAL_INT: Final[Tag] = 1
68+
LITERAL_STR: Final[Tag] = 2
69+
LITERAL_BOOL: Final[Tag] = 3
70+
LITERAL_FLOAT: Final[Tag] = 4
71+
LITERAL_COMPLEX: Final[Tag] = 5
72+
LITERAL_NONE: Final[Tag] = 6
6073

6174

62-
def read_literal(data: Buffer, marker: int) -> int | str | bool | float:
63-
if marker == LITERAL_INT:
75+
def read_literal(data: Buffer, tag: Tag) -> int | str | bool | float:
76+
if tag == LITERAL_INT:
6477
return read_int(data)
65-
elif marker == LITERAL_STR:
78+
elif tag == LITERAL_STR:
6679
return read_str(data)
67-
elif marker == LITERAL_BOOL:
80+
elif tag == LITERAL_BOOL:
6881
return read_bool(data)
69-
elif marker == LITERAL_FLOAT:
82+
elif tag == LITERAL_FLOAT:
7083
return read_float(data)
71-
assert False, f"Unknown literal marker {marker}"
84+
assert False, f"Unknown literal tag {tag}"
7285

7386

7487
def write_literal(data: Buffer, value: int | str | bool | float | complex | None) -> None:
7588
if isinstance(value, bool):
76-
write_int(data, LITERAL_BOOL)
89+
write_tag(data, LITERAL_BOOL)
7790
write_bool(data, value)
7891
elif isinstance(value, int):
79-
write_int(data, LITERAL_INT)
92+
write_tag(data, LITERAL_INT)
8093
write_int(data, value)
8194
elif isinstance(value, str):
82-
write_int(data, LITERAL_STR)
95+
write_tag(data, LITERAL_STR)
8396
write_str(data, value)
8497
elif isinstance(value, float):
85-
write_int(data, LITERAL_FLOAT)
98+
write_tag(data, LITERAL_FLOAT)
8699
write_float(data, value)
87100
elif isinstance(value, complex):
88-
write_int(data, LITERAL_COMPLEX)
101+
write_tag(data, LITERAL_COMPLEX)
89102
write_float(data, value.real)
90103
write_float(data, value.imag)
91104
else:
92-
write_int(data, LITERAL_NONE)
105+
write_tag(data, LITERAL_NONE)
93106

94107

95108
def read_int_opt(data: Buffer) -> int | None:

mypy/checker.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5552,10 +5552,10 @@ def visit_continue_stmt(self, s: ContinueStmt) -> None:
55525552
return
55535553

55545554
def visit_match_stmt(self, s: MatchStmt) -> None:
5555-
named_subject = self._make_named_statement_for_match(s)
55565555
# In sync with similar actions elsewhere, narrow the target if
55575556
# we are matching an AssignmentExpr
55585557
unwrapped_subject = collapse_walrus(s.subject)
5558+
named_subject = self._make_named_statement_for_match(s, unwrapped_subject)
55595559
with self.binder.frame_context(can_skip=False, fall_through=0):
55605560
subject_type = get_proper_type(self.expr_checker.accept(s.subject))
55615561

@@ -5646,9 +5646,8 @@ def visit_match_stmt(self, s: MatchStmt) -> None:
56465646
with self.binder.frame_context(can_skip=False, fall_through=2):
56475647
pass
56485648

5649-
def _make_named_statement_for_match(self, s: MatchStmt) -> Expression:
5649+
def _make_named_statement_for_match(self, s: MatchStmt, subject: Expression) -> Expression:
56505650
"""Construct a fake NameExpr for inference if a match clause is complex."""
5651-
subject = s.subject
56525651
if self.binder.can_put_directly(subject):
56535652
# Already named - we should infer type of it as given
56545653
return subject

mypy/checker_shared.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ def checking_await_set(self) -> Iterator[None]:
272272
def get_precise_awaitable_type(self, typ: Type, local_errors: ErrorWatcher) -> Type | None:
273273
raise NotImplementedError
274274

275+
@abstractmethod
276+
def add_any_attribute_to_type(self, typ: Type, name: str) -> Type:
277+
raise NotImplementedError
278+
275279
@abstractmethod
276280
def is_defined_in_stub(self, typ: Instance, /) -> bool:
277281
raise NotImplementedError

mypy/checkexpr.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6004,6 +6004,10 @@ def analyze_cond_branch(
60046004
def _combined_context(self, ty: Type | None) -> Type | None:
60056005
ctx_items = []
60066006
if ty is not None:
6007+
if has_any_type(ty):
6008+
# HACK: Any should be contagious, `dict[str, Any] or <x>` should still
6009+
# infer Any in x.
6010+
return ty
60076011
ctx_items.append(ty)
60086012
if self.type_context and self.type_context[-1] is not None:
60096013
ctx_items.append(self.type_context[-1])

mypy/checkpattern.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -671,12 +671,15 @@ def visit_class_pattern(self, o: ClassPattern) -> PatternType:
671671
has_local_errors = local_errors.has_new_errors()
672672
if has_local_errors or key_type is None:
673673
key_type = AnyType(TypeOfAny.from_error)
674-
self.msg.fail(
675-
message_registry.CLASS_PATTERN_UNKNOWN_KEYWORD.format(
676-
typ.str_with_options(self.options), keyword
677-
),
678-
pattern,
679-
)
674+
if not (type_info and type_info.fullname == "builtins.object"):
675+
self.msg.fail(
676+
message_registry.CLASS_PATTERN_UNKNOWN_KEYWORD.format(
677+
typ.str_with_options(self.options), keyword
678+
),
679+
pattern,
680+
)
681+
elif keyword is not None:
682+
new_type = self.chk.add_any_attribute_to_type(new_type, keyword)
680683

681684
inner_type, inner_rest_type, inner_captures = self.accept(pattern, key_type)
682685
if is_uninhabited(inner_type):

mypy/dmypy/client.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ def __init__(self, prog: str, **kwargs: Any) -> None:
3636
parser = argparse.ArgumentParser(
3737
prog="dmypy", description="Client for mypy daemon mode", fromfile_prefix_chars="@"
3838
)
39-
if sys.version_info >= (3, 14):
40-
parser.color = True # Set as init arg in 3.14
41-
4239
parser.set_defaults(action=None)
4340
parser.add_argument(
4441
"--status-file", default=DEFAULT_STATUS_FILE, help="status file to retrieve daemon details"

mypy/fastparse.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,7 @@
129129
PY_MINOR_VERSION: Final = sys.version_info[1]
130130

131131
import ast as ast3
132-
133-
# TODO: Index, ExtSlice are deprecated in 3.9.
134-
from ast import AST, Attribute, Call, FunctionType, Index, Name, Starred, UAdd, UnaryOp, USub
132+
from ast import AST, Attribute, Call, FunctionType, Name, Starred, UAdd, UnaryOp, USub
135133

136134

137135
def ast3_parse(
@@ -1779,18 +1777,6 @@ def visit_Slice(self, n: ast3.Slice) -> SliceExpr:
17791777
e = SliceExpr(self.visit(n.lower), self.visit(n.upper), self.visit(n.step))
17801778
return self.set_line(e, n)
17811779

1782-
# ExtSlice(slice* dims)
1783-
def visit_ExtSlice(self, n: ast3.ExtSlice) -> TupleExpr:
1784-
# cast for mypyc's benefit on Python 3.9
1785-
return TupleExpr(self.translate_expr_list(cast(Any, n).dims))
1786-
1787-
# Index(expr value)
1788-
def visit_Index(self, n: Index) -> Node:
1789-
# cast for mypyc's benefit on Python 3.9
1790-
value = self.visit(cast(Any, n).value)
1791-
assert isinstance(value, Node)
1792-
return value
1793-
17941780
# Match(expr subject, match_case* cases) # python 3.10 and later
17951781
def visit_Match(self, n: Match) -> MatchStmt:
17961782
node = MatchStmt(

mypy/main.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,8 +485,6 @@ def define_options(
485485
stdout=stdout,
486486
stderr=stderr,
487487
)
488-
if sys.version_info >= (3, 14):
489-
parser.color = True # Set as init arg in 3.14
490488

491489
strict_flag_names: list[str] = []
492490
strict_flag_assignments: list[tuple[str, bool]] = []

0 commit comments

Comments
 (0)