Mypy: Import of Protocol is broken aftre form typing import *

Created on 3 Jan 2018  路  8Comments  路  Source: python/mypy

This code:

from typing import *
from typing_extensions import Protocol

leads to a weird error:

Incompatible import of "Protocol" (imported name has type "typing_extensions._SpecialForm", local name has type "typing._SpecialForm")
bug priority-1-normal topic-protocols

Most helpful comment

Is there a way to avoid this error when writing something like the follow?

# Protocol is only available in Python 3.8+.
try:
    from typing import Protocol
except ImportError:
    from typing_extensions import Protocol

All 8 comments

This happens because the typing stub exposes a Protocol type (https://github.com/python/typeshed/blob/fb2c7b34e27232198b7b742bca93640c5b77c26f/stdlib/3/typing.pyi#L22), even though the actual _Protocol class is internal to the typing module (not in __all__).

So another example is that

from typing import *
class MyProtocol(Protocol):
    pass

passes mypy even though it will fail to run because Protocol is undefined.

From reading https://github.com/python/mypy/issues/452, this can be solved by renaming Protocol to _Protocol in the stub, and also in semantic analysis when typing.Protocol is mentioned. Should I open a PR?

An alternative solution might be importing Protocol from a separate stub, taking advantage of special rules for imports??

From reading #452, this can be solved by renaming Protocol to _Protocol in the stub, and also in semantic analysis when typing.Protocol is mentioned. Should I open a PR?

It also appears in several other places, so it will be hard to rename all of them. In addition, this is kind of intentional, as a first step of moving Protocol to typing. I think a better solution may be to just add a line from typing import Protocol as Protocol to typing_extensions stub.

What is the correct workaround to this problem? I'm doing this now:

from typing import *
from typing_extensions import Protocol #type: ignore

Not using star imports is the best way. Also Protocol is in typing in Python 3.8, so you will not need the second line. Finally, there is a dirty trick:

from typing import *
if not TYPE_CHECKING:
    from typing_extensions import Protocol

Is there a way to avoid this error when writing something like the follow?

# Protocol is only available in Python 3.8+.
try:
    from typing import Protocol
except ImportError:
    from typing_extensions import Protocol

@GPHemsley I wrote that exact same snippet of code and landed on this page trying to fix the resulting typing error. I'm going to unstick myself by simply adding # type: ignore to each of those imports, and check back when my project can move to 3.8 properly.

@GPHemsley @eblume does using sys.version_info checks work? Mypy is better able to reason about things if you use version checks.

@ethanhs sys.version_info seems to works just fine. Thanks!

Was this page helpful?
0 / 5 - 0 ratings