Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

type[A] cannot be instantiated via partial if A is abstract #17556

Closed
iutlu opened this issue Jul 22, 2024 · 3 comments · Fixed by #17898
Closed

type[A] cannot be instantiated via partial if A is abstract #17556

iutlu opened this issue Jul 22, 2024 · 3 comments · Fixed by #17898
Labels
bug mypy got something wrong

Comments

@iutlu
Copy link

iutlu commented Jul 22, 2024

For a variable cls annotated as cls: type[A] where A is an ABC, the semantics from #2853 suggest that mypy resolves the type of the variable to concrete subclasses of A. The semantics do not seem to apply if the referenced concrete subclass is not instantiated directly via cls(), but rather via a partial as in partial(cls, *args, **kwargs)().

Mypy complains with cannot instantiate abstract class errors if a class variable referencing a presumed-concrete subclass of an ABC is invoked via partial:

To Reproduce

from abc import ABC, abstractmethod
from functools import partial
from typing import final


class A(ABC):
    @final
    def __init__(self, *, x: object, y: object) -> None:
        self.x = x
        self.y = y

    @abstractmethod
    def m(self) -> None:
        pass


class C(A):
    def m(self) -> None:
        """Implementation."""


def fun(cls: type[A]) -> None:
    cls(x=3, y=5)  # allowed
    partial_cls = partial(cls, x=3, y=5)  # cannot instantiate abstract class A
    partial_cls()  # cannot instantiate abstract class A

Expected Behavior

I'd have expected this to work, since if cls in the above example refers to a concrete subclass per #2853, it should be legal to use partial on it.

Instead, we get

Cannot instantiate abstract class "A" with abstract attribute "m"Mypy[abstract](https://mypy.readthedocs.io/en/latest/_refs.html#code-abstract)

Your Environment

  • Mypy version used: 1.11
  • Mypy configuration options from mypy.ini (and other config files):
[tool.mypy]
disallow_any_generics = true
disallow_subclassing_any = true
disallow_incomplete_defs = true
disallow_untyped_decorators = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
warn_unreachable = true
implicit_reexport = false
strict_equality = true
show_column_numbers = true
enable_incomplete_feature = ["NewGenericSyntax"]
plugins = [
  'pydantic.mypy',
  'pydantic.v1.mypy'
]
  • Python version used: 3.12
@iutlu iutlu added the bug mypy got something wrong label Jul 22, 2024
@wrobell
Copy link

wrobell commented Jul 22, 2024

Could that be related?

from functools import partial
import typing as tp

T = tp.TypeVar('T', str, int)

def f(a: str, t: type[T]) -> T:
    if t is int:
        return 1
    elif t is str:
        return '1'
    else:
        assert False
    
f1 = partial(f, '1')
f1(int)
f1(str)

Then

main.py:8: error: Incompatible return value type (got "int", expected "str")  [return-value]
main.py:10: error: Incompatible return value type (got "str", expected "int")  [return-value]
main.py:15: error: Argument 1 to "f" has incompatible type "type[int]"; expected "type[str]"  [arg-type]
Found 3 errors in 1 file (checked 1 source file)

@hauntsaninja
Copy link
Collaborator

#17898 should fix this

@wrobell your issue can be tracked at #17411

@wrobell
Copy link

wrobell commented Oct 8, 2024

@hauntsaninja thank you

JukkaL pushed a commit that referenced this issue Oct 9, 2024
JukkaL pushed a commit that referenced this issue Oct 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants