Skip to content

Comments

[red-knot] Support calling a typing.Callable#16888

Merged
dhruvmanila merged 1 commit intomainfrom
dhruv/callable-call
Mar 22, 2025
Merged

[red-knot] Support calling a typing.Callable#16888
dhruvmanila merged 1 commit intomainfrom
dhruv/callable-call

Conversation

@dhruvmanila
Copy link
Member

Summary

Part of #15382, this PR adds support for calling a variable that's annotated with typing.Callable.

Test Plan

Add test cases in a new call/annotation.md file.

@dhruvmanila dhruvmanila added the ty Multi-file analysis & type inference label Mar 21, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Mar 21, 2025

mypy_primer results

Changes were detected when running on open source projects
pyinstrument (https://github.com/joerick/pyinstrument)
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/metrics/overhead.py:32:16: Object of type `() -> Unknown` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/metrics/overhead.py:45:24: Object of type `() -> Unknown` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/middleware.py:50:13: Object of type `(request) -> Unknown` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/test/util.py:116:13: Object of type `(...) -> Unknown` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/renderers/jsonrenderer.py:41:50: Object of type `(str, /) -> str` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/renderers/jsonrenderer.py:42:57: Object of type `(str, /) -> str` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/renderers/jsonrenderer.py:43:51: Object of type `(str, /) -> str` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/renderers/jsonrenderer.py:58:54: Object of type `(str, /) -> str` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/renderers/jsonrenderer.py:61:56: Object of type `(str, /) -> str` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/renderers/jsonrenderer.py:72:60: Object of type `(str, /) -> str` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/frame.py:349:52: Object of type `(str, /) -> str` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pyinstrument/pyinstrument/util.py:36:12: Object of type `(...) -> Any` is not callable
- Found 300 diagnostics
+ Found 288 diagnostics

isort (https://github.com/pycqa/isort)
- error[lint:call-non-callable] /tmp/mypy_primer/projects/isort/isort/sorting.py:120:34: Object of type `((str, /) -> Any) | None` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/isort/isort/wrap.py:30:17: Object of type `(...) -> str` is not callable
+ error[lint:call-non-callable] /tmp/mypy_primer/projects/isort/isort/sorting.py:120:34: Object of type `None` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/isort/isort/wrap.py:53:36: Object of type `(...) -> str` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/isort/isort/output.py:170:18: Object of type `(str, str, object, /) -> str` is not callable
+ error[lint:call-non-callable] /tmp/mypy_primer/projects/isort/isort/output.py:170:18: Object of type `None` is not callable
+ error[lint:call-non-callable] /tmp/mypy_primer/projects/isort/isort/literal.py:65:29: Object of type `None` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/isort/isort/literal.py:65:29: Object of type `(str, str, object, /) -> str` is not callable
- Found 78 diagnostics
+ Found 76 diagnostics

itsdangerous (https://github.com/pallets/itsdangerous)
- error[lint:call-non-callable] /tmp/mypy_primer/projects/itsdangerous/src/itsdangerous/encoding.py:54:12: Object of type `(bytes, /) -> tuple[int]` is not callable
- Found 56 diagnostics
+ Found 55 diagnostics

rich (https://github.com/Textualize/rich)
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/tests/test_console.py:685:12: Object of type `() -> int | float` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/tests/test_console.py:686:12: Object of type `() -> datetime` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/tests/test_cells.py:70:20: Object of type `(str, /) -> bool` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/tests/test_cells.py:75:16: Object of type `(str, /) -> bool` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/tests/test_cells.py:78:20: Object of type `(str, /) -> bool` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/tests/test_cells.py:81:20: Object of type `(str, /) -> bool` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/spinner.py:53:27: Object of type `() -> int | float` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/console.py:509:27: Object of type `(...) -> @Todo` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/console.py:1900:17: Object of type `() -> FrameType | None` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/cells.py:46:8: Object of type `(str, /) -> bool` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/cells.py:61:16: Object of type `(str, /) -> int` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/cells.py:62:8: Object of type `(str, /) -> bool` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/cells.py:99:8: Object of type `(str, /) -> bool` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/_log_render.py:57:36: Object of type `() -> datetime` is not callable
- error[lint:call-non-callable] /tmp/mypy_primer/projects/rich/rich/segment.py:173:12: Object of type `(str, /) -> bool` is not callable
- Found 604 diagnostics
+ Found 589 diagnostics

pybind11 (https://github.com/pybind/pybind11)
- error[lint:call-non-callable] /tmp/mypy_primer/projects/pybind11/tests/test_virtual_functions.py:280:13: Object of type `() -> Unknown` is not callable
- Found 278 diagnostics
+ Found 277 diagnostics

@dhruvmanila
Copy link
Member Author

The ecosystem checks looks good except for two things:

  1. Support narrowing on attribute and subscript expressions ty#164
  2. I think I'll need to implement is_disjoint_from support for the following code to work:
def test(key: Optional[Callable[[str], Any]] = None) -> None:
    if key is not None:
        reveal_type(key)  # revealed: ((str, /) -> Any) | ~None

        def key_callback(text: str) -> Any:
            reveal_type(key)  # revealed: ((str, /) -> Any) | None
            # red-knot: Object of type `None` is not callable [lint:call-non-callable]
            return key(text)

@dhruvmanila dhruvmanila marked this pull request as ready for review March 21, 2025 11:37
Comment on lines +20 to +24
def _(c: Callable[[int, str], None]):
# error: [unknown-argument] "Argument `a` does not match any known parameter"
# error: [unknown-argument] "Argument `b` does not match any known parameter"
# error: [missing-argument] "No arguments provided for required parameters 1, 2"
reveal_type(c(a=1, b="b")) # revealed: None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's room for the error message to be improved here, but it's out of scope for this PR:

Suggested change
def _(c: Callable[[int, str], None]):
# error: [unknown-argument] "Argument `a` does not match any known parameter"
# error: [unknown-argument] "Argument `b` does not match any known parameter"
# error: [missing-argument] "No arguments provided for required parameters 1, 2"
reveal_type(c(a=1, b="b")) # revealed: None
def _(c: Callable[[int, str], None]):
# error: [unknown-argument] "Keyword argument `a` does not match any known parameter (`c` accepts no keyword arguments)"
# error: [unknown-argument] "Keyword argument `b` does not match any known parameter (`c` accepts no keyword arguments)"
# error: [missing-argument] "No arguments provided for required parameters 1, 2"
reveal_type(c(a=1, b="b")) # revealed: None

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, totally.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#16919, feel free to update the description or comment to provide more context and examples.

Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Tests were most of the work here, it looks like :)

@dhruvmanila dhruvmanila force-pushed the dhruv/callable-call branch from f29d27a to 079810b Compare March 22, 2025 21:01
@dhruvmanila dhruvmanila merged commit 0360c6b into main Mar 22, 2025
23 checks passed
@dhruvmanila dhruvmanila deleted the dhruv/callable-call branch March 22, 2025 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants