Skip to content

Commit

Permalink
[pylint consider-using-any-or-all] Fix or disable all detected issues (
Browse files Browse the repository at this point in the history
…#12954)

* Avoid constructing a list of names
* noqa a a suggestion in already nested for
  • Loading branch information
Pierre-Sassoulas authored and mwychung committed Nov 14, 2024
1 parent 4734520 commit f308043
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 9 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ lovetheguitar
Lukas Bednar
Luke Murphy
Maciek Fijalkowski
Maggie Chung
Maho
Maik Figura
Mandeep Bhutani
Expand Down
2 changes: 2 additions & 0 deletions changelog/12842.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Added dedicated page about using types with pytest
See :ref:`types` for detailed usage.
137 changes: 137 additions & 0 deletions doc/en/how-to/types.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
.. _types:

How to use Types with Pytest
===========================================

You can add typing in pytest functions that helps to specify what type of data a function expects and returns.
This guide explains how to apply typing in pytest to improve code readability and prevent type-related errors.


1. Introduction to Typing
-----------------

Typing in Python helps developers specify the expected data types of variables, function parameters, and return values.
It improves code clarity and prevents type errors.

For example:


.. code-block:: python
def add(x: int, y: int) -> int:
return x + y
In this example:
`x: int` and `y: int` mean that `x` and `y` should be integers.
`-> int` shows that the function returns an integer.

It makes the intentions clear that both the input and output are expected to be integers.

2. Typing Test Functions
-----------------
Test functions in pytest check whether the code runs correctly.
While test functions do not return values, we can add `-> None` as the return type.

For example:

.. code-block:: python
import pytest
def test_add() -> None:
result = add(2, 3)
assert result == 5
In this function:
`test_add` is typed as `-> None` because it does not return anything.
The assertion `assert result == 5` checks if the result is correct.

Example result:
If the input data type is incorrect, like passing `add("2", 3)`, a `TypeError` will occur.

3. Typing Fixtures
-----------------
Fixtures in pytest helps set up data or provides resources needed for tests.
Adding type hints helps clarify what kind of data the fixtures returns, making code easier to read and easier to debug.

* Basic Fixture Typing:

If a fixture returns a number, you can specify it returns an `int`:

.. code-block:: python
import pytest
@pytest.fixture
def sample_fixture() -> int:
return 38
def test_sample_fixture(sample_fixture: int) -> None:
assert sample_fixture == 38
In this example:
`sample_fixture()` is typed to return an `int`.
In `test_sample_fixture`, using typing with fixtures, it ensures the return is an integer.
If you change the return from an integer to a string (``"42"``), the test will fail.


* Typing Fixtures with Lists and Dictionaries:
Here are the examples showing how to use List and Dict types in pytest.
When you want to use complex data structures like lists or dictionaries, import `List` and `Dict` from Python's `typing` module to specify the types.
Note: From Python 3.5 or later, typing module is built-in module in Python.


.. code-block:: python
from typing import List
import pytest
# Fixture returning a list of integers
@pytest.fixture
def sample_list() -> List[int]:
return [5, 10, 15]
def test_sample_list(sample_list: List[int]) -> None:
assert sum(sample_list) == 30
In this example, `List[int]` ensures that the list contains only integers, allowing functions like sum() to operate.


.. code-block:: python
from typing import Dict
import pytest
# Fixture returning a dictionary
@pytest.fixture
def sample_dict() -> Dict[str, int]:
return {"a": 50, "b": 100}
def test_sample_dict(sample_dict: Dict[str, int]) -> None:
assert sample_dict["a"] == 50
In this example, `Dict[str, int]` ensures that each key is a string and each value is an integer, ensuring clarity and consistency when accessing dictionary elements by key.


4. Typing Parameterized Tests
----------
`@pytest.mark.parametrize` allows developer to run the test multiple times with different sets of arguments.
Adding types helps to maintain consistency of values, especially for complex inputs.

For example, you are testing if adding 1 to `input_value` results in `expected_output` for each set of arguments.

.. code-block:: python
import pytest
@pytest.mark.parametrize("input_value, expected_output", [(1, 2), (5, 6), (100, 101)])
def test_increment(input_value: int, expected_output: int) -> None:
assert input_value + 1 == expected_output
In this example:
You are expecting the type of both `input_value` and `expected_output` are integers.


Conclusion
----------
Using typing in pytest helps improve readability of the tests and fixture returns, and prevent errors.
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ disable = [
"condition-evals-to-constant",
"consider-alternative-union-syntax",
"confusing-consecutive-elif",
"consider-using-any-or-all",
"consider-using-assignment-expr",
"consider-using-dict-items",
"consider-using-from-import",
Expand Down
10 changes: 2 additions & 8 deletions src/_pytest/mark/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,7 @@ def __call__(self, subname: str, /, **kwargs: str | int | bool | None) -> bool:
if kwargs:
raise UsageError("Keyword expressions do not support call parameters.")
subname = subname.lower()
names = (name.lower() for name in self._names)

for name in names:
if subname in name:
return True
return False
return any(subname in name.lower() for name in self._names)


def deselect_by_keyword(items: list[Item], config: Config) -> None:
Expand Down Expand Up @@ -243,10 +238,9 @@ def __call__(self, name: str, /, **kwargs: str | int | bool | None) -> bool:
if not (matches := self.own_mark_name_mapping.get(name, [])):
return False

for mark in matches:
for mark in matches: # pylint: disable=consider-using-any-or-all
if all(mark.kwargs.get(k, NOT_SET) == v for k, v in kwargs.items()):
return True

return False


Expand Down

0 comments on commit f308043

Please sign in to comment.