pytest/testing/python
karlicoss eced426fd3
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).
2025-06-27 09:20:41 +03:00
..
approx.py Fix `approx` usage with `decimal.FloatOperation` trap set (#13543) 2025-06-22 13:41:16 -03:00
collect.py use callable protocols for pytest.skip/exit/fail/xfail instead of _WithException wrapper with __call__ attribute (#13445) 2025-06-27 09:20:41 +03:00
fixtures.py Fix handling of positional-only parameters in test methods (#13377) 2025-04-18 21:18:36 +00:00
integration.py Prohibit pytest.mark.usefixtures in pytest.param (#12828) 2024-10-09 16:13:56 -03:00
metafunc.py python: a bit nicer error on duplicate parametrization 2025-06-02 00:45:03 +03:00
raises.py officially support python 3.14 (#13440) 2025-05-31 10:46:15 +01:00
raises_group.py raisesgroup followups (#13279) 2025-03-29 13:08:12 +00:00
show_fixtures_per_test.py RFC: from __future__ import annotations + migrate 2024-06-20 11:03:03 +02:00