Mypy infers `x.get("a") or x.get("b", "c")` to `str | None`, even when `x` is `dict[str, str]`
Bug Report
Mypy wrongly infers the type of the expression x.get("a") or x.get("b", "c") to be str | None, even when x is explicitly a dict[str, str].
To Reproduce
def works(x: dict[str, str]) -> str:
a = x.get("a")
b = x.get("b", "c")
return a or b
def also_works(x: dict[str, str]) -> str: return x.get("a", x.get("b", "c"))
def also_fine(x: dict[str, str]) -> str: return x.get("a") or x.get("b") or "c"
def breaks(x: dict[str, str]) -> str: return x.get("a") or x.get("b", "c")
https://mypy-play.net/?mypy=latest&python=3.11&gist=33335d3d1d19e5858beb76ed65ce8470
I realise the examples are not logically equivalent, but they should all evaluate to strings
Expected Behavior
No errors.
Actual Behavior
Mypy returns main.py:8: error: Incompatible return value type (got "str | None", expected "str") [return-value]
Your Environment
- Mypy version used: 1.4.0
- Mypy command-line flags: N/A
- Mypy configuration options from
mypy.ini(and other config files): N/A - Python version used: 3.11
Very strange error. If I had to guess, I'd say it has to do with the slightly weird signature of .get(): https://github.com/python/typeshed/pull/10294
You could try defining your own .get() as in the linked PR and see whether the problem persists.
@AlexWaygood topic-type-context?
Ahh, never mind :(
def f4(x: dict[str, str]) -> str:
q = x.get("a") or x.get("b", "c") # N: Revealed type is "Union[builtins.str, None]"
reveal_type(q)
return q # E: Incompatible return value type (got "str | None", expected "str") [return-value]
It does feel like a type context issue, but I think @tmke8 may be right and this is python/typeshed#10293. Unfortunately, as the typeshed PR indicates, that issue may not be easy to fix.
It does feel like a type context issue, but I think @tmke8 may be right and this is python/typeshed#10293. Unfortunately, as the typeshed PR indicates, that issue may not be easy to fix.
(I just merged a different typeshed PR that also hopefully fixes python/typeshed#10293, but had a much less horrifying report from mypy_primer.)
I confirmed that with https://github.com/python/typeshed/issues/10293, the issue is resolved, so no mypy changes will be necessary here. The fix might not make it into mypy v1.5, but it will definitely be included in mypy v1.6 if not.
With mypy v1.4.1:
>mypy -c "x: dict[str, str] = {}; reveal_type(x.get('a') or x.get('b', 'c'))" --custom-typeshed-dir .
<string>:1: note: Revealed type is "builtins.str"
Success: no issues found in 1 source file
With mypy v1.4.1 and --custom-typeshed-dir pointing to an up-to-date clone of typeshed:
>mypy -c "x: dict[str, str] = {}; reveal_type(x.get('a') or x.get('b', 'c'))" --custom-typeshed-dir .
<string>:1: note: Revealed type is "builtins.str"
Success: no issues found in 1 source file