diff -r 69d479e9aa82 Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst Tue Apr 15 22:41:36 2014 +0200 +++ b/Doc/library/unittest.mock.rst Wed Apr 16 21:28:47 2014 +0530 @@ -198,7 +198,7 @@ the `new_callable` argument to `patch`. -.. class:: Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, **kwargs) +.. class:: Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs) Create a new `Mock` object. `Mock` takes several optional arguments that specify the behaviour of the Mock object: @@ -235,6 +235,12 @@ this is a new Mock (created on first access). See the :attr:`return_value` attribute. + * `unsafe`: By default if any attribute starts with *assert* or + *assret* will raise an `AttributeError`. Passing `unsafe=True` will allow + access to these attributes. + + .. versionadded:: 3.5 + * `wraps`: Item for the mock object to wrap. If `wraps` is not None then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a diff -r 69d479e9aa82 Lib/unittest/mock.py --- a/Lib/unittest/mock.py Tue Apr 15 22:41:36 2014 +0200 +++ b/Lib/unittest/mock.py Wed Apr 16 21:28:47 2014 +0530 @@ -379,7 +379,7 @@ def __init__( self, spec=None, wraps=None, name=None, spec_set=None, parent=None, _spec_state=None, _new_name='', _new_parent=None, - _spec_as_instance=False, _eat_self=None, **kwargs + _spec_as_instance=False, _eat_self=None, unsafe=False, **kwargs ): if _new_parent is None: _new_parent = parent @@ -409,6 +409,7 @@ __dict__['_mock_mock_calls'] = _CallList() __dict__['method_calls'] = _CallList() + __dict__['_mock_unsafe'] = unsafe if kwargs: self.configure_mock(**kwargs) @@ -565,13 +566,16 @@ def __getattr__(self, name): - if name == '_mock_methods': + if name in {'_mock_methods', '_mock_unsafe'}: raise AttributeError(name) elif self._mock_methods is not None: if name not in self._mock_methods or name in _all_magics: raise AttributeError("Mock object has no attribute %r" % name) elif _is_magic(name): raise AttributeError(name) + if not self._mock_unsafe: + if name.startswith('assert') or name.startswith('assret'): + raise AttributeError(name) result = self._mock_children.get(name) if result is _deleted: diff -r 69d479e9aa82 Lib/unittest/test/testmock/testmock.py --- a/Lib/unittest/test/testmock/testmock.py Tue Apr 15 22:41:36 2014 +0200 +++ b/Lib/unittest/test/testmock/testmock.py Wed Apr 16 21:28:47 2014 +0530 @@ -1187,6 +1187,17 @@ m = mock.create_autospec(object(), name='sweet_func') self.assertIn('sweet_func', repr(m)) + #Issue21238 + def test_mock_unsafe(self): + m = Mock() + with self.assertRaises(AttributeError): + m.assert_foo_call() + with self.assertRaises(AttributeError): + m.assret_foo_call() + m = Mock(unsafe=True) + m.assert_foo_call() + m.assret_foo_call() + def test_mock_add_spec(self): class _One(object): one = 1