From c69294320c6ede89297bc28aa348aaed6909df5b Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:56:59 -0700 Subject: [PATCH] Improvements to functools.partial of types (#17898) Fixes https://github.com/python/mypy/issues/17556 , fixes https://github.com/python/mypy/issues/17659 --- mypy/checker.py | 8 ++--- test-data/unit/check-functools.test | 36 +++++++++++++++++++ test-data/unit/lib-stub/typing_extensions.pyi | 2 ++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 8d77bb02eeb2..e95bd36174ab 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -686,10 +686,10 @@ def extract_callable_type(self, inner_type: Type | None, ctx: Context) -> Callab if isinstance(inner_type, TypeVarLikeType): inner_type = get_proper_type(inner_type.upper_bound) if isinstance(inner_type, TypeType): - if isinstance(inner_type.item, Instance): - inner_type = expand_type_by_instance( - type_object_type(inner_type.item.type, self.named_type), inner_type.item - ) + inner_type = get_proper_type( + self.expr_checker.analyze_type_type_callee(inner_type.item, ctx) + ) + if isinstance(inner_type, CallableType): outer_type = inner_type elif isinstance(inner_type, Instance): diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index 9f8fbd42440b..50de3789ebd2 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -557,3 +557,39 @@ def bar(f: S) -> S: g = functools.partial(f, "foo") return f [builtins fixtures/primitives.pyi] + + +[case testFunctoolsPartialAbstractType] +# flags: --python-version 3.9 +from abc import ABC, abstractmethod +from functools import partial + +class A(ABC): + def __init__(self) -> None: ... + @abstractmethod + def method(self) -> None: ... + +def f1(cls: type[A]) -> None: + cls() + partial_cls = partial(cls) + partial_cls() + +def f2() -> None: + A() # E: Cannot instantiate abstract class "A" with abstract attribute "method" + partial_cls = partial(A) # E: Cannot instantiate abstract class "A" with abstract attribute "method" + partial_cls() # E: Cannot instantiate abstract class "A" with abstract attribute "method" +[builtins fixtures/tuple.pyi] + + +[case testFunctoolsPartialSelfType] +from functools import partial +from typing_extensions import Self + +class A: + def __init__(self, ts: float, msg: str) -> None: ... + + @classmethod + def from_msg(cls, msg: str) -> Self: + factory = partial(cls, ts=0) + return factory(msg=msg) +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/lib-stub/typing_extensions.pyi b/test-data/unit/lib-stub/typing_extensions.pyi index d9d7067efe0f..cb054b0e6b4f 100644 --- a/test-data/unit/lib-stub/typing_extensions.pyi +++ b/test-data/unit/lib-stub/typing_extensions.pyi @@ -43,6 +43,8 @@ Required: _SpecialForm NotRequired: _SpecialForm ReadOnly: _SpecialForm +Self: _SpecialForm + @final class TypeAliasType: def __init__(