Open keis opened 6 years ago
Unfortunately we received several complains about false positives with this flag recently. My guess is this bug is tightly related to https://github.com/python/mypy/issues/5843, not exactly a duplicate, but the underlying reason is most likely the same.
This seems to be a regression between 0.630 and 0.641. I have a few scripts that make liberal use of lambda
statements, and it seems to be a problem with all of them now.
Here is my best attempt to isolate an example from my codebase:
import datetime as dt
import typing as t
class DeploymentResponse(t.NamedTuple):
uid: str
createdDate: dt.datetime
class DeploymentListResponse(t.NamedTuple):
items: t.List[DeploymentResponse]
def get_deployments() -> DeploymentListResponse: ...
def prune_deployments(IDs: t.Iterable[str]) -> None: ...
def prune_api_deployments(keep_latest: bool, keep_IDs: t.Iterable[str]) -> None:
response: DeploymentListResponse = get_deployments()
obsolete_IDs = { d.uid for d in response.items }.difference(keep_IDs)
# Works fine with mypy 0.630 but produces errors with 0.641 (see below).
if keep_latest:
obsolete_IDs.discard( max(response.items, key=lambda i: i.createdDate).uid )
# Works fine in both 0.630 and 0.641 because the lambda does not need to be
# inferred. This code is redundant, just for this example.
if keep_latest:
selector: t.Callable[[DeploymentResponse], dt.datetime] = lambda i: i.createdDate
obsolete_IDs.discard( max(response.items, key=selector).uid )
prune_deployments(IDs=obsolete_IDs)
return
This code was tested on Python 3.6.1 using both mypy 0.630 and 0.641 with the --disallow-any-expr
flag. There are no errors using 0.630, but 0.641 produces the following output:
test.py:26: error: Expression type contains "Any" (has type "Callable[[Any], Any]")
test.py:26: error: Expression has type "Any"
Of course, the workaround is obvious — don't make mypy infer the type of the lambda
, but that gets very verbose and tiresome quickly, especially since lambda
is usually quick and concise.
what's interesting is that when using reveal_type
within the lambda, it activates twice with two different results:
from typing import Callable, NoReturn, overload
@overload
def foo(value: str, predicate: Callable[[str], object]) -> None:
...
@overload
def foo(value: int, predicate: Callable[[int], object]) -> None:
...
def foo(value: int | str, predicate: Callable[[NoReturn], object]) -> None:
...
# error: Expression type contains "Any" (has type "Callable[[Any], Any]") [misc]
# note: Revealed type is "Any"
# note: Revealed type is "builtins.int"
foo(1, lambda value: reveal_type(value))
This is resolved in basedmypy https://mypy-play.net/?mypy=basedmypy-2.2.1&python=3.11&gist=66a86e78f129539cd320cd9d1a535a82
Using mypy 0.641 with the --disallow-any-expr flag and this sample using
@overload
produces
However mypy seems to be able to infer the type of the lambda because if I modify the last line to read
mypy correctly identifies that
"int" has no attribute "bad"
, sprinkling some prints on the mypy source also reveals it figures out it's a(int, int) -> int
at some point.foo_not_overloaded checks without trouble and so does using a plain
def
instead of the lambda.