Python version dependent type annotations

Viewed 756

Problem:

I want to use type annotation for collections.deque, but since we have to support older python version (3.4 and 3.5, which to be exact - and doesn't matter that they are not officially supported), I want my code to be valid in all python version we have to support.

My original code:

from collections import deque
from typing import Deque
a = deque() # type: Deque[int]

it works just fine in 3.7, but in 3.5, I get ImportError: cannot import name 'Deque'.

What I tried:

so I was thinking of modifying it like this:

from typing import Sequence
try:
    from typing import Deque
except ImportError:
    Deque = Sequence

from collections import deque
a = deque() # type: Deque[int]

But then I get errors:

$ mypy . --pretty
a.py:5: error: Cannot assign multiple types to name "Deque" without an explicit "Type[...]" annotation
    Deque = Sequence
    ^
a.py:5: error: Incompatible types in assignment (expression has type "Type[Sequence[Any]]", variable has
type "Type[deque[Any]]")
    Deque = Sequence
        ^
Found 2 errors in 1 file (checked 1 source file)

Question:

Is there a way of having the same code which would be valid even in python3.4 and python3.5 while having type annotation for deque?

Note:

Yes, I know 3.4 and 3.5 are not officially suported. But that fact does not help me at all. Please don't tell me to upgrade.

2 Answers

Type checkers use their own version of typing features, regardless whether the runtime typing library supports them. A type such as Deque[int] can be used freely for checking in any version as long as it is not used at runtime.

  • If the typing module is available on all desired version, guard the imports:

    from collections import deque
    from typing import TYPE_CHECKING
    if TYPE_CHECKING:             # not entered at runtime
        from typing import Deque  # only happens during static type checking
    
    a = deque() # type: Deque[int]
    

    The typing module can be added to pre-3.5 version as a backport.

  • The general solution for versions not supporting all required type features are pyi stub files.

    # a.py
    from collections import deque
    
    a = deque()
    
    # a.pyi
    from typing import Deque
    
    a: Deque[int] = ...
    

Perhaps this (or a variation of it) would work

import sys
if sys.version_info[:2] >= (3,7):
    from typing import Deque
else:
    from typing import Sequence as Deque

from collections import deque    
a = deque() # type: Deque[int]
    
Related