-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
min()/max() with default value cause issues with key function type #17536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I looked a bit into this and managed to create an example that's isolated from the from typing import List, Union, Callable, TypeVar, reveal_type
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")
def bar(a: _T1, b: _T2, function: Callable[[_T2], None]) -> Union[_T1, _T2]:
raise NotImplementedError()
# this does not cause an issue,
result_1 = bar(42, [42], lambda a_list: a_list.append(42))
reveal_type(result_1) # note: Revealed type is "Union[builtins.int, builtins.list[builtins.int]]"
# this is the same call, we set the same type, but it causes an issue with the lambda body
result_2: Union[int, List[int]] = bar(
42,
[42],
lambda a_list: a_list.append(42) # error: Item "int" of "int | list[int]" has no attribute "append" [union-attr]
) Looking at the code, this seems to be because |
Looks like a duplicate of #14664 Thanks for taking a deeper look into this @pfaion! Fair warning, this may be a tricky issue. This has to do with the way mypy infers the types of generic callables, and in particular the relative "trust" given to the type context vs the argument types. Currently, mypy infers the type of generic callables in two steps: first using the type context to infer against type variables in the return type, and second using the argument types to infer any remaining type variables. The issue in this case is that, during the first step, mypy can use the type context to fully resolve the type variables into a broad supertype, which then gets propagated down into the argument checks, which then fail due to the inferred type being too broad. The tricky bit is that, on its own, this "trusting the type context" behavior is a intended feature. It's what lets mypy use return types and explicit type annotations (which are generally very trustworthy) to type check inner expressions (which is often where the actual problems are). For example, it's what makes this possible: def foo(x: list[int]) -> None: ...
foo([1, 2, 3, "4", 5]) # List item 3 has incompatible type "str"; expected "int" Here, mypy needs to infer the type of the list being passed to The fix to this issue will probably involve reworking the way that mypy uses the type context during type inference. I'm guessing this will invovle some major code changes, and probably has a high risk of breaking existing behavior. Good luck to whoever attempts it! :-) |
Hmmm... ok, that is unfortunate. I think if you'd infer the type from the arguments, you might be able to provide something like: Or maybe an exception needs to be made for "constructors" in this context? The example you gave sounded like you're interested in errors coming from inner expressions before errors coming from outer expressions. I'm wondering if that really is generally the case, or if that's an exception for when the inner expression is about constructing a type, where that would be more helpful? I might try understanding the surrounding code a bit more. But thanks for the heads-up, I understand now how tricky this is. I was a bit confused why the type inference was started from the return type, but I thought there must be some explanation behind that! |
Bug Report
Hi everyone, thanks for all the work on mypy, I love this tool! 👏
I run into an issue with this code:
See playground: https://mypy-play.net/?mypy=latest&python=3.12&gist=3daadb92c263a8447595aa7640a04599
Expected Behavior:
mypy should not report any errors
Actual Behavior
mypy reports an error:
Environment
mypy 1.10.1 (compiled: yes)
mypy.ini
(and other config files): nonePython 3.12.2
Additional Details
I found this issue from 2019, which seems to be the same issue: #6460
Here people reported that it was an issue with typeshed, which was fixed in typeshed with this PR: python/typeshed#2833
I checked current trunk for typeshed and cannot spot any issue with the stubs for
max()
, the type correctly seems to indicate that the key function has nothing to do with the type of the default parameter: https://github.com/python/typeshed/blob/d482d4e83c9d247e79c87d954a9ccb11f85bfc37/stdlib/builtins.pyi#L1515-L1516So while it seems this issue was once fixed it the past, it looks like it might have reappeared through a different cause.
The text was updated successfully, but these errors were encountered: