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

assert_type does not handle 'Type[]' of Protocol types correctly #15701

Closed
ippeiukai opened this issue Jul 18, 2023 · 4 comments
Closed

assert_type does not handle 'Type[]' of Protocol types correctly #15701

ippeiukai opened this issue Jul 18, 2023 · 4 comments
Labels
assert-type assert_type() bug mypy got something wrong topic-protocols

Comments

@ippeiukai
Copy link

ippeiukai commented Jul 18, 2023

Bug Report

According to PEP 544, "Variables and parameters annotated with Type[Proto] accept only concrete (non-protocol) subtypes of Proto." (https://peps.python.org/pep-0544/#type-and-class-objects-vs-protocols)

Using assert_type to check if Proto is accepted as Type[Proto] fails to report an error.

(from #15666)

To Reproduce

from typing import assert_type, Type, Protocol
from abc import ABC, abstractmethod


# == case 1 ==

class Proto(Protocol):
    def meth(self):
        ...


class Concrete(Proto):
    def meth(self):
        pass


var: Type[Proto]
var = Proto    # Error (according to PEP 544)
var = Concrete # OK
var().meth()   # OK

assert_type(Proto, Type[Proto])  # should report error


# == case 2 ==

class PureAbstract(ABC):
    @abstractmethod
    def meth(self):
        ...


class Concrete2(PureAbstract):
    def meth(self):
        pass


var2: Type[PureAbstract]
var2 = PureAbstract # ??? (Should pure abstract class behave like Protocol here?)
var2 = Concrete2    # OK
var().meth()        # OK

assert_type(PureAbstract, Type[PureAbstract])  # should report error if above is error


# == for ref ==

class Abstract(ABC):
    def meth(self):
        pass


class Concrete3(Abstract):
    ...


var3: Type[Abstract]
var3 = Abstract  # OK
var3 = Concrete3 # OK
var().meth()     # OK

assert_type(Abstract, Type[Abstract]) # OK

Expected Behavior

assert_type should confirm that Proto does not have an inferred type of Type[Proto].

Actual Behavior

assert_type accepts Proto to have an inferred type of Type[Proto].

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.11
@ippeiukai ippeiukai added the bug mypy got something wrong label Jul 18, 2023
@erictraut
Copy link

Mypy is doing the right thing here. The expression Proto refers to a class, and the type of this expression is type[Proto]. The statement assert_type(Proto, type[Proto]) therefore does not generate an error.

The text you quoted from PEP 544 applies only for type expressions used to annotate a variable or a parameter, and mypy is correctly generating an error in that case.

@AlexWaygood AlexWaygood closed this as not planned Won't fix, can't repro, duplicate, stale Jul 18, 2023
@ippeiukai
Copy link
Author

I’m confused 😕.

So, value of Proto actually has an infered type of type[Proto], yet it cannot be assigned to a variable annotated with type[Proto]?

@erictraut
Copy link

That's correct. The types match, but an assignment operation is not permitted because of the specific rule that you quoted in PEP 544. The justification for this rule is explained in the PEP, if you're curious.

@ippeiukai
Copy link
Author

ippeiukai commented Jul 19, 2023

I see. Thank you for explaining.

From the way PEP was written, I automatically assumed value of Proto got to be NonConcreteType[Proto] or something that cannot be assigned to type[Proto].

Python typing is so complex and I appreciate mypy team’s handling it for us.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assert-type assert_type() bug mypy got something wrong topic-protocols
Projects
None yet
Development

No branches or pull requests

3 participants