summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRan Benita <ran@unusedvar.com>2020-11-06 19:27:33 +0200
committerRan Benita <ran@unusedvar.com>2020-11-09 11:28:15 +0200
commit6f13d1b03b1e1af7def99505234075878407767d (patch)
tree48ff8f9b17347a521f8151d3a9e0d5691d4a2def
parent3bcd316f076b185bcc89c41a41345861f752aff7 (diff)
downloadpytest-6f13d1b03b1e1af7def99505234075878407767d.tar.gz
Export MonkeyPatch as pytest.MonkeyPatch
We want to export `pytest.MonkeyPatch` for the purpose of type-annotating the `monkeypatch` fixture. For other fixtures we export in this way, we also make direct construction of them (e.g. `MonkeyPatch()`) private. But unlike the others, `MonkeyPatch` is also widely used directly already, mostly because the `monkeypatch` fixture only works in `function` scope (issue #363), but also in other cases. So making it private will be annoying and we don't offer a decent replacement yet. So, let's just make direct construction public & documented.
-rw-r--r--changelog/8006.feature.rst8
-rw-r--r--doc/en/reference.rst6
-rw-r--r--src/_pytest/monkeypatch.py18
-rw-r--r--src/pytest/__init__.py2
-rw-r--r--testing/test_monkeypatch.py10
5 files changed, 36 insertions, 8 deletions
diff --git a/changelog/8006.feature.rst b/changelog/8006.feature.rst
new file mode 100644
index 000000000..0203689ba
--- /dev/null
+++ b/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.
diff --git a/doc/en/reference.rst b/doc/en/reference.rst
index c04b8da0b..cbe89fe0b 100644
--- a/doc/en/reference.rst
+++ b/doc/en/reference.rst
@@ -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:
diff --git a/src/_pytest/monkeypatch.py b/src/_pytest/monkeypatch.py
index df4726705..31b7b125b 100644
--- a/src/_pytest/monkeypatch.py
+++ b/src/_pytest/monkeypatch.py
@@ -111,8 +111,17 @@ notset = Notset()
@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]] = []
@@ -120,8 +129,9 @@ class MonkeyPatch:
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.
@@ -140,7 +150,7 @@ class 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:
diff --git a/src/pytest/__init__.py b/src/pytest/__init__.py
index a9c1ee028..d7a5b2299 100644
--- a/src/pytest/__init__.py
+++ b/src/pytest/__init__.py
@@ -19,6 +19,7 @@ from _pytest.freeze_support import freeze_includes
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
@@ -74,6 +75,7 @@ __all__ = [
"main",
"mark",
"Module",
+ "MonkeyPatch",
"Package",
"param",
"PytestAssertRewriteWarning",
diff --git a/testing/test_monkeypatch.py b/testing/test_monkeypatch.py
index 73fe313e5..c20ff7480 100644
--- a/testing/test_monkeypatch.py
+++ b/testing/test_monkeypatch.py
@@ -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: