Content-Length: 386060 | pFad | http://github.com/python/mypy/commit/#start-of-content

683BDC35 Tighten metaclass __call__ handling in protocols (#19191) · python/mypy@5fbfff9 · GitHub
Skip to content

Commit 5fbfff9

Browse files
authored
Tighten metaclass __call__ handling in protocols (#19191)
Fixes #19184 This fixes an (edge-case) regression introduced in 1.16. Fix is straightforward, only ignore `__call__` if it comes from an _actual_ metaclass.
1 parent 0ea8488 commit 5fbfff9

File tree

4 files changed

+27
-5
lines changed

4 files changed

+27
-5
lines changed

mypy/constraints.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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/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/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

test-data/unit/check-protocols.test

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4529,3 +4529,25 @@ def bad() -> Proto:
45294529
class Impl:
45304530
@defer
45314531
def f(self) -> int: ...
4532+
4533+
[case testInferCallableProtoWithAnySubclass]
4534+
from typing import Any, Generic, Protocol, TypeVar
4535+
4536+
T = TypeVar("T", covariant=True)
4537+
4538+
Unknown: Any
4539+
class Mock(Unknown):
4540+
def __init__(self, **kwargs: Any) -> None: ...
4541+
def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
4542+
4543+
class Factory(Protocol[T]):
4544+
def __call__(self, **kwargs: Any) -> T: ...
4545+
4546+
4547+
class Test(Generic[T]):
4548+
def __init__(self, f: Factory[T]) -> None:
4549+
...
4550+
4551+
t = Test(Mock())
4552+
reveal_type(t) # N: Revealed type is "__main__.Test[Any]"
4553+
[builtins fixtures/dict.pyi]

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/python/mypy/commit/#start-of-content

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy