Skip to content

Commit 67bcf4b

Browse files
Merge branch 'master' into patch-3
2 parents 8ca882c + 04afa49 commit 67bcf4b

Some content is hidden

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

65 files changed

+882
-259
lines changed

mypy/checkexpr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4420,7 +4420,7 @@ def visit_index_with_type(
44204420
elif isinstance(left_type, FunctionLike) and left_type.is_type_obj():
44214421
if left_type.type_object().is_enum:
44224422
return self.visit_enum_index_expr(left_type.type_object(), e.index, e)
4423-
elif self.chk.options.python_version >= (3, 9) and (
4423+
elif (
44244424
left_type.type_object().type_vars
44254425
or left_type.type_object().fullname == "builtins.type"
44264426
):

mypy/constraints.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ def _infer_constraints(
416416
infer_constraints_if_possible(t_item, actual, direction)
417417
for t_item in template.items
418418
],
419-
eager=False,
419+
eager=isinstance(actual, AnyType),
420420
)
421421
if result:
422422
return result
@@ -1066,8 +1066,8 @@ def infer_constraints_from_protocol_members(
10661066
inst, erase_typevars(temp), ignore_pos_arg_names=True
10671067
):
10681068
continue
1069-
# This exception matches the one in subtypes.py, see PR #14121 for context.
1070-
if member == "__call__" and instance.type.is_metaclass():
1069+
# This exception matches the one in typeops.py, see PR #14121 for context.
1070+
if member == "__call__" and instance.type.is_metaclass(precise=True):
10711071
continue
10721072
res.extend(infer_constraints(temp, inst, self.direction))
10731073
if mypy.subtypes.IS_SETTABLE in mypy.subtypes.get_member_flags(member, protocol):

mypy/fastparse.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2060,7 +2060,6 @@ def visit_Constant(self, n: Constant) -> Type:
20602060
contents = bytes_to_human_readable_repr(val)
20612061
return RawExpressionType(contents, "builtins.bytes", self.line, column=n.col_offset)
20622062
# Everything else is invalid.
2063-
return self.invalid_type(n)
20642063

20652064
# UnaryOp(op, operand)
20662065
def visit_UnaryOp(self, n: UnaryOp) -> Type:

mypy/join.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import mypy.typeops
99
from mypy.expandtype import expand_type
1010
from mypy.maptype import map_instance_to_supertype
11-
from mypy.nodes import CONTRAVARIANT, COVARIANT, INVARIANT, VARIANCE_NOT_READY
11+
from mypy.nodes import CONTRAVARIANT, COVARIANT, INVARIANT, VARIANCE_NOT_READY, TypeInfo
1212
from mypy.state import state
1313
from mypy.subtypes import (
1414
SubtypeContext,
@@ -168,9 +168,20 @@ def join_instances_via_supertype(self, t: Instance, s: Instance) -> ProperType:
168168
# Compute the "best" supertype of t when joined with s.
169169
# The definition of "best" may evolve; for now it is the one with
170170
# the longest MRO. Ties are broken by using the earlier base.
171-
best: ProperType | None = None
171+
172+
# Go over both sets of bases in case there's an explicit Protocol base. This is important
173+
# to ensure commutativity of join (although in cases where both classes have relevant
174+
# Protocol bases this maybe might still not be commutative)
175+
base_types: dict[TypeInfo, None] = {} # dict to deduplicate but preserve order
172176
for base in t.type.bases:
173-
mapped = map_instance_to_supertype(t, base.type)
177+
base_types[base.type] = None
178+
for base in s.type.bases:
179+
if base.type.is_protocol and is_subtype(t, base):
180+
base_types[base.type] = None
181+
182+
best: ProperType | None = None
183+
for base_type in base_types:
184+
mapped = map_instance_to_supertype(t, base_type)
174185
res = self.join_instances(mapped, s)
175186
if best is None or is_better(res, best):
176187
best = res
@@ -662,6 +673,10 @@ def is_better(t: Type, s: Type) -> bool:
662673
if isinstance(t, Instance):
663674
if not isinstance(s, Instance):
664675
return True
676+
if t.type.is_protocol != s.type.is_protocol:
677+
if t.type.fullname != "builtins.object" and s.type.fullname != "builtins.object":
678+
# mro of protocol is not really relevant
679+
return not t.type.is_protocol
665680
# Use len(mro) as a proxy for the better choice.
666681
if len(t.type.mro) > len(s.type.mro):
667682
return True

mypy/nodes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3359,11 +3359,11 @@ def calculate_metaclass_type(self) -> mypy.types.Instance | None:
33593359
return c
33603360
return None
33613361

3362-
def is_metaclass(self) -> bool:
3362+
def is_metaclass(self, *, precise: bool = False) -> bool:
33633363
return (
33643364
self.has_base("builtins.type")
33653365
or self.fullname == "abc.ABCMeta"
3366-
or self.fallback_to_any
3366+
or (self.fallback_to_any and not precise)
33673367
)
33683368

33693369
def has_base(self, fullname: str) -> bool:

mypy/semanal.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@
265265
TPDICT_NAMES,
266266
TYPE_ALIAS_NAMES,
267267
TYPE_CHECK_ONLY_NAMES,
268+
TYPE_NAMES,
268269
TYPE_VAR_LIKE_NAMES,
269270
TYPED_NAMEDTUPLE_NAMES,
270271
UNPACK_TYPE_NAMES,
@@ -1116,21 +1117,7 @@ def is_expected_self_type(self, typ: Type, is_classmethod: bool) -> bool:
11161117
return self.is_expected_self_type(typ.item, is_classmethod=False)
11171118
if isinstance(typ, UnboundType):
11181119
sym = self.lookup_qualified(typ.name, typ, suppress_errors=True)
1119-
if (
1120-
sym is not None
1121-
and (
1122-
sym.fullname == "typing.Type"
1123-
or (
1124-
sym.fullname == "builtins.type"
1125-
and (
1126-
self.is_stub_file
1127-
or self.is_future_flag_set("annotations")
1128-
or self.options.python_version >= (3, 9)
1129-
)
1130-
)
1131-
)
1132-
and typ.args
1133-
):
1120+
if sym is not None and sym.fullname in TYPE_NAMES and typ.args:
11341121
return self.is_expected_self_type(typ.args[0], is_classmethod=False)
11351122
return False
11361123
if isinstance(typ, TypeVarType):

mypy/typeanal.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@
6565
FINAL_TYPE_NAMES,
6666
LITERAL_TYPE_NAMES,
6767
NEVER_NAMES,
68+
TUPLE_NAMES,
6869
TYPE_ALIAS_NAMES,
70+
TYPE_NAMES,
6971
UNPACK_TYPE_NAMES,
7072
AnyType,
7173
BoolTypeQuery,
@@ -607,10 +609,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ
607609
code=codes.VALID_TYPE,
608610
)
609611
return AnyType(TypeOfAny.from_error)
610-
elif fullname == "typing.Tuple" or (
611-
fullname == "builtins.tuple"
612-
and (self.always_allow_new_syntax or self.options.python_version >= (3, 9))
613-
):
612+
elif fullname in TUPLE_NAMES:
614613
# Tuple is special because it is involved in builtin import cycle
615614
# and may be not ready when used.
616615
sym = self.api.lookup_fully_qualified_or_none("builtins.tuple")
@@ -645,10 +644,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ
645644
return make_optional_type(item)
646645
elif fullname == "typing.Callable":
647646
return self.analyze_callable_type(t)
648-
elif fullname == "typing.Type" or (
649-
fullname == "builtins.type"
650-
and (self.always_allow_new_syntax or self.options.python_version >= (3, 9))
651-
):
647+
elif fullname in TYPE_NAMES:
652648
if len(t.args) == 0:
653649
if fullname == "typing.Type":
654650
any_type = self.get_omitted_any(t)

mypy/typeops.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,7 @@ def named_type(fullname: str) -> Instance:
12571257

12581258
return type_object_type(left.type, named_type)
12591259

1260-
if member == "__call__" and left.type.is_metaclass():
1260+
if member == "__call__" and left.type.is_metaclass(precise=True):
12611261
# Special case: we want to avoid falling back to metaclass __call__
12621262
# if constructor signature didn't match, this can cause many false negatives.
12631263
return None

mypy/types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@
8484
TypeVisitor as TypeVisitor,
8585
)
8686

87+
TUPLE_NAMES: Final = ("builtins.tuple", "typing.Tuple")
88+
TYPE_NAMES: Final = ("builtins.type", "typing.Type")
89+
8790
TYPE_VAR_LIKE_NAMES: Final = (
8891
"typing.TypeVar",
8992
"typing_extensions.TypeVar",

mypy/typeshed/stdlib/_asyncio.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,4 @@ if sys.version_info >= (3, 12):
107107
if sys.version_info >= (3, 14):
108108
def future_discard_from_awaited_by(future: Future[Any], waiter: Future[Any], /) -> None: ...
109109
def future_add_to_awaited_by(future: Future[Any], waiter: Future[Any], /) -> None: ...
110+
def all_tasks(loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ...

0 commit comments

Comments
 (0)