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

Protocol type object is not resolved correctly with overload #15666

Closed
ippeiukai opened this issue Jul 14, 2023 · 1 comment
Closed

Protocol type object is not resolved correctly with overload #15666

ippeiukai opened this issue Jul 14, 2023 · 1 comment
Labels
bug mypy got something wrong

Comments

@ippeiukai
Copy link

ippeiukai commented Jul 14, 2023

Bug Report

Function overloads that take type as argument does not match Protocol subclass objects.

This bug prevents use of Protocol classes with DI container like python-inject.
https://github.com/ivankorobkov/python-inject/blob/05ad3e87bb179ce56cabb272bd5f75cca2880f7c/inject/__init__.py#L394-L402

To Reproduce

from abc import ABCMeta, abstractmethod
from typing import Any, cast, NewType, overload, Protocol, runtime_checkable, TypeVar
from typing_extensions import assert_type

T = TypeVar( "T")


@overload
def get_instance(t: type[T]) -> T: ...
@overload
def get_instance(t: Any) -> object: ...

def get_instance(t):
    return cast(Any, object())  # dummy (e.g. should implement a DI container)


# normal class
class C:
    def foo(self) -> str:
        return ''

assert_type(C, type[C])


# abstract class
class A(metaclass=ABCMeta):
    def foo(self) -> str:
        return ''

assert_type(A, type[A])


# pure abstract class
class PA(metaclass=ABCMeta):
    @abstractmethod
    def foo(self) -> str:
        ...

assert_type(PA, type[PA])


# Protocol type
class P(Protocol):
    def foo(self) -> str:
        ...

assert_type(P, type[P])


# runtime-checkable Protocol type
@runtime_checkable
class RP(Protocol):
    def foo(self) -> str:
        ...

assert_type(RP, type[RP])


# NewType
NT = NewType("NT", PA)

assert_type(NT, type[NT])


c = get_instance(C)
assert_type(c, C)

a = get_instance(A)
assert_type(a, A)

pa = get_instance(PA)
assert_type(pa, PA)  # error: Expression is of type "object", not "PA"  [assert-type]

p = get_instance(P)
assert_type(p, P)  # error: Expression is of type "object", not "P"  [assert-type]

rp = get_instance(RP)
assert_type(rp, RP)  # error: Expression is of type "object", not "RP"  [assert-type]

nt = get_instance(NT)
assert_type(nt, NT)

Expected Behavior

There should be no type checking error.
Protocol class P should match type[P] in overloads.

Actual Behavior

Type checking errors are raised for Protocol types.
Protocol class P does match type[P] in overloads.

Your Environment

  • Mypy version used: 1.4.1
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.10.9 with typing-extensions 4.3.0
@ippeiukai ippeiukai added the bug mypy got something wrong label Jul 14, 2023
@ippeiukai
Copy link
Author

I've learnt this is actually as spec'ed in PEP 544.
https://peps.python.org/pep-0544/#type-and-class-objects-vs-protocols

However, some inconsistencies remain problematic. I will create new issues for them.

  • pure abstract case being error
  • assert_type not picking up error

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

No branches or pull requests

1 participant