Bug I found yesterday, here is the Minimal, Complete, Reproducible example:
# test.py
try:
from typing import Literal # type: ignore
except ImportError:
from typing_extensions import Literal # type: ignore
def get(
table: Literal["cabinets", "feeders", "objects"]
) -> bool:
return table in ("cabinets", "feeders", "objects")
Install Python3.7 virtualenv with mypy and Literal via install bash script:
#!/bin/bash
rm -rf venv
python3.7 -m virtualenv venv
./venv/bin/pip install --no-cache-dir typing_extensions mypy
Run mypy checks via test bash script:
#!/bin/bash
./venv/bin/mypy test.py --ignore-missing-imports --disallow-untyped-defs --show-error-codes
And you will get:
test.py:7: error: Name 'cabinets' is not defined [name-defined]
test.py:7: error: Name 'feeders' is not defined [name-defined]
test.py:7: error: Name 'objects' is not defined [name-defined]
Found 3 errors in 1 file (checked 1 source file)
If you define classes above the get function - it will not give you those errors:
class cabinets: pass
class feeders: pass
class objects: pass
If you define type alias:
try:
from typing import Literal # type: ignore
except ImportError:
from typing_extensions import Literal # type: ignore
TableType = Literal["cabinets", "feeders", "objects"]
def get(
table: TableType
) -> bool:
return table in ("cabinets", "feeders", "objects")
It will give you this error:
test.py:9: error: Variable "test.TableType" is not valid as a type [valid-type]
test.py:9: note: See https://mypy.readthedocs.io/en/latest/common_issues.html#variables-vs-type-aliases
Expected behaviour
It just works and check that table is either "cabinets", "feeders" or "objects" string.
mypy and Python versions
./venv/bin/python --version
Python 3.7.5
./venv/bin/mypy --version
mypy 0.782
Maybe I am not using Literal correctly? But mypy don't give me errors when I use it with pydantic models.
New info: using Python 3.8, where from typing import Literal is used, issue no longer exist
You need to import Literal like this:
import sys
if sys.version_info >= (3, 8):
from typing import Literal
else:
from typing_extensions import Literal
@Akuli thanks a lot! Can you tell what the problem was with try/catch import?
I don't know. Maybe mypy doesn't support try,except imports?
I'm guessing the issue is that mypy goes with the first import, from typing, but you're on 3.7 and typing.Literal doesn't exist, so it just gets turned into Any, and mypy thinks you're doing a normal generic and interprets the arguments as types, not strings.