Search code examples
pythonlisttuplesimmutabilitymypy

python mypy error with immutable list as tuple


I encounter a weird error while defining an immutable list type:

import sys
from re import split
from typing import Tuple, List, NewType

tokens = split("(\d+\.\d+)", sys.argv[1])

# this works perfectly
# Tokens = NewType("Tokens", List[str])
# print(Tokens(tokens))

# this doesn't work ...
Tokens = NewType("Tokens", Tuple[str])
print(Tokens(tuple(tokens)))

Here is the error that I get:

> mypy main.py
main.py:13: error: Argument 1 to "Tokens" has incompatible type "Tuple[Union[str, Any], ...]"; expected "Tuple[str]"
Found 1 error in 1 file (checked 1 source file)

Solution

  • Why the error occurs

    When you using tuple() to transform a list to tuple, Python or at least Mypy doesn't know the exact type of elements in the tuple. Thus the error occurs. Using different approaches to transform the list to tuple leads to different Mypy error:

    token_x = tuple(tokens)
    token_y = tuple(i for i in tokens)
    token_z = (*tokens, )
    
    main.py:15: error: Argument 1 to "Tokens" has incompatible type "Tuple[Union[str, Any], ...]"; expected "Tuple[str]"
    main.py:16: error: Argument 1 to "Tokens" has incompatible type "Tuple[Union[str, Any], ...]"; expected "Tuple[str]"
    main.py:17: error: Argument 1 to "Tokens" has incompatible type "Tuple[Any, ...]"; expected "Tuple[str]"
    

    Solution

    import sys
    from re import split
    from typing import Tuple, List, NewType
    
    tokens: List[str] = split("(\d+\.\d+)", sys.argv[1]) # explicit annotation on here is great but not necessary
    token_x = tuple(tokens)
    token_y = tuple(i for i in tokens)
    token_z = (*tokens,)
    
    # this works perfectly
    # Tokens = NewType("Tokens", List[str])
    # print(Tokens(tokens))
    
    # this doesn't work ...
    Tokens = NewType("Tokens", Tuple[str, ...]) # explicitly annotate with Tuple[str, ...]
    Tokens = NewType("Tokens", Sequence[str]) # or using Sequence[str], which is recommended by Mypy offical document
    print(Tokens(token_x))
    print(Tokens(token_y))
    print(Tokens(token_z))
    

    Appendix

    Related question: How to annotate function that takes a tuple of variable length? (variadic tuple type annotation)

    Meaning of Tuple[str, ...]: str, ... stands of all the elements in the tuple are str

    Mypy offical Doc: https://mypy.readthedocs.io/en/stable/kinds_of_types.html#tuple-types