Closes Issue 21238: New keyword argument `unsafe` to Mock.

It raises `AttributeError` incase of an attribute startswith assert
or assret.
This commit is contained in:
Kushal Das 2014-04-16 23:32:21 +05:30
parent c3ac9af6d0
commit 8c14534df6
4 changed files with 27 additions and 3 deletions

View File

@ -198,7 +198,7 @@ a `MagicMock` for you. You can specify an alternative class of `Mock` using
the `new_callable` argument to `patch`. 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 Create a new `Mock` object. `Mock` takes several optional arguments
that specify the behaviour of the Mock object: that specify the behaviour of the Mock object:
@ -235,6 +235,12 @@ the `new_callable` argument to `patch`.
this is a new Mock (created on first access). See the this is a new Mock (created on first access). See the
:attr:`return_value` attribute. :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 * `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 calling the Mock will pass the call through to the wrapped object
(returning the real result). Attribute access on the mock will return a (returning the real result). Attribute access on the mock will return a

View File

@ -379,7 +379,7 @@ class NonCallableMock(Base):
def __init__( def __init__(
self, spec=None, wraps=None, name=None, spec_set=None, self, spec=None, wraps=None, name=None, spec_set=None,
parent=None, _spec_state=None, _new_name='', _new_parent=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: if _new_parent is None:
_new_parent = parent _new_parent = parent
@ -409,6 +409,7 @@ class NonCallableMock(Base):
__dict__['_mock_mock_calls'] = _CallList() __dict__['_mock_mock_calls'] = _CallList()
__dict__['method_calls'] = _CallList() __dict__['method_calls'] = _CallList()
__dict__['_mock_unsafe'] = unsafe
if kwargs: if kwargs:
self.configure_mock(**kwargs) self.configure_mock(**kwargs)
@ -565,13 +566,16 @@ class NonCallableMock(Base):
def __getattr__(self, name): def __getattr__(self, name):
if name == '_mock_methods': if name in {'_mock_methods', '_mock_unsafe'}:
raise AttributeError(name) raise AttributeError(name)
elif self._mock_methods is not None: elif self._mock_methods is not None:
if name not in self._mock_methods or name in _all_magics: if name not in self._mock_methods or name in _all_magics:
raise AttributeError("Mock object has no attribute %r" % name) raise AttributeError("Mock object has no attribute %r" % name)
elif _is_magic(name): elif _is_magic(name):
raise AttributeError(name) raise AttributeError(name)
if not self._mock_unsafe:
if name.startswith(('assert', 'assret')):
raise AttributeError(name)
result = self._mock_children.get(name) result = self._mock_children.get(name)
if result is _deleted: if result is _deleted:

View File

@ -1187,6 +1187,17 @@ class MockTest(unittest.TestCase):
m = mock.create_autospec(object(), name='sweet_func') m = mock.create_autospec(object(), name='sweet_func')
self.assertIn('sweet_func', repr(m)) 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): def test_mock_add_spec(self):
class _One(object): class _One(object):
one = 1 one = 1

View File

@ -50,6 +50,9 @@ Core and Builtins
Library Library
------- -------
- Issue #21238: New keyword argument `unsafe` to Mock. It raises
`AttributeError` incase of an attribute startswith assert or assret.
- Issue #20896: ssl.get_server_certificate() now uses PROTOCOL_SSLv23, not - Issue #20896: ssl.get_server_certificate() now uses PROTOCOL_SSLv23, not
PROTOCOL_SSLv3, for maximum compatibility. PROTOCOL_SSLv3, for maximum compatibility.