summaryrefslogtreecommitdiff
path: root/mocker.py
diff options
context:
space:
mode:
authorGustavo Niemeyer <gustavo@niemeyer.net>2007-12-11 21:37:53 -0200
committerGustavo Niemeyer <gustavo@niemeyer.net>2007-12-11 21:37:53 -0200
commitd7c9c348405704cb69e9658df28d6008c5b2df7e (patch)
treeb7f7a6028a07f9347657ca800c87261be87787fb /mocker.py
parent44bfc93ffda5ece9eeb4e0c725aed23ccd9ed8e3 (diff)
downloadmocker-d7c9c348405704cb69e9658df28d6008c5b2df7e.tar.gz
Fixed patching of objects which define __getattr__.0.10.1
Diffstat (limited to 'mocker.py')
-rw-r--r--mocker.py28
1 files changed, 25 insertions, 3 deletions
diff --git a/mocker.py b/mocker.py
index 6de88e9..1e92f72 100644
--- a/mocker.py
+++ b/mocker.py
@@ -24,7 +24,7 @@ __all__ = ["Mocker", "expect", "IS", "CONTAINS", "IN", "MATCH",
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
__license__ = "PSF License"
-__version__ = "0.10"
+__version__ = "0.10.1"
ERROR_PREFIX = "[Mocker] "
@@ -1693,7 +1693,7 @@ class RunCounter(Task):
def verify(self):
if not self.min <= self._runs <= self.max:
if self._runs < self.min:
- raise AssertionError("Performed less times than expected.")
+ raise AssertionError("Performed fewer times than expected.")
raise AssertionError("Performed more times than expected.")
@@ -2016,7 +2016,21 @@ class Patcher(Task):
def execute(self, action, object):
attr = self._get_kind_attr(action.kind)
unpatched = self.get_unpatched_attr(object, attr)
- return unpatched(*action.args, **action.kwargs)
+ try:
+ return unpatched(*action.args, **action.kwargs)
+ except AttributeError:
+ if action.kind == "getattr":
+ # The normal behavior of Python is to try __getattribute__,
+ # and if it raises AttributeError, try __getattr__. We've
+ # tried the unpatched __getattribute__ above, and we'll now
+ # try __getattr__.
+ try:
+ __getattr__ = unpatched("__getattr__")
+ except AttributeError:
+ pass
+ else:
+ return __getattr__(*action.args, **action.kwargs)
+ raise
class PatchedMethod(object):
@@ -2037,6 +2051,14 @@ class PatchedMethod(object):
return mock.__mocker_act__(self._kind, args, kwargs, object)
return method
+ def __call__(self, obj, *args, **kwargs):
+ # At least with __getattribute__, Python seems to use *both* the
+ # descriptor API and also call the class attribute directly. It
+ # looks like an interpreter bug, or at least an undocumented
+ # inconsistency.
+ return self.__get__(obj)(*args, **kwargs)
+
+
def patcher_recorder(mocker, event):
mock = event.path.root_mock
if mock.__mocker_patcher__ and len(event.path.actions) == 1: