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

Error messages when Type[X] is not a subtype of Type[SomeProtocol] are not very descriptive #5390

Open
Michael0x2a opened this issue Jul 25, 2018 · 3 comments

Comments

@Michael0x2a
Copy link
Collaborator

Consider the following code, which contains a type error. We expect a Type[MyProtocol], but we pass in a Type[SomeClass] instead, where SomeClass is incompatible with MyProtocol:

from typing import *

class MyProtocol(Protocol):
    def foo(self) -> int: pass

class SomeClass:
    def foo(self) -> str: pass

def test(x: Type[MyProtocol]) -> None: pass

test(SomeClass)

The error message we get is just Argument 1 to "test" has incompatible type "Type[SomeClass]"; expected "Type[MyProtocol]".

It would be nice if we got the more detailed error message we usually get when misusing protocols instead. For example, if we modify the code to:

def test(x: MyProtocol) -> None: pass
test(SomeClass())

...we get:

../probe/test2.py:15: error: Argument 1 to "test" has incompatible type "SomeClass"; expected "MyProtocol"
../probe/test2.py:15: note: Following member(s) of "SomeClass" have conflicts:
../probe/test2.py:15: note:     Expected:
../probe/test2.py:15: note:         def foo(self) -> int
../probe/test2.py:15: note:     Got:
../probe/test2.py:15: note:         def foo(self) -> str

I think this is probably just an oversight having specifically to do with Type -- doing stuff like:

T = TypeVar('T')
class Wrapper(Generic[T]):
    def __init__(self, x: T) -> None: pass

def test(x: Wrapper[MyProtocol]) -> None: pass
test(Wrapper(SomeClass()))

...results in the same nice error message, as expected.

(I would just go ahead and fix this myself, but I'm busy with other things atm, so filing this here so I don't forget about it/in case somebody else has some spare time.)

@Michael0x2a Michael0x2a changed the title Error messages when Type[X] is not a subtype of Type[SomeProtocol] are not very descriptive Error messages when Type[X] is not a subtype of Type[SomeProtocol] are not very descriptive Jul 25, 2018
@ilevkivskyi
Copy link
Member

I think it was just overlooked (as maybe some other cases). Also note that after fixing #4536 there will be two more cases like this: a protocol vs. Type[...], and a protocol vs. CallableType with is_type_obj() returning True.

@ariebovenberg
Copy link

Not sure if related, but there is also similar behavior with List[X]:

from typing import *

class MyProtocol(Protocol):
    def foo(self) -> int: pass

class SomeClass:
    def foo(self) -> str: pass

def test(x: List[MyProtocol]) -> None: pass

items = [SomeClass()]

test(items)

which only gives this message:

error: Argument 1 to "test" has incompatible type "List[SomeClass]"; expected "List[MyProtocol]"

Specifying this:

test([SomeClass()])

does give the desired, more informative, output:

error: List item 0 has incompatible type "SomeClass"; expected "MyProtocol"
note: Following member(s) of "SomeClass" have conflicts:
note:     Expected:
note:         def foo(self) -> int
note:     Got:
note:         def foo(self) -> str

@ilevkivskyi
Copy link
Member

This is a bit different, and it looks like it will be hard to give a better error message in this case, because we would need to track the "source" of incompatibility for generic classes.

@AlexWaygood AlexWaygood added the topic-error-reporting How we report errors label Apr 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants