Bug Report
In my understanding Callable[..., Any] is about as general as callables get, and therefore arbitrary functions should be compatible therewith. However, while it does accept typed functions (def (...) -> ...) and types.FunctionTypes, if the typing info is at any point lost and the function resolves to a bare function, Callable[..., Any] would no longer accept it.
(A clear and concise description of what the bug is.)
To Reproduce
(Gist: https://gist.github.com/mypy-play/da65c6f9c2dfc5bcc565ca5df5f1c9f1)
Consider the following example:
from collections.abc import Callable
from types import FunctionType
from typing import Any, cast, reveal_type
def foo0() -> None:
...
def foo1(x: int) -> None:
...
def foo2(x: str, y: float) -> None:
...
def select_from_dict(arg: int) -> None:
foo: Callable[..., Any]
foobar = reveal_type({
1: foo0,
2: foo1,
3: foo2,
})[arg]
reveal_type(foobar)
foo = foobar
def assign_from_chained_ternary(arg: int) -> None:
foo: Callable[..., Any] = reveal_type(
foo0
if arg == 1 else
foo1
if arg == 2 else
foo2
)
def direct_assignment(arg: int) -> None:
foo: Callable[..., Any]
if arg == 1:
foo = reveal_type(foo0)
elif arg == 2:
foo = reveal_type(foo1)
elif arg == 3:
foo = reveal_type(foo2)
else:
raise RuntimeError
def assign_with_explicit_cast(arg: int) -> None:
foo: Callable[..., Any]
if arg == 1:
foo = reveal_type(cast(FunctionType, foo0))
elif arg == 2:
foo = reveal_type(cast(FunctionType, foo1))
elif arg == 3:
foo = reveal_type(cast(FunctionType, foo2))
else:
raise RuntimeError
while select_from_dict(), assign_from_chained_ternary(), direct_assignment(), and assign_with_explicit_cast() should be analogous in behaviors, we see from the mypy output that:
def (...) -> ..., (def (...) -> ...) | (def (...) -> ...) | ... and types.FuctionType are all considered compatible with Callable[..., Any], as they should.
- Meanwhile, by shoving the functions into a
dict they are resolved into opaque functions, which somehow is considered incompatible.
Expected Behavior
The code should type-check.
Actual Behavior
main.py:19: note: Revealed type is "dict[int, function]"
main.py:24: note: Revealed type is "function"
main.py:25: error: Incompatible types in assignment (expression has type "function", variable has type "Callable[..., Any]") [assignment]
main.py:30: note: Revealed type is "(def ()) | (def (x: int)) | (def (x: str, y: float))"
main.py:41: note: Revealed type is "def ()"
main.py:43: note: Revealed type is "def (x: int)"
main.py:45: note: Revealed type is "def (x: str, y: float)"
main.py:53: note: Revealed type is "types.FunctionType"
main.py:55: note: Revealed type is "types.FunctionType"
main.py:57: note: Revealed type is "types.FunctionType"
Found 1 error in 1 file (checked 1 source file)
Your Environment
- Mypy version used: 2.3.0 (Playground)
- Mypy command-line flags: nil
- Mypy configuration options from
mypy.ini (and other config files): nil
- Python version used: 3.14
Possible related issues
#10740
Bug Report
In my understanding
Callable[..., Any]is about as general as callables get, and therefore arbitrary functions should be compatible therewith. However, while it does accept typed functions (def (...) -> ...) andtypes.FunctionTypes, if the typing info is at any point lost and the function resolves to a barefunction,Callable[..., Any]would no longer accept it.(A clear and concise description of what the bug is.)
To Reproduce
(Gist: https://gist.github.com/mypy-play/da65c6f9c2dfc5bcc565ca5df5f1c9f1)
Consider the following example:
while
select_from_dict(),assign_from_chained_ternary(),direct_assignment(), andassign_with_explicit_cast()should be analogous in behaviors, we see from themypyoutput that:def (...) -> ...,(def (...) -> ...) | (def (...) -> ...) | ...andtypes.FuctionTypeare all considered compatible withCallable[..., Any], as they should.dictthey are resolved into opaquefunctions, which somehow is considered incompatible.Expected Behavior
The code should type-check.
Actual Behavior
Your Environment
mypy.ini(and other config files): nilPossible related issues
#10740