mypy complains Incompatible return value type (got "Optional[str]", expected "str") when a function can only return str

Viewed 1966
import os
from typing import Optional

_DEFAULT = 'abc'

def _get_value(param: Optional[str]) -> str:
    return param or os.getenv("PARAM", _DEFAULT)

For this function, mypy would complain

Incompatible return value type (got "Optional[str]", expected "str")

but I thought this function will never return None. Am I missing something?

2 Answers

The mypy type checker doesn't seem to be able to parse or conditions. You have to explicitly check for None values:

if param:
    return param
else:
    return os.getenv("PARAM", _DEFAULT)

Edit: The above code technically checks for falsy values instead of None but it is functionally equivalent to your example.

mypy seems to be missing some inference of "old style ternary" functions -- those of the form A or B or A and B or C

looking at reveal_type for the three expressions

# reveal_type(param)
t.py:9: note: Revealed type is 'Union[builtins.str, None]'
# reveal_type(os.getenv("PARAM", _DEFAULT)
t.py:10: note: Revealed type is 'builtins.str'
# param or reveal_type(os.getenv("PARAM", _DEFAULT)
t.py:11: note: Revealed type is 'Union[builtins.str, None]'

you can get around this by using a true ternary:

def _get_value(param: Optional[str]) -> str:
    return param if param is not None else os.getenv("PARAM", _DEFAULT)
Related