summaryrefslogtreecommitdiffstats
path: root/Lib/unittest/mock.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/unittest/mock.py')
-rw-r--r--Lib/unittest/mock.py36
1 files changed, 35 insertions, 1 deletions
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 298b41e..5846eeb 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -804,6 +804,35 @@ class NonCallableMock(Base):
return message % (action, expected_string, actual_string)
+ def _get_call_signature_from_name(self, name):
+ """
+ * If call objects are asserted against a method/function like obj.meth1
+ then there could be no name for the call object to lookup. Hence just
+ return the spec_signature of the method/function being asserted against.
+ * If the name is not empty then remove () and split by '.' to get
+ list of names to iterate through the children until a potential
+ match is found. A child mock is created only during attribute access
+ so if we get a _SpecState then no attributes of the spec were accessed
+ and can be safely exited.
+ """
+ if not name:
+ return self._spec_signature
+
+ sig = None
+ names = name.replace('()', '').split('.')
+ children = self._mock_children
+
+ for name in names:
+ child = children.get(name)
+ if child is None or isinstance(child, _SpecState):
+ break
+ else:
+ children = child._mock_children
+ sig = child._spec_signature
+
+ return sig
+
+
def _call_matcher(self, _call):
"""
Given a call (or simply an (args, kwargs) tuple), return a
@@ -811,7 +840,12 @@ class NonCallableMock(Base):
This is a best effort method which relies on the spec's signature,
if available, or falls back on the arguments themselves.
"""
- sig = self._spec_signature
+
+ if isinstance(_call, tuple) and len(_call) > 2:
+ sig = self._get_call_signature_from_name(_call[0])
+ else:
+ sig = self._spec_signature
+
if sig is not None:
if len(_call) == 2:
name = ''