You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
use callable protocols for pytest.skip/exit/fail/xfail instead of _WithException wrapper with __call__ attribute (#13445)
This is a more canonical way of typing generic callbacks/decorators
(see https://mypy.readthedocs.io/en/stable/protocols.html#callback-protocols)
This helps with potential issues/ambiguity with __call__ semanics in
type checkers -- according to python spec, __call__ needs to be present
on the class, rather than as an instance attribute to be considered callable.
This worked in mypy because it didn't handle the spec 100% correctly (in this case this has no negative consequences)
However, ty type checker is stricter/more correct about it and every pytest.skip usage results in:
```
error[call-non-callable]: Object of type _WithException[Unknown, <class 'Skipped'>] is not callable
```
For more context, see:
[ty] Understand classes that inherit from subscripted Protocol[] as generic astral-sh/ruff#17832 (comment)
https://discuss.python.org/t/when-should-we-assume-callable-types-are-method-descriptors/92938
Testing:
Tested with running mypy against the following snippet:
import pytest
reveal_type(pytest.skip)
reveal_type(pytest.skip.Exception)
reveal_type(pytest.skip(reason="whatever"))
Before the change:
```
$ mypy test_pytest_skip.py
test_pytest_skip.py:2: note: Revealed type is "_pytest.outcomes._WithException[def (reason: builtins.str =, *, allow_module_level: builtins.bool =) -> Never, def (msg: Union[builtins.str, None] =, pytrace: builtins.bool =, allow_module_level: builtins.bool =, *, _use_item_location: builtins.bool =) -> _pytest.outcomes.Skipped]"
test_pytest_skip.py:3: note: Revealed type is "def (msg: Union[builtins.str, None] =, pytrace: builtins.bool =, allow_module_level: builtins.bool =, *, _use_item_location: builtins.bool =) -> _pytest.outcomes.Skipped"
test_pytest_skip.py:4: note: Revealed type is "Never"
```
After the change:
```
$ mypy test_pytest_skip.py
test_pytest_skip.py:2: note: Revealed type is "_pytest.outcomes._Skip"
test_pytest_skip.py:3: note: Revealed type is "type[_pytest.outcomes.Skipped]"
test_pytest_skip.py:4: note: Revealed type is "Never"
```
ty type checker is also inferring the same types correctly now.
All types are matching and propagated correctly (most importantly, Never as a result of pytest.skip(...) call).
0 commit comments