New upstream version 3.11.1

This commit is contained in:
Timo Röhling 2023-07-05 14:29:02 +02:00
parent b4297c2616
commit 2b3250c1c1
17 changed files with 399 additions and 68 deletions

View file

@ -1,39 +1,67 @@
name: deploy
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: 'Release version'
required: true
default: '1.2.3'
jobs:
deploy:
package:
runs-on: ubuntu-latest
env:
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.event.inputs.version }}
steps:
- uses: actions/checkout@v1
- name: Set up Python
uses: actions/setup-python@v1
- uses: actions/checkout@v3
- name: Build and Check Package
uses: hynek/build-and-inspect-python-package@v1.5
deploy:
needs: package
runs-on: ubuntu-latest
environment: deploy
permissions:
id-token: write # For PyPI trusted publishers.
contents: write # For tag and release notes.
steps:
- uses: actions/checkout@v3
- name: Download Package
uses: actions/download-artifact@v3
with:
python-version: "3.7"
- name: Install wheel
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: |
python -m build
name: Packages
path: dist
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@master
uses: pypa/gh-action-pypi-publish@v1.8.5
- name: Push tag
run: |
git config user.name "pytest bot"
git config user.email "pytestbot@gmail.com"
git tag --annotate --message=v${{ github.event.inputs.version }} v${{ github.event.inputs.version }} ${{ github.sha }}
git push origin v${{ github.event.inputs.version }}
- name: Set up Python
uses: actions/setup-python@v4.5.0
with:
user: __token__
password: ${{ secrets.pypi_token }}
python-version: "3.10"
- name: Generate release notes
run: |
pip install pypandoc
sudo apt-get install pandoc
python scripts/gen-release-notes.py
- name: GitHub Release
uses: softprops/action-gh-release@v1
with:
body_path: scripts/latest-release-notes.md
files: dist/*
tag_name: v${{ github.event.inputs.version }}

View file

@ -1,17 +1,37 @@
name: test
on: [push, pull_request]
on:
push:
branches:
- main
- "test-me-*"
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build and Check Package
uses: hynek/build-and-inspect-python-package@v1.5
test:
needs: [package]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python: ["3.7", "3.8", "3.9", "3.10"]
python: ["3.7", "3.8", "3.9", "3.10", "3.11"]
os: [ubuntu-latest, windows-latest]
include:
- python: "3.7"
@ -22,17 +42,29 @@ jobs:
tox_env: "py39"
- python: "3.10"
tox_env: "py310"
- python: "3.11"
tox_env: "py311"
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
- name: Download Package
uses: actions/download-artifact@v3
with:
name: Packages
path: dist
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- name: Install tox
run: |
python -m pip install --upgrade pip
pip install tox
- name: Test
shell: bash
run: |
tox -e ${{ matrix.tox_env }}
tox run -e ${{ matrix.tox_env }} --installpkg `find dist/*.tar.gz`

View file

@ -1,12 +1,12 @@
exclude: '^($|.*\.bin)'
repos:
- repo: https://github.com/psf/black
rev: 22.6.0
rev: 23.3.0
hooks:
- id: black
args: [--safe, --quiet]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@ -18,13 +18,13 @@ repos:
files: ^(CHANGELOG.rst|README.rst|HOWTORELEASE.rst|changelog/.*)$
language: python
additional_dependencies: [pygments, restructuredtext_lint]
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.3.0
- repo: https://github.com/asottile/reorder-python-imports
rev: v3.9.0
hooks:
- id: reorder-python-imports
args: ['--application-directories=.:src']
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.961 # NOTE: keep this in sync with tox.ini
rev: v1.3.0 # NOTE: keep this in sync with tox.ini
hooks:
- id: mypy
files: ^(src|tests)

View file

@ -1,10 +1,35 @@
Releases
========
3.11.1 (2023-06-15)
-------------------
* Fixed introspection for failed ``assert_has_calls`` (`#365`_).
* Updated type annotations for ``mocker.patch`` and ``mocker.spy`` (`#364`_).
.. _#365: https://github.com/pytest-dev/pytest-mock/pull/365
.. _#364: https://github.com/pytest-dev/pytest-mock/pull/364
3.10.0 (2022-10-05)
-------------------
* Added new ``mocker.stop(m)`` method to stop specific ``mocker.patch`` or ``mocker.spy`` calls (`#319`_).
.. _#319: https://github.com/pytest-dev/pytest-mock/pull/319
3.9.0 (2022-09-28)
------------------
* Expose ``NonCallableMagicMock`` via the ``mocker`` fixture (`#318`_).
.. _#318: https://github.com/pytest-dev/pytest-mock/pull/318
3.8.2 (2022-07-05)
------------------
- Fixed `AsyncMock` support for Python 3.7+ in `mocker.async_stub` (`#302`_).
- Fixed ``AsyncMock`` support for Python 3.7+ in ``mocker.async_stub`` (`#302`_).
.. _#302: https://github.com/pytest-dev/pytest-mock/pull/302

View file

@ -1,11 +1,15 @@
Metadata-Version: 2.1
Name: pytest-mock
Version: 3.8.2
Version: 3.11.1
Summary: Thin-wrapper around the mock package for easier use with pytest
Home-page: https://github.com/pytest-dev/pytest-mock/
Author: Bruno Oliveira
Author-email: nicoddemus@gmail.com
License: MIT
Project-URL: Documentation, https://pytest-mock.readthedocs.io/en/latest/
Project-URL: Changelog, https://pytest-mock.readthedocs.io/en/latest/changelog.html
Project-URL: Source, https://github.com/pytest-dev/pytest-mock/
Project-URL: Tracker, https://github.com/pytest-dev/pytest-mock/issues
Keywords: pytest mock
Platform: any
Classifier: Development Status :: 5 - Production/Stable
@ -18,9 +22,11 @@ Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
Provides-Extra: dev
License-File: LICENSE

View file

@ -1,7 +1,7 @@
Here are the steps on how to make a new release.
1. Create a ``release-VERSION`` branch from ``upstream/master``.
1. Create a ``release-VERSION`` branch from ``upstream/main``.
2. Update ``CHANGELOG.rst``.
3. Push a branch with the changes.
4. Once all builds pass, push a tag to ``upstream``.
3. Push the branch to ``upstream``.
4. Once all tests pass, start the ``deploy`` workflow manually.
5. Merge the PR.

2
docs/_static/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -15,7 +15,7 @@ Tests are run with ``tox``, you can run the baseline environments before submitt
.. code-block:: console
$ tox -e py38,linting
$ tox -e py38
Style checks and formatting are done automatically during commit courtesy of
`pre-commit <https://pre-commit.com>`_.

View file

@ -21,6 +21,7 @@ The supported methods are:
* `mocker.patch.multiple <https://docs.python.org/3/library/unittest.mock.html#patch-multiple>`_
* `mocker.patch.dict <https://docs.python.org/3/library/unittest.mock.html#patch-dict>`_
* `mocker.stopall <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch.stopall>`_
* `mocker.stop <https://docs.python.org/3/library/unittest.mock.html#patch-methods-start-and-stop>`_
* ``mocker.resetall()``: calls `reset_mock() <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.reset_mock>`_ in all mocked objects up to this point.
Also, as a convenience, these names from the ``mock`` module are accessible directly from ``mocker``:
@ -94,6 +95,27 @@ As of version 3.0.0, ``mocker.spy`` also works with ``async def`` functions.
.. _#175: https://github.com/pytest-dev/pytest-mock/issues/175
As of version 3.10, spying can be also selectively stopped.
.. code-block:: python
def test_with_unspy(mocker):
class Foo:
def bar(self):
return 42
spy = mocker.spy(Foo, "bar")
foo = Foo()
assert foo.bar() == 42
assert spy.call_count == 1
mocker.stop(spy)
assert foo.bar() == 42
assert spy.call_count == 1
``mocker.stop()`` can also be used by ``mocker.patch`` calls.
Stub
----

View file

@ -20,6 +20,11 @@ output_lines = []
first_heading_found = False
for line in md_text.splitlines():
if line.startswith("# "):
# Skip the first section (normally # Releases).
pass
elif line.startswith("## "):
# First second-level section, note it and skip the text,
# as we are only interested in the individual release items.
if first_heading_found:
break
first_heading_found = True

View file

@ -1,5 +1,3 @@
from io import open
from setuptools import find_packages
from setuptools import setup
@ -22,6 +20,7 @@ setup(
author_email="nicoddemus@gmail.com",
description="Thin-wrapper around the mock package for easier use with pytest",
long_description=open("README.rst", encoding="utf-8").read(),
long_description_content_type="text/x-rst",
keywords="pytest mock",
extras_require={"dev": ["pre-commit", "tox", "pytest-asyncio"]},
classifiers=[
@ -35,7 +34,14 @@ setup(
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development :: Testing",
],
project_urls={
"Documentation": "https://pytest-mock.readthedocs.io/en/latest/",
"Changelog": "https://pytest-mock.readthedocs.io/en/latest/changelog.html",
"Source": "https://github.com/pytest-dev/pytest-mock/",
"Tracker": "https://github.com/pytest-dev/pytest-mock/issues",
},
)

View file

@ -1,11 +1,15 @@
Metadata-Version: 2.1
Name: pytest-mock
Version: 3.8.2
Version: 3.11.1
Summary: Thin-wrapper around the mock package for easier use with pytest
Home-page: https://github.com/pytest-dev/pytest-mock/
Author: Bruno Oliveira
Author-email: nicoddemus@gmail.com
License: MIT
Project-URL: Documentation, https://pytest-mock.readthedocs.io/en/latest/
Project-URL: Changelog, https://pytest-mock.readthedocs.io/en/latest/changelog.html
Project-URL: Source, https://github.com/pytest-dev/pytest-mock/
Project-URL: Tracker, https://github.com/pytest-dev/pytest-mock/issues
Keywords: pytest mock
Platform: any
Classifier: Development Status :: 5 - Production/Stable
@ -18,9 +22,11 @@ Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
Provides-Extra: dev
License-File: LICENSE

View file

@ -19,6 +19,7 @@ docs/index.rst
docs/remarks.rst
docs/requirements.txt
docs/usage.rst
docs/_static/.gitignore
scripts/gen-release-notes.py
src/pytest_mock/__init__.py
src/pytest_mock/_util.py

View file

@ -1,5 +1,4 @@
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
__version__ = version = '3.8.2'
__version_tuple__ = version_tuple = (3, 8, 2)
__version__ = version = '3.11.1'
__version_tuple__ = version_tuple = (3, 11, 1)

View file

@ -27,10 +27,16 @@ from ._util import parse_ini_boolean
_T = TypeVar("_T")
if sys.version_info[:2] > (3, 7):
if sys.version_info >= (3, 8):
AsyncMockType = unittest.mock.AsyncMock
MockType = Union[
unittest.mock.MagicMock,
unittest.mock.AsyncMock,
unittest.mock.NonCallableMagicMock,
]
else:
AsyncMockType = Any
MockType = Union[unittest.mock.MagicMock, unittest.mock.NonCallableMagicMock]
class PytestMockWarning(UserWarning):
@ -44,16 +50,16 @@ class MockerFixture:
"""
def __init__(self, config: Any) -> None:
self._patches = [] # type: List[Any]
self._mocks = [] # type: List[Any]
self._patches_and_mocks: List[Tuple[Any, unittest.mock.MagicMock]] = []
self.mock_module = mock_module = get_mock_module(config)
self.patch = self._Patcher(
self._patches, self._mocks, mock_module
self._patches_and_mocks, mock_module
) # type: MockerFixture._Patcher
# aliases for convenience
self.Mock = mock_module.Mock
self.MagicMock = mock_module.MagicMock
self.NonCallableMock = mock_module.NonCallableMock
self.NonCallableMagicMock = mock_module.NonCallableMagicMock
self.PropertyMock = mock_module.PropertyMock
if hasattr(mock_module, "AsyncMock"):
self.AsyncMock = mock_module.AsyncMock
@ -81,8 +87,10 @@ class MockerFixture:
else:
supports_reset_mock_with_args = (self.Mock,)
for m in self._mocks:
for p, m in self._patches_and_mocks:
# See issue #237.
if not hasattr(m, "reset_mock"):
continue
if isinstance(m, supports_reset_mock_with_args):
m.reset_mock(return_value=return_value, side_effect=side_effect)
else:
@ -93,12 +101,24 @@ class MockerFixture:
Stop all patchers started by this fixture. Can be safely called multiple
times.
"""
for p in reversed(self._patches):
for p, m in reversed(self._patches_and_mocks):
p.stop()
self._patches[:] = []
self._mocks[:] = []
self._patches_and_mocks.clear()
def spy(self, obj: object, name: str) -> unittest.mock.MagicMock:
def stop(self, mock: unittest.mock.MagicMock) -> None:
"""
Stops a previous patch or spy call by passing the ``MagicMock`` object
returned by it.
"""
for index, (p, m) in enumerate(self._patches_and_mocks):
if mock is m:
p.stop()
del self._patches_and_mocks[index]
break
else:
raise ValueError("This mock object is not registered")
def spy(self, obj: object, name: str) -> MockType:
"""
Create a spy of method. It will run method normally, but it is now
possible to use `mock` call features with it, like call count.
@ -185,23 +205,21 @@ class MockerFixture:
DEFAULT = object()
def __init__(self, patches, mocks, mock_module):
self._patches = patches
self._mocks = mocks
def __init__(self, patches_and_mocks, mock_module):
self.__patches_and_mocks = patches_and_mocks
self.mock_module = mock_module
def _start_patch(
self, mock_func: Any, warn_on_mock_enter: bool, *args: Any, **kwargs: Any
) -> unittest.mock.MagicMock:
) -> MockType:
"""Patches something by calling the given function from the mock
module, registering the patch to stop it later and returns the
mock object resulting from the mock call.
"""
p = mock_func(*args, **kwargs)
mocked = p.start() # type: unittest.mock.MagicMock
self._patches.append(p)
mocked: MockType = p.start()
self.__patches_and_mocks.append((p, mocked))
if hasattr(mocked, "reset_mock"):
self._mocks.append(mocked)
# 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:
@ -213,7 +231,7 @@ class MockerFixture:
"Mocks returned by pytest-mock do not need to be used as context managers. "
"The mocker fixture automatically undoes mocking at the end of a test. "
"This warning can be ignored if it was triggered by mocking a context manager. "
"https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager",
"https://pytest-mock.readthedocs.io/en/latest/remarks.html#usage-as-context-manager",
PytestMockWarning,
stacklevel=depth,
)
@ -230,7 +248,7 @@ class MockerFixture:
autospec: Optional[object] = None,
new_callable: object = None,
**kwargs: Any
) -> unittest.mock.MagicMock:
) -> MockType:
"""API to mock.patch.object"""
if new is self.DEFAULT:
new = self.mock_module.DEFAULT
@ -259,7 +277,7 @@ class MockerFixture:
autospec: Optional[builtins.object] = None,
new_callable: builtins.object = None,
**kwargs: Any
) -> unittest.mock.MagicMock:
) -> MockType:
"""This is equivalent to mock.patch.object except that the returned mock
does not issue a warning when used as a context manager."""
if new is self.DEFAULT:
@ -287,7 +305,7 @@ class MockerFixture:
autospec: Optional[builtins.object] = None,
new_callable: Optional[builtins.object] = None,
**kwargs: Any
) -> Dict[str, unittest.mock.MagicMock]:
) -> Dict[str, MockType]:
"""API to mock.patch.multiple"""
return self._start_patch(
self.mock_module.patch.multiple,
@ -329,7 +347,7 @@ class MockerFixture:
autospec: Optional[builtins.object] = ...,
new_callable: None = ...,
**kwargs: Any
) -> unittest.mock.MagicMock:
) -> MockType:
...
@overload
@ -455,6 +473,54 @@ def assert_wrapper(
raise e
def assert_has_calls_wrapper(
__wrapped_mock_method__: Callable[..., Any], *args: Any, **kwargs: Any
) -> None:
__tracebackhide__ = True
try:
__wrapped_mock_method__(*args, **kwargs)
return
except AssertionError as e:
any_order = kwargs.get("any_order", False)
if getattr(e, "_mock_introspection_applied", 0) or any_order:
msg = str(e)
else:
__mock_self = args[0]
msg = str(e)
if __mock_self.call_args_list is not None:
actual_calls = list(__mock_self.call_args_list)
expect_calls = args[1]
introspection = ""
from itertools import zip_longest
for actual_call, expect_call in zip_longest(actual_calls, expect_calls):
if actual_call is not None:
actual_args, actual_kwargs = actual_call
else:
actual_args = tuple()
actual_kwargs = {}
if expect_call is not None:
_, expect_args, expect_kwargs = expect_call
else:
expect_args = tuple()
expect_kwargs = {}
try:
assert actual_args == expect_args
except AssertionError as e_args:
introspection += "\nArgs:\n" + str(e_args)
try:
assert actual_kwargs == expect_kwargs
except AssertionError as e_kwargs:
introspection += "\nKwargs:\n" + str(e_kwargs)
if introspection:
msg += "\n\npytest introspection follows:\n" + introspection
e = AssertionError(msg)
e._mock_introspection_applied = True # type:ignore[attr-defined]
raise e
def wrap_assert_not_called(*args: Any, **kwargs: Any) -> None:
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_not_called"], *args, **kwargs)
@ -477,7 +543,9 @@ def wrap_assert_called_once_with(*args: Any, **kwargs: Any) -> None:
def wrap_assert_has_calls(*args: Any, **kwargs: Any) -> None:
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_has_calls"], *args, **kwargs)
assert_has_calls_wrapper(
_mock_module_originals["assert_has_calls"], *args, **kwargs
)
def wrap_assert_any_call(*args: Any, **kwargs: Any) -> None:

View file

@ -160,6 +160,7 @@ def test_mock_patch_dict_resetall(mocker: MockerFixture) -> None:
"MagicMock",
"Mock",
"mock_open",
"NonCallableMagicMock",
"NonCallableMock",
"PropertyMock",
"sentinel",
@ -418,7 +419,6 @@ def test_class_method_with_metaclass_spy(mocker: MockerFixture) -> None:
pass
class Foo:
__metaclass__ = MetaFoo
@classmethod
@ -630,6 +630,86 @@ def test_assert_has_calls(mocker: MockerFixture) -> None:
stub.assert_has_calls([mocker.call("bar")])
def test_assert_has_calls_multiple_calls(mocker: MockerFixture) -> None:
stub = mocker.stub()
stub("foo")
stub("bar")
stub("baz")
stub.assert_has_calls([mocker.call("foo"), mocker.call("bar"), mocker.call("baz")])
with assert_traceback():
stub.assert_has_calls(
[
mocker.call("foo"),
mocker.call("bar"),
mocker.call("baz"),
mocker.call("bat"),
]
)
with assert_traceback():
stub.assert_has_calls(
[mocker.call("foo"), mocker.call("baz"), mocker.call("bar")]
)
def test_assert_has_calls_multiple_calls_subset(mocker: MockerFixture) -> None:
stub = mocker.stub()
stub("foo")
stub("bar")
stub("baz")
stub.assert_has_calls([mocker.call("bar"), mocker.call("baz")])
with assert_traceback():
stub.assert_has_calls([mocker.call("foo"), mocker.call("baz")])
with assert_traceback():
stub.assert_has_calls(
[mocker.call("foo"), mocker.call("bar"), mocker.call("bat")]
)
with assert_traceback():
stub.assert_has_calls([mocker.call("baz"), mocker.call("bar")])
def test_assert_has_calls_multiple_calls_any_order(mocker: MockerFixture) -> None:
stub = mocker.stub()
stub("foo")
stub("bar")
stub("baz")
stub.assert_has_calls(
[mocker.call("foo"), mocker.call("baz"), mocker.call("bar")], any_order=True
)
with assert_traceback():
stub.assert_has_calls(
[
mocker.call("foo"),
mocker.call("baz"),
mocker.call("bar"),
mocker.call("bat"),
],
any_order=True,
)
def test_assert_has_calls_multiple_calls_any_order_subset(
mocker: MockerFixture,
) -> None:
stub = mocker.stub()
stub("foo")
stub("bar")
stub("baz")
stub.assert_has_calls([mocker.call("baz"), mocker.call("foo")], any_order=True)
with assert_traceback():
stub.assert_has_calls(
[mocker.call("baz"), mocker.call("foo"), mocker.call("bat")], any_order=True
)
def test_assert_has_calls_no_calls(
mocker: MockerFixture,
) -> None:
stub = mocker.stub()
stub.assert_has_calls([])
with assert_traceback():
stub.assert_has_calls([mocker.call("foo")])
def test_monkeypatch_ini(testdir: Any, mocker: MockerFixture) -> None:
# Make sure the following function actually tests something
stub = mocker.stub()
@ -637,7 +717,6 @@ def test_monkeypatch_ini(testdir: Any, mocker: MockerFixture) -> None:
testdir.makepyfile(
"""
import py.code
def test_foo(mocker):
stub = mocker.stub()
assert stub.assert_called_with.__module__ == stub.__module__
@ -884,7 +963,7 @@ def test_warn_patch_object_context_manager(mocker: MockerFixture) -> None:
"Mocks returned by pytest-mock do not need to be used as context managers. "
"The mocker fixture automatically undoes mocking at the end of a test. "
"This warning can be ignored if it was triggered by mocking a context manager. "
"https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager"
"https://pytest-mock.readthedocs.io/en/latest/remarks.html#usage-as-context-manager"
)
with pytest.warns(
@ -901,7 +980,7 @@ def test_warn_patch_context_manager(mocker: MockerFixture) -> None:
"Mocks returned by pytest-mock do not need to be used as context managers. "
"The mocker fixture automatically undoes mocking at the end of a test. "
"This warning can be ignored if it was triggered by mocking a context manager. "
"https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager"
"https://pytest-mock.readthedocs.io/en/latest/remarks.html#usage-as-context-manager"
)
with pytest.warns(
@ -1099,3 +1178,56 @@ def test_used_with_session_scope(testdir: Any) -> None:
result = testdir.runpytest_subprocess()
assert "AssertionError" not in result.stderr.str()
result.stdout.fnmatch_lines("* 1 passed in *")
def test_stop_patch(mocker):
class UnSpy:
def foo(self):
return 42
m = mocker.patch.object(UnSpy, "foo", return_value=0)
assert UnSpy().foo() == 0
mocker.stop(m)
assert UnSpy().foo() == 42
with pytest.raises(ValueError):
mocker.stop(m)
def test_stop_instance_patch(mocker):
class UnSpy:
def foo(self):
return 42
m = mocker.patch.object(UnSpy, "foo", return_value=0)
un_spy = UnSpy()
assert un_spy.foo() == 0
mocker.stop(m)
assert un_spy.foo() == 42
def test_stop_spy(mocker):
class UnSpy:
def foo(self):
return 42
spy = mocker.spy(UnSpy, "foo")
assert UnSpy().foo() == 42
assert spy.call_count == 1
mocker.stop(spy)
assert UnSpy().foo() == 42
assert spy.call_count == 1
def test_stop_instance_spy(mocker):
class UnSpy:
def foo(self):
return 42
spy = mocker.spy(UnSpy, "foo")
un_spy = UnSpy()
assert un_spy.foo() == 42
assert spy.call_count == 1
mocker.stop(spy)
assert un_spy.foo() == 42
assert spy.call_count == 1

View file

@ -1,9 +1,8 @@
[tox]
minversion = 3.5.3
envlist = py{37,38,39,310}, norewrite
envlist = py{37,38,39,310,311}, norewrite
[testenv]
passenv = USER USERNAME
deps =
coverage
mock