Uh oh!
There was an error while loading. Please reload this page.
bpo-37047: Refactor AsyncMock setup logic for autospeccing - #13574
Conversation
* Handle late binding while setting attributes on AsyncMock during create_autospec. * Refactor out async mock setup logic outside the function. * Add awaited attribute during setup. * Fix assert_not_awaited error message.
tirkarthi
commented
May 25, 2019
I am not sure if a NEWS entry is needed since the changes were not released but added one just in case it doesn't make it for 3.8 beta 1. Note to self and reviewer :
|
pablogsal
commented
May 25, 2019
CC: @mariocj89 |
| def _is_async_func(func): | ||
| if getattr(func, '__code__', None): |
There was a problem hiding this comment.
Is it possible to have an async callable class? If so this won’t work.
Would a check for ‘callable’ work here?
There was a problem hiding this comment.
I don't understand "Asunción callable class" Do you mean something like async class Foo: pass which I think is not supported. Please add an example of the same.
There was a problem hiding this comment.
There is no async version of callable() builtin like acallable().asyncio.iscoroutinefunction() works for functions only
There was a problem hiding this comment.
👍 note that the following will probably produce a standard mock rather than an async mock:
classA:
asyncdef__call__(self):
awaitasyncio.sleep(1)
a=A()
# Creating a spec for a will not quite likely not create the right kind of mock, as a does not have __code__.We can cover this in a different PR if possible I guess.
There was a problem hiding this comment.
Yes, it produces a MagicMock but there could be a class with a mix of sync and async dunder methods too so not sure of the behavior and how to detect classes like this. I would like to cover it as part of different PR since this contain fixes for create_autospec. Thanks for catching this.
fromunittest.mockimportcreate_autospecclassA:
asyncdef__call__(self):
awaitasyncio.sleep(1)
a=create_autospec(A)
b=a()
print(a)
print(b())<MagicMock spec='A' id='4410501232'>
<MagicMock name='mock()()' id='4416843600'>
| 'assert_any_await', | ||
| 'assert_has_awaits', | ||
| 'assert_not_awaited'): | ||
| def f(attribute, *args, **kwargs): |
There was a problem hiding this comment.
I would use a different name than arte for this function. It makes it harder to read.
Or even better, take this function out of the loop.
There was a problem hiding this comment.
Why do we do this over directly assigning the result of getattr here? Is it because the mock might still not be configured? Just confirming.
There was a problem hiding this comment.
I would use a different name than arte for this function. It makes it harder to read. Or even better, take this function out of the loop.
I moved it out of the loop and used a different variable name. I have added a comment. Feel free to suggest if it can be rephrased better.
Why do we do this over directly assigning the result of getattr here? Is it because the mock might still not be configured? Just confirming.
Yes, this is similar to a synchronous function being specced where a new function object is returned that needs to be configured like in _setup_func where synchronous mock helpers are attached to function object and when called delegate to mock's helper. The original async setup code was trying to do the same except defining a named function for every helper it uses a wrapper function and uses getattr to get the corresponding method as it is being called.
defassert_called_with(*args, **kwargs):
returnmock.assert_called_with(*args, **kwargs)
funcopy.assert_called_with=assert_called_with# Could be rewritten as in this PRdefwrapper(attribute, *args, **kwargs):
returngetattr(mock, attr)(*args, **kwargs)
setattr(funcopy, 'assert_called_with', partial(wrapper, 'assert_called_with'))| @@ -0,0 +1,2 @@ | |||
| Handle late binding and attribute access in AsyncMock setup for | |||
| autospeccing. Document newly implemented async methods in MagicMock. | |||
There was a problem hiding this comment.
Note: If you want to make this a link you can convert the AsyncMock and MagicMock to
:class:unittest.mock.AsyncMock and :class:unittest.mock.MagicMock
1st1
commented
May 27, 2019
@tirkarthi Do you want me or Andrew to merge this? |
tirkarthi
commented
May 27, 2019
@1st1 Yes, this can be merged and all the items listed in the issue are complete. Thanks for the review everyone. |
1st1
commented
May 27, 2019
Thank you, @tirkarthi! |
…13574) Handle late binding and attribute access in unittest.mock.AsyncMock setup for autospeccing.
https://bugs.python.org/issue37047