From 62436189d4055f3354db90891761b13389be4e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20R=C3=B6hling?= Date: Mon, 13 Nov 2023 00:36:04 +0100 Subject: [PATCH] New upstream version 3.12.0 --- .github/workflows/test.yml | 19 +++++------ .pre-commit-config.yaml | 8 ++--- .readthedocs.yml | 15 +++++++++ CHANGELOG.rst | 21 ++++++++++++ PKG-INFO | 12 ++++--- docs/remarks.rst | 20 ------------ docs/usage.rst | 30 +++++++++++++++++ scripts/gen-release-notes.py | 49 +++++++++++++++++----------- setup.py | 4 +-- src/pytest_mock.egg-info/PKG-INFO | 12 ++++--- src/pytest_mock.egg-info/SOURCES.txt | 1 + src/pytest_mock/_version.py | 16 +++++++-- src/pytest_mock/plugin.py | 13 ++++++-- tests/test_pytest_mock.py | 22 ++++++++++++- tox.ini | 6 ++-- 15 files changed, 176 insertions(+), 72 deletions(-) create mode 100644 .readthedocs.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fdea6f3..7eef5be 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,19 +31,16 @@ jobs: strategy: fail-fast: false matrix: - python: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python: ["3.8", "3.9", "3.10", "3.11", "3.12"] os: [ubuntu-latest, windows-latest] + tox_env: ["py"] include: - - python: "3.7" - tox_env: "py37" - - python: "3.8" - tox_env: "py38" - - python: "3.9" - tox_env: "py39" - - python: "3.10" - tox_env: "py310" - - python: "3.11" - tox_env: "py311" + - python: "3.12" + os: ubuntu-latest + tox_env: "norewrite" + - python: "3.12" + os: windows-latest + tox_env: "norewrite" steps: - uses: actions/checkout@v3 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 170bd5a..9fd5499 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ exclude: '^($|.*\.bin)' repos: - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 23.9.1 hooks: - id: black args: [--safe, --quiet] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -19,12 +19,12 @@ repos: language: python additional_dependencies: [pygments, restructuredtext_lint] - repo: https://github.com/asottile/reorder-python-imports - rev: v3.9.0 + rev: v3.12.0 hooks: - id: reorder-python-imports args: ['--application-directories=.:src'] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.3.0 # NOTE: keep this in sync with tox.ini + rev: v1.6.0 # NOTE: keep this in sync with tox.ini hooks: - id: mypy files: ^(src|tests) diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..c2dd354 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,15 @@ +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +sphinx: + configuration: docs/conf.py + fail_on_warning: true + +python: + install: + - requirements: docs/requirements.txt + - path: . diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d2dbe80..052f803 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,9 +1,30 @@ Releases ======== +3.12.0 (2023-10-19) +------------------- + +* Added support for Python 3.12. +* Dropped support for EOL Python 3.7. +* ``mocker.resetall()`` now also resets mocks created by ``mocker.create_autospec`` (`#390`_). + +.. _#390: https://github.com/pytest-dev/pytest-mock/pull/390 + 3.11.1 (2023-06-15) ------------------- +(This release source code is identical to ``3.11.0`` except a small internal fix to deployment/CI) + +* 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.11.0 (2023-06-15) +------------------- + * Fixed introspection for failed ``assert_has_calls`` (`#365`_). * Updated type annotations for ``mocker.patch`` and ``mocker.spy`` (`#364`_). diff --git a/PKG-INFO b/PKG-INFO index b60a1a9..2a31ccb 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest-mock -Version: 3.11.1 +Version: 3.12.0 Summary: Thin-wrapper around the mock package for easier use with pytest Home-page: https://github.com/pytest-dev/pytest-mock/ Author: Bruno Oliveira @@ -18,17 +18,21 @@ Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 -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.12 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: Software Development :: Testing -Requires-Python: >=3.7 +Requires-Python: >=3.8 Description-Content-Type: text/x-rst -Provides-Extra: dev License-File: LICENSE +Requires-Dist: pytest>=5.0 +Provides-Extra: dev +Requires-Dist: pre-commit; extra == "dev" +Requires-Dist: tox; extra == "dev" +Requires-Dist: pytest-asyncio; extra == "dev" =========== pytest-mock diff --git a/docs/remarks.rst b/docs/remarks.rst index 5e20038..ef4ea68 100644 --- a/docs/remarks.rst +++ b/docs/remarks.rst @@ -100,23 +100,3 @@ to improve the flow of the test: # ... But this is arguably a little more complex than using ``pytest-mock``. - -Usage as context manager ------------------------- - -Although mocker's API is intentionally the same as ``mock.patch``'s, its use -as context manager and function decorator is **not** supported through the -fixture: - -.. code-block:: python - - def test_context_manager(mocker): - a = A() - with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): # DO NOT DO THIS - assert a.doIt() == True - -The purpose of this plugin is to make the use of context managers and -function decorators for mocking unnecessary, so it will emit a warning when used as such. - -If you really intend to mock a context manager, ``mocker.patch.context_manager`` exists -which won't issue the above warning. diff --git a/docs/usage.rst b/docs/usage.rst index 4c313b0..1b29d45 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -136,3 +136,33 @@ It may receive an optional name that is shown in its ``repr``, useful for debugg .. seealso:: ``async_stub`` method, which actually the same as ``stub`` but makes async stub. + + +Usage as context manager +------------------------ + +Although mocker's API is intentionally the same as ``mock.patch``'s, its use +as context manager and function decorator is **not** supported through the +fixture: + +.. code-block:: python + + def test_context_manager(mocker): + a = A() + with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): # DO NOT DO THIS + assert a.doIt() == True + +The purpose of this plugin is to make the use of context managers and +function decorators for mocking unnecessary, so it will emit a warning when used as such. + +If you really intend to mock a context manager, ``mocker.patch.context_manager`` exists +which won't issue the above warning. + +Where to patch +-------------- + +A common issue where mocking appears not to be working is patching in the wrong place. + +See this `section in the unittest docs `__ which provides a comprehensive explanation. + +Also see this excellent blog post: `Why your mock doesn't work `__. diff --git a/scripts/gen-release-notes.py b/scripts/gen-release-notes.py index d6b9b88..a41eaf2 100644 --- a/scripts/gen-release-notes.py +++ b/scripts/gen-release-notes.py @@ -1,10 +1,10 @@ """ Generates the release notes for the latest release, in Markdown. -Convert CHANGELOG.rst to Markdown, and extracts just the latest release. - -Writes to ``scripts/latest-release-notes.md``, which can be -used with https://github.com/softprops/action-gh-release. +1. Extracts the latest release from the CHANGELOG.rst file. +2. Converts it to Markdown using pypandoc. +3. Writes to ``scripts/latest-release-notes.md``, which can be + used with https://github.com/softprops/action-gh-release. """ from pathlib import Path @@ -12,25 +12,36 @@ import pypandoc this_dir = Path(__file__).parent rst_text = (this_dir.parent / "CHANGELOG.rst").read_text(encoding="UTF-8") -md_text = pypandoc.convert_text( - rst_text, "md", format="rst", extra_args=["--wrap=preserve"] -) 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: +capture = False +for line in rst_text.splitlines(): + # Only start capturing after the latest release section. + if line.startswith("-------"): + capture = not capture + if not capture: + # We only need to capture the latest release, so stop. break - first_heading_found = True - else: + continue + + if capture: output_lines.append(line) +# Drop last line, as it contains the previous release section title. +del output_lines[-1] + +trimmed_rst = "\n".join(output_lines).strip() +print(">>Trimmed RST follows:") +print(trimmed_rst) +print(">>Trimmed RST ends") + +md_text = pypandoc.convert_text( + trimmed_rst, "md", format="rst", extra_args=["--wrap=preserve"] +) +print(">>Converted Markdown follows:") +print(md_text) +print(">>Converted Markdown ends") + output_fn = this_dir / "latest-release-notes.md" -output_fn.write_text("\n".join(output_lines), encoding="UTF-8") +output_fn.write_text(md_text, encoding="UTF-8") print(output_fn, "generated.") diff --git a/setup.py b/setup.py index 0381dc9..748f804 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( package_data={ "pytest_mock": ["py.typed"], }, - python_requires=">=3.7", + python_requires=">=3.8", install_requires=["pytest>=5.0"], use_scm_version={"write_to": "src/pytest_mock/_version.py"}, setup_requires=["setuptools_scm"], @@ -30,11 +30,11 @@ setup( "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Testing", ], diff --git a/src/pytest_mock.egg-info/PKG-INFO b/src/pytest_mock.egg-info/PKG-INFO index b60a1a9..2a31ccb 100644 --- a/src/pytest_mock.egg-info/PKG-INFO +++ b/src/pytest_mock.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest-mock -Version: 3.11.1 +Version: 3.12.0 Summary: Thin-wrapper around the mock package for easier use with pytest Home-page: https://github.com/pytest-dev/pytest-mock/ Author: Bruno Oliveira @@ -18,17 +18,21 @@ Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 -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.12 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: Software Development :: Testing -Requires-Python: >=3.7 +Requires-Python: >=3.8 Description-Content-Type: text/x-rst -Provides-Extra: dev License-File: LICENSE +Requires-Dist: pytest>=5.0 +Provides-Extra: dev +Requires-Dist: pre-commit; extra == "dev" +Requires-Dist: tox; extra == "dev" +Requires-Dist: pytest-asyncio; extra == "dev" =========== pytest-mock diff --git a/src/pytest_mock.egg-info/SOURCES.txt b/src/pytest_mock.egg-info/SOURCES.txt index 32e22db..a12a29b 100644 --- a/src/pytest_mock.egg-info/SOURCES.txt +++ b/src/pytest_mock.egg-info/SOURCES.txt @@ -1,5 +1,6 @@ .gitignore .pre-commit-config.yaml +.readthedocs.yml CHANGELOG.rst LICENSE README.rst diff --git a/src/pytest_mock/_version.py b/src/pytest_mock/_version.py index cb3b8cf..9e1a899 100644 --- a/src/pytest_mock/_version.py +++ b/src/pytest_mock/_version.py @@ -1,4 +1,16 @@ # file generated by setuptools_scm # don't change, don't track in version control -__version__ = version = '3.11.1' -__version_tuple__ = version_tuple = (3, 11, 1) +TYPE_CHECKING = False +if TYPE_CHECKING: + from typing import Tuple, Union + VERSION_TUPLE = Tuple[Union[int, str], ...] +else: + VERSION_TUPLE = object + +version: str +__version__: str +__version_tuple__: VERSION_TUPLE +version_tuple: VERSION_TUPLE + +__version__ = version = '3.12.0' +__version_tuple__ = version_tuple = (3, 12, 0) diff --git a/src/pytest_mock/plugin.py b/src/pytest_mock/plugin.py index 4e9609a..673f98b 100644 --- a/src/pytest_mock/plugin.py +++ b/src/pytest_mock/plugin.py @@ -66,12 +66,20 @@ class MockerFixture: self.call = mock_module.call self.ANY = mock_module.ANY self.DEFAULT = mock_module.DEFAULT - self.create_autospec = mock_module.create_autospec self.sentinel = mock_module.sentinel self.mock_open = mock_module.mock_open if hasattr(mock_module, "seal"): self.seal = mock_module.seal + def create_autospec( + self, spec: Any, spec_set: bool = False, instance: bool = False, **kwargs: Any + ) -> MockType: + m: MockType = self.mock_module.create_autospec( + spec, spec_set, instance, **kwargs + ) + self._patches_and_mocks.append((None, m)) + return m + def resetall( self, *, return_value: bool = False, side_effect: bool = False ) -> None: @@ -102,7 +110,8 @@ class MockerFixture: times. """ for p, m in reversed(self._patches_and_mocks): - p.stop() + if p is not None: + p.stop() self._patches_and_mocks.clear() def stop(self, mock: unittest.mock.MagicMock) -> None: diff --git a/tests/test_pytest_mock.py b/tests/test_pytest_mock.py index 3d53241..fdeed0c 100644 --- a/tests/test_pytest_mock.py +++ b/tests/test_pytest_mock.py @@ -60,6 +60,15 @@ class UnixFS: return os.listdir(path) +class TestObject: + """ + Class that is used for testing create_autospec with child mocks + """ + + def run(self) -> str: + return "not mocked" + + @pytest.fixture def check_unix_fs_mocked( tmpdir: Any, mocker: MockerFixture @@ -156,7 +165,6 @@ def test_mock_patch_dict_resetall(mocker: MockerFixture) -> None: [ "ANY", "call", - "create_autospec", "MagicMock", "Mock", "mock_open", @@ -185,23 +193,35 @@ def test_mocker_resetall(mocker: MockerFixture) -> None: listdir = mocker.patch("os.listdir", return_value="foo") open = mocker.patch("os.open", side_effect=["bar", "baz"]) + mocked_object = mocker.create_autospec(TestObject) + mocked_object.run.return_value = "mocked" + assert listdir("/tmp") == "foo" assert open("/tmp/foo.txt") == "bar" + assert mocked_object.run() == "mocked" listdir.assert_called_once_with("/tmp") open.assert_called_once_with("/tmp/foo.txt") + mocked_object.run.assert_called_once() mocker.resetall() assert not listdir.called assert not open.called + assert not mocked_object.called assert listdir.return_value == "foo" assert list(open.side_effect) == ["baz"] + assert mocked_object.run.return_value == "mocked" mocker.resetall(return_value=True, side_effect=True) 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" + class TestMockerStub: def test_call(self, mocker: MockerFixture) -> None: diff --git a/tox.ini b/tox.ini index afcf56a..a2b3e21 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.5.3 -envlist = py{37,38,39,310,311}, norewrite +envlist = py{38,39,310,311,312}, norewrite [testenv] deps = @@ -8,11 +8,11 @@ deps = mock pytest-asyncio commands = - coverage run --append --source={envsitepackagesdir}/pytest_mock -m pytest tests + coverage run --append --source={envsitepackagesdir}/pytest_mock -m pytest tests --color=yes [testenv:norewrite] commands = - pytest tests --assert=plain + pytest tests --assert=plain --color=yes [pytest] addopts = -r a