Skip to content

Conversation

@hauntsaninja
Copy link
Collaborator

@hauntsaninja hauntsaninja commented Dec 2, 2025

Fixes #20346

I assume the behaviour here came from the bad old days before strict optional :-)

@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

Diff from mypy_primer, showing the effect of this PR on open source code:

spark (https://github.com/apache/spark)
- python/pyspark/core/rdd.py:1664: error: Unused "type: ignore" comment  [unused-ignore]

mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ pymongo/pyopenssl_context.py:277: error: Incompatible return value type (got "None", expected "int")  [return-value]
+ pymongo/synchronous/topology.py:1054: error: No overload variant of "gather" matches argument types "list[None]", "bool"  [call-overload]
+ pymongo/synchronous/topology.py:1054: note: Error code "call-overload" not covered by "type: ignore" comment
+ pymongo/synchronous/topology.py:1054: note: Possible overload variants:
+ pymongo/synchronous/topology.py:1054: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2, _T3] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2, _T3, _T4] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2, _T3, _T4, _T5] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2, _T3, _T4, _T5, _T6] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], Future[_T6] | Awaitable[_T6], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4, _T5, _T6]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T] gather(*coros_or_futures: Future[_T] | Awaitable[_T], return_exceptions: Literal[False] = ...) -> Future[list[_T]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2, _T3] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2, _T3, _T4] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2, _T3, _T4, _T5] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T1, _T2, _T3, _T4, _T5, _T6] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], Future[_T6] | Awaitable[_T6], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException, _T6 | BaseException]]
+ pymongo/synchronous/topology.py:1054: note:     def [_T] gather(*coros_or_futures: Future[_T] | Awaitable[_T], return_exceptions: bool) -> Future[list[_T | BaseException]]
+ pymongo/synchronous/pool.py:865: error: No overload variant of "gather" matches argument types "list[None]", "bool"  [call-overload]
+ pymongo/synchronous/pool.py:865: note: Possible overload variants:
+ pymongo/synchronous/pool.py:865: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2, _T3] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2, _T3, _T4] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2, _T3, _T4, _T5] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2, _T3, _T4, _T5, _T6] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], Future[_T6] | Awaitable[_T6], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4, _T5, _T6]]
+ pymongo/synchronous/pool.py:865: note:     def [_T] gather(*coros_or_futures: Future[_T] | Awaitable[_T], return_exceptions: Literal[False] = ...) -> Future[list[_T]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2, _T3] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2, _T3, _T4] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2, _T3, _T4, _T5] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException]]
+ pymongo/synchronous/pool.py:865: note:     def [_T1, _T2, _T3, _T4, _T5, _T6] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], Future[_T6] | Awaitable[_T6], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException, _T6 | BaseException]]
+ pymongo/synchronous/pool.py:865: note:     def [_T] gather(*coros_or_futures: Future[_T] | Awaitable[_T], return_exceptions: bool) -> Future[list[_T | BaseException]]
+ pymongo/synchronous/pool.py:902: error: No overload variant of "gather" matches argument types "list[None]", "bool"  [call-overload]
+ pymongo/synchronous/pool.py:902: note: Possible overload variants:
+ pymongo/synchronous/pool.py:902: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2, _T3] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2, _T3, _T4] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2, _T3, _T4, _T5] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2, _T3, _T4, _T5, _T6] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], Future[_T6] | Awaitable[_T6], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4, _T5, _T6]]
+ pymongo/synchronous/pool.py:902: note:     def [_T] gather(*coros_or_futures: Future[_T] | Awaitable[_T], return_exceptions: Literal[False] = ...) -> Future[list[_T]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2, _T3] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2, _T3, _T4] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2, _T3, _T4, _T5] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException]]
+ pymongo/synchronous/pool.py:902: note:     def [_T1, _T2, _T3, _T4, _T5, _T6] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], Future[_T6] | Awaitable[_T6], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException, _T6 | BaseException]]
+ pymongo/synchronous/pool.py:902: note:     def [_T] gather(*coros_or_futures: Future[_T] | Awaitable[_T], return_exceptions: bool) -> Future[list[_T | BaseException]]
+ pymongo/synchronous/pool.py:953: error: No overload variant of "gather" matches argument types "list[None]", "bool"  [call-overload]
+ pymongo/synchronous/pool.py:953: note: Possible overload variants:
+ pymongo/synchronous/pool.py:953: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2, _T3] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2, _T3, _T4] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2, _T3, _T4, _T5] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4, _T5]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2, _T3, _T4, _T5, _T6] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], Future[_T6] | Awaitable[_T6], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1, _T2, _T3, _T4, _T5, _T6]]
+ pymongo/synchronous/pool.py:953: note:     def [_T] gather(*coros_or_futures: Future[_T] | Awaitable[_T], return_exceptions: Literal[False] = ...) -> Future[list[_T]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2, _T3] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2, _T3, _T4] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2, _T3, _T4, _T5] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException]]
+ pymongo/synchronous/pool.py:953: note:     def [_T1, _T2, _T3, _T4, _T5, _T6] gather(Future[_T1] | Awaitable[_T1], Future[_T2] | Awaitable[_T2], Future[_T3] | Awaitable[_T3], Future[_T4] | Awaitable[_T4], Future[_T5] | Awaitable[_T5], Future[_T6] | Awaitable[_T6], /, *, return_exceptions: bool) -> Future[tuple[_T1 | BaseException, _T2 | BaseException, _T3 | BaseException, _T4 | BaseException, _T5 | BaseException, _T6 | BaseException]]
+ pymongo/synchronous/pool.py:953: note:     def [_T] gather(*coros_or_futures: Future[_T] | Awaitable[_T], return_exceptions: bool) -> Future[list[_T | BaseException]]
+ pymongo/synchronous/monitor.py:197: error: No overload variant of "gather" matches argument types "None", "None", "bool"  [call-overload]
+ pymongo/synchronous/monitor.py:197: note: Error code "call-overload" not covered by "type: ignore" comment
+ pymongo/synchronous/monitor.py:197: note: Possible overload variants:
+ pymongo/synchronous/monitor.py:197: note:     def [_T1] gather(Future[_T1] | Awaitable[_T1], /, *, return_exceptions: Literal[False] = ...) -> Future[tuple[_T1]]

... (truncated 29 lines) ...

core (https://github.com/home-assistant/core)
+ homeassistant/components/ping/helpers.py:165: error: Incompatible types in "await" (actual type "None", expected type "Awaitable[Any]")  [misc]
+ homeassistant/components/ping/helpers.py:165: note: Error code "misc" not covered by "type: ignore" comment

ibis (https://github.com/ibis-project/ibis)
+ ibis/backends/__init__.py:1273: error: "None" has no attribute "__iter__" (not iterable)  [attr-defined]
+ ibis/backends/clickhouse/__init__.py:253: error: "None" has no attribute "__iter__" (not iterable)  [attr-defined]

@hauntsaninja hauntsaninja merged commit 4eb6b50 into python:master Dec 2, 2025
22 checks passed
@hauntsaninja hauntsaninja deleted the none-return-fix branch December 2, 2025 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Function returning None gives Any even with func-returns-value error disabled

3 participants