Reputation: 27673
I have a project which needs to support Python 3.7, but I would like to use typing.Protocol
, which was added in 3.8. To support 3.7, I have a minor bit of fallback code which just uses object
:
import typing
_Protocol = getattr(typing, 'Protocol', object)
class Foo(_Protocol):
def bar(self) -> int:
pass
This all functions as I would expect. The issue is, when running MyPy, I get the following error:
test.py:5: error: Variable "test._Protocol" is not valid as a type
test.py:5: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
test.py:5: error: Invalid base class "_Protocol"
The linked "Variables vs type aliases" section in that error message indicates that I should annotate _Protocol
with : typing.Type[object]
(which does not work) or use typing.TypeAlias
(which isn't available until Python 3.9).
How can I indicate to MyPy that _Protocol
is valid as a type?
Another workaround I tried was in "Python version and system platform checks":
if sys.version_info >= (3, 8):
_Protocol = typing.Protocol
else:
_Protocol = object
However, this ends with the same error.
Upvotes: 3
Views: 2126
Reputation: 27673
It seems that MyPy can properly understand Protocol
as part of an import statement:
if sys.version_info >= (3, 8):
from typing import Protocol as _Protocol
else:
_Protocol = object
class Foo(_Protocol):
def bar(self) -> int: ...
MyPy will still flag usage of Foo
as a type specification in Python 3.7, so you need a similar workaround for using it:
if sys.version_info >= (3, 8):
_Foo = Foo
else:
_Foo = typing.Any
def bar(x: _Foo):
pass
It's worth noting that MyPy does not understand more clever things like _Foo = Foo if sys.version_info >= (3, 8) else typing.Any
-- you have to use the simple format.
Upvotes: 0
Reputation: 3420
Use typing_extensions
and typing.TYPE_CHECKING
to import typing_extensions
only when type-checking the code.
import typing
if typing.TYPE_CHECKING:
from typing_extensions import Protocol
else:
Protocol = object
class Foo(Protocol):
def bar(self) -> int:
...
typing_extensions checks the Python version and uses typing.Protocol
for versions >=3.8
:
# 3.8+
if hasattr(typing, 'Protocol'):
Protocol = typing.Protocol
# 3.7
else:
...
Upvotes: 3