15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# mock.py
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Test tools for mocking and patching.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright (C) 2007-2009 Michael Foord
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# E-mail: fuzzyman AT voidspace DOT org DOT uk
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# mock 0.6.0
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# http://www.voidspace.org.uk/python/mock/
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Released subject to the BSD License
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Please see http://www.voidspace.org.uk/python/license.shtml
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# 2009-11-25: Licence downloaded from above URL.
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# BEGIN DOWNLOADED LICENSE
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright (c) 2003-2009, Michael Foord
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# All rights reserved.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# E-mail : fuzzyman AT voidspace DOT org DOT uk
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Redistribution and use in source and binary forms, with or without
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# modification, are permitted provided that the following conditions are
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# met:
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions of source code must retain the above copyright
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#       notice, this list of conditions and the following disclaimer.
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Redistributions in binary form must reproduce the above
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#       copyright notice, this list of conditions and the following
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#       disclaimer in the documentation and/or other materials provided
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#       with the distribution.
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#     * Neither the name of Michael Foord nor the name of Voidspace
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#       may be used to endorse or promote products derived from this
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#       software without specific prior written permission.
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# END DOWNLOADED LICENSE
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Comments, suggestions and bug reports welcome.
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)__all__ = (
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'Mock',
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'patch',
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'patch_object',
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'sentinel',
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    'DEFAULT'
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles))
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)__version__ = '0.6.0'
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class SentinelObject(object):
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, name):
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.name = name
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __repr__(self):
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return '<SentinelObject "%s">' % self.name
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class Sentinel(object):
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self):
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._sentinels = {}
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __getattr__(self, name):
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._sentinels.setdefault(name, SentinelObject(name))
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)sentinel = Sentinel()
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)DEFAULT = sentinel.DEFAULT
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class OldStyleClass:
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    pass
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)ClassType = type(OldStyleClass)
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _is_magic(name):
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return '__%s__' % name[2:-2] == name
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _copy(value):
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if type(value) in (dict, list, tuple, set):
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return type(value)(value)
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return value
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class Mock(object):
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 name=None, parent=None, wraps=None):
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._parent = parent
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._name = name
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if spec is not None and not isinstance(spec, list):
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            spec = [member for member in dir(spec) if not _is_magic(member)]
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._methods = spec
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._children = {}
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._return_value = return_value
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.side_effect = side_effect
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._wraps = wraps
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.reset_mock()
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def reset_mock(self):
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.called = False
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.call_args = None
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.call_count = 0
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.call_args_list = []
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.method_calls = []
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for child in self._children.itervalues():
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            child.reset_mock()
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if isinstance(self._return_value, Mock):
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._return_value.reset_mock()
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __get_return_value(self):
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._return_value is DEFAULT:
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._return_value = Mock()
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._return_value
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __set_return_value(self, value):
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self._return_value = value
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return_value = property(__get_return_value, __set_return_value)
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __call__(self, *args, **kwargs):
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.called = True
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.call_count += 1
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.call_args = (args, kwargs)
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.call_args_list.append((args, kwargs))
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        parent = self._parent
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        name = self._name
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        while parent is not None:
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            parent.method_calls.append((name, args, kwargs))
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if parent._parent is None:
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            name = parent._name + '.' + name
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            parent = parent._parent
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ret_val = DEFAULT
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self.side_effect is not None:
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (isinstance(self.side_effect, Exception) or
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                isinstance(self.side_effect, (type, ClassType)) and
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                issubclass(self.side_effect, Exception)):
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                raise self.side_effect
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ret_val = self.side_effect(*args, **kwargs)
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if ret_val is DEFAULT:
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ret_val = self.return_value
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._wraps is not None and self._return_value is DEFAULT:
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return self._wraps(*args, **kwargs)
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if ret_val is DEFAULT:
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ret_val = self.return_value
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return ret_val
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __getattr__(self, name):
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self._methods is not None:
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if name not in self._methods:
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                raise AttributeError("Mock object has no attribute '%s'" % name)
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif _is_magic(name):
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            raise AttributeError(name)
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if name not in self._children:
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            wraps = None
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if self._wraps is not None:
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                wraps = getattr(self._wraps, name)
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            self._children[name] = Mock(parent=self, name=name, wraps=wraps)
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return self._children[name]
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def assert_called_with(self, *args, **kwargs):
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        assert self.call_args == (args, kwargs), 'Expected: %s\nCalled with: %s' % ((args, kwargs), self.call_args)
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _dot_lookup(thing, comp, import_path):
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    try:
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return getattr(thing, comp)
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    except AttributeError:
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        __import__(import_path)
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return getattr(thing, comp)
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _importer(target):
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    components = target.split('.')
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    import_path = components.pop(0)
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    thing = __import__(import_path)
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for comp in components:
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        import_path += ".%s" % comp
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        thing = _dot_lookup(thing, comp, import_path)
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return thing
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class _patch(object):
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __init__(self, target, attribute, new, spec, create):
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.target = target
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.attribute = attribute
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.new = new
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.spec = spec
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.create = create
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.has_local = False
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __call__(self, func):
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if hasattr(func, 'patchings'):
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            func.patchings.append(self)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return func
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        def patched(*args, **keywargs):
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # don't use a with here (backwards compatability with 2.5)
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            extra_args = []
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for patching in patched.patchings:
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                arg = patching.__enter__()
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if patching.new is DEFAULT:
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    extra_args.append(arg)
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            args += tuple(extra_args)
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try:
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return func(*args, **keywargs)
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            finally:
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for patching in getattr(patched, 'patchings', []):
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    patching.__exit__()
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        patched.patchings = [self]
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        patched.__name__ = func.__name__
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno",
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                                func.func_code.co_firstlineno)
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return patched
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def get_original(self):
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        target = self.target
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        name = self.attribute
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        create = self.create
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        original = DEFAULT
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if _has_local_attr(target, name):
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            try:
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                original = target.__dict__[name]
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            except AttributeError:
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                # for instances of classes with slots, they have no __dict__
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                original = getattr(target, name)
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        elif not create and not hasattr(target, name):
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            raise AttributeError("%s does not have the attribute %r" % (target, name))
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return original
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __enter__(self):
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        new, spec, = self.new, self.spec
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        original = self.get_original()
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if new is DEFAULT:
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            # XXXX what if original is DEFAULT - shouldn't use it as a spec
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            inherit = False
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if spec == True:
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                # set spec to the object we are replacing
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                spec = original
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if isinstance(spec, (type, ClassType)):
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    inherit = True
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            new = Mock(spec=spec)
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if inherit:
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                new.return_value = Mock(spec=spec)
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        self.temp_original = original
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        setattr(self.target, self.attribute, new)
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return new
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    def __exit__(self, *_):
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if self.temp_original is not DEFAULT:
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            setattr(self.target, self.attribute, self.temp_original)
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else:
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            delattr(self.target, self.attribute)
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        del self.temp_original
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def patch_object(target, attribute, new=DEFAULT, spec=None, create=False):
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return _patch(target, attribute, new, spec, create)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def patch(target, new=DEFAULT, spec=None, create=False):
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    try:
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        target, attribute = target.rsplit('.', 1)
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    except (TypeError, ValueError):
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        raise TypeError("Need a valid target to patch. You supplied: %r" % (target,))
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    target = _importer(target)
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return _patch(target, attribute, new, spec, create)
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _has_local_attr(obj, name):
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    try:
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return name in vars(obj)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    except TypeError:
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        # objects without a __dict__
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return hasattr(obj, name)
310