Skip to content

Commit 0d0b2ed

Browse files
committed
Merge remote-tracking branch 'upstream/master' into 3.8-collections-imports
2 parents c04fb4d + b9056f9 commit 0d0b2ed

35 files changed

+887
-616
lines changed

.github/workflows/mypy_primer.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ jobs:
7474
name: Save PR number
7575
run: |
7676
echo ${{ github.event.pull_request.number }} | tee pr_number.txt
77-
- if: ${{ matrix.shard-index == 0 }}
78-
name: Upload mypy_primer diff + PR number
77+
- name: Upload mypy_primer diff + PR number
7978
uses: actions/upload-artifact@v4
79+
if: ${{ matrix.shard-index == 0 }}
8080
with:
8181
name: mypy_primer_diffs-${{ matrix.shard-index }}
8282
path: |

.github/workflows/mypy_primer_comment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
with:
4949
github-token: ${{ secrets.GITHUB_TOKEN }}
5050
script: |
51-
const MAX_CHARACTERS = 30000
51+
const MAX_CHARACTERS = 50000
5252
const MAX_CHARACTERS_PER_PROJECT = MAX_CHARACTERS / 3
5353
5454
const fs = require('fs')

.pre-commit-config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
exclude: '^(mypyc/external/)|(mypy/typeshed/)|misc/typeshed_patches' # Exclude all vendored code from lints
22
repos:
33
- repo: https://github.com/pre-commit/pre-commit-hooks
4-
rev: v4.5.0
4+
rev: v5.0.0
55
hooks:
66
- id: trailing-whitespace
77
- id: end-of-file-fixer
88
- repo: https://github.com/psf/black-pre-commit-mirror
9-
rev: 24.8.0
9+
rev: 24.10.0
1010
hooks:
1111
- id: black
1212
exclude: '^(test-data/)'
1313
- repo: https://github.com/astral-sh/ruff-pre-commit
14-
rev: v0.6.9
14+
rev: v0.8.4
1515
hooks:
1616
- id: ruff
1717
args: [--exit-non-zero-on-fix]
1818
- repo: https://github.com/python-jsonschema/check-jsonschema
19-
rev: 0.29.4
19+
rev: 0.30.0
2020
hooks:
2121
- id: check-dependabot
2222
- id: check-github-workflows
2323
- repo: https://github.com/rhysd/actionlint
24-
rev: v1.7.3
24+
rev: v1.7.4
2525
hooks:
2626
- id: actionlint
2727
args: [

CHANGELOG.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,25 @@
22

33
## Next release
44

5-
...
5+
### `--strict-bytes`
6+
7+
By default, mypy treats an annotation of ``bytes`` as permitting ``bytearray`` and ``memoryview``.
8+
[PEP 688](https://peps.python.org/pep-0688) specified the removal of this special case.
9+
Use this flag to disable this behavior. `--strict-bytes` will be enabled by default in **mypy 2.0**.
10+
11+
Contributed by Ali Hamdan (PR [18137](https://github.com/python/mypy/pull/18263/)) and
12+
Shantanu Jain (PR [13952](https://github.com/python/mypy/pull/13952)).
13+
14+
### Improvements to partial type handling in loops
15+
16+
This change results in mypy better modelling control flow within loops and hence detecting several
17+
issues it previously did not detect. In some cases, this change may require use of an additional
18+
explicit annotation of a variable.
19+
20+
Contributed by Christoph Tyralla (PR [18180](https://github.com/python/mypy/pull/18180)).
21+
22+
(Speaking of partial types, another reminder that mypy plans on enabling `--local-partial-types`
23+
by default in **mypy 2.0**).
624

725
## Mypy 1.14
826

mypy/checkexpr.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5346,9 +5346,10 @@ def visit_lambda_expr(self, e: LambdaExpr) -> Type:
53465346
self.chk.return_types.append(AnyType(TypeOfAny.special_form))
53475347
# Type check everything in the body except for the final return
53485348
# statement (it can contain tuple unpacking before return).
5349-
with self.chk.binder.frame_context(
5350-
can_skip=True, fall_through=0
5351-
), self.chk.scope.push_function(e):
5349+
with (
5350+
self.chk.binder.frame_context(can_skip=True, fall_through=0),
5351+
self.chk.scope.push_function(e),
5352+
):
53525353
# Lambdas can have more than one element in body,
53535354
# when we add "fictional" AssignmentStatement nodes, like in:
53545355
# `lambda (a, b): a`

mypy/fastparse.py

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
import copy
43
import re
54
import sys
65
import warnings
@@ -242,13 +241,6 @@ def parse(
242241
path=fnam,
243242
).visit(ast)
244243
except SyntaxError as e:
245-
# alias to please mypyc
246-
is_py38_or_earlier = sys.version_info < (3, 9)
247-
if is_py38_or_earlier and e.filename == "<fstring>":
248-
# In Python 3.8 and earlier, syntax errors in f-strings have lineno relative to the
249-
# start of the f-string. This would be misleading, as mypy will report the error as the
250-
# lineno within the file.
251-
e.lineno = None
252244
message = e.msg
253245
if feature_version > sys.version_info.minor and message.startswith("invalid syntax"):
254246
python_version_str = f"{options.python_version[0]}.{options.python_version[1]}"
@@ -2070,40 +2062,15 @@ def visit_Index(self, n: ast3.Index) -> Type:
20702062
def visit_Slice(self, n: ast3.Slice) -> Type:
20712063
return self.invalid_type(n, note="did you mean to use ',' instead of ':' ?")
20722064

2073-
# Subscript(expr value, slice slice, expr_context ctx) # Python 3.8 and before
20742065
# Subscript(expr value, expr slice, expr_context ctx) # Python 3.9 and later
20752066
def visit_Subscript(self, n: ast3.Subscript) -> Type:
2076-
if sys.version_info >= (3, 9): # Really 3.9a5 or later
2077-
sliceval: Any = n.slice
2078-
# Python 3.8 or earlier use a different AST structure for subscripts
2079-
elif isinstance(n.slice, ast3.Index):
2080-
sliceval: Any = n.slice.value
2081-
elif isinstance(n.slice, ast3.Slice):
2082-
sliceval = copy.deepcopy(n.slice) # so we don't mutate passed AST
2083-
if getattr(sliceval, "col_offset", None) is None:
2084-
# Fix column information so that we get Python 3.9+ message order
2085-
sliceval.col_offset = sliceval.lower.col_offset
2086-
else:
2087-
assert isinstance(n.slice, ast3.ExtSlice)
2088-
dims = cast(List[ast3.expr], copy.deepcopy(n.slice.dims))
2089-
for s in dims:
2090-
# These fields don't actually have a col_offset attribute but we add
2091-
# it manually.
2092-
if getattr(s, "col_offset", None) is None:
2093-
if isinstance(s, ast3.Index):
2094-
s.col_offset = s.value.col_offset
2095-
elif isinstance(s, ast3.Slice):
2096-
assert s.lower is not None
2097-
s.col_offset = s.lower.col_offset
2098-
sliceval = ast3.Tuple(dims, n.ctx)
2099-
21002067
empty_tuple_index = False
2101-
if isinstance(sliceval, ast3.Tuple):
2102-
params = self.translate_expr_list(sliceval.elts)
2103-
if len(sliceval.elts) == 0:
2068+
if isinstance(n.slice, ast3.Tuple):
2069+
params = self.translate_expr_list(n.slice.elts)
2070+
if len(n.slice.elts) == 0:
21042071
empty_tuple_index = True
21052072
else:
2106-
params = [self.visit(sliceval)]
2073+
params = [self.visit(n.slice)]
21072074

21082075
value = self.visit(n.value)
21092076
if isinstance(value, UnboundType) and not value.args:

mypy/main.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from collections.abc import Sequence
1212
from gettext import gettext
1313
from io import TextIOWrapper
14-
from typing import IO, Any, Final, NoReturn, TextIO
14+
from typing import IO, Any, Final, NoReturn, Protocol, TextIO
1515

1616
from mypy import build, defaults, state, util
1717
from mypy.config_parser import (
@@ -36,6 +36,11 @@
3636
from mypy.split_namespace import SplitNamespace
3737
from mypy.version import __version__
3838

39+
40+
class _SupportsWrite(Protocol):
41+
def write(self, s: str, /) -> object: ...
42+
43+
3944
orig_stat: Final = os.stat
4045
MEM_PROFILE: Final = False # If True, dump memory profile
4146

@@ -373,17 +378,17 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
373378
# =====================
374379
# Help-printing methods
375380
# =====================
376-
def print_usage(self, file: IO[str] | None = None) -> None:
381+
def print_usage(self, file: _SupportsWrite | None = None) -> None:
377382
if file is None:
378383
file = self.stdout
379384
self._print_message(self.format_usage(), file)
380385

381-
def print_help(self, file: IO[str] | None = None) -> None:
386+
def print_help(self, file: _SupportsWrite | None = None) -> None:
382387
if file is None:
383388
file = self.stdout
384389
self._print_message(self.format_help(), file)
385390

386-
def _print_message(self, message: str, file: IO[str] | None = None) -> None:
391+
def _print_message(self, message: str, file: _SupportsWrite | None = None) -> None:
387392
if message:
388393
if file is None:
389394
file = self.stderr

mypy/messages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2701,7 +2701,7 @@ def format_literal_value(typ: LiteralType) -> str:
27012701
if func.is_type_obj():
27022702
# The type of a type object type can be derived from the
27032703
# return type (this always works).
2704-
return format(TypeType.make_normalized(erase_type(func.items[0].ret_type)))
2704+
return format(TypeType.make_normalized(func.items[0].ret_type))
27052705
elif isinstance(func, CallableType):
27062706
if func.type_guard is not None:
27072707
return_type = f"TypeGuard[{format(func.type_guard)}]"

mypy/mixedtraverser.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ def __init__(self) -> None:
3030

3131
# Symbol nodes
3232

33-
def visit_var(self, var: Var) -> None:
33+
def visit_var(self, var: Var, /) -> None:
3434
self.visit_optional_type(var.type)
3535

36-
def visit_func(self, o: FuncItem) -> None:
36+
def visit_func(self, o: FuncItem, /) -> None:
3737
super().visit_func(o)
3838
self.visit_optional_type(o.type)
3939

40-
def visit_class_def(self, o: ClassDef) -> None:
40+
def visit_class_def(self, o: ClassDef, /) -> None:
4141
# TODO: Should we visit generated methods/variables as well, either here or in
4242
# TraverserVisitor?
4343
super().visit_class_def(o)
@@ -46,67 +46,67 @@ def visit_class_def(self, o: ClassDef) -> None:
4646
for base in info.bases:
4747
base.accept(self)
4848

49-
def visit_type_alias_expr(self, o: TypeAliasExpr) -> None:
49+
def visit_type_alias_expr(self, o: TypeAliasExpr, /) -> None:
5050
super().visit_type_alias_expr(o)
5151
self.in_type_alias_expr = True
5252
o.node.target.accept(self)
5353
self.in_type_alias_expr = False
5454

55-
def visit_type_var_expr(self, o: TypeVarExpr) -> None:
55+
def visit_type_var_expr(self, o: TypeVarExpr, /) -> None:
5656
super().visit_type_var_expr(o)
5757
o.upper_bound.accept(self)
5858
for value in o.values:
5959
value.accept(self)
6060

61-
def visit_typeddict_expr(self, o: TypedDictExpr) -> None:
61+
def visit_typeddict_expr(self, o: TypedDictExpr, /) -> None:
6262
super().visit_typeddict_expr(o)
6363
self.visit_optional_type(o.info.typeddict_type)
6464

65-
def visit_namedtuple_expr(self, o: NamedTupleExpr) -> None:
65+
def visit_namedtuple_expr(self, o: NamedTupleExpr, /) -> None:
6666
super().visit_namedtuple_expr(o)
6767
assert o.info.tuple_type
6868
o.info.tuple_type.accept(self)
6969

70-
def visit__promote_expr(self, o: PromoteExpr) -> None:
70+
def visit__promote_expr(self, o: PromoteExpr, /) -> None:
7171
super().visit__promote_expr(o)
7272
o.type.accept(self)
7373

74-
def visit_newtype_expr(self, o: NewTypeExpr) -> None:
74+
def visit_newtype_expr(self, o: NewTypeExpr, /) -> None:
7575
super().visit_newtype_expr(o)
7676
self.visit_optional_type(o.old_type)
7777

7878
# Statements
7979

80-
def visit_assignment_stmt(self, o: AssignmentStmt) -> None:
80+
def visit_assignment_stmt(self, o: AssignmentStmt, /) -> None:
8181
super().visit_assignment_stmt(o)
8282
self.visit_optional_type(o.type)
8383

84-
def visit_for_stmt(self, o: ForStmt) -> None:
84+
def visit_for_stmt(self, o: ForStmt, /) -> None:
8585
super().visit_for_stmt(o)
8686
self.visit_optional_type(o.index_type)
8787

88-
def visit_with_stmt(self, o: WithStmt) -> None:
88+
def visit_with_stmt(self, o: WithStmt, /) -> None:
8989
super().visit_with_stmt(o)
9090
for typ in o.analyzed_types:
9191
typ.accept(self)
9292

9393
# Expressions
9494

95-
def visit_cast_expr(self, o: CastExpr) -> None:
95+
def visit_cast_expr(self, o: CastExpr, /) -> None:
9696
super().visit_cast_expr(o)
9797
o.type.accept(self)
9898

99-
def visit_assert_type_expr(self, o: AssertTypeExpr) -> None:
99+
def visit_assert_type_expr(self, o: AssertTypeExpr, /) -> None:
100100
super().visit_assert_type_expr(o)
101101
o.type.accept(self)
102102

103-
def visit_type_application(self, o: TypeApplication) -> None:
103+
def visit_type_application(self, o: TypeApplication, /) -> None:
104104
super().visit_type_application(o)
105105
for t in o.types:
106106
t.accept(self)
107107

108108
# Helpers
109109

110-
def visit_optional_type(self, t: Type | None) -> None:
110+
def visit_optional_type(self, t: Type | None, /) -> None:
111111
if t:
112112
t.accept(self)

mypy/modulefinder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ def default_lib_path(
751751
return path
752752

753753

754-
@functools.lru_cache(maxsize=None)
754+
@functools.cache
755755
def get_search_dirs(python_executable: str | None) -> tuple[list[str], list[str]]:
756756
"""Find package directories for given python. Guaranteed to return absolute paths.
757757

0 commit comments

Comments
 (0)