Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 15f2d17

Browse files
committed
Merge
2 parents 27adf44 + ebc1a30 commit 15f2d17

3 files changed

Lines changed: 32 additions & 7 deletions

File tree

Lib/unittest/mock.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,7 @@ def _is_started(patcher):
10541054
class _patch(object):
10551055

10561056
attribute_name = None
1057-
_active_patches = set()
1057+
_active_patches = []
10581058

10591059
def __init__(
10601060
self, getter, attribute, new, spec, create,
@@ -1330,13 +1330,18 @@ def __exit__(self, *exc_info):
13301330
def start(self):
13311331
"""Activate a patch, returning any created mock."""
13321332
result = self.__enter__()
1333-
self._active_patches.add(self)
1333+
self._active_patches.append(self)
13341334
return result
13351335

13361336

13371337
def stop(self):
13381338
"""Stop an active patch."""
1339-
self._active_patches.discard(self)
1339+
try:
1340+
self._active_patches.remove(self)
1341+
except ValueError:
1342+
# If the patch hasn't been started this will fail
1343+
pass
1344+
13401345
return self.__exit__()
13411346

13421347

@@ -1629,8 +1634,8 @@ def _clear_dict(in_dict):
16291634

16301635

16311636
def _patch_stopall():
1632-
"""Stop all active patches."""
1633-
for patch in list(_patch._active_patches):
1637+
"""Stop all active patches. LIFO to unroll nested patches."""
1638+
for patch in reversed(_patch._active_patches):
16341639
patch.stop()
16351640

16361641

Lib/unittest/test/testmock/testpatch.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from unittest.mock import (
1313
NonCallableMock, CallableMixin, patch, sentinel,
1414
MagicMock, Mock, NonCallableMagicMock, patch, _patch,
15-
DEFAULT, call, _get_target
15+
DEFAULT, call, _get_target, _patch
1616
)
1717

1818

@@ -1799,6 +1799,23 @@ def patched(mock_path):
17991799
patched()
18001800
self.assertIs(os.path, path)
18011801

1802+
def test_stopall_lifo(self):
1803+
stopped = []
1804+
class thing(object):
1805+
one = two = three = None
1806+
1807+
def get_patch(attribute):
1808+
class mypatch(_patch):
1809+
def stop(self):
1810+
stopped.append(attribute)
1811+
return super(mypatch, self).stop()
1812+
return mypatch(lambda: thing, attribute, None, None,
1813+
False, None, None, None, {})
1814+
[get_patch(val).start() for val in ("one", "two", "three")]
1815+
patch.stopall()
1816+
1817+
self.assertEqual(stopped, ["three", "two", "one"])
1818+
18021819

18031820
if __name__ == '__main__':
18041821
unittest.main()

Misc/NEWS

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,12 @@ Core and Builtins
4646
Library
4747
-------
4848

49+
- Issue #21239: patch.stopall() didn't work deterministically when the same
50+
name was patched more than once.
51+
4952
- Issue #21203: Updated fileConfig and dictConfig to remove inconsistencies.
5053
Thanks to Jure Koren for the patch.
51-
54+
5255
- Issue #21222: Passing name keyword argument to mock.create_autospec now
5356
works.
5457

0 commit comments

Comments
 (0)