Skip to content

Commit 8a088dc

Browse files
Merge branch 'master' into fix_typevar_default
2 parents 818175d + 843d133 commit 8a088dc

Some content is hidden

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

71 files changed

+1481
-422
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ repos:
4141
# actionlint has a shellcheck integration which extracts shell scripts in `run:` steps from GitHub Actions
4242
# and checks these with shellcheck. This is arguably its most useful feature,
4343
# but the integration only works if shellcheck is installed
44-
- "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.10.0"
44+
- "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.11.0"
4545
- repo: https://github.com/woodruffw/zizmor-pre-commit
4646
rev: v1.5.2
4747
hooks:

mypy-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ typing_extensions>=4.6.0
44
mypy_extensions>=1.0.0
55
pathspec>=0.9.0
66
tomli>=1.1.0; python_version<'3.11'
7-
librt>=0.1.0
7+
librt>=0.2.1

mypy/cache.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
from collections.abc import Sequence
44
from typing import Final
55

6-
from mypy_extensions import u8
7-
from native_internal import (
6+
from librt.internal import (
87
Buffer as Buffer,
98
read_bool as read_bool,
109
read_float as read_float,
@@ -17,6 +16,7 @@
1716
write_str as write_str,
1817
write_tag as write_tag,
1918
)
19+
from mypy_extensions import u8
2020

2121
# Always use this type alias to refer to type tags.
2222
Tag = u8

mypy/checkexpr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,7 @@ def check_call_expr_with_callee_type(
15021502
def check_union_call_expr(self, e: CallExpr, object_type: UnionType, member: str) -> Type:
15031503
"""Type check calling a member expression where the base type is a union."""
15041504
res: list[Type] = []
1505-
for typ in object_type.relevant_items():
1505+
for typ in flatten_nested_unions(object_type.relevant_items()):
15061506
# Member access errors are already reported when visiting the member expression.
15071507
with self.msg.filter_errors():
15081508
item = analyze_member_access(

mypy/checkpattern.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from mypy.maptype import map_instance_to_supertype
1515
from mypy.meet import narrow_declared_type
1616
from mypy.messages import MessageBuilder
17-
from mypy.nodes import ARG_POS, Context, Expression, NameExpr, TypeAlias, TypeInfo, Var
17+
from mypy.nodes import ARG_POS, Context, Expression, NameExpr, TypeAlias, Var
1818
from mypy.options import Options
1919
from mypy.patterns import (
2020
AsPattern,
@@ -37,6 +37,7 @@
3737
)
3838
from mypy.types import (
3939
AnyType,
40+
FunctionLike,
4041
Instance,
4142
LiteralType,
4243
NoneType,
@@ -538,27 +539,20 @@ def visit_class_pattern(self, o: ClassPattern) -> PatternType:
538539
# Check class type
539540
#
540541
type_info = o.class_ref.node
541-
if type_info is None:
542-
typ: Type = AnyType(TypeOfAny.from_error)
543-
elif isinstance(type_info, TypeAlias) and not type_info.no_args:
542+
typ = self.chk.expr_checker.accept(o.class_ref)
543+
p_typ = get_proper_type(typ)
544+
if isinstance(type_info, TypeAlias) and not type_info.no_args:
544545
self.msg.fail(message_registry.CLASS_PATTERN_GENERIC_TYPE_ALIAS, o)
545546
return self.early_non_match()
546-
elif isinstance(type_info, TypeInfo):
547-
typ = fill_typevars_with_any(type_info)
548-
elif isinstance(type_info, TypeAlias):
549-
typ = type_info.target
550-
elif (
551-
isinstance(type_info, Var)
552-
and type_info.type is not None
553-
and isinstance(get_proper_type(type_info.type), AnyType)
554-
):
555-
typ = type_info.type
556-
else:
557-
if isinstance(type_info, Var) and type_info.type is not None:
558-
name = type_info.type.str_with_options(self.options)
559-
else:
560-
name = type_info.name
561-
self.msg.fail(message_registry.CLASS_PATTERN_TYPE_REQUIRED.format(name), o)
547+
elif isinstance(p_typ, FunctionLike) and p_typ.is_type_obj():
548+
typ = fill_typevars_with_any(p_typ.type_object())
549+
elif not isinstance(p_typ, AnyType):
550+
self.msg.fail(
551+
message_registry.CLASS_PATTERN_TYPE_REQUIRED.format(
552+
typ.str_with_options(self.options)
553+
),
554+
o,
555+
)
562556
return self.early_non_match()
563557

564558
new_type, rest_type = self.chk.conditional_types_with_intersection(
@@ -697,6 +691,8 @@ def should_self_match(self, typ: Type) -> bool:
697691
typ = get_proper_type(typ)
698692
if isinstance(typ, TupleType):
699693
typ = typ.partial_fallback
694+
if isinstance(typ, AnyType):
695+
return False
700696
if isinstance(typ, Instance) and typ.type.get("__match_args__") is not None:
701697
# Named tuples and other subtypes of builtins that define __match_args__
702698
# should not self match.

mypy/errors.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -806,8 +806,8 @@ def generate_unused_ignore_errors(self, file: str) -> None:
806806
continue
807807
if codes.UNUSED_IGNORE.code in ignored_codes:
808808
continue
809-
used_ignored_codes = used_ignored_lines[line]
810-
unused_ignored_codes = set(ignored_codes) - set(used_ignored_codes)
809+
used_ignored_codes = set(used_ignored_lines[line])
810+
unused_ignored_codes = [c for c in ignored_codes if c not in used_ignored_codes]
811811
# `ignore` is used
812812
if not ignored_codes and used_ignored_codes:
813813
continue
@@ -817,7 +817,7 @@ def generate_unused_ignore_errors(self, file: str) -> None:
817817
# Display detail only when `ignore[...]` specifies more than one error code
818818
unused_codes_message = ""
819819
if len(ignored_codes) > 1 and unused_ignored_codes:
820-
unused_codes_message = f"[{', '.join(sorted(unused_ignored_codes))}]"
820+
unused_codes_message = f"[{', '.join(unused_ignored_codes)}]"
821821
message = f'Unused "type: ignore{unused_codes_message}" comment'
822822
for unused in unused_ignored_codes:
823823
narrower = set(used_ignored_codes) & codes.sub_code_map[unused]

mypy/fastparse.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,12 @@ def parse(
232232
assert options.python_version[0] >= 3
233233
feature_version = options.python_version[1]
234234
try:
235-
# Disable deprecation warnings about \u
235+
# Disable
236+
# - deprecation warnings for 'invalid escape sequence' (Python 3.11 and below)
237+
# - syntax warnings for 'invalid escape sequence' (3.12+) and 'return in finally' (3.14+)
236238
with warnings.catch_warnings():
237239
warnings.filterwarnings("ignore", category=DeprecationWarning)
240+
warnings.filterwarnings("ignore", category=SyntaxWarning)
238241
ast = ast3_parse(source, fnam, "exec", feature_version=feature_version)
239242

240243
tree = ASTConverter(

mypy/meet.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,9 @@ def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
170170
):
171171
# We put this branch early to get T(bound=Union[A, B]) instead of
172172
# Union[T(bound=A), T(bound=B)] that will be confusing for users.
173-
return declared.copy_modified(upper_bound=original_narrowed)
173+
return declared.copy_modified(
174+
upper_bound=narrow_declared_type(declared.upper_bound, original_narrowed)
175+
)
174176
elif not is_overlapping_types(declared, narrowed, prohibit_none_typevar_overlap=True):
175177
if state.strict_optional:
176178
return UninhabitedType()

mypy/plugins/default.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import mypy.errorcodes as codes
77
from mypy import message_registry
8-
from mypy.nodes import DictExpr, IntExpr, StrExpr, UnaryExpr
8+
from mypy.nodes import DictExpr, Expression, IntExpr, StrExpr, UnaryExpr
99
from mypy.plugin import (
1010
AttributeContext,
1111
ClassDefContext,
@@ -263,30 +263,40 @@ def typed_dict_get_callback(ctx: MethodContext) -> Type:
263263
if keys is None:
264264
return ctx.default_return_type
265265

266+
default_type: Type
267+
default_arg: Expression | None
268+
if len(ctx.arg_types) <= 1 or not ctx.arg_types[1]:
269+
default_arg = None
270+
default_type = NoneType()
271+
elif len(ctx.arg_types[1]) == 1 and len(ctx.args[1]) == 1:
272+
default_arg = ctx.args[1][0]
273+
default_type = ctx.arg_types[1][0]
274+
else:
275+
return ctx.default_return_type
276+
266277
output_types: list[Type] = []
267278
for key in keys:
268-
value_type = get_proper_type(ctx.type.items.get(key))
279+
value_type: Type | None = ctx.type.items.get(key)
269280
if value_type is None:
270281
return ctx.default_return_type
271282

272-
if len(ctx.arg_types) == 1:
283+
if key in ctx.type.required_keys:
273284
output_types.append(value_type)
274-
elif len(ctx.arg_types) == 2 and len(ctx.arg_types[1]) == 1 and len(ctx.args[1]) == 1:
275-
default_arg = ctx.args[1][0]
285+
else:
286+
# HACK to deal with get(key, {})
276287
if (
277288
isinstance(default_arg, DictExpr)
278289
and len(default_arg.items) == 0
279-
and isinstance(value_type, TypedDictType)
290+
and isinstance(vt := get_proper_type(value_type), TypedDictType)
280291
):
281-
# Special case '{}' as the default for a typed dict type.
282-
output_types.append(value_type.copy_modified(required_keys=set()))
292+
output_types.append(vt.copy_modified(required_keys=set()))
283293
else:
284294
output_types.append(value_type)
285-
output_types.append(ctx.arg_types[1][0])
286-
287-
if len(ctx.arg_types) == 1:
288-
output_types.append(NoneType())
295+
output_types.append(default_type)
289296

297+
# for nicer reveal_type, put default at the end, if it is present
298+
if default_type in output_types:
299+
output_types = [t for t in output_types if t != default_type] + [default_type]
290300
return make_simplified_union(output_types)
291301
return ctx.default_return_type
292302

mypy/semanal.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,11 +1791,10 @@ def push_type_args(
17911791
return None
17921792
tvs.append((p.name, tv))
17931793

1794-
for name, tv in tvs:
1795-
if self.is_defined_type_param(name):
1796-
self.fail(f'"{name}" already defined as a type parameter', context)
1794+
if self.is_defined_type_param(p.name):
1795+
self.fail(f'"{p.name}" already defined as a type parameter', context)
17971796
else:
1798-
self.add_symbol(name, tv, context, no_progress=True, type_param=True)
1797+
self.add_symbol(p.name, tv, context, no_progress=True, type_param=True)
17991798

18001799
return tvs
18011800

0 commit comments

Comments
 (0)