the following code:
import logging
print(type(1))
print(type(logging.WARNING))
prints:
<class 'int'>
<class 'int'>
yet, according to mypy, the first line of this code snippet is legal, but the second is not (Variable "logging.WARNING" is not valid as a type):
OneOrTwo = Literal[1,2] # ok
WarningOrError = Literal[logging.WARNING, logging.ERROR] # not ok
I do not understand why the definition of OneOrTwo is ok but WarningOrError is not.
I would like also know what could be done to use a legal equivalent of WarningOrError, i.e. something I could use like this:
def a(arg: WarningOrError)->None:
pass
note: mypy redirects to https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases , but this did not clarify things for me.
Literal
only accepts literal arguments. PEP586 has very rigid definitions of what constitutes a "literal" in this context. You can read about it here. The problem with your definition of WarningOrError
is that the actual definition of logging.ERROR
and WARNING
makes them mutable (you can look at the source code of logging
here), and hence illegal literals. Constant expressions like 1
or 2
, on the other hand, can be known statically (they never change!) and therefore are acceptable literals.
Among the accepted legal literals, Enum
objects can help you achieve what you want:
import logging
from typing import Literal
from enum import Enum
class Log(Enum):
ERROR = logging.ERROR
WARNING = logging.WARNING
LogType = Literal[Log.ERROR, Log.WARNING]
def a(arr: LogType):
pass