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