Skip to content

Commit 422c4fc

Browse files
authored
gh-119600: mock: do not access attributes of original when new_callable is set (#119601)
In order to patch flask.g e.g. as in #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.
1 parent 6efe346 commit 422c4fc

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
@@ -1508,13 +1508,12 @@ def __enter__(self):
15081508
if isinstance(original, type):
15091509
# If we're patching out a class and there is a spec
15101510
inherit = True
1511-
if spec is None and _is_async_obj(original):
1512-
Klass = AsyncMock
1513-
else:
1514-
Klass = MagicMock
1515-
_kwargs = {}
1511+
1512+
# Determine the Klass to use
15161513
if new_callable is not None:
15171514
Klass = new_callable
1515+
elif spec is None and _is_async_obj(original):
1516+
Klass = AsyncMock
15181517
elif spec is not None or spec_set is not None:
15191518
this_spec = spec
15201519
if spec_set is not None:
@@ -1527,7 +1526,12 @@ def __enter__(self):
15271526
Klass = AsyncMock
15281527
elif not_callable:
15291528
Klass = NonCallableMagicMock
1529+
else:
1530+
Klass = MagicMock
1531+
else:
1532+
Klass = MagicMock
15301533

1534+
_kwargs = {}
15311535
if spec is not None:
15321536
_kwargs['spec'] = spec
15331537
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)