This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Incorrect error handling in unittest.mock
Type: behavior Stage: patch review
Components: Library (Lib) Versions: Python 3.9, Python 3.8, Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: bmclarnon, cjw296, michael.foord, ncoghlan, serhiy.storchaka, xtreak
Priority: normal Keywords: patch

Created on 2020-03-31 16:07 by bmclarnon, last changed 2022-04-11 14:59 by admin.

Pull Requests
URL Status Linked Edit
PR 19338 closed python-dev, 2020-04-03 16:30
PR 19351 merged serhiy.storchaka, 2020-04-03 21:52
PR 19483 merged serhiy.storchaka, 2020-04-12 11:18
PR 19484 merged serhiy.storchaka, 2020-04-12 11:36
Messages (8)
msg365395 - (view) Author: Barry McLarnon (bmclarnon) * Date: 2020-03-31 16:07
The error handling in mock.decorate_callable (3.5-3.7) and mock.decoration_helper (3.8-3.9) is incorrectly implemented. If the error handler is triggered in the loop, the `patching` variable is out of scope and raises an unhandled `UnboundLocalError` instead.

This happened as a result of a 3rd-party library that attempts to clear the `patchings` list of a decorated function. The below code shows a recreation of the incorrect error handling:

import functools
from unittest import mock


def is_valid():
    return True


def mock_is_valid():
    return False


def decorate(f):
    @functools.wraps(f)
    def decorate_wrapper(*args, **kwargs):
        # This happens in a 3rd-party library
        f.patchings = []
        return f(*args, **kwargs)

    return decorate_wrapper


@decorate
@mock.patch('test.is_valid', new=mock_is_valid)
def test_patch():
    raise Exception()
msg365707 - (view) Author: Barry McLarnon (bmclarnon) * Date: 2020-04-03 16:31
After further investigation, it seems this was fixed in https://github.com/python/cpython/commit/436c2b0d67da68465e709a96daac7340af3a5238

However, this fix was as part of an unrelated changeset and in a different function in 3.8+, and was never rolled back to 3.7 and below. PR opened to add the missing attribute instantiation to 3.7.
msg365728 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-03 21:50
I think that the current code is not correct. __exit__ should not be called if __enter__ is failed. If some __enter__ implementation calls other __enter__s it should manually call corresponding __exit__s.
msg366195 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-11 07:59
New changeset 4b222c9491d1700e9bdd98e6889b8d0ea1c7321e by Serhiy Storchaka in branch 'master':
bpo-40126: Fix reverting multiple patches in unittest.mock. (GH-19351)
https://github.com/python/cpython/commit/4b222c9491d1700e9bdd98e6889b8d0ea1c7321e
msg366222 - (view) Author: Barry McLarnon (bmclarnon) * Date: 2020-04-11 23:21
Issue still exists in 3.7 and below, as it was part of a different function before. Current PR doesn't resolve the original issue that was raised.
msg366238 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-12 11:53
New changeset ee249d798ba08f065efbf4f450880a446c6ca49d by Serhiy Storchaka in branch '3.8':
[3.8] bpo-40126: Fix reverting multiple patches in unittest.mock. (GH-19351) (GH-19483)
https://github.com/python/cpython/commit/ee249d798ba08f065efbf4f450880a446c6ca49d
msg366239 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-12 11:54
New changeset 4057e8f9b56789223a1e691d7601003aceb84ad1 by Serhiy Storchaka in branch '3.7':
[3.7] bpo-40126: Fix reverting multiple patches in unittest.mock. (GH-19351) (GH-19484)
https://github.com/python/cpython/commit/4057e8f9b56789223a1e691d7601003aceb84ad1
msg366241 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-12 11:57
3.5 and 3.6 are in security fixes only mode, and this issue is not a security issue. After merging PR 19484 I cannot reproduce the original issue anymore.

I left this issue open for the case if I find a way to write tests for the merged changes.
History
Date User Action Args
2022-04-11 14:59:28adminsetgithub: 84307
2020-04-12 11:57:36serhiy.storchakasetmessages: + msg366241
versions: - Python 3.5, Python 3.6
2020-04-12 11:54:06serhiy.storchakasetmessages: + msg366239
2020-04-12 11:53:49serhiy.storchakasetmessages: + msg366238
2020-04-12 11:36:08serhiy.storchakasetpull_requests: + pull_request18837
2020-04-12 11:18:29serhiy.storchakasetpull_requests: + pull_request18835
2020-04-11 23:21:54bmclarnonsetmessages: + msg366222
versions: + Python 3.5, Python 3.6
2020-04-11 07:59:31serhiy.storchakasetmessages: + msg366195
2020-04-04 05:28:30xtreaksetnosy: + cjw296, xtreak
2020-04-03 21:52:23serhiy.storchakasetpull_requests: + pull_request18714
2020-04-03 21:50:50serhiy.storchakasetnosy: + serhiy.storchaka, ncoghlan, michael.foord

messages: + msg365728
versions: + Python 3.8, Python 3.9, - Python 3.5, Python 3.6
2020-04-03 20:10:40bmclarnonsetcomponents: + Library (Lib), - Tests
2020-04-03 16:31:38bmclarnonsetnosy: - python-dev

messages: + msg365707
versions: - Python 3.8, Python 3.9
2020-04-03 16:30:36python-devsetkeywords: + patch
nosy: + python-dev

pull_requests: + pull_request18701
stage: patch review
2020-03-31 16:07:24bmclarnoncreate