classification
Title: unittest.mock.patch.stopall intermittently doesn't work when the same thing is patched multiple times
Type: behavior Stage: resolved
Components: Versions: Python 3.5, Python 3.4
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: michael.foord Nosy List: michael.foord, python-dev
Priority: normal Keywords:

Created on 2014-04-15 15:54 by michael.foord, last changed 2014-04-15 21:22 by python-dev. This issue is now closed.

Messages (2)
msg216322 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2014-04-15 15:54
stopall does not always stop all patches to single target
http://code.google.com/p/mock/issues/detail?id=226

What steps will reproduce the problem?

python code to reproduce error

import mock

def myfunc():
   return 'hello'

m = mock.patch('__main__.myfunc').start()
m.return_value = 'firstmock'
myfunc()

m2 = mock.patch('__main__.myfunc').start()
m2.return_value = 'secondmock'
myfunc()

mock.patch.stopall()
myfunc()


What is the expected output? What do you see instead?
I would expect the output from above to be:
'firstmock'
'secondmock'
'hello'

Instead, sometimes it comes out as:
'firstmock'
'secondmock'
'firstmock'

This result is non-deterministic though so it may also come out as expected. Re-run several times to get the error.

This is a result of using a set to store the active patches. Conversion from a set to a list is non-deterministic because the set has no notion of order.

Please provide any additional information below.

This use case may seem strange, but it shows up in large unit tests where a base class sets up a default patch to catch external calls or something similar and then an individual unit test requiring specific mock behavior patches it differently.

I have a patch here that fixes the problem using a list to store the patches to maintain order and call them in reverse order to stop them in the correct order.

https://code.google.com/r/blak111-mockfix/source/detail?r=3c2f72b0253075d628afb333a79b7cb118132294
msg216388 - (view) Author: Roundup Robot (python-dev) Date: 2014-04-15 21:22
New changeset 727b7e9c40e3 by Michael Foord in branch '3.4':
Closes issue 21239. unittest.mock.patch.stopall() did not work deterministically when the same name was patched multiple times.
http://hg.python.org/cpython/rev/727b7e9c40e3
History
Date User Action Args
2014-04-15 21:22:29python-devsetstatus: open -> closed

nosy: + python-dev
messages: + msg216388

resolution: fixed
stage: patch review -> resolved
2014-04-15 15:54:31michael.foordcreate