-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
#3290 improve monkeypatch #3382
#3290 improve monkeypatch #3382
Conversation
testing/test_monkeypatch.py
Outdated
|
||
|
||
def test_context(testdir): | ||
testdir.makepyfile(""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can be constructed as unittest directly taking monkeypatch, no need to invoke a nested acceptance test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. @feuillemorte please take a look at the other tests in this module for inspiration. 😁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@feuillemorte please rebase on features
because this is a new feature.
Thanks for all the hard work!
@@ -106,6 +108,14 @@ def __init__(self): | |||
self._cwd = None | |||
self._savesyspath = None | |||
|
|||
@contextmanager | |||
def context(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a docstring here, something along the lines:
"""
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>`_.
"""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
doc/en/monkeypatch.rst
Outdated
@@ -61,6 +61,17 @@ 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. | |||
|
|||
To avoid damage of pytest from patching python stdlib functions use ``with`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest here to change this to:
.. 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.
testing/test_monkeypatch.py
Outdated
|
||
|
||
def test_context(testdir): | ||
testdir.makepyfile(""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. @feuillemorte please take a look at the other tests in this module for inspiration. 😁
changelog/3290.bugfix
Outdated
@@ -0,0 +1,2 @@ | |||
Improved `monkeypatch` to support some form of with statement. Now you can use `with monkeypatch.context() as m:` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a new feature so it should be named 3290.feature
instead. Also I suggest using this text:
``monkeypatch`` now supports a ``context()`` function which acts as a context manager which undoes all patching done within the ``with`` block.
The fact that it can be used to avoid blowing up pytest itself is not the highlight of the new feature, just a recommended workaround.
What do you mean? |
I mean that need to fix #2180 problem in this PR. you wrote:
So, I get a test: import unittest
import requests
from unittest.mock import patch, mock_open
class PyTestIssue(unittest.TestCase):
def test_open(self):
with patch('builtins.open', mock_open(read_data='')):
requests.get('http://www.google.com') And try to fix an exception by importing from builtins import open And it has no effect, test failed with exception. |
rebased to |
@feuillemorte if you import/alias a name to a new place, then patching it at the old place has no effect to the new place |
Sorry, I didn't get. def test_open():
with patch('builtins.open', mock_open(read_data='')): # here we mocking builtin function and go to context manager
# here we have mocked open function
#and pytest also want to call open, but open is mocked
#and I have no idea how to split context manager and
#pytest functions. open() mocked globally in context
#manager and directly importing in pytest is not working here
requests.get('http://www.google.com')
open() # here open() is also mocked and must to behave as mocked
open() # here is normal behavior |
@feuillemorte I now noticed that #2180 definitely can't be fixed, the error occurs inside So don't worry about it, I'm closing #2180 as "not fixable". |
All comments are fixed |
Thanks again @feuillemorte, awesome work! 👍 |
Fixes #3290.
I added to
rewrite.py
(not in this PR)but it has no effect :(