diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b685670..9d19fe9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: language: python additional_dependencies: [pygments, restructuredtext_lint] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.21 + rev: v0.16.1 hooks: - id: ruff args: ["--fix"] diff --git a/src/pytest_mock/__init__.py b/src/pytest_mock/__init__.py index b130ef5..aa26595 100644 --- a/src/pytest_mock/__init__.py +++ b/src/pytest_mock/__init__.py @@ -15,16 +15,16 @@ __all__ = [ "AsyncMockType", - "MockerFixture", "MockFixture", "MockType", + "MockerFixture", "PytestMockWarning", "SpyType", + "class_mocker", + "mocker", + "module_mocker", + "package_mocker", "pytest_addoption", "pytest_configure", "session_mocker", - "package_mocker", - "module_mocker", - "class_mocker", - "mocker", ] diff --git a/src/pytest_mock/_util.py b/src/pytest_mock/_util.py index d3a732a..9b93f52 100644 --- a/src/pytest_mock/_util.py +++ b/src/pytest_mock/_util.py @@ -1,5 +1,3 @@ -from typing import Union - _mock_module = None @@ -15,7 +13,7 @@ def get_mock_module(config): config.getini("mock_use_standalone_module") ) if use_standalone_module: - import mock + import mock # noqa _mock_module = mock else: @@ -26,11 +24,11 @@ def get_mock_module(config): return _mock_module -def parse_ini_boolean(value: Union[bool, str]) -> bool: +def parse_ini_boolean(value: bool | str) -> bool: if isinstance(value, bool): return value if value.lower() == "true": return True if value.lower() == "false": return False - raise ValueError("unknown string for bool: %r" % value) + raise ValueError(f"unknown string for bool: {value!r}") diff --git a/src/pytest_mock/plugin.py b/src/pytest_mock/plugin.py index 79f6ef1..eaf1488 100644 --- a/src/pytest_mock/plugin.py +++ b/src/pytest_mock/plugin.py @@ -4,6 +4,7 @@ import itertools import unittest.mock import warnings +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable from collections.abc import Iterator @@ -11,10 +12,7 @@ from dataclasses import dataclass from dataclasses import field from typing import Any -from typing import Callable -from typing import Optional from typing import TypeVar -from typing import Union from typing import cast from typing import overload @@ -26,11 +24,11 @@ _T = TypeVar("_T") AsyncMockType = unittest.mock.AsyncMock -MockType = Union[ - unittest.mock.MagicMock, - unittest.mock.AsyncMock, - unittest.mock.NonCallableMagicMock, -] +MockType = ( + unittest.mock.MagicMock + | unittest.mock.AsyncMock + | unittest.mock.NonCallableMagicMock +) class SpyType(unittest.mock.Mock): @@ -39,9 +37,9 @@ class SpyType(unittest.mock.Mock): """ spy_return: Any - spy_return_iter: Optional[Iterator[Any]] + spy_return_iter: Iterator[Any] | None spy_return_list: list[Any] - spy_exception: Optional[BaseException] + spy_exception: BaseException | None class PytestMockWarning(UserWarning): @@ -51,7 +49,7 @@ class PytestMockWarning(UserWarning): @dataclass class MockCacheItem: mock: MockType - patch: Optional[Any] = None + patch: Any | None = None @dataclass @@ -229,7 +227,7 @@ async def async_wrapper(*args, **kwargs): spy_obj.spy_exception = None return spy_obj - def stub(self, name: Optional[str] = None) -> unittest.mock.MagicMock: + def stub(self, name: str | None = None) -> unittest.mock.MagicMock: """ Create a stub method. It accepts any arguments. Ideal to register to callbacks in tests. @@ -242,7 +240,7 @@ def stub(self, name: Optional[str] = None) -> unittest.mock.MagicMock: self.mock_module.MagicMock(spec=lambda *args, **kwargs: None, name=name), ) - def async_stub(self, name: Optional[str] = None) -> AsyncMockType: + def async_stub(self, name: str | None = None) -> AsyncMockType: """ Create a async stub method. It accepts any arguments. Ideal to register to callbacks in tests. @@ -277,7 +275,7 @@ def _start_patch( p = mock_func(*args, **kwargs) mocked: MockType = p.start() self.__mock_cache.add(mock=mocked, patch=p) - if hasattr(mocked, "reset_mock"): + if hasattr(mocked, "reset_mock"): # noqa:SIM102 # check if `mocked` is actually a mock object, as depending on autospec or target # parameters `mocked` can be anything if hasattr(mocked, "__enter__") and warn_on_mock_enter: @@ -296,10 +294,10 @@ def object( target: object, attribute: str, new: object = DEFAULT, - spec: Optional[object] = None, + spec: object | None = None, create: bool = False, - spec_set: Optional[object] = None, - autospec: Optional[object] = None, + spec_set: object | None = None, + autospec: object | None = None, new_callable: object = None, **kwargs: Any, ) -> MockType: @@ -325,10 +323,10 @@ def context_manager( target: builtins.object, attribute: str, new: builtins.object = DEFAULT, - spec: Optional[builtins.object] = None, + spec: builtins.object | None = None, create: bool = False, - spec_set: Optional[builtins.object] = None, - autospec: Optional[builtins.object] = None, + spec_set: builtins.object | None = None, + autospec: builtins.object | None = None, new_callable: builtins.object = None, **kwargs: Any, ) -> MockType: @@ -353,11 +351,11 @@ def context_manager( def multiple( self, target: builtins.object, - spec: Optional[builtins.object] = None, + spec: builtins.object | None = None, create: bool = False, - spec_set: Optional[builtins.object] = None, - autospec: Optional[builtins.object] = None, - new_callable: Optional[builtins.object] = None, + spec_set: builtins.object | None = None, + autospec: builtins.object | None = None, + new_callable: builtins.object | None = None, **kwargs: Any, ) -> dict[str, MockType]: """API to mock.patch.multiple""" @@ -375,8 +373,8 @@ def multiple( def dict( self, - in_dict: Union[Mapping[Any, Any], str], - values: Union[Mapping[Any, Any], Iterable[tuple[Any, Any]]] = (), + in_dict: Mapping[Any, Any] | str, + values: Mapping[Any, Any] | Iterable[tuple[Any, Any]] = (), clear: bool = False, **kwargs: Any, ) -> Any: @@ -395,10 +393,10 @@ def __call__( self, target: str, new: None = ..., - spec: Optional[builtins.object] = ..., + spec: builtins.object | None = ..., create: bool = ..., - spec_set: Optional[builtins.object] = ..., - autospec: Optional[builtins.object] = ..., + spec_set: builtins.object | None = ..., + autospec: builtins.object | None = ..., new_callable: None = ..., **kwargs: Any, ) -> MockType: ... @@ -408,10 +406,10 @@ def __call__( self, target: str, new: _T, - spec: Optional[builtins.object] = ..., + spec: builtins.object | None = ..., create: bool = ..., - spec_set: Optional[builtins.object] = ..., - autospec: Optional[builtins.object] = ..., + spec_set: builtins.object | None = ..., + autospec: builtins.object | None = ..., new_callable: None = ..., **kwargs: Any, ) -> _T: ... @@ -421,10 +419,10 @@ def __call__( self, target: str, new: None, - spec: Optional[builtins.object], + spec: builtins.object | None, create: bool, - spec_set: Optional[builtins.object], - autospec: Optional[builtins.object], + spec_set: builtins.object | None, + autospec: builtins.object | None, new_callable: Callable[[], _T], **kwargs: Any, ) -> _T: ... @@ -434,10 +432,10 @@ def __call__( self, target: str, new: None = ..., - spec: Optional[builtins.object] = ..., + spec: builtins.object | None = ..., create: bool = ..., - spec_set: Optional[builtins.object] = ..., - autospec: Optional[builtins.object] = ..., + spec_set: builtins.object | None = ..., + autospec: builtins.object | None = ..., *, new_callable: Callable[[], _T], **kwargs: Any, @@ -447,11 +445,11 @@ def __call__( self, target: str, new: builtins.object = DEFAULT, - spec: Optional[builtins.object] = None, + spec: builtins.object | None = None, create: bool = False, - spec_set: Optional[builtins.object] = None, - autospec: Optional[builtins.object] = None, - new_callable: Optional[Callable[[], Any]] = None, + spec_set: builtins.object | None = None, + autospec: builtins.object | None = None, + new_callable: Callable[[], Any] | None = None, **kwargs: Any, ) -> Any: """API to mock.patch""" @@ -520,7 +518,7 @@ def assert_wrapper( msg += "\n\npytest introspection follows:\n" + introspection e = AssertionError(msg) e._mock_introspection_applied = True # type:ignore[attr-defined] - raise e + raise e # noqa:TRY201 def assert_has_calls_wrapper( @@ -547,13 +545,13 @@ def assert_has_calls_wrapper( if actual_call is not None: actual_args, actual_kwargs = actual_call else: - actual_args = tuple() + actual_args = () actual_kwargs = {} if expect_call is not None: _, expect_args, expect_kwargs = expect_call else: - expect_args = tuple() + expect_args = () expect_kwargs = {} try: @@ -568,7 +566,7 @@ def assert_has_calls_wrapper( msg += "\n\npytest introspection follows:\n" + introspection e = AssertionError(msg) e._mock_introspection_applied = True # type:ignore[attr-defined] - raise e + raise e # noqa:TRY201 def wrap_assert_not_called(*args: Any, **kwargs: Any) -> None: diff --git a/tests/test_pytest_mock.py b/tests/test_pytest_mock.py index c753b01..c497aea 100644 --- a/tests/test_pytest_mock.py +++ b/tests/test_pytest_mock.py @@ -3,12 +3,12 @@ import re import sys import warnings +from collections.abc import Callable 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 unittest.mock import AsyncMock from unittest.mock import MagicMock @@ -50,7 +50,7 @@ def needs_assert_rewrite(pytestconfig): if option != "rewrite": pytest.skip( "this test needs assertion rewrite to work but current option " - 'is "{}"'.format(option) + f'is "{option}"' ) @@ -631,7 +631,7 @@ def bar(self) -> Iterable[int]: def test_spy_return_iter_resets(mocker: MockerFixture) -> None: class Foo: - iterables: Any = [ + iterables: Any = [ # noqa:RUF012 (i for i in range(3)), 99, ] @@ -778,8 +778,8 @@ def test_assert_called_args_with_introspection(mocker: MockerFixture) -> None: def test_assert_called_kwargs_with_introspection(mocker: MockerFixture) -> None: stub = mocker.stub() - complex_kwargs = dict(foo={"bar": 1, "baz": "spam"}) - wrong_kwargs = dict(foo={"goo": 1, "baz": "bran"}) + complex_kwargs = {"foo": {"bar": 1, "baz": "spam"}} + wrong_kwargs = {"foo": {"goo": 1, "baz": "bran"}} stub(**complex_kwargs) stub.assert_called_with(**complex_kwargs) @@ -1134,11 +1134,13 @@ def doIt(self): "https://pytest-mock.readthedocs.io/en/latest/usage.html#usage-as-context-manager" ) - with pytest.warns( - PytestMockWarning, match=re.escape(expected_warning_msg) - ) as warn_record: - with mocker.patch.object(a, "doIt", return_value=True): - assert a.doIt() is True + with ( + pytest.warns( + PytestMockWarning, match=re.escape(expected_warning_msg) + ) as warn_record, + mocker.patch.object(a, "doIt", return_value=True), + ): + assert a.doIt() is True assert warn_record[0].filename == __file__ @@ -1151,11 +1153,13 @@ def test_warn_patch_context_manager(mocker: MockerFixture) -> None: "https://pytest-mock.readthedocs.io/en/latest/usage.html#usage-as-context-manager" ) - with pytest.warns( - PytestMockWarning, match=re.escape(expected_warning_msg) - ) as warn_record: - with mocker.patch("json.loads"): - pass + with ( + pytest.warns( + PytestMockWarning, match=re.escape(expected_warning_msg) + ) as warn_record, + mocker.patch("json.loads"), + ): + pass assert warn_record[0].filename == __file__ @@ -1190,7 +1194,7 @@ def doIt(self): a = A() - with warnings.catch_warnings(record=True) as warn_record: + with warnings.catch_warnings(record=True) as warn_record: # noqa:SIM117 with mocker.patch.context_manager(a, "doIt", return_value=True): assert a.doIt() is True