Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14-dev"]
python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
os: [ubuntu-latest, windows-latest]
tox_env: ["py"]
include:
Expand All @@ -64,6 +64,7 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
allow-prereleases: true

- name: Install tox
run: |
Expand Down
7 changes: 5 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
Releases
========

UNRELEASED
----------
3.15.0
------

*2025-09-04*

* Python 3.8 (EOL) is no longer supported.
* `#524 <https://github.com/pytest-dev/pytest-mock/pull/524>`_: Added ``spy_return_iter`` to ``mocker.spy``, which contains a duplicate of the return value of the spied method if it is an ``Iterator``.

3.14.1 (2025-05-26)
Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dependencies = [
"pytest>=6.2.5",
]
dynamic = ["version"]
requires-python = ">=3.8"
requires-python = ">=3.9"
readme = "README.rst"
license = {text = "MIT"}
keywords = ["pytest", "mock"]
Expand All @@ -27,7 +27,6 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand Down
2 changes: 1 addition & 1 deletion src/pytest_mock/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def get_mock_module(config):
config.getini("mock_use_standalone_module")
)
if use_standalone_module:
import mock
from unittest import mock

_mock_module = mock
else:
Expand Down
24 changes: 10 additions & 14 deletions src/pytest_mock/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@
import itertools
import unittest.mock
import warnings
from collections.abc import Generator
from collections.abc import Iterable
from collections.abc import Iterator
from collections.abc import Mapping
from dataclasses import dataclass
from dataclasses import field
from typing import Any
from typing import Callable
from typing import Dict
from typing import Generator
from typing import Iterable
from typing import Iterator
from typing import List
from typing import Mapping
from typing import Optional
from typing import Tuple
from typing import Type
from typing import TypeVar
from typing import Union
from typing import cast
Expand Down Expand Up @@ -53,7 +49,7 @@ class MockCache:
Cache MagicMock and Patcher instances so we can undo them later.
"""

cache: List[MockCacheItem] = field(default_factory=list)
cache: list[MockCacheItem] = field(default_factory=list)

def _find(self, mock: MockType) -> MockCacheItem:
for mock_item in self.cache:
Expand Down Expand Up @@ -125,7 +121,7 @@ def resetall(
:param bool return_value: Reset the return_value of mocks.
:param bool side_effect: Reset the side_effect of mocks.
"""
supports_reset_mock_with_args: Tuple[Type[Any], ...]
supports_reset_mock_with_args: tuple[type[Any], ...]
if hasattr(self, "AsyncMock"):
supports_reset_mock_with_args = (self.Mock, self.AsyncMock)
else:
Expand Down Expand Up @@ -348,7 +344,7 @@ def multiple(
autospec: Optional[builtins.object] = None,
new_callable: Optional[builtins.object] = None,
**kwargs: Any,
) -> Dict[str, MockType]:
) -> dict[str, MockType]:
"""API to mock.patch.multiple"""
return self._start_patch(
self.mock_module.patch.multiple,
Expand All @@ -365,7 +361,7 @@ def multiple(
def dict(
self,
in_dict: Union[Mapping[Any, Any], str],
values: Union[Mapping[Any, Any], Iterable[Tuple[Any, Any]]] = (),
values: Union[Mapping[Any, Any], Iterable[tuple[Any, Any]]] = (),
clear: bool = False,
**kwargs: Any,
) -> Any:
Expand Down Expand Up @@ -477,8 +473,8 @@ def _mocker(pytestconfig: Any) -> Generator[MockerFixture, None, None]:
session_mocker = pytest.fixture(scope="session")(_mocker)


_mock_module_patches = [] # type: List[Any]
_mock_module_originals = {} # type: Dict[str, Any]
_mock_module_patches: list[Any] = []
_mock_module_originals: dict[str, Any] = {}


def assert_wrapper(
Expand Down
21 changes: 8 additions & 13 deletions tests/test_pytest_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
import re
import sys
import warnings
from collections.abc import Generator
from collections.abc import Iterable
from collections.abc import Iterator
from contextlib import contextmanager
from typing import Any
from typing import Callable
from typing import Generator
from typing import Iterable
from typing import Iterator
from typing import Tuple
from typing import Type
from unittest.mock import AsyncMock
from unittest.mock import MagicMock

Expand Down Expand Up @@ -102,15 +100,15 @@ def check(mocked_rm, mocked_ls):
return check


def mock_using_patch_object(mocker: MockerFixture) -> Tuple[MagicMock, MagicMock]:
def mock_using_patch_object(mocker: MockerFixture) -> tuple[MagicMock, MagicMock]:
return mocker.patch.object(os, "remove"), mocker.patch.object(os, "listdir")


def mock_using_patch(mocker: MockerFixture) -> Tuple[MagicMock, MagicMock]:
def mock_using_patch(mocker: MockerFixture) -> tuple[MagicMock, MagicMock]:
return mocker.patch("os.remove"), mocker.patch("os.listdir")


def mock_using_patch_multiple(mocker: MockerFixture) -> Tuple[MagicMock, MagicMock]:
def mock_using_patch_multiple(mocker: MockerFixture) -> tuple[MagicMock, MagicMock]:
r = mocker.patch.multiple("os", remove=mocker.DEFAULT, listdir=mocker.DEFAULT)
return r["remove"], r["listdir"]

Expand Down Expand Up @@ -212,10 +210,7 @@ def test_mocker_resetall(mocker: MockerFixture) -> None:
assert isinstance(listdir.return_value, mocker.Mock)
assert open.side_effect is None

if sys.version_info >= (3, 9):
# The reset on child mocks have been implemented in 3.9
# https://bugs.python.org/issue38932
assert mocked_object.run.return_value != "mocked"
assert mocked_object.run.return_value != "mocked"


class TestMockerStub:
Expand Down Expand Up @@ -291,7 +286,7 @@ def bar(self, arg):
),
)
def test_instance_method_spy_exception(
exc_cls: Type[BaseException],
exc_cls: type[BaseException],
mocker: MockerFixture,
) -> None:
class Foo:
Expand Down
3 changes: 1 addition & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
[tox]
minversion = 3.5.3
envlist = py{38,39,310,311,312,313,314}, norewrite, pytest6
envlist = py{39,310,311,312,313,314}, norewrite, pytest6

[testenv]
deps =
coverage
mock
pytest-asyncio
pytest6: pytest==6.2.5
commands =
Expand Down
Loading