From ba878c6d9d0360f52bb8eed1b99fe9bfeff0f80a Mon Sep 17 00:00:00 2001 From: holger krekel Date: Mon, 28 Jul 2014 10:34:01 +0200 Subject: [PATCH] add changelog entry and refactor unittest.mock.patch fix a bit --- AUTHORS | 1 + CHANGELOG | 3 +++ _pytest/python.py | 35 ++++++++++++----------------------- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/AUTHORS b/AUTHORS index a720b5962..31b7f1b80 100644 --- a/AUTHORS +++ b/AUTHORS @@ -44,3 +44,4 @@ Daniel Grana Andy Freeland Trevor Bekolay David Mohr +Nicolas Delaby diff --git a/CHANGELOG b/CHANGELOG index 954de32ab..b49cea8b8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ NEXT or a tuple of exception classes. Thanks David Mohr for the complete PR. +- fix integration of pytest with unittest.mock.patch decorator when + it uses the "new" argument. Thanks Nicolas Delaby for test and PR. + 2.6 ----------------------------------- diff --git a/_pytest/python.py b/_pytest/python.py index ac981ddb1..fbcdca691 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1861,28 +1861,17 @@ class FixtureDef: return ("" % (self.argname, self.scope, self.baseid)) -def handle_mock_module_patching(function, startindex): - """ - Special treatment when test_function is decorated - by mock.patch - """ - for candidate_module_name in ('mock', 'unittest.mock'): - # stdlib comes last, because mock might be also installed - # as a third party with upgraded version compare to - # unittest.mock - try: - mock = sys.modules[candidate_module_name] - except KeyError: - pass - else: - for patching in getattr(function, "patchings", []): - if (not patching.attribute_name - and patching.new is mock.DEFAULT): - startindex += 1 - break - else: - startindex += len(getattr(function, "patchings", [])) - return startindex +def num_mock_patch_args(function): + """ return number of arguments used up by mock arguments (if any) """ + patchings = getattr(function, "patchings", None) + if not patchings: + return 0 + mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None)) + if mock is not None: + return len([p for p in patchings + if not p.attribute_name and p.new is mock.DEFAULT]) + return len(patchings) + def getfuncargnames(function, startindex=None): # XXX merge with main.py's varnames @@ -1893,7 +1882,7 @@ def getfuncargnames(function, startindex=None): if startindex is None: startindex = inspect.ismethod(function) and 1 or 0 if realfunction != function: - startindex = handle_mock_module_patching(function, startindex) + startindex += num_mock_patch_args(function) function = realfunction argnames = inspect.getargs(py.code.getrawcode(function))[0] defaults = getattr(function, 'func_defaults',