Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export MonkeyPatch as pytest.MonkeyPatch #8006

Merged
merged 1 commit into from Nov 9, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions changelog/8006.feature.rst
@@ -0,0 +1,8 @@
It is now possible to construct a :class:`~pytest.MonkeyPatch` object directly as ``pytest.MonkeyPatch()``,
in cases when the :fixture:`monkeypatch` fixture cannot be used. Previously some users imported it
from the private `_pytest.monkeypatch.MonkeyPatch` namespace.

Additionally, :meth:`MonkeyPatch.context <pytest.MonkeyPatch.context>` is now a classmethod,
and can be used as ``with MonkeyPatch.context() as mp: ...``. This is the recommended way to use
``MonkeyPatch`` directly, since unlike the ``monkeypatch`` fixture, an instance created directly
is not ``undo()``-ed automatically.
6 changes: 2 additions & 4 deletions doc/en/reference.rst
Expand Up @@ -486,16 +486,14 @@ caplog
monkeypatch
~~~~~~~~~~~

.. currentmodule:: _pytest.monkeypatch

**Tutorial**: :doc:`monkeypatch`.

.. autofunction:: _pytest.monkeypatch.monkeypatch()
:no-auto-options:

Returns a :class:`MonkeyPatch` instance.
Returns a :class:`~pytest.MonkeyPatch` instance.

.. autoclass:: _pytest.monkeypatch.MonkeyPatch
.. autoclass:: pytest.MonkeyPatch
:members:


Expand Down
18 changes: 14 additions & 4 deletions src/_pytest/monkeypatch.py
Expand Up @@ -111,17 +111,27 @@ def __repr__(self) -> str:

@final
class MonkeyPatch:
"""Object returned by the ``monkeypatch`` fixture keeping a record of
setattr/item/env/syspath changes."""
"""Helper to conveniently monkeypatch attributes/items/environment
variables/syspath.

Returned by the :fixture:`monkeypatch` fixture.

:versionchanged:: 6.2
Can now also be used directly as `pytest.MonkeyPatch()`, for when
the fixture is not available. In this case, use
:meth:`with MonkeyPatch.context() as mp: <context>` or remember to call
:meth:`undo` explicitly.
"""

def __init__(self) -> None:
self._setattr: List[Tuple[object, str, object]] = []
self._setitem: List[Tuple[MutableMapping[Any, Any], object, object]] = ([])
self._cwd: Optional[str] = None
self._savesyspath: Optional[List[str]] = None

@classmethod
@contextmanager
def context(self) -> Generator["MonkeyPatch", None, None]:
def context(cls) -> Generator["MonkeyPatch", None, None]:
"""Context manager that returns a new :class:`MonkeyPatch` object
which undoes any patching done inside the ``with`` block upon exit.

Expand All @@ -140,7 +150,7 @@ def test_partial(monkeypatch):
such as mocking ``stdlib`` functions that might break pytest itself if mocked (for examples
of this see `#3290 <https://github.com/pytest-dev/pytest/issues/3290>`_.
"""
m = MonkeyPatch()
m = cls()
try:
yield m
finally:
Expand Down
2 changes: 2 additions & 0 deletions src/pytest/__init__.py
Expand Up @@ -19,6 +19,7 @@
from _pytest.main import Session
from _pytest.mark import MARK_GEN as mark
from _pytest.mark import param
from _pytest.monkeypatch import MonkeyPatch
from _pytest.nodes import Collector
from _pytest.nodes import File
from _pytest.nodes import Item
Expand Down Expand Up @@ -74,6 +75,7 @@
"main",
"mark",
"Module",
"MonkeyPatch",
"Package",
"param",
"PytestAssertRewriteWarning",
Expand Down
10 changes: 10 additions & 0 deletions testing/test_monkeypatch.py
Expand Up @@ -409,6 +409,16 @@ def test_context() -> None:
assert inspect.isclass(functools.partial)


def test_context_classmethod() -> None:
class A:
x = 1

with MonkeyPatch.context() as m:
m.setattr(A, "x", 2)
assert A.x == 2
assert A.x == 1


def test_syspath_prepend_with_namespace_packages(
testdir: Testdir, monkeypatch: MonkeyPatch
) -> None:
Expand Down