~ubuntuone-control-tower/ubuntuone-storage-protocol/stable-1-6

« back to all changes in this revision

Viewing changes to contrib/mocker.py

  • Committer: Tarmac
  • Author(s): Rodney Dawes
  • Date: 2010-11-16 15:10:48 UTC
  • mfrom: (121.1.4 use-packages)
  • Revision ID: tarmac-20101116151048-b0e20j7lorb4yhe1
Switch to using packaged mocker and ubuntuone-dev-tools
Use pyflakes with u1lint and also run pep8
Fix a lot of pylint/pyflakes/pep8 errors

Show diffs side-by-side

added added

removed removed

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