-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
bpo-37555: Update _CallList.__contains__ to respect ANY #14700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
94ddf54
b4c7d78
ad99a9d
49c5310
874fb69
d72d6f5
f0e8411
f295eac
18e964b
883841a
f4844c7
84489c8
344ef17
bdf430d
d3522b1
f47699d
38650c9
24973c0
001d708
25dec66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -814,7 +814,8 @@ def _call_matcher(self, _call): | |||||||||
else: | ||||||||||
name, args, kwargs = _call | ||||||||||
try: | ||||||||||
return name, sig.bind(*args, **kwargs) | ||||||||||
bound_call = sig.bind(*args, **kwargs) | ||||||||||
return call(name, bound_call.args, bound_call.kwargs) | ||||||||||
except TypeError as e: | ||||||||||
return e.with_traceback(None) | ||||||||||
else: | ||||||||||
|
@@ -863,9 +864,9 @@ def assert_called_with(self, /, *args, **kwargs): | |||||||||
def _error_message(): | ||||||||||
msg = self._format_mock_failure_message(args, kwargs) | ||||||||||
return msg | ||||||||||
expected = self._call_matcher((args, kwargs)) | ||||||||||
expected = self._call_matcher(_Call((args, kwargs), two=True)) | ||||||||||
actual = self._call_matcher(self.call_args) | ||||||||||
if expected != actual: | ||||||||||
if actual != expected: | ||||||||||
cause = expected if isinstance(expected, Exception) else None | ||||||||||
raise AssertionError(_error_message()) from cause | ||||||||||
|
||||||||||
|
@@ -925,10 +926,10 @@ def assert_any_call(self, /, *args, **kwargs): | |||||||||
The assert passes if the mock has *ever* been called, unlike | ||||||||||
`assert_called_with` and `assert_called_once_with` that only pass if | ||||||||||
the call is the most recent one.""" | ||||||||||
expected = self._call_matcher((args, kwargs)) | ||||||||||
expected = self._call_matcher(_Call((args, kwargs), two=True)) | ||||||||||
cause = expected if isinstance(expected, Exception) else None | ||||||||||
actual = [self._call_matcher(c) for c in self.call_args_list] | ||||||||||
if expected not in actual: | ||||||||||
cause = expected if isinstance(expected, Exception) else None | ||||||||||
if cause or expected not in _AnyComparer(actual): | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think as per my commit we can remove Line 340 in 455122a
__contains__ does an equal per item and hence it does the same check at _Call.__eq__ Line 2394 in 455122a
There are also no test failures and I see the behavior around comparison to be the same. We also can skip the check for cause as I go with the approach. @ElizabethU Thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tirkarthi I'm all for removing
Are those four tests working for you? If so, I'm pretty confused since these failures really make sense to me. In Line 2394 in 455122a
self is call(<ANY>, 1) and other is an item from the list, meaning that when it hits the reversed comparison at the end of the methodLine 2444 in 455122a
ANY is on the right, and it doesn't work.
At least that's what I'm seeing on my machine. I'd be really excited if you've found a way around There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see any failures on checking out your branch and cherry picking my changes on to your branch. My terminal output as below assuming I am doing it correct.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also don't have any changes more to push too as I can see.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's a list and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirmed that this change in the order of comparison to be crucial to my patch over change in the arguments. That means we can either
Thoughts?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking a bit further there is also mock backport which would need to run on 3.6+ so this would cause problems. Now I am more leaning towards to reverting my change to keep ANYCompare though the interpreter is fixed in 3.9+. At this point I think I depended on the patch in 3.9 during debugging and made some incorrect assumptions with respect to ordering, sorry about that. I would be okay with this landing on 3.8+ with ANYcompare and the backport can work on 3.6+ with the PR. @ElizabethU Feel free to revert my patch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am able to get it to work by rebasing 🎉 🎊 🎺 Thanks, I should have tried that earlier, but I thought since I was still having the problem on your branch and you had that passing, that it couldn't be a rebase. I should have tried anyway. My input on the patch for 3.9 is that it's great and a big improvement over what I had alone and I would love to see it get reviewed whenever there's time. As for backporting, maybe we'd still need the Thank you so, so much for sticking with me through this. I've learned so much, and your expertise has been a big part of that. I hope I can contribute again and take up a lot less of your time now that I know the routine and some of the codebase. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tirkarthi Ah, I didn't see your last comments. So reverting is the right thing to do? I do like the patch, and was hoping we could keep it for 3.9, but I'm unfamiliar with the mock backport situation, and why it means we couldn't use the patch in just 3.9? I'm reverting the patch per your instructions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, anything that means things work on 3.6+ would be very much appreciated by me :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One more case: Please do the check for cause to be exception
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you @tirkarthi ! I also saw in your patch you added the |
||||||||||
expected_string = self._format_mock_call_signature(args, kwargs) | ||||||||||
raise AssertionError( | ||||||||||
'%s call not found' % expected_string | ||||||||||
|
@@ -981,6 +982,22 @@ def _calls_repr(self, prefix="Calls"): | |||||||||
return f"\n{prefix}: {safe_repr(self.mock_calls)}." | ||||||||||
|
||||||||||
|
||||||||||
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 | ||||||||||
their traditional locations so that ANY is guaranteed to be on | ||||||||||
the left.""" | ||||||||||
def __contains__(self, item): | ||||||||||
for _call in self: | ||||||||||
if len(item) != len(_call): | ||||||||||
continue | ||||||||||
if all([ | ||||||||||
expected == actual | ||||||||||
for expected, actual in zip(item, _call) | ||||||||||
]): | ||||||||||
return True | ||||||||||
return False | ||||||||||
|
||||||||||
|
||||||||||
def _try_iter(obj): | ||||||||||
if obj is None: | ||||||||||
|
@@ -2132,9 +2149,9 @@ def _error_message(): | |||||||||
msg = self._format_mock_failure_message(args, kwargs, action='await') | ||||||||||
return msg | ||||||||||
|
||||||||||
expected = self._call_matcher((args, kwargs)) | ||||||||||
expected = self._call_matcher(_Call((args, kwargs), two=True)) | ||||||||||
actual = self._call_matcher(self.await_args) | ||||||||||
if expected != actual: | ||||||||||
if actual != expected: | ||||||||||
cause = expected if isinstance(expected, Exception) else None | ||||||||||
raise AssertionError(_error_message()) from cause | ||||||||||
|
||||||||||
|
@@ -2153,10 +2170,10 @@ def assert_any_await(self, /, *args, **kwargs): | |||||||||
""" | ||||||||||
Assert the mock has ever been awaited with the specified arguments. | ||||||||||
""" | ||||||||||
expected = self._call_matcher((args, kwargs)) | ||||||||||
expected = self._call_matcher(_Call((args, kwargs), two=True)) | ||||||||||
cause = expected if isinstance(expected, Exception) else None | ||||||||||
actual = [self._call_matcher(c) for c in self.await_args_list] | ||||||||||
if expected not in actual: | ||||||||||
cause = expected if isinstance(expected, Exception) else None | ||||||||||
if cause or expected not in _AnyComparer(actual): | ||||||||||
expected_string = self._format_mock_call_signature(args, kwargs) | ||||||||||
raise AssertionError( | ||||||||||
'%s await not found' % expected_string | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Fix `NonCallableMock._call_matcher` returning tuple instead of `_Call` object | ||
when `self._spec_signature` exists. Patch by Elizabeth Uselton |
Uh oh!
There was an error while loading. Please reload this page.