Fixes an issue where the organization home page would throw a 505 when no projects...
[Melange.git] / thirdparty / mocker / mocker.py
blob1e92f72da55fd677c3f5957f7cc7446102005757
1 """
2 Copyright (c) 2007 Gustavo Niemeyer <gustavo@niemeyer.net>
4 Graceful platform for test doubles in Python (mocks, stubs, fakes, and dummies).
5 """
6 import __builtin__
7 import tempfile
8 import unittest
9 import inspect
10 import shutil
11 import types
12 import sys
13 import os
14 import gc
17 if sys.version_info < (2, 4):
18 from sets import Set as set # pragma: nocover
21 __all__ = ["Mocker", "expect", "IS", "CONTAINS", "IN", "MATCH",
22 "ANY", "ARGS", "KWARGS"]
25 __author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
26 __license__ = "PSF License"
27 __version__ = "0.10.1"
30 ERROR_PREFIX = "[Mocker] "
33 # --------------------------------------------------------------------
34 # Exceptions
36 class MatchError(AssertionError):
37 """Raised when an unknown expression is seen in playback mode."""
40 # --------------------------------------------------------------------
41 # Helper for chained-style calling.
43 class expect(object):
44 """This is a simple helper that allows a different call-style.
46 With this class one can comfortably do chaining of calls to the
47 mocker object responsible by the object being handled. For instance::
49 expect(obj.attr).result(3).count(1, 2)
51 Is the same as::
53 obj.attr
54 mocker.result(3)
55 mocker.count(1, 2)
57 """
59 def __init__(self, mock, attr=None):
60 self._mock = mock
61 self._attr = attr
63 def __getattr__(self, attr):
64 return self.__class__(self._mock, attr)
66 def __call__(self, *args, **kwargs):
67 getattr(self._mock.__mocker__, self._attr)(*args, **kwargs)
68 return self
71 # --------------------------------------------------------------------
72 # Extensions to Python's unittest.
74 class MockerTestCase(unittest.TestCase):
75 """unittest.TestCase subclass with Mocker support.
77 @ivar mocker: The mocker instance.
79 This is a convenience only. Mocker may easily be used with the
80 standard C{unittest.TestCase} class if wanted.
82 Test methods have a Mocker instance available on C{self.mocker}.
83 At the end of each test method, expectations of the mocker will
84 be verified, and any requested changes made to the environment
85 will be restored.
87 In addition to the integration with Mocker, this class provides
88 a few additional helper methods.
89 """
91 expect = expect
93 def __init__(self, methodName="runTest"):
94 # So here is the trick: we take the real test method, wrap it on
95 # a function that do the job we have to do, and insert it in the
96 # *instance* dictionary, so that getattr() will return our
97 # replacement rather than the class method.
98 test_method = getattr(self, methodName, None)
99 if test_method is not None:
100 def test_method_wrapper():
101 try:
102 result = test_method()
103 except:
104 raise
105 else:
106 if (self.mocker.is_recording() and
107 self.mocker.get_events()):
108 raise RuntimeError("Mocker must be put in replay "
109 "mode with self.mocker.replay()")
110 if (hasattr(result, "addCallback") and
111 hasattr(result, "addErrback")):
112 def verify(result):
113 self.mocker.verify()
114 return result
115 result.addCallback(verify)
116 else:
117 self.mocker.verify()
118 return result
119 # Copy all attributes from the original method..
120 for attr in dir(test_method):
121 # .. unless they're present in our wrapper already.
122 if not hasattr(test_method_wrapper, attr) or attr == "__doc__":
123 setattr(test_method_wrapper, attr,
124 getattr(test_method, attr))
125 setattr(self, methodName, test_method_wrapper)
127 # We could overload run() normally, but other well-known testing
128 # frameworks do it as well, and some of them won't call the super,
129 # which might mean that cleanup wouldn't happen. With that in mind,
130 # we make integration easier by using the following trick.
131 run_method = self.run
132 def run_wrapper(*args, **kwargs):
133 try:
134 return run_method(*args, **kwargs)
135 finally:
136 self.__cleanup()
137 self.run = run_wrapper
139 self.mocker = Mocker()
141 self.__cleanup_funcs = []
142 self.__cleanup_paths = []
144 super(MockerTestCase, self).__init__(methodName)
146 def __cleanup(self):
147 for path in self.__cleanup_paths:
148 if os.path.isfile(path):
149 os.unlink(path)
150 elif os.path.isdir(path):
151 shutil.rmtree(path)
152 self.mocker.restore()
153 for func, args, kwargs in self.__cleanup_funcs:
154 func(*args, **kwargs)
156 def addCleanup(self, func, *args, **kwargs):
157 self.__cleanup_funcs.append((func, args, kwargs))
159 def makeFile(self, content=None, suffix="", prefix="tmp", basename=None,
160 dirname=None, path=None):
161 """Create a temporary file and return the path to it.
163 @param content: Initial content for the file.
164 @param suffix: Suffix to be given to the file's basename.
165 @param prefix: Prefix to be given to the file's basename.
166 @param basename: Full basename for the file.
167 @param dirname: Put file inside this directory.
169 The file is removed after the test runs.
171 if path is not None:
172 self.__cleanup_paths.append(path)
173 elif basename is not None:
174 if dirname is None:
175 dirname = tempfile.mkdtemp()
176 self.__cleanup_paths.append(dirname)
177 path = os.path.join(dirname, basename)
178 else:
179 fd, path = tempfile.mkstemp(suffix, prefix, dirname)
180 self.__cleanup_paths.append(path)
181 os.close(fd)
182 if content is None:
183 os.unlink(path)
184 if content is not None:
185 file = open(path, "w")
186 file.write(content)
187 file.close()
188 return path
190 def makeDir(self, suffix="", prefix="tmp", dirname=None, path=None):
191 """Create a temporary directory and return the path to it.
193 @param suffix: Suffix to be given to the file's basename.
194 @param prefix: Prefix to be given to the file's basename.
195 @param dirname: Put directory inside this parent directory.
197 The directory is removed after the test runs.
199 if path is not None:
200 os.makedirs(path)
201 else:
202 path = tempfile.mkdtemp(suffix, prefix, dirname)
203 self.__cleanup_paths.append(path)
204 return path
206 def failUnlessIs(self, first, second, msg=None):
207 """Assert that C{first} is the same object as C{second}."""
208 if first is not second:
209 raise self.failureException(msg or "%r is not %r" % (first, second))
211 def failIfIs(self, first, second, msg=None):
212 """Assert that C{first} is not the same object as C{second}."""
213 if first is second:
214 raise self.failureException(msg or "%r is %r" % (first, second))
216 def failUnlessIn(self, first, second, msg=None):
217 """Assert that C{first} is contained in C{second}."""
218 if first not in second:
219 raise self.failureException(msg or "%r not in %r" % (first, second))
221 def failUnlessStartsWith(self, first, second, msg=None):
222 """Assert that C{first} starts with C{second}."""
223 if first[:len(second)] != second:
224 raise self.failureException(msg or "%r doesn't start with %r" %
225 (first, second))
227 def failIfStartsWith(self, first, second, msg=None):
228 """Assert that C{first} doesn't start with C{second}."""
229 if first[:len(second)] == second:
230 raise self.failureException(msg or "%r starts with %r" %
231 (first, second))
233 def failUnlessEndsWith(self, first, second, msg=None):
234 """Assert that C{first} starts with C{second}."""
235 if first[len(first)-len(second):] != second:
236 raise self.failureException(msg or "%r doesn't end with %r" %
237 (first, second))
239 def failIfEndsWith(self, first, second, msg=None):
240 """Assert that C{first} doesn't start with C{second}."""
241 if first[len(first)-len(second):] == second:
242 raise self.failureException(msg or "%r ends with %r" %
243 (first, second))
245 def failIfIn(self, first, second, msg=None):
246 """Assert that C{first} is not contained in C{second}."""
247 if first in second:
248 raise self.failureException(msg or "%r in %r" % (first, second))
250 def failUnlessApproximates(self, first, second, tolerance, msg=None):
251 """Assert that C{first} is near C{second} by at most C{tolerance}."""
252 if abs(first - second) > tolerance:
253 raise self.failureException(msg or "abs(%r - %r) > %r" %
254 (first, second, tolerance))
256 def failIfApproximates(self, first, second, tolerance, msg=None):
257 """Assert that C{first} is far from C{second} by at least C{tolerance}.
259 if abs(first - second) <= tolerance:
260 raise self.failureException(msg or "abs(%r - %r) <= %r" %
261 (first, second, tolerance))
263 def failUnlessMethodsMatch(self, first, second):
264 """Assert that public methods in C{first} are present in C{second}.
266 This method asserts that all public methods found in C{first} are also
267 present in C{second} and accept the same arguments. C{first} may
268 have its own private methods, though, and may not have all methods
269 found in C{second}. Note that if a private method in C{first} matches
270 the name of one in C{second}, their specification is still compared.
272 This is useful to verify if a fake or stub class have the same API as
273 the real class being simulated.
275 first_methods = dict(inspect.getmembers(first, inspect.ismethod))
276 second_methods = dict(inspect.getmembers(second, inspect.ismethod))
277 for name, first_method in first_methods.items():
278 first_argspec = inspect.getargspec(first_method)
279 first_formatted = inspect.formatargspec(*first_argspec)
281 second_method = second_methods.get(name)
282 if second_method is None:
283 if name[:1] == "_":
284 continue # First may have its own private methods.
285 raise self.failureException("%s.%s%s not present in %s" %
286 (first.__name__, name, first_formatted, second.__name__))
288 second_argspec = inspect.getargspec(second_method)
289 if first_argspec != second_argspec:
290 second_formatted = inspect.formatargspec(*second_argspec)
291 raise self.failureException("%s.%s%s != %s.%s%s" %
292 (first.__name__, name, first_formatted,
293 second.__name__, name, second_formatted))
296 assertIs = failUnlessIs
297 assertIsNot = failIfIs
298 assertIn = failUnlessIn
299 assertNotIn = failIfIn
300 assertStartsWith = failUnlessStartsWith
301 assertNotStartsWith = failIfStartsWith
302 assertEndsWith = failUnlessEndsWith
303 assertNotEndsWith = failIfEndsWith
304 assertApproximates = failUnlessApproximates
305 assertNotApproximates = failIfApproximates
306 assertMethodsMatch = failUnlessMethodsMatch
308 # The following are missing in Python < 2.4.
309 assertTrue = unittest.TestCase.failUnless
310 assertFalse = unittest.TestCase.failIf
312 # The following is provided for compatibility with Twisted's trial.
313 assertIdentical = assertIs
314 assertNotIdentical = assertIsNot
315 failUnlessIdentical = failUnlessIs
316 failIfIdentical = failIfIs
319 # --------------------------------------------------------------------
320 # Mocker.
322 class classinstancemethod(object):
324 def __init__(self, method):
325 self.method = method
327 def __get__(self, obj, cls=None):
328 def bound_method(*args, **kwargs):
329 return self.method(cls, obj, *args, **kwargs)
330 return bound_method
333 class MockerBase(object):
334 """Controller of mock objects.
336 A mocker instance is used to command recording and replay of
337 expectations on any number of mock objects.
339 Expectations should be expressed for the mock object while in
340 record mode (the initial one) by using the mock object itself,
341 and using the mocker (and/or C{expect()} as a helper) to define
342 additional behavior for each event. For instance::
344 mock = mocker.mock()
345 mock.hello()
346 mocker.result("Hi!")
347 mocker.replay()
348 assert mock.hello() == "Hi!"
349 mock.restore()
350 mock.verify()
352 In this short excerpt a mock object is being created, then an
353 expectation of a call to the C{hello()} method was recorded, and
354 when called the method should return the value C{10}. Then, the
355 mocker is put in replay mode, and the expectation is satisfied by
356 calling the C{hello()} method, which indeed returns 10. Finally,
357 a call to the L{restore()} method is performed to undo any needed
358 changes made in the environment, and the L{verify()} method is
359 called to ensure that all defined expectations were met.
361 The same logic can be expressed more elegantly using the
362 C{with mocker:} statement, as follows::
364 mock = mocker.mock()
365 mock.hello()
366 mocker.result("Hi!")
367 with mocker:
368 assert mock.hello() == "Hi!"
370 Also, the MockerTestCase class, which integrates the mocker on
371 a unittest.TestCase subclass, may be used to reduce the overhead
372 of controlling the mocker. A test could be written as follows::
374 class SampleTest(MockerTestCase):
376 def test_hello(self):
377 mock = self.mocker.mock()
378 mock.hello()
379 self.mocker.result("Hi!")
380 self.mocker.replay()
381 self.assertEquals(mock.hello(), "Hi!")
384 _recorders = []
386 # For convenience only.
387 on = expect
389 class __metaclass__(type):
390 def __init__(self, name, bases, dict):
391 # Make independent lists on each subclass, inheriting from parent.
392 self._recorders = list(getattr(self, "_recorders", ()))
394 def __init__(self):
395 self._recorders = self._recorders[:]
396 self._events = []
397 self._recording = True
398 self._ordering = False
399 self._last_orderer = None
401 def is_recording(self):
402 """Return True if in recording mode, False if in replay mode.
404 Recording is the initial state.
406 return self._recording
408 def replay(self):
409 """Change to replay mode, where recorded events are reproduced.
411 If already in replay mode, the mocker will be restored, with all
412 expectations reset, and then put again in replay mode.
414 An alternative and more comfortable way to replay changes is
415 using the 'with' statement, as follows::
417 mocker = Mocker()
418 <record events>
419 with mocker:
420 <reproduce events>
422 The 'with' statement will automatically put mocker in replay
423 mode, and will also verify if all events were correctly reproduced
424 at the end (using L{verify()}), and also restore any changes done
425 in the environment (with L{restore()}).
427 Also check the MockerTestCase class, which integrates the
428 unittest.TestCase class with mocker.
430 if not self._recording:
431 for event in self._events:
432 event.restore()
433 else:
434 self._recording = False
435 for event in self._events:
436 event.replay()
438 def restore(self):
439 """Restore changes in the environment, and return to recording mode.
441 This should always be called after the test is complete (succeeding
442 or not). There are ways to call this method automatically on
443 completion (e.g. using a C{with mocker:} statement, or using the
444 L{MockerTestCase} class.
446 if not self._recording:
447 self._recording = True
448 for event in self._events:
449 event.restore()
451 def reset(self):
452 """Reset the mocker state.
454 This will restore environment changes, if currently in replay
455 mode, and then remove all events previously recorded.
457 if not self._recording:
458 self.restore()
459 self.unorder()
460 del self._events[:]
462 def get_events(self):
463 """Return all recorded events."""
464 return self._events[:]
466 def add_event(self, event):
467 """Add an event.
469 This method is used internally by the implementation, and
470 shouldn't be needed on normal mocker usage.
472 self._events.append(event)
473 if self._ordering:
474 orderer = event.add_task(Orderer(event.path))
475 if self._last_orderer:
476 orderer.add_dependency(self._last_orderer)
477 self._last_orderer = orderer
478 return event
480 def verify(self):
481 """Check if all expectations were met, and raise AssertionError if not.
483 The exception message will include a nice description of which
484 expectations were not met, and why.
486 errors = []
487 for event in self._events:
488 try:
489 event.verify()
490 except AssertionError, e:
491 error = str(e)
492 if not error:
493 raise RuntimeError("Empty error message from %r"
494 % event)
495 errors.append(error)
496 if errors:
497 message = [ERROR_PREFIX + "Unmet expectations:", ""]
498 for error in errors:
499 lines = error.splitlines()
500 message.append("=> " + lines.pop(0))
501 message.extend([" " + line for line in lines])
502 message.append("")
503 raise AssertionError(os.linesep.join(message))
505 def mock(self, spec_and_type=None, spec=None, type=None,
506 name=None, count=True):
507 """Return a new mock object.
509 @param spec_and_type: Handy positional argument which sets both
510 spec and type.
511 @param spec: Method calls will be checked for correctness against
512 the given class.
513 @param type: If set, the Mock's __class__ attribute will return
514 the given type. This will make C{isinstance()} calls
515 on the object work.
516 @param name: Name for the mock object, used in the representation of
517 expressions. The name is rarely needed, as it's usually
518 guessed correctly from the variable name used.
519 @param count: If set to false, expressions may be executed any number
520 of times, unless an expectation is explicitly set using
521 the L{count()} method. By default, expressions are
522 expected once.
524 if spec_and_type is not None:
525 spec = type = spec_and_type
526 return Mock(self, spec=spec, type=type, name=name, count=count)
528 def proxy(self, object, spec=True, type=True, name=None, count=True,
529 passthrough=True):
530 """Return a new mock object which proxies to the given object.
532 Proxies are useful when only part of the behavior of an object
533 is to be mocked. Unknown expressions may be passed through to
534 the real implementation implicitly (if the C{passthrough} argument
535 is True), or explicitly (using the L{passthrough()} method
536 on the event).
538 @param object: Real object to be proxied, and replaced by the mock
539 on replay mode. It may also be an "import path",
540 such as C{"time.time"}, in which case the object
541 will be the C{time} function from the C{time} module.
542 @param spec: Method calls will be checked for correctness against
543 the given object, which may be a class or an instance
544 where attributes will be looked up. Defaults to the
545 the C{object} parameter. May be set to None explicitly,
546 in which case spec checking is disabled. Checks may
547 also be disabled explicitly on a per-event basis with
548 the L{nospec()} method.
549 @param type: If set, the Mock's __class__ attribute will return
550 the given type. This will make C{isinstance()} calls
551 on the object work. Defaults to the type of the
552 C{object} parameter. May be set to None explicitly.
553 @param name: Name for the mock object, used in the representation of
554 expressions. The name is rarely needed, as it's usually
555 guessed correctly from the variable name used.
556 @param count: If set to false, expressions may be executed any number
557 of times, unless an expectation is explicitly set using
558 the L{count()} method. By default, expressions are
559 expected once.
560 @param passthrough: If set to False, passthrough of actions on the
561 proxy to the real object will only happen when
562 explicitly requested via the L{passthrough()}
563 method.
565 if isinstance(object, basestring):
566 if name is None:
567 name = object
568 import_stack = object.split(".")
569 attr_stack = []
570 while import_stack:
571 module_path = ".".join(import_stack)
572 try:
573 object = __import__(module_path, {}, {}, [""])
574 except ImportError:
575 attr_stack.insert(0, import_stack.pop())
576 if not import_stack:
577 raise
578 continue
579 else:
580 for attr in attr_stack:
581 object = getattr(object, attr)
582 break
583 if spec is True:
584 spec = object
585 if type is True:
586 type = __builtin__.type(object)
587 return Mock(self, spec=spec, type=type, object=object,
588 name=name, count=count, passthrough=passthrough)
590 def replace(self, object, spec=True, type=True, name=None, count=True,
591 passthrough=True):
592 """Create a proxy, and replace the original object with the mock.
594 On replay, the original object will be replaced by the returned
595 proxy in all dictionaries found in the running interpreter via
596 the garbage collecting system. This should cover module
597 namespaces, class namespaces, instance namespaces, and so on.
599 @param object: Real object to be proxied, and replaced by the mock
600 on replay mode. It may also be an "import path",
601 such as C{"time.time"}, in which case the object
602 will be the C{time} function from the C{time} module.
603 @param spec: Method calls will be checked for correctness against
604 the given object, which may be a class or an instance
605 where attributes will be looked up. Defaults to the
606 the C{object} parameter. May be set to None explicitly,
607 in which case spec checking is disabled. Checks may
608 also be disabled explicitly on a per-event basis with
609 the L{nospec()} method.
610 @param type: If set, the Mock's __class__ attribute will return
611 the given type. This will make C{isinstance()} calls
612 on the object work. Defaults to the type of the
613 C{object} parameter. May be set to None explicitly.
614 @param name: Name for the mock object, used in the representation of
615 expressions. The name is rarely needed, as it's usually
616 guessed correctly from the variable name used.
617 @param passthrough: If set to False, passthrough of actions on the
618 proxy to the real object will only happen when
619 explicitly requested via the L{passthrough()}
620 method.
622 mock = self.proxy(object, spec, type, name, count, passthrough)
623 event = self._get_replay_restore_event()
624 event.add_task(ProxyReplacer(mock))
625 return mock
627 def patch(self, object, spec=True):
628 """Patch an existing object to reproduce recorded events.
630 @param object: Class or instance to be patched.
631 @param spec: Method calls will be checked for correctness against
632 the given object, which may be a class or an instance
633 where attributes will be looked up. Defaults to the
634 the C{object} parameter. May be set to None explicitly,
635 in which case spec checking is disabled. Checks may
636 also be disabled explicitly on a per-event basis with
637 the L{nospec()} method.
639 The result of this method is still a mock object, which can be
640 used like any other mock object to record events. The difference
641 is that when the mocker is put on replay mode, the *real* object
642 will be modified to behave according to recorded expectations.
644 Patching works in individual instances, and also in classes.
645 When an instance is patched, recorded events will only be
646 considered on this specific instance, and other instances should
647 behave normally. When a class is patched, the reproduction of
648 events will be considered on any instance of this class once
649 created (collectively).
651 Observe that, unlike with proxies which catch only events done
652 through the mock object, *all* accesses to recorded expectations
653 will be considered; even these coming from the object itself
654 (e.g. C{self.hello()} is considered if this method was patched).
655 While this is a very powerful feature, and many times the reason
656 to use patches in the first place, it's important to keep this
657 behavior in mind.
659 Patching of the original object only takes place when the mocker
660 is put on replay mode, and the patched object will be restored
661 to its original state once the L{restore()} method is called
662 (explicitly, or implicitly with alternative conventions, such as
663 a C{with mocker:} block, or a MockerTestCase class).
665 if spec is True:
666 spec = object
667 patcher = Patcher()
668 event = self._get_replay_restore_event()
669 event.add_task(patcher)
670 mock = Mock(self, object=object, patcher=patcher,
671 passthrough=True, spec=spec)
672 object.__mocker_mock__ = mock
673 return mock
675 def act(self, path):
676 """This is called by mock objects whenever something happens to them.
678 This method is part of the implementation between the mocker
679 and mock objects.
681 if self._recording:
682 event = self.add_event(Event(path))
683 for recorder in self._recorders:
684 recorder(self, event)
685 return Mock(self, path)
686 else:
687 # First run events that may run, then run unsatisfied events, then
688 # ones not previously run. We put the index in the ordering tuple
689 # instead of the actual event because we want a stable sort
690 # (ordering between 2 events is undefined).
691 events = self._events
692 order = [(events[i].satisfied()*2 + events[i].has_run(), i)
693 for i in range(len(events))]
694 order.sort()
695 postponed = None
696 for weight, i in order:
697 event = events[i]
698 if event.matches(path):
699 if event.may_run(path):
700 return event.run(path)
701 elif postponed is None:
702 postponed = event
703 if postponed is not None:
704 return postponed.run(path)
705 raise MatchError(ERROR_PREFIX + "Unexpected expression: %s" % path)
707 def get_recorders(cls, self):
708 """Return recorders associated with this mocker class or instance.
710 This method may be called on mocker instances and also on mocker
711 classes. See the L{add_recorder()} method for more information.
713 return (self or cls)._recorders[:]
714 get_recorders = classinstancemethod(get_recorders)
716 def add_recorder(cls, self, recorder):
717 """Add a recorder to this mocker class or instance.
719 @param recorder: Callable accepting C{(mocker, event)} as parameters.
721 This is part of the implementation of mocker.
723 All registered recorders are called for translating events that
724 happen during recording into expectations to be met once the state
725 is switched to replay mode.
727 This method may be called on mocker instances and also on mocker
728 classes. When called on a class, the recorder will be used by
729 all instances, and also inherited on subclassing. When called on
730 instances, the recorder is added only to the given instance.
732 (self or cls)._recorders.append(recorder)
733 return recorder
734 add_recorder = classinstancemethod(add_recorder)
736 def remove_recorder(cls, self, recorder):
737 """Remove the given recorder from this mocker class or instance.
739 This method may be called on mocker classes and also on mocker
740 instances. See the L{add_recorder()} method for more information.
742 (self or cls)._recorders.remove(recorder)
743 remove_recorder = classinstancemethod(remove_recorder)
745 def result(self, value):
746 """Make the last recorded event return the given value on replay.
748 @param value: Object to be returned when the event is replayed.
750 self.call(lambda *args, **kwargs: value)
752 def generate(self, sequence):
753 """Last recorded event will return a generator with the given sequence.
755 @param sequence: Sequence of values to be generated.
757 def generate(*args, **kwargs):
758 for value in sequence:
759 yield value
760 self.call(generate)
762 def throw(self, exception):
763 """Make the last recorded event raise the given exception on replay.
765 @param exception: Class or instance of exception to be raised.
767 def raise_exception(*args, **kwargs):
768 raise exception
769 self.call(raise_exception)
771 def call(self, func):
772 """Make the last recorded event cause the given function to be called.
774 @param func: Function to be called.
776 The result of the function will be used as the event result.
778 self._events[-1].add_task(FunctionRunner(func))
780 def count(self, min, max=False):
781 """Last recorded event must be replayed between min and max times.
783 @param min: Minimum number of times that the event must happen.
784 @param max: Maximum number of times that the event must happen. If
785 not given, it defaults to the same value of the C{min}
786 parameter. If set to None, there is no upper limit, and
787 the expectation is met as long as it happens at least
788 C{min} times.
790 event = self._events[-1]
791 for task in event.get_tasks():
792 if isinstance(task, RunCounter):
793 event.remove_task(task)
794 event.add_task(RunCounter(min, max))
796 def is_ordering(self):
797 """Return true if all events are being ordered.
799 See the L{order()} method.
801 return self._ordering
803 def unorder(self):
804 """Disable the ordered mode.
806 See the L{order()} method for more information.
808 self._ordering = False
809 self._last_orderer = None
811 def order(self, *path_holders):
812 """Create an expectation of order between two or more events.
814 @param path_holders: Objects returned as the result of recorded events.
816 By default, mocker won't force events to happen precisely in
817 the order they were recorded. Calling this method will change
818 this behavior so that events will only match if reproduced in
819 the correct order.
821 There are two ways in which this method may be used. Which one
822 is used in a given occasion depends only on convenience.
824 If no arguments are passed, the mocker will be put in a mode where
825 all the recorded events following the method call will only be met
826 if they happen in order. When that's used, the mocker may be put
827 back in unordered mode by calling the L{unorder()} method, or by
828 using a 'with' block, like so::
830 with mocker.ordered():
831 <record events>
833 In this case, only expressions in <record events> will be ordered,
834 and the mocker will be back in unordered mode after the 'with' block.
836 The second way to use it is by specifying precisely which events
837 should be ordered. As an example::
839 mock = mocker.mock()
840 expr1 = mock.hello()
841 expr2 = mock.world
842 expr3 = mock.x.y.z
843 mocker.order(expr1, expr2, expr3)
845 This method of ordering only works when the expression returns
846 another object.
848 Also check the L{after()} and L{before()} methods, which are
849 alternative ways to perform this.
851 if not path_holders:
852 self._ordering = True
853 return OrderedContext(self)
855 last_orderer = None
856 for path_holder in path_holders:
857 if type(path_holder) is Path:
858 path = path_holder
859 else:
860 path = path_holder.__mocker_path__
861 for event in self._events:
862 if event.path is path:
863 for task in event.get_tasks():
864 if isinstance(task, Orderer):
865 orderer = task
866 break
867 else:
868 orderer = Orderer(path)
869 event.add_task(orderer)
870 if last_orderer:
871 orderer.add_dependency(last_orderer)
872 last_orderer = orderer
873 break
875 def after(self, *path_holders):
876 """Last recorded event must happen after events referred to.
878 @param path_holders: Objects returned as the result of recorded events
879 which should happen before the last recorded event
881 As an example, the idiom::
883 expect(mock.x).after(mock.y, mock.z)
885 is an alternative way to say::
887 expr_x = mock.x
888 expr_y = mock.y
889 expr_z = mock.z
890 mocker.order(expr_y, expr_x)
891 mocker.order(expr_z, expr_x)
893 See L{order()} for more information.
895 last_path = self._events[-1].path
896 for path_holder in path_holders:
897 self.order(path_holder, last_path)
899 def before(self, *path_holders):
900 """Last recorded event must happen before events referred to.
902 @param path_holders: Objects returned as the result of recorded events
903 which should happen after the last recorded event
905 As an example, the idiom::
907 expect(mock.x).before(mock.y, mock.z)
909 is an alternative way to say::
911 expr_x = mock.x
912 expr_y = mock.y
913 expr_z = mock.z
914 mocker.order(expr_x, expr_y)
915 mocker.order(expr_x, expr_z)
917 See L{order()} for more information.
919 last_path = self._events[-1].path
920 for path_holder in path_holders:
921 self.order(last_path, path_holder)
923 def nospec(self):
924 """Don't check method specification of real object on last event.
926 By default, when using a mock created as the result of a call to
927 L{proxy()}, L{replace()}, and C{patch()}, or when passing the spec
928 attribute to the L{mock()} method, method calls on the given object
929 are checked for correctness against the specification of the real
930 object (or the explicitly provided spec).
932 This method will disable that check specifically for the last
933 recorded event.
935 event = self._events[-1]
936 for task in event.get_tasks():
937 if isinstance(task, SpecChecker):
938 event.remove_task(task)
940 def passthrough(self, result_callback=None):
941 """Make the last recorded event run on the real object once seen.
943 @param result_callback: If given, this function will be called with
944 the result of the *real* method call as the only argument.
946 This can only be used on proxies, as returned by the L{proxy()}
947 and L{replace()} methods, or on mocks representing patched objects,
948 as returned by the L{patch()} method.
950 event = self._events[-1]
951 if event.path.root_object is None:
952 raise TypeError("Mock object isn't a proxy")
953 event.add_task(PathExecuter(result_callback))
955 def __enter__(self):
956 """Enter in a 'with' context. This will run replay()."""
957 self.replay()
958 return self
960 def __exit__(self, type, value, traceback):
961 """Exit from a 'with' context.
963 This will run restore() at all times, but will only run verify()
964 if the 'with' block itself hasn't raised an exception. Exceptions
965 in that block are never swallowed.
967 self.restore()
968 if type is None:
969 self.verify()
970 return False
972 def _get_replay_restore_event(self):
973 """Return unique L{ReplayRestoreEvent}, creating if needed.
975 Some tasks only want to replay/restore. When that's the case,
976 they shouldn't act on other events during replay. Also, they
977 can all be put in a single event when that's the case. Thus,
978 we add a single L{ReplayRestoreEvent} as the first element of
979 the list.
981 if not self._events or type(self._events[0]) != ReplayRestoreEvent:
982 self._events.insert(0, ReplayRestoreEvent())
983 return self._events[0]
986 class OrderedContext(object):
988 def __init__(self, mocker):
989 self._mocker = mocker
991 def __enter__(self):
992 return None
994 def __exit__(self, type, value, traceback):
995 self._mocker.unorder()
998 class Mocker(MockerBase):
999 __doc__ = MockerBase.__doc__
1001 # Decorator to add recorders on the standard Mocker class.
1002 recorder = Mocker.add_recorder
1005 # --------------------------------------------------------------------
1006 # Mock object.
1008 class Mock(object):
1010 def __init__(self, mocker, path=None, name=None, spec=None, type=None,
1011 object=None, passthrough=False, patcher=None, count=True):
1012 self.__mocker__ = mocker
1013 self.__mocker_path__ = path or Path(self, object)
1014 self.__mocker_name__ = name
1015 self.__mocker_spec__ = spec
1016 self.__mocker_object__ = object
1017 self.__mocker_passthrough__ = passthrough
1018 self.__mocker_patcher__ = patcher
1019 self.__mocker_replace__ = False
1020 self.__mocker_type__ = type
1021 self.__mocker_count__ = count
1023 def __mocker_act__(self, kind, args=(), kwargs={}, object=None):
1024 if self.__mocker_name__ is None:
1025 self.__mocker_name__ = find_object_name(self, 2)
1026 action = Action(kind, args, kwargs, self.__mocker_path__)
1027 path = self.__mocker_path__ + action
1028 if object is not None:
1029 path.root_object = object
1030 try:
1031 return self.__mocker__.act(path)
1032 except MatchError, exception:
1033 root_mock = path.root_mock
1034 if (path.root_object is not None and
1035 root_mock.__mocker_passthrough__):
1036 return path.execute(path.root_object)
1037 # Reinstantiate to show raise statement on traceback, and
1038 # also to make the traceback shown shorter.
1039 raise MatchError(str(exception))
1040 except AssertionError, e:
1041 lines = str(e).splitlines()
1042 message = [ERROR_PREFIX + "Unmet expectation:", ""]
1043 message.append("=> " + lines.pop(0))
1044 message.extend([" " + line for line in lines])
1045 message.append("")
1046 raise AssertionError(os.linesep.join(message))
1048 def __getattribute__(self, name):
1049 if name.startswith("__mocker_"):
1050 return super(Mock, self).__getattribute__(name)
1051 if name == "__class__":
1052 if self.__mocker__.is_recording() or self.__mocker_type__ is None:
1053 return type(self)
1054 return self.__mocker_type__
1055 return self.__mocker_act__("getattr", (name,))
1057 def __setattr__(self, name, value):
1058 if name.startswith("__mocker_"):
1059 return super(Mock, self).__setattr__(name, value)
1060 return self.__mocker_act__("setattr", (name, value))
1062 def __delattr__(self, name):
1063 return self.__mocker_act__("delattr", (name,))
1065 def __call__(self, *args, **kwargs):
1066 return self.__mocker_act__("call", args, kwargs)
1068 def __contains__(self, value):
1069 return self.__mocker_act__("contains", (value,))
1071 def __getitem__(self, key):
1072 return self.__mocker_act__("getitem", (key,))
1074 def __setitem__(self, key, value):
1075 return self.__mocker_act__("setitem", (key, value))
1077 def __delitem__(self, key):
1078 return self.__mocker_act__("delitem", (key,))
1080 def __len__(self):
1081 # MatchError is turned on an AttributeError so that list() and
1082 # friends act properly when trying to get length hints on
1083 # something that doesn't offer them.
1084 try:
1085 result = self.__mocker_act__("len")
1086 except MatchError, e:
1087 raise AttributeError(str(e))
1088 if type(result) is Mock:
1089 return 0
1090 return result
1092 def __nonzero__(self):
1093 try:
1094 return self.__mocker_act__("nonzero")
1095 except MatchError, e:
1096 return True
1098 def __iter__(self):
1099 # XXX On py3k, when next() becomes __next__(), we'll be able
1100 # to return the mock itself because it will be considered
1101 # an iterator (we'll be mocking __next__ as well, which we
1102 # can't now).
1103 result = self.__mocker_act__("iter")
1104 if type(result) is Mock:
1105 return iter([])
1106 return result
1108 # When adding a new action kind here, also add support for it on
1109 # Action.execute() and Path.__str__().
1112 def find_object_name(obj, depth=0):
1113 """Try to detect how the object is named on a previous scope."""
1114 try:
1115 frame = sys._getframe(depth+1)
1116 except:
1117 return None
1118 for name, frame_obj in frame.f_locals.iteritems():
1119 if frame_obj is obj:
1120 return name
1121 self = frame.f_locals.get("self")
1122 if self is not None:
1123 try:
1124 items = list(self.__dict__.iteritems())
1125 except:
1126 pass
1127 else:
1128 for name, self_obj in items:
1129 if self_obj is obj:
1130 return name
1131 return None
1134 # --------------------------------------------------------------------
1135 # Action and path.
1137 class Action(object):
1139 def __init__(self, kind, args, kwargs, path=None):
1140 self.kind = kind
1141 self.args = args
1142 self.kwargs = kwargs
1143 self.path = path
1144 self._execute_cache = {}
1146 def __repr__(self):
1147 if self.path is None:
1148 return "Action(%r, %r, %r)" % (self.kind, self.args, self.kwargs)
1149 return "Action(%r, %r, %r, %r)" % \
1150 (self.kind, self.args, self.kwargs, self.path)
1152 def __eq__(self, other):
1153 return (self.kind == other.kind and
1154 self.args == other.args and
1155 self.kwargs == other.kwargs)
1157 def __ne__(self, other):
1158 return not self.__eq__(other)
1160 def matches(self, other):
1161 return (self.kind == other.kind and
1162 match_params(self.args, self.kwargs, other.args, other.kwargs))
1164 def execute(self, object):
1165 # This caching scheme may fail if the object gets deallocated before
1166 # the action, as the id might get reused. It's somewhat easy to fix
1167 # that with a weakref callback. For our uses, though, the object
1168 # should never get deallocated before the action itself, so we'll
1169 # just keep it simple.
1170 if id(object) in self._execute_cache:
1171 return self._execute_cache[id(object)]
1172 execute = getattr(object, "__mocker_execute__", None)
1173 if execute is not None:
1174 result = execute(self, object)
1175 else:
1176 kind = self.kind
1177 if kind == "getattr":
1178 result = getattr(object, self.args[0])
1179 elif kind == "setattr":
1180 result = setattr(object, self.args[0], self.args[1])
1181 elif kind == "delattr":
1182 result = delattr(object, self.args[0])
1183 elif kind == "call":
1184 result = object(*self.args, **self.kwargs)
1185 elif kind == "contains":
1186 result = self.args[0] in object
1187 elif kind == "getitem":
1188 result = object[self.args[0]]
1189 elif kind == "setitem":
1190 result = object[self.args[0]] = self.args[1]
1191 elif kind == "delitem":
1192 del object[self.args[0]]
1193 result = None
1194 elif kind == "len":
1195 result = len(object)
1196 elif kind == "nonzero":
1197 result = bool(object)
1198 elif kind == "iter":
1199 result = iter(object)
1200 else:
1201 raise RuntimeError("Don't know how to execute %r kind." % kind)
1202 self._execute_cache[id(object)] = result
1203 return result
1206 class Path(object):
1208 def __init__(self, root_mock, root_object=None, actions=()):
1209 self.root_mock = root_mock
1210 self.root_object = root_object
1211 self.actions = tuple(actions)
1212 self.__mocker_replace__ = False
1214 def parent_path(self):
1215 if not self.actions:
1216 return None
1217 return self.actions[-1].path
1218 parent_path = property(parent_path)
1220 def __add__(self, action):
1221 """Return a new path which includes the given action at the end."""
1222 return self.__class__(self.root_mock, self.root_object,
1223 self.actions + (action,))
1225 def __eq__(self, other):
1226 """Verify if the two paths are equal.
1228 Two paths are equal if they refer to the same mock object, and
1229 have the actions with equal kind, args and kwargs.
1231 if (self.root_mock is not other.root_mock or
1232 self.root_object is not other.root_object or
1233 len(self.actions) != len(other.actions)):
1234 return False
1235 for action, other_action in zip(self.actions, other.actions):
1236 if action != other_action:
1237 return False
1238 return True
1240 def matches(self, other):
1241 """Verify if the two paths are equivalent.
1243 Two paths are equal if they refer to the same mock object, and
1244 have the same actions performed on them.
1246 if (self.root_mock is not other.root_mock or
1247 len(self.actions) != len(other.actions)):
1248 return False
1249 for action, other_action in zip(self.actions, other.actions):
1250 if not action.matches(other_action):
1251 return False
1252 return True
1254 def execute(self, object):
1255 """Execute all actions sequentially on object, and return result.
1257 for action in self.actions:
1258 object = action.execute(object)
1259 return object
1261 def __str__(self):
1262 """Transform the path into a nice string such as obj.x.y('z')."""
1263 result = self.root_mock.__mocker_name__ or "<mock>"
1264 for action in self.actions:
1265 if action.kind == "getattr":
1266 result = "%s.%s" % (result, action.args[0])
1267 elif action.kind == "setattr":
1268 result = "%s.%s = %r" % (result, action.args[0], action.args[1])
1269 elif action.kind == "delattr":
1270 result = "del %s.%s" % (result, action.args[0])
1271 elif action.kind == "call":
1272 args = [repr(x) for x in action.args]
1273 items = list(action.kwargs.iteritems())
1274 items.sort()
1275 for pair in items:
1276 args.append("%s=%r" % pair)
1277 result = "%s(%s)" % (result, ", ".join(args))
1278 elif action.kind == "contains":
1279 result = "%r in %s" % (action.args[0], result)
1280 elif action.kind == "getitem":
1281 result = "%s[%r]" % (result, action.args[0])
1282 elif action.kind == "setitem":
1283 result = "%s[%r] = %r" % (result, action.args[0],
1284 action.args[1])
1285 elif action.kind == "delitem":
1286 result = "del %s[%r]" % (result, action.args[0])
1287 elif action.kind == "len":
1288 result = "len(%s)" % result
1289 elif action.kind == "nonzero":
1290 result = "bool(%s)" % result
1291 elif action.kind == "iter":
1292 result = "iter(%s)" % result
1293 else:
1294 raise RuntimeError("Don't know how to format kind %r" %
1295 action.kind)
1296 return result
1299 class SpecialArgument(object):
1300 """Base for special arguments for matching parameters."""
1302 def __init__(self, object=None):
1303 self.object = object
1305 def __repr__(self):
1306 if self.object is None:
1307 return self.__class__.__name__
1308 else:
1309 return "%s(%r)" % (self.__class__.__name__, self.object)
1311 def matches(self, other):
1312 return True
1314 def __eq__(self, other):
1315 return type(other) == type(self) and self.object == other.object
1318 class ANY(SpecialArgument):
1319 """Matches any single argument."""
1321 ANY = ANY()
1324 class ARGS(SpecialArgument):
1325 """Matches zero or more positional arguments."""
1327 ARGS = ARGS()
1330 class KWARGS(SpecialArgument):
1331 """Matches zero or more keyword arguments."""
1333 KWARGS = KWARGS()
1336 class IS(SpecialArgument):
1338 def matches(self, other):
1339 return self.object is other
1341 def __eq__(self, other):
1342 return type(other) == type(self) and self.object is other.object
1345 class CONTAINS(SpecialArgument):
1347 def matches(self, other):
1348 try:
1349 other.__contains__
1350 except AttributeError:
1351 try:
1352 iter(other)
1353 except TypeError:
1354 # If an object can't be iterated, and has no __contains__
1355 # hook, it'd blow up on the test below. We test this in
1356 # advance to prevent catching more errors than we really
1357 # want.
1358 return False
1359 return self.object in other
1362 class IN(SpecialArgument):
1364 def matches(self, other):
1365 return other in self.object
1368 class MATCH(SpecialArgument):
1370 def matches(self, other):
1371 return bool(self.object(other))
1373 def __eq__(self, other):
1374 return type(other) == type(self) and self.object is other.object
1377 def match_params(args1, kwargs1, args2, kwargs2):
1378 """Match the two sets of parameters, considering special parameters."""
1380 has_args = ARGS in args1
1381 has_kwargs = KWARGS in args1
1383 if has_kwargs:
1384 args1 = [arg1 for arg1 in args1 if arg1 is not KWARGS]
1385 elif len(kwargs1) != len(kwargs2):
1386 return False
1388 if not has_args and len(args1) != len(args2):
1389 return False
1391 # Either we have the same number of kwargs, or unknown keywords are
1392 # accepted (KWARGS was used), so check just the ones in kwargs1.
1393 for key, arg1 in kwargs1.iteritems():
1394 if key not in kwargs2:
1395 return False
1396 arg2 = kwargs2[key]
1397 if isinstance(arg1, SpecialArgument):
1398 if not arg1.matches(arg2):
1399 return False
1400 elif arg1 != arg2:
1401 return False
1403 # Keywords match. Now either we have the same number of
1404 # arguments, or ARGS was used. If ARGS wasn't used, arguments
1405 # must match one-on-one necessarily.
1406 if not has_args:
1407 for arg1, arg2 in zip(args1, args2):
1408 if isinstance(arg1, SpecialArgument):
1409 if not arg1.matches(arg2):
1410 return False
1411 elif arg1 != arg2:
1412 return False
1413 return True
1415 # Easy choice. Keywords are matching, and anything on args is accepted.
1416 if (ARGS,) == args1:
1417 return True
1419 # We have something different there. If we don't have positional
1420 # arguments on the original call, it can't match.
1421 if not args2:
1422 # Unless we have just several ARGS (which is bizarre, but..).
1423 for arg1 in args1:
1424 if arg1 is not ARGS:
1425 return False
1426 return True
1428 # Ok, all bets are lost. We have to actually do the more expensive
1429 # matching. This is an algorithm based on the idea of the Levenshtein
1430 # Distance between two strings, but heavily hacked for this purpose.
1431 args2l = len(args2)
1432 if args1[0] is ARGS:
1433 args1 = args1[1:]
1434 array = [0]*args2l
1435 else:
1436 array = [1]*args2l
1437 for i in range(len(args1)):
1438 last = array[0]
1439 if args1[i] is ARGS:
1440 for j in range(1, args2l):
1441 last, array[j] = array[j], min(array[j-1], array[j], last)
1442 else:
1443 array[0] = i or int(args1[i] != args2[0])
1444 for j in range(1, args2l):
1445 last, array[j] = array[j], last or int(args1[i] != args2[j])
1446 if 0 not in array:
1447 return False
1448 if array[-1] != 0:
1449 return False
1450 return True
1453 # --------------------------------------------------------------------
1454 # Event and task base.
1456 class Event(object):
1457 """Aggregation of tasks that keep track of a recorded action.
1459 An event represents something that may or may not happen while the
1460 mocked environment is running, such as an attribute access, or a
1461 method call. The event is composed of several tasks that are
1462 orchestrated together to create a composed meaning for the event,
1463 including for which actions it should be run, what happens when it
1464 runs, and what's the expectations about the actions run.
1467 def __init__(self, path=None):
1468 self.path = path
1469 self._tasks = []
1470 self._has_run = False
1472 def add_task(self, task):
1473 """Add a new task to this taks."""
1474 self._tasks.append(task)
1475 return task
1477 def remove_task(self, task):
1478 self._tasks.remove(task)
1480 def get_tasks(self):
1481 return self._tasks[:]
1483 def matches(self, path):
1484 """Return true if *all* tasks match the given path."""
1485 for task in self._tasks:
1486 if not task.matches(path):
1487 return False
1488 return bool(self._tasks)
1490 def has_run(self):
1491 return self._has_run
1493 def may_run(self, path):
1494 """Verify if any task would certainly raise an error if run.
1496 This will call the C{may_run()} method on each task and return
1497 false if any of them returns false.
1499 for task in self._tasks:
1500 if not task.may_run(path):
1501 return False
1502 return True
1504 def run(self, path):
1505 """Run all tasks with the given action.
1507 @param path: The path of the expression run.
1509 Running an event means running all of its tasks individually and in
1510 order. An event should only ever be run if all of its tasks claim to
1511 match the given action.
1513 The result of this method will be the last result of a task
1514 which isn't None, or None if they're all None.
1516 self._has_run = True
1517 result = None
1518 errors = []
1519 for task in self._tasks:
1520 try:
1521 task_result = task.run(path)
1522 except AssertionError, e:
1523 error = str(e)
1524 if not error:
1525 raise RuntimeError("Empty error message from %r" % task)
1526 errors.append(error)
1527 else:
1528 if task_result is not None:
1529 result = task_result
1530 if errors:
1531 message = [str(self.path)]
1532 if str(path) != message[0]:
1533 message.append("- Run: %s" % path)
1534 for error in errors:
1535 lines = error.splitlines()
1536 message.append("- " + lines.pop(0))
1537 message.extend([" " + line for line in lines])
1538 raise AssertionError(os.linesep.join(message))
1539 return result
1541 def satisfied(self):
1542 """Return true if all tasks are satisfied.
1544 Being satisfied means that there are no unmet expectations.
1546 for task in self._tasks:
1547 try:
1548 task.verify()
1549 except AssertionError:
1550 return False
1551 return True
1553 def verify(self):
1554 """Run verify on all tasks.
1556 The verify method is supposed to raise an AssertionError if the
1557 task has unmet expectations, with a one-line explanation about
1558 why this item is unmet. This method should be safe to be called
1559 multiple times without side effects.
1561 errors = []
1562 for task in self._tasks:
1563 try:
1564 task.verify()
1565 except AssertionError, e:
1566 error = str(e)
1567 if not error:
1568 raise RuntimeError("Empty error message from %r" % task)
1569 errors.append(error)
1570 if errors:
1571 message = [str(self.path)]
1572 for error in errors:
1573 lines = error.splitlines()
1574 message.append("- " + lines.pop(0))
1575 message.extend([" " + line for line in lines])
1576 raise AssertionError(os.linesep.join(message))
1578 def replay(self):
1579 """Put all tasks in replay mode."""
1580 self._has_run = False
1581 for task in self._tasks:
1582 task.replay()
1584 def restore(self):
1585 """Restore the state of all tasks."""
1586 for task in self._tasks:
1587 task.restore()
1590 class ReplayRestoreEvent(Event):
1591 """Helper event for tasks which need replay/restore but shouldn't match."""
1593 def matches(self, path):
1594 return False
1597 class Task(object):
1598 """Element used to track one specific aspect on an event.
1600 A task is responsible for adding any kind of logic to an event.
1601 Examples of that are counting the number of times the event was
1602 made, verifying parameters if any, and so on.
1605 def matches(self, path):
1606 """Return true if the task is supposed to be run for the given path.
1608 return True
1610 def may_run(self, path):
1611 """Return false if running this task would certainly raise an error."""
1612 return True
1614 def run(self, path):
1615 """Perform the task item, considering that the given action happened.
1618 def verify(self):
1619 """Raise AssertionError if expectations for this item are unmet.
1621 The verify method is supposed to raise an AssertionError if the
1622 task has unmet expectations, with a one-line explanation about
1623 why this item is unmet. This method should be safe to be called
1624 multiple times without side effects.
1627 def replay(self):
1628 """Put the task in replay mode.
1630 Any expectations of the task should be reset.
1633 def restore(self):
1634 """Restore any environmental changes made by the task.
1636 Verify should continue to work after this is called.
1640 # --------------------------------------------------------------------
1641 # Task implementations.
1643 class OnRestoreCaller(Task):
1644 """Call a given callback when restoring."""
1646 def __init__(self, callback):
1647 self._callback = callback
1649 def restore(self):
1650 self._callback()
1653 class PathMatcher(Task):
1654 """Match the action path against a given path."""
1656 def __init__(self, path):
1657 self.path = path
1659 def matches(self, path):
1660 return self.path.matches(path)
1662 def path_matcher_recorder(mocker, event):
1663 event.add_task(PathMatcher(event.path))
1665 Mocker.add_recorder(path_matcher_recorder)
1668 class RunCounter(Task):
1669 """Task which verifies if the number of runs are within given boundaries.
1672 def __init__(self, min, max=False):
1673 self.min = min
1674 if max is None:
1675 self.max = sys.maxint
1676 elif max is False:
1677 self.max = min
1678 else:
1679 self.max = max
1680 self._runs = 0
1682 def replay(self):
1683 self._runs = 0
1685 def may_run(self, path):
1686 return self._runs < self.max
1688 def run(self, path):
1689 self._runs += 1
1690 if self._runs > self.max:
1691 self.verify()
1693 def verify(self):
1694 if not self.min <= self._runs <= self.max:
1695 if self._runs < self.min:
1696 raise AssertionError("Performed fewer times than expected.")
1697 raise AssertionError("Performed more times than expected.")
1700 class ImplicitRunCounter(RunCounter):
1701 """RunCounter inserted by default on any event.
1703 This is a way to differentiate explicitly added counters and
1704 implicit ones.
1707 def run_counter_recorder(mocker, event):
1708 """Any event may be repeated once, unless disabled by default."""
1709 if event.path.root_mock.__mocker_count__:
1710 event.add_task(ImplicitRunCounter(1))
1712 Mocker.add_recorder(run_counter_recorder)
1714 def run_counter_removal_recorder(mocker, event):
1716 Events created by getattr actions which lead to other events
1717 may be repeated any number of times. For that, we remove implicit
1718 run counters of any getattr actions leading to the current one.
1720 parent_path = event.path.parent_path
1721 for event in mocker.get_events()[::-1]:
1722 if (event.path is parent_path and
1723 event.path.actions[-1].kind == "getattr"):
1724 for task in event.get_tasks():
1725 if type(task) is ImplicitRunCounter:
1726 event.remove_task(task)
1728 Mocker.add_recorder(run_counter_removal_recorder)
1731 class MockReturner(Task):
1732 """Return a mock based on the action path."""
1734 def __init__(self, mocker):
1735 self.mocker = mocker
1737 def run(self, path):
1738 return Mock(self.mocker, path)
1740 def mock_returner_recorder(mocker, event):
1741 """Events that lead to other events must return mock objects."""
1742 parent_path = event.path.parent_path
1743 for event in mocker.get_events():
1744 if event.path is parent_path:
1745 for task in event.get_tasks():
1746 if isinstance(task, MockReturner):
1747 break
1748 else:
1749 event.add_task(MockReturner(mocker))
1750 break
1752 Mocker.add_recorder(mock_returner_recorder)
1755 class FunctionRunner(Task):
1756 """Task that runs a function everything it's run.
1758 Arguments of the last action in the path are passed to the function,
1759 and the function result is also returned.
1762 def __init__(self, func):
1763 self._func = func
1765 def run(self, path):
1766 action = path.actions[-1]
1767 return self._func(*action.args, **action.kwargs)
1770 class PathExecuter(Task):
1771 """Task that executes a path in the real object, and returns the result."""
1773 def __init__(self, result_callback=None):
1774 self._result_callback = result_callback
1776 def get_result_callback(self):
1777 return self._result_callback
1779 def run(self, path):
1780 result = path.execute(path.root_object)
1781 if self._result_callback is not None:
1782 self._result_callback(result)
1783 return result
1786 class Orderer(Task):
1787 """Task to establish an order relation between two events.
1789 An orderer task will only match once all its dependencies have
1790 been run.
1793 def __init__(self, path):
1794 self.path = path
1795 self._run = False
1796 self._dependencies = []
1798 def replay(self):
1799 self._run = False
1801 def has_run(self):
1802 return self._run
1804 def may_run(self, path):
1805 for dependency in self._dependencies:
1806 if not dependency.has_run():
1807 return False
1808 return True
1810 def run(self, path):
1811 for dependency in self._dependencies:
1812 if not dependency.has_run():
1813 raise AssertionError("Should be after: %s" % dependency.path)
1814 self._run = True
1816 def add_dependency(self, orderer):
1817 self._dependencies.append(orderer)
1819 def get_dependencies(self):
1820 return self._dependencies
1823 class SpecChecker(Task):
1824 """Task to check if arguments of the last action conform to a real method.
1827 def __init__(self, method):
1828 self._method = method
1829 self._unsupported = False
1831 if method:
1832 try:
1833 self._args, self._varargs, self._varkwargs, self._defaults = \
1834 inspect.getargspec(method)
1835 except TypeError:
1836 self._unsupported = True
1837 else:
1838 if self._defaults is None:
1839 self._defaults = ()
1840 if type(method) is type(self.run):
1841 self._args = self._args[1:]
1843 def get_method(self):
1844 return self._method
1846 def _raise(self, message):
1847 spec = inspect.formatargspec(self._args, self._varargs,
1848 self._varkwargs, self._defaults)
1849 raise AssertionError("Specification is %s%s: %s" %
1850 (self._method.__name__, spec, message))
1852 def verify(self):
1853 if not self._method:
1854 raise AssertionError("Method not found in real specification")
1856 def may_run(self, path):
1857 try:
1858 self.run(path)
1859 except AssertionError:
1860 return False
1861 return True
1863 def run(self, path):
1864 if not self._method:
1865 raise AssertionError("Method not found in real specification")
1866 if self._unsupported:
1867 return # Can't check it. Happens with builtin functions. :-(
1868 action = path.actions[-1]
1869 obtained_len = len(action.args)
1870 obtained_kwargs = action.kwargs.copy()
1871 nodefaults_len = len(self._args) - len(self._defaults)
1872 for i, name in enumerate(self._args):
1873 if i < obtained_len and name in action.kwargs:
1874 self._raise("%r provided twice" % name)
1875 if (i >= obtained_len and i < nodefaults_len and
1876 name not in action.kwargs):
1877 self._raise("%r not provided" % name)
1878 obtained_kwargs.pop(name, None)
1879 if obtained_len > len(self._args) and not self._varargs:
1880 self._raise("too many args provided")
1881 if obtained_kwargs and not self._varkwargs:
1882 self._raise("unknown kwargs: %s" % ", ".join(obtained_kwargs))
1884 def spec_checker_recorder(mocker, event):
1885 spec = event.path.root_mock.__mocker_spec__
1886 if spec:
1887 actions = event.path.actions
1888 if len(actions) == 1:
1889 if actions[0].kind == "call":
1890 method = getattr(spec, "__call__", None)
1891 event.add_task(SpecChecker(method))
1892 elif len(actions) == 2:
1893 if actions[0].kind == "getattr" and actions[1].kind == "call":
1894 method = getattr(spec, actions[0].args[0], None)
1895 event.add_task(SpecChecker(method))
1897 Mocker.add_recorder(spec_checker_recorder)
1900 class ProxyReplacer(Task):
1901 """Task which installs and deinstalls proxy mocks.
1903 This task will replace a real object by a mock in all dictionaries
1904 found in the running interpreter via the garbage collecting system.
1907 def __init__(self, mock):
1908 self.mock = mock
1909 self.__mocker_replace__ = False
1911 def replay(self):
1912 global_replace(self.mock.__mocker_object__, self.mock)
1914 def restore(self):
1915 global_replace(self.mock, self.mock.__mocker_object__)
1918 def global_replace(remove, install):
1919 """Replace object 'remove' with object 'install' on all dictionaries."""
1920 for referrer in gc.get_referrers(remove):
1921 if (type(referrer) is dict and
1922 referrer.get("__mocker_replace__", True)):
1923 for key, value in referrer.items():
1924 if value is remove:
1925 referrer[key] = install
1928 class Undefined(object):
1930 def __repr__(self):
1931 return "Undefined"
1933 Undefined = Undefined()
1936 class Patcher(Task):
1938 def __init__(self):
1939 super(Patcher, self).__init__()
1940 self._monitored = {} # {kind: {id(object): object}}
1941 self._patched = {}
1943 def is_monitoring(self, obj, kind):
1944 monitored = self._monitored.get(kind)
1945 if monitored:
1946 if id(obj) in monitored:
1947 return True
1948 cls = type(obj)
1949 if issubclass(cls, type):
1950 cls = obj
1951 bases = set([id(base) for base in cls.__mro__])
1952 bases.intersection_update(monitored)
1953 return bool(bases)
1954 return False
1956 def monitor(self, obj, kind):
1957 if kind not in self._monitored:
1958 self._monitored[kind] = {}
1959 self._monitored[kind][id(obj)] = obj
1961 def patch_attr(self, obj, attr, value):
1962 original = obj.__dict__.get(attr, Undefined)
1963 self._patched[id(obj), attr] = obj, attr, original
1964 setattr(obj, attr, value)
1966 def get_unpatched_attr(self, obj, attr):
1967 cls = type(obj)
1968 if issubclass(cls, type):
1969 cls = obj
1970 result = Undefined
1971 for mro_cls in cls.__mro__:
1972 key = (id(mro_cls), attr)
1973 if key in self._patched:
1974 result = self._patched[key][2]
1975 if result is not Undefined:
1976 break
1977 elif attr in mro_cls.__dict__:
1978 result = mro_cls.__dict__.get(attr, Undefined)
1979 break
1980 if isinstance(result, object) and hasattr(type(result), "__get__"):
1981 if cls is obj:
1982 obj = None
1983 return result.__get__(obj, cls)
1984 return result
1986 def _get_kind_attr(self, kind):
1987 if kind == "getattr":
1988 return "__getattribute__"
1989 return "__%s__" % kind
1991 def replay(self):
1992 for kind in self._monitored:
1993 attr = self._get_kind_attr(kind)
1994 seen = set()
1995 for obj in self._monitored[kind].itervalues():
1996 cls = type(obj)
1997 if issubclass(cls, type):
1998 cls = obj
1999 if cls not in seen:
2000 seen.add(cls)
2001 unpatched = getattr(cls, attr, Undefined)
2002 self.patch_attr(cls, attr,
2003 PatchedMethod(kind, unpatched,
2004 self.is_monitoring))
2005 self.patch_attr(cls, "__mocker_execute__",
2006 self.execute)
2008 def restore(self):
2009 for obj, attr, original in self._patched.itervalues():
2010 if original is Undefined:
2011 delattr(obj, attr)
2012 else:
2013 setattr(obj, attr, original)
2014 self._patched.clear()
2016 def execute(self, action, object):
2017 attr = self._get_kind_attr(action.kind)
2018 unpatched = self.get_unpatched_attr(object, attr)
2019 try:
2020 return unpatched(*action.args, **action.kwargs)
2021 except AttributeError:
2022 if action.kind == "getattr":
2023 # The normal behavior of Python is to try __getattribute__,
2024 # and if it raises AttributeError, try __getattr__. We've
2025 # tried the unpatched __getattribute__ above, and we'll now
2026 # try __getattr__.
2027 try:
2028 __getattr__ = unpatched("__getattr__")
2029 except AttributeError:
2030 pass
2031 else:
2032 return __getattr__(*action.args, **action.kwargs)
2033 raise
2036 class PatchedMethod(object):
2038 def __init__(self, kind, unpatched, is_monitoring):
2039 self._kind = kind
2040 self._unpatched = unpatched
2041 self._is_monitoring = is_monitoring
2043 def __get__(self, obj, cls=None):
2044 object = obj or cls
2045 if not self._is_monitoring(object, self._kind):
2046 return self._unpatched.__get__(obj, cls)
2047 def method(*args, **kwargs):
2048 if self._kind == "getattr" and args[0].startswith("__mocker_"):
2049 return self._unpatched.__get__(obj, cls)(args[0])
2050 mock = object.__mocker_mock__
2051 return mock.__mocker_act__(self._kind, args, kwargs, object)
2052 return method
2054 def __call__(self, obj, *args, **kwargs):
2055 # At least with __getattribute__, Python seems to use *both* the
2056 # descriptor API and also call the class attribute directly. It
2057 # looks like an interpreter bug, or at least an undocumented
2058 # inconsistency.
2059 return self.__get__(obj)(*args, **kwargs)
2062 def patcher_recorder(mocker, event):
2063 mock = event.path.root_mock
2064 if mock.__mocker_patcher__ and len(event.path.actions) == 1:
2065 patcher = mock.__mocker_patcher__
2066 patcher.monitor(mock.__mocker_object__, event.path.actions[0].kind)
2068 Mocker.add_recorder(patcher_recorder)