Skip to content

Commit fa291a3

Browse files
[3.12] gh-119600: mock: do not access attributes of original when new_callable is set (GH-119601) (#120335)
gh-119600: mock: do not access attributes of original when new_callable is set (GH-119601) In order to patch flask.g e.g. as in GH-84982, that proxies getattr must not be invoked. For that, mock must not try to read from the original object. In some cases that is unavoidable, e.g. when doing autospec. However, patch("flask.g", new_callable=MagicMock) should be entirely safe. (cherry picked from commit 422c4fc) Co-authored-by: Robert Collins <[email protected]>
1 parent a9f2daf commit fa291a3

File tree

4 files changed

+29
-5
lines changed

4 files changed

+29
-5
lines changed

Lib/test/test_unittest/testmock/support.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,14 @@ def wibble(self): pass
1414

1515
class X(object):
1616
pass
17+
18+
# A standin for weurkzeug.local.LocalProxy - issue 119600
19+
def _inaccessible(*args, **kwargs):
20+
raise AttributeError
21+
22+
23+
class OpaqueProxy:
24+
__getattribute__ = _inaccessible
25+
26+
27+
g = OpaqueProxy()

Lib/test/test_unittest/testmock/testpatch.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,6 +2045,13 @@ def test(): pass
20452045
with self.assertRaises(TypeError):
20462046
test()
20472047

2048+
def test_patch_proxy_object(self):
2049+
@patch("test.test_unittest.testmock.support.g", new_callable=MagicMock())
2050+
def test(_):
2051+
pass
2052+
2053+
test()
2054+
20482055

20492056
if __name__ == '__main__':
20502057
unittest.main()

Lib/unittest/mock.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,13 +1478,12 @@ def __enter__(self):
14781478
if isinstance(original, type):
14791479
# If we're patching out a class and there is a spec
14801480
inherit = True
1481-
if spec is None and _is_async_obj(original):
1482-
Klass = AsyncMock
1483-
else:
1484-
Klass = MagicMock
1485-
_kwargs = {}
1481+
1482+
# Determine the Klass to use
14861483
if new_callable is not None:
14871484
Klass = new_callable
1485+
elif spec is None and _is_async_obj(original):
1486+
Klass = AsyncMock
14881487
elif spec is not None or spec_set is not None:
14891488
this_spec = spec
14901489
if spec_set is not None:
@@ -1497,7 +1496,12 @@ def __enter__(self):
14971496
Klass = AsyncMock
14981497
elif not_callable:
14991498
Klass = NonCallableMagicMock
1499+
else:
1500+
Klass = MagicMock
1501+
else:
1502+
Klass = MagicMock
15001503

1504+
_kwargs = {}
15011505
if spec is not None:
15021506
_kwargs['spec'] = spec
15031507
if spec_set is not None:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :func:`unittest.mock.patch` to not read attributes of the target when
2+
``new_callable`` is set. Patch by Robert Collins.

0 commit comments

Comments
 (0)