Commit fddcfa27 authored by Michael Foord's avatar Michael Foord

Closes issue 17660. You no longer need to explicitly pass create=True when patching builtin names.

parent fba913f7
...@@ -1031,6 +1031,12 @@ patch ...@@ -1031,6 +1031,12 @@ patch
default because it can be dangerous. With it switched on you can write default because it can be dangerous. With it switched on you can write
passing tests against APIs that don't actually exist! passing tests against APIs that don't actually exist!
.. note::
.. versionchanged:: 3.5
If you are patching builtins in a module then you don't
need to pass `create=True`, it will be added by default.
Patch can be used as a `TestCase` class decorator. It works by Patch can be used as a `TestCase` class decorator. It works by
decorating each test method in the class. This reduces the boilerplate decorating each test method in the class. This reduces the boilerplate
code when your test methods share a common patchings set. `patch` finds code when your test methods share a common patchings set. `patch` finds
...@@ -1401,6 +1407,21 @@ It is also possible to stop all patches which have been started by using ...@@ -1401,6 +1407,21 @@ It is also possible to stop all patches which have been started by using
Stop all active patches. Only stops patches started with `start`. Stop all active patches. Only stops patches started with `start`.
.. patch-builtins:
patch builtins
~~~~~~~~~~~~~~~
You can patch any builtins within a module. The following example patches
builtin `ord`:
>>> @patch('__main__.ord')
... def test(mock_ord):
... mock_ord.return_value = 101
... print(ord('c'))
...
>>> test()
101
TEST_PREFIX TEST_PREFIX
~~~~~~~~~~~ ~~~~~~~~~~~
...@@ -2011,7 +2032,7 @@ Mocking context managers with a :class:`MagicMock` is common enough and fiddly ...@@ -2011,7 +2032,7 @@ Mocking context managers with a :class:`MagicMock` is common enough and fiddly
enough that a helper function is useful. enough that a helper function is useful.
>>> m = mock_open() >>> m = mock_open()
>>> with patch('__main__.open', m, create=True): >>> with patch('__main__.open', m):
... with open('foo', 'w') as h: ... with open('foo', 'w') as h:
... h.write('some stuff') ... h.write('some stuff')
... ...
...@@ -2026,7 +2047,7 @@ enough that a helper function is useful. ...@@ -2026,7 +2047,7 @@ enough that a helper function is useful.
And for reading files: And for reading files:
>>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: >>> with patch('__main__.open', mock_open(read_data='bibble')) as m:
... with open('foo') as h: ... with open('foo') as h:
... result = h.read() ... result = h.read()
... ...
......
...@@ -27,9 +27,13 @@ __version__ = '1.0' ...@@ -27,9 +27,13 @@ __version__ = '1.0'
import inspect import inspect
import pprint import pprint
import sys import sys
import builtins
from types import ModuleType
from functools import wraps, partial from functools import wraps, partial
_builtins = {name for name in dir(builtins) if not name.startswith('_')}
BaseExceptions = (BaseException,) BaseExceptions = (BaseException,)
if 'java' in sys.platform: if 'java' in sys.platform:
# jython # jython
...@@ -1166,6 +1170,9 @@ class _patch(object): ...@@ -1166,6 +1170,9 @@ class _patch(object):
else: else:
local = True local = True
if name in _builtins and isinstance(target, ModuleType):
self.create = True
if not self.create and original is DEFAULT: if not self.create and original is DEFAULT:
raise AttributeError( raise AttributeError(
"%s does not have the attribute %r" % (target, name) "%s does not have the attribute %r" % (target, name)
......
...@@ -377,7 +377,7 @@ class PatchTest(unittest.TestCase): ...@@ -377,7 +377,7 @@ class PatchTest(unittest.TestCase):
def test_patchobject_wont_create_by_default(self): def test_patchobject_wont_create_by_default(self):
try: try:
@patch.object(SomeClass, 'frooble', sentinel.Frooble) @patch.object(SomeClass, 'ord', sentinel.Frooble)
def test(): def test():
self.fail('Patching non existent attributes should fail') self.fail('Patching non existent attributes should fail')
...@@ -386,7 +386,27 @@ class PatchTest(unittest.TestCase): ...@@ -386,7 +386,27 @@ class PatchTest(unittest.TestCase):
pass pass
else: else:
self.fail('Patching non existent attributes should fail') self.fail('Patching non existent attributes should fail')
self.assertFalse(hasattr(SomeClass, 'frooble')) self.assertFalse(hasattr(SomeClass, 'ord'))
def test_patch_builtins_without_create(self):
@patch(__name__+'.ord')
def test_ord(mock_ord):
mock_ord.return_value = 101
return ord('c')
@patch(__name__+'.open')
def test_open(mock_open):
m = mock_open.return_value
m.read.return_value = 'abcd'
fobj = open('doesnotexists.txt')
data = fobj.read()
fobj.close()
return data
self.assertEqual(test_ord(), 101)
self.assertEqual(test_open(), 'abcd')
def test_patch_with_static_methods(self): def test_patch_with_static_methods(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment