diff options
author | Christian Klein <167265+cklein@users.noreply.github.com> | 2023-01-06 18:38:50 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-06 18:38:50 (GMT) |
commit | 1d4d677d1c90fcf4886ded0bf04b8f9d5b60b909 (patch) | |
tree | 3fc895376703b2960e4e7776a21868d9fdaba4b4 /Lib/unittest | |
parent | 9ffbc58f5cb6d2b002f8785886588d646af517db (diff) | |
download | cpython-1d4d677d1c90fcf4886ded0bf04b8f9d5b60b909.zip cpython-1d4d677d1c90fcf4886ded0bf04b8f9d5b60b909.tar.gz cpython-1d4d677d1c90fcf4886ded0bf04b8f9d5b60b909.tar.bz2 |
gh-100690: Raise an AttributeError when the assert_ prefix is forgotten when using Mock (#100691)
Mock objects which are not unsafe will now raise an AttributeError when accessing an
attribute that matches the name of an assertion but without the prefix `assert_`, e.g. accessing `called_once` instead of `assert_called_once`.
This is in addition to this already happening for accessing attributes with prefixes assert, assret, asert, aseert, and assrt.
Diffstat (limited to 'Lib/unittest')
-rw-r--r-- | Lib/unittest/mock.py | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 47928e5..78827d6 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -653,7 +653,7 @@ class NonCallableMock(Base): elif _is_magic(name): raise AttributeError(name) if not self._mock_unsafe and (not self._mock_methods or name not in self._mock_methods): - if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')): + if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')) or name in ATTRIB_DENY_LIST: raise AttributeError( f"{name!r} is not a valid assertion. Use a spec " f"for the mock if {name!r} is meant to be an attribute.") @@ -1062,6 +1062,10 @@ class NonCallableMock(Base): return f"\n{prefix}: {safe_repr(self.mock_calls)}." +# Denylist for forbidden attribute names in safe mode +ATTRIB_DENY_LIST = {name.removeprefix("assert_") for name in dir(NonCallableMock) if name.startswith("assert_")} + + class _AnyComparer(list): """A list which checks if it contains a call which may have an argument of ANY, flipping the components of item and self from @@ -1231,9 +1235,11 @@ class Mock(CallableMixin, NonCallableMock): `return_value` attribute. * `unsafe`: By default, accessing any attribute whose name starts with - *assert*, *assret*, *asert*, *aseert* or *assrt* will raise an - AttributeError. Passing `unsafe=True` will allow access to - these attributes. + *assert*, *assret*, *asert*, *aseert*, or *assrt* raises an AttributeError. + Additionally, an AttributeError is raised when accessing + attributes that match the name of an assertion method without the prefix + `assert_`, e.g. accessing `called_once` instead of `assert_called_once`. + Passing `unsafe=True` will allow access to these attributes. * `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 |