summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Sobolev <mail@sobolevn.me>2022-11-11 08:04:30 (GMT)
committerGitHub <noreply@github.com>2022-11-11 08:04:30 (GMT)
commit67b4d2772c5124b908f8ed9b13166a79bbeb88d2 (patch)
tree5f1615e79bf0b5d47c5b73fd34aa9a4d97a7f6e4
parent97c493dd3543c7c3bb5319587c162f46271d4c5d (diff)
downloadcpython-67b4d2772c5124b908f8ed9b13166a79bbeb88d2.zip
cpython-67b4d2772c5124b908f8ed9b13166a79bbeb88d2.tar.gz
cpython-67b4d2772c5124b908f8ed9b13166a79bbeb88d2.tar.bz2
gh-98086: Now ``patch.dict`` can decorate async functions (#98095)
-rw-r--r--Lib/test/test_unittest/testmock/testasync.py17
-rw-r--r--Lib/unittest/mock.py18
-rw-r--r--Misc/NEWS.d/next/Library/2022-10-08-19-39-27.gh-issue-98086.y---WC.rst1
3 files changed, 36 insertions, 0 deletions
diff --git a/Lib/test/test_unittest/testmock/testasync.py b/Lib/test/test_unittest/testmock/testasync.py
index 1bab671..e05a228 100644
--- a/Lib/test/test_unittest/testmock/testasync.py
+++ b/Lib/test/test_unittest/testmock/testasync.py
@@ -149,6 +149,23 @@ class AsyncPatchCMTest(unittest.TestCase):
run(test_async())
+ def test_patch_dict_async_def(self):
+ foo = {'a': 'a'}
+ @patch.dict(foo, {'a': 'b'})
+ async def test_async():
+ self.assertEqual(foo['a'], 'b')
+
+ self.assertTrue(iscoroutinefunction(test_async))
+ run(test_async())
+
+ def test_patch_dict_async_def_context(self):
+ foo = {'a': 'a'}
+ async def test_async():
+ with patch.dict(foo, {'a': 'b'}):
+ self.assertEqual(foo['a'], 'b')
+
+ run(test_async())
+
class AsyncMockTest(unittest.TestCase):
def test_iscoroutinefunction_default(self):
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 096b1a5..a273753 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -1809,6 +1809,12 @@ class _patch_dict(object):
def __call__(self, f):
if isinstance(f, type):
return self.decorate_class(f)
+ if inspect.iscoroutinefunction(f):
+ return self.decorate_async_callable(f)
+ return self.decorate_callable(f)
+
+
+ def decorate_callable(self, f):
@wraps(f)
def _inner(*args, **kw):
self._patch_dict()
@@ -1820,6 +1826,18 @@ class _patch_dict(object):
return _inner
+ def decorate_async_callable(self, f):
+ @wraps(f)
+ async def _inner(*args, **kw):
+ self._patch_dict()
+ try:
+ return await f(*args, **kw)
+ finally:
+ self._unpatch_dict()
+
+ return _inner
+
+
def decorate_class(self, klass):
for attr in dir(klass):
attr_value = getattr(klass, attr)
diff --git a/Misc/NEWS.d/next/Library/2022-10-08-19-39-27.gh-issue-98086.y---WC.rst b/Misc/NEWS.d/next/Library/2022-10-08-19-39-27.gh-issue-98086.y---WC.rst
new file mode 100644
index 0000000..f4a1d27
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-10-08-19-39-27.gh-issue-98086.y---WC.rst
@@ -0,0 +1 @@
+Make sure ``patch.dict()`` can be applied on async functions.