Merge remote-tracking branch 'upstream/features' into features
This commit is contained in:
@@ -4,6 +4,8 @@ from __future__ import absolute_import, division, print_function
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from contextlib import contextmanager
|
||||
|
||||
import six
|
||||
from _pytest.fixtures import fixture
|
||||
|
||||
@@ -106,6 +108,29 @@ class MonkeyPatch(object):
|
||||
self._cwd = None
|
||||
self._savesyspath = None
|
||||
|
||||
@contextmanager
|
||||
def context(self):
|
||||
"""
|
||||
Context manager that returns a new :class:`MonkeyPatch` object which
|
||||
undoes any patching done inside the ``with`` block upon exit:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import functools
|
||||
def test_partial(monkeypatch):
|
||||
with monkeypatch.context() as m:
|
||||
m.setattr(functools, "partial", 3)
|
||||
|
||||
Useful in situations where it is desired to undo some patches before the test ends,
|
||||
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()
|
||||
try:
|
||||
yield m
|
||||
finally:
|
||||
m.undo()
|
||||
|
||||
def setattr(self, target, name, value=notset, raising=True):
|
||||
""" Set attribute value on target, memorizing the old value.
|
||||
By default raise AttributeError if the attribute did not exist.
|
||||
|
||||
2
changelog/3290.feature
Normal file
2
changelog/3290.feature
Normal file
@@ -0,0 +1,2 @@
|
||||
``monkeypatch`` now supports a ``context()`` function which acts as a context manager which undoes all patching done
|
||||
within the ``with`` block.
|
||||
@@ -61,6 +61,22 @@ so that any attempts within tests to create http requests will fail.
|
||||
``compile``, etc., because it might break pytest's internals. If that's
|
||||
unavoidable, passing ``--tb=native``, ``--assert=plain`` and ``--capture=no`` might
|
||||
help although there's no guarantee.
|
||||
|
||||
.. note::
|
||||
|
||||
Mind that patching ``stdlib`` functions and some third-party libraries used by pytest
|
||||
might break pytest itself, therefore in those cases it is recommended to use
|
||||
:meth:`MonkeyPatch.context` to limit the patching to the block you want tested:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import functools
|
||||
def test_partial(monkeypatch):
|
||||
with monkeypatch.context() as m:
|
||||
m.setattr(functools, "partial", 3)
|
||||
assert functools.partial == 3
|
||||
|
||||
See issue `#3290 <https://github.com/pytest-dev/pytest/issues/3290>`_ for details.
|
||||
|
||||
|
||||
.. currentmodule:: _pytest.monkeypatch
|
||||
|
||||
@@ -327,3 +327,15 @@ def test_issue1338_name_resolving():
|
||||
monkeypatch.delattr('requests.sessions.Session.request')
|
||||
finally:
|
||||
monkeypatch.undo()
|
||||
|
||||
|
||||
def test_context():
|
||||
monkeypatch = MonkeyPatch()
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
|
||||
with monkeypatch.context() as m:
|
||||
m.setattr(functools, "partial", 3)
|
||||
assert not inspect.isclass(functools.partial)
|
||||
assert inspect.isclass(functools.partial)
|
||||
|
||||
Reference in New Issue
Block a user