Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

upgrading mock.py

  • Loading branch information...
commit 67db0dcfc4d5b267943546370902a922ceb945f9 1 parent 3dcf3ac
Jeff Balogh authored
View
1  .gitignore
@@ -6,3 +6,4 @@ pip-log.txt
lxml
pylibmc
.gitconfig
+!*.egg-info
View
191 lib/python/mock-0.7.1-py2.7.egg-info/PKG-INFO
@@ -0,0 +1,191 @@
+Metadata-Version: 1.0
+Name: mock
+Version: 0.7.1
+Summary: A Python Mocking and Patching Library for Testing
+Home-page: http://www.voidspace.org.uk/python/mock/
+Author: Michael Foord
+Author-email: michael@voidspace.org.uk
+License: UNKNOWN
+Description: mock is a Python module that provides a core Mock class. It removes the need
+ to create a host of stubs throughout your test suite. After performing an
+ action, you can make assertions about which methods / attributes were used and
+ arguments they were called with. You can also specify return values and set
+ needed attributes in the normal way.
+
+ mock is tested on Python versions 2.4-2.7 and Python 3.
+
+ The mock module also provides utility functions / objects to assist with
+ testing, particularly monkey patching.
+
+ * `PDF documentation for 0.7.1
+ <http://www.voidspace.org.uk/downloads/mock-0.7.1.pdf>`_
+ * `mock on google code (repository and issue tracker)
+ <http://code.google.com/p/mock/>`_
+ * `mock documentation
+ <http://www.voidspace.org.uk/python/mock/>`_
+ * `mock on PyPI <http://pypi.python.org/pypi/mock/>`_
+ * `Mailing list (testing-in-python@lists.idyll.org)
+ <http://lists.idyll.org/listinfo/testing-in-python>`_
+
+ Mock is very easy to use and is designed for use with
+ `unittest <http://pypi.python.org/pypi/unittest2>`_. Mock is based on
+ the 'action -> assertion' pattern instead of 'record -> replay' used by many
+ mocking frameworks. See the
+ `mock documentation <http://www.voidspace.org.uk/python/mock/>`_ for full
+ details.
+
+ Mock objects create all attributes and methods as you access them and store
+ details of how they have been used. You can configure them, to specify return
+ values or limit what attributes are available, and then make assertions about
+ how they have been used::
+
+ >>> from mock import Mock
+ >>> real = ProductionClass()
+ >>> real.method = Mock(return_value=3)
+ >>> real.method(3, 4, 5, key='value')
+ 3
+ >>> real.method.assert_called_with(3, 4, 5, key='value')
+
+ ``side_effect`` allows you to perform side effects, return different values or
+ raise an exception when a mock is called::
+
+ >>> from mock import Mock
+ >>> mock = Mock(side_effect=KeyError('foo'))
+ >>> mock()
+ Traceback (most recent call last):
+ ...
+ KeyError: 'foo'
+ >>> values = [1, 2, 3]
+ >>> def side_effect():
+ ... return values.pop()
+ ...
+ >>> mock.side_effect = side_effect
+ >>> mock(), mock(), mock()
+ (3, 2, 1)
+
+ Mock has many other ways you can configure it and control its behaviour. For
+ example the ``spec`` argument configures the mock to take its specification from
+ another object. Attempting to access attributes or methods on the mock that
+ don't exist on the spec will fail with an ``AttributeError``.
+
+ The ``patch`` decorator / context manager makes it easy to mock classes or
+ objects in a module under test. The object you specify will be replaced with a
+ mock (or other object) during the test and restored when the test ends::
+
+ >>> from mock import patch
+ >>> @patch('test_module.ClassName1')
+ ... @patch('test_module.ClassName2')
+ ... def test(MockClass2, MockClass1):
+ ... test_module.ClassName1()
+ ... test_module.ClassName2()
+
+ ... assert MockClass1.called
+ ... assert MockClass2.called
+ ...
+ >>> test()
+
+ .. note::
+
+ When you nest patch decorators the mocks are passed in to the decorated
+ function in the same order they applied (the normal *python* order that
+ decorators are applied). This means from the bottom up, so in the example
+ above the mock for `test_module.ClassName2` is passed in first.
+
+ With `patch` it matters that you patch objects in the namespace where they
+ are looked up. This is normally straightforward, but for a quick guide
+ read `where to patch
+ <http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch>`_.
+
+ As well as a decorator `patch` can be used as a context manager in a with
+ statement::
+
+ >>> with patch.object(ProductionClass, 'method') as mock_method:
+ ... mock_method.return_value = None
+ ... real = ProductionClass()
+ ... real.method(1, 2, 3)
+ ...
+ >>> mock_method.assert_called_with(1, 2, 3)
+
+ There is also `patch.dict` for setting values in a dictionary just during the
+ scope of a test and restoring the dictionary to its original state when the
+ test ends::
+
+ >>> foo = {'key': 'value'}
+ >>> original = foo.copy()
+ >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):
+ ... assert foo == {'newkey': 'newvalue'}
+ ...
+ >>> assert foo == original
+
+ Mock now supports the mocking of Python magic methods. The easiest way of
+ using magic methods is with the ``MagicMock`` class. It allows you to do
+ things like::
+
+ >>> from mock import MagicMock
+ >>> mock = MagicMock()
+ >>> mock.__str__.return_value = 'foobarbaz'
+ >>> str(mock)
+ 'foobarbaz'
+ >>> mock.__str__.assert_called_with()
+
+ Mock allows you to assign functions (or other Mock instances) to magic methods
+ and they will be called appropriately. The MagicMock class is just a Mock
+ variant that has all of the magic methods pre-created for you (well - all the
+ useful ones anyway).
+
+ The following is an example of using magic methods with the ordinary Mock
+ class::
+
+ >>> from mock import Mock
+ >>> mock = Mock()
+ >>> mock.__str__ = Mock()
+ >>> mock.__str__.return_value = 'wheeeeee'
+ >>> str(mock)
+ 'wheeeeee'
+
+ `mocksignature` is a useful companion to Mock and patch. It creates
+ copies of functions that delegate to a mock, but have the same signature as the
+ original function. This ensures that your mocks will fail in the same way as
+ your production code if they are called incorrectly::
+
+ >>> from mock import mocksignature
+ >>> def function(a, b, c):
+ ... pass
+ ...
+ >>> function2 = mocksignature(function)
+ >>> function2.mock.return_value = 'fishy'
+ >>> function2(1, 2, 3)
+ 'fishy'
+ >>> function2.mock.assert_called_with(1, 2, 3)
+ >>> function2('wrong arguments')
+ Traceback (most recent call last):
+ ...
+ TypeError: <lambda>() takes exactly 3 arguments (1 given)
+
+ `mocksignature` can also be used on classes, where it copies the signature of
+ the `__init__` method, and on callable objects where it copies the signature of
+ the `__call__` method.
+
+ The distribution contains tests and documentation. The tests require
+ `unittest2 <http://pypi.python.org/pypi/unittest2>`_ to run.
+
+Keywords: testing,test,mock,mocking,unittest,patching,stubs,fakes,doubles
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 2.4
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.0
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Operating System :: OS Independent
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Software Development :: Testing
View
121 lib/python/mock-0.7.1-py2.7.egg-info/SOURCES.txt
@@ -0,0 +1,121 @@
+MANIFEST.in
+README.txt
+mock.py
+setup.cfg
+setup.py
+docs/changelog.txt
+docs/compare.txt
+docs/conf.py
+docs/examples.txt
+docs/getting-started.txt
+docs/index.txt
+docs/magicmock.txt
+docs/mock.txt
+docs/mocksignature.txt
+docs/patch.txt
+docs/sentinel.txt
+docs/_static/adctheme.css
+docs/_static/breadcrumb_background.png
+docs/_static/documentation.png
+docs/_static/header_sm_mid.png
+docs/_static/mobile.css
+docs/_static/scrn1.png
+docs/_static/scrn2.png
+docs/_static/searchfield_leftcap.png
+docs/_static/searchfield_repeat.png
+docs/_static/searchfield_rightcap.png
+docs/_static/title_background.png
+docs/_static/triangle_closed.png
+docs/_static/triangle_left.png
+docs/_static/triangle_open.png
+docs/_templates/layout.html
+html/changelog.html
+html/compare.html
+html/examples.html
+html/genindex.html
+html/getting-started.html
+html/index.html
+html/magicmock.html
+html/mock.html
+html/mocksignature.html
+html/objects.inv
+html/output.txt
+html/patch.html
+html/search.html
+html/searchindex.js
+html/sentinel.html
+html/.doctrees/changelog.doctree
+html/.doctrees/compare.doctree
+html/.doctrees/examples.doctree
+html/.doctrees/getting-started.doctree
+html/.doctrees/index.doctree
+html/.doctrees/magicmock.doctree
+html/.doctrees/mock.doctree
+html/.doctrees/mocksignature.doctree
+html/.doctrees/patch.doctree
+html/.doctrees/sentinel.doctree
+html/_sources/changelog.txt
+html/_sources/compare.txt
+html/_sources/examples.txt
+html/_sources/getting-started.txt
+html/_sources/index.txt
+html/_sources/magicmock.txt
+html/_sources/mock.txt
+html/_sources/mocksignature.txt
+html/_sources/patch.txt
+html/_sources/sentinel.txt
+html/_static/adctheme.css
+html/_static/agogo.css
+html/_static/basic.css
+html/_static/bgfooter.png
+html/_static/bgtop.png
+html/_static/breadcrumb_background.png
+html/_static/contents.png
+html/_static/darkmetal.png
+html/_static/default.css
+html/_static/doctools.js
+html/_static/documentation.png
+html/_static/file.png
+html/_static/header_sm_mid.png
+html/_static/headerbg.png
+html/_static/jquery.js
+html/_static/logo.png
+html/_static/metal.png
+html/_static/minus.png
+html/_static/mobile.css
+html/_static/navigation.png
+html/_static/plus.png
+html/_static/print.css
+html/_static/pygments.css
+html/_static/scrn1.png
+html/_static/scrn2.png
+html/_static/scrolls.css
+html/_static/searchfield_leftcap.png
+html/_static/searchfield_repeat.png
+html/_static/searchfield_rightcap.png
+html/_static/searchtools.js
+html/_static/sidebar.js
+html/_static/sphinxdoc.css
+html/_static/theme_extras.js
+html/_static/title_background.png
+html/_static/toc.js
+html/_static/triangle_closed.png
+html/_static/triangle_left.png
+html/_static/triangle_open.png
+html/_static/underscore.js
+html/_static/watermark.png
+html/_static/watermark_blur.png
+mock.egg-info/PKG-INFO
+mock.egg-info/SOURCES.txt
+mock.egg-info/dependency_links.txt
+mock.egg-info/top_level.txt
+tests/__init__.py
+tests/_testwith.py
+tests/support.py
+tests/support_with.py
+tests/testmagicmethods.py
+tests/testmock.py
+tests/testmocksignature.py
+tests/testpatch.py
+tests/testsentinel.py
+tests/testwith.py
View
1  lib/python/mock-0.7.1-py2.7.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
View
7 lib/python/mock-0.7.1-py2.7.egg-info/installed-files.txt
@@ -0,0 +1,7 @@
+../mock.py
+../mock.pyc
+./
+dependency_links.txt
+PKG-INFO
+SOURCES.txt
+top_level.txt
View
1  lib/python/mock-0.7.1-py2.7.egg-info/top_level.txt
@@ -0,0 +1 @@
+mock
View
1,229 lib/python/mock.py
@@ -1,271 +1,958 @@
-# mock.py
-# Test tools for mocking and patching.
-# Copyright (C) 2007-2009 Michael Foord
-# E-mail: fuzzyman AT voidspace DOT org DOT uk
-
-# mock 0.6.0
-# http://www.voidspace.org.uk/python/mock/
-
-# Released subject to the BSD License
-# Please see http://www.voidspace.org.uk/python/license.shtml
-
-# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
-# Comments, suggestions and bug reports welcome.
-
-
-__all__ = (
- 'Mock',
- 'patch',
- 'patch_object',
- 'sentinel',
- 'DEFAULT'
-)
-
-__version__ = '0.6.0'
-
-class SentinelObject(object):
- def __init__(self, name):
- self.name = name
-
- def __repr__(self):
- return '<SentinelObject "%s">' % self.name
-
-
-class Sentinel(object):
- def __init__(self):
- self._sentinels = {}
-
- def __getattr__(self, name):
- return self._sentinels.setdefault(name, SentinelObject(name))
-
-
-sentinel = Sentinel()
-
-DEFAULT = sentinel.DEFAULT
-
-class OldStyleClass:
- pass
-ClassType = type(OldStyleClass)
-
-def _is_magic(name):
- return '__%s__' % name[2:-2] == name
-
-def _copy(value):
- if type(value) in (dict, list, tuple, set):
- return type(value)(value)
- return value
-
-
-class Mock(object):
-
- def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
- name=None, parent=None, wraps=None):
- self._parent = parent
- self._name = name
- if spec is not None and not isinstance(spec, list):
- spec = [member for member in dir(spec) if not _is_magic(member)]
-
- self._methods = spec
- self._children = {}
- self._return_value = return_value
- self.side_effect = side_effect
- self._wraps = wraps
-
- self.reset_mock()
-
-
- def reset_mock(self):
- self.called = False
- self.call_args = None
- self.call_count = 0
- self.call_args_list = []
- self.method_calls = []
- for child in self._children.itervalues():
- child.reset_mock()
- if isinstance(self._return_value, Mock):
- self._return_value.reset_mock()
-
-
- def __get_return_value(self):
- if self._return_value is DEFAULT:
- self._return_value = Mock()
- return self._return_value
-
- def __set_return_value(self, value):
- self._return_value = value
-
- return_value = property(__get_return_value, __set_return_value)
-
-
- def __call__(self, *args, **kwargs):
- self.called = True
- self.call_count += 1
- self.call_args = (args, kwargs)
- self.call_args_list.append((args, kwargs))
-
- parent = self._parent
- name = self._name
- while parent is not None:
- parent.method_calls.append((name, args, kwargs))
- if parent._parent is None:
- break
- name = parent._name + '.' + name
- parent = parent._parent
-
- ret_val = DEFAULT
- if self.side_effect is not None:
- if (isinstance(self.side_effect, Exception) or
- isinstance(self.side_effect, (type, ClassType)) and
- issubclass(self.side_effect, Exception)):
- raise self.side_effect
-
- ret_val = self.side_effect(*args, **kwargs)
- if ret_val is DEFAULT:
- ret_val = self.return_value
-
- if self._wraps is not None and self._return_value is DEFAULT:
- return self._wraps(*args, **kwargs)
- if ret_val is DEFAULT:
- ret_val = self.return_value
- return ret_val
-
-
- def __getattr__(self, name):
- if self._methods is not None:
- if name not in self._methods:
- raise AttributeError("Mock object has no attribute '%s'" % name)
- elif _is_magic(name):
- raise AttributeError(name)
-
- if name not in self._children:
- wraps = None
- if self._wraps is not None:
- wraps = getattr(self._wraps, name)
- self._children[name] = Mock(parent=self, name=name, wraps=wraps)
-
- return self._children[name]
-
-
- def assert_called_with(self, *args, **kwargs):
- assert self.call_args == (args, kwargs), 'Expected: %s\nCalled with: %s' % ((args, kwargs), self.call_args)
-
-
-def _dot_lookup(thing, comp, import_path):
- try:
- return getattr(thing, comp)
- except AttributeError:
- __import__(import_path)
- return getattr(thing, comp)
-
-
-def _importer(target):
- components = target.split('.')
- import_path = components.pop(0)
- thing = __import__(import_path)
-
- for comp in components:
- import_path += ".%s" % comp
- thing = _dot_lookup(thing, comp, import_path)
- return thing
-
-
-class _patch(object):
- def __init__(self, target, attribute, new, spec, create):
- self.target = target
- self.attribute = attribute
- self.new = new
- self.spec = spec
- self.create = create
- self.has_local = False
-
-
- def __call__(self, func):
- if hasattr(func, 'patchings'):
- func.patchings.append(self)
- return func
-
- def patched(*args, **keywargs):
- # don't use a with here (backwards compatability with 2.5)
- extra_args = []
- for patching in patched.patchings:
- arg = patching.__enter__()
- if patching.new is DEFAULT:
- extra_args.append(arg)
- args += tuple(extra_args)
- try:
- return func(*args, **keywargs)
- finally:
- for patching in getattr(patched, 'patchings', []):
- patching.__exit__()
-
- patched.patchings = [self]
- patched.__name__ = func.__name__
- patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno",
- func.func_code.co_firstlineno)
- return patched
-
-
- def get_original(self):
- target = self.target
- name = self.attribute
- create = self.create
-
- original = DEFAULT
- if _has_local_attr(target, name):
- try:
- original = target.__dict__[name]
- except AttributeError:
- # for instances of classes with slots, they have no __dict__
- original = getattr(target, name)
- elif not create and not hasattr(target, name):
- raise AttributeError("%s does not have the attribute %r" % (target, name))
- return original
-
-
- def __enter__(self):
- new, spec, = self.new, self.spec
- original = self.get_original()
- if new is DEFAULT:
- # XXXX what if original is DEFAULT - shouldn't use it as a spec
- inherit = False
- if spec == True:
- # set spec to the object we are replacing
- spec = original
- if isinstance(spec, (type, ClassType)):
- inherit = True
- new = Mock(spec=spec)
- if inherit:
- new.return_value = Mock(spec=spec)
- self.temp_original = original
- setattr(self.target, self.attribute, new)
- return new
-
-
- def __exit__(self, *_):
- if self.temp_original is not DEFAULT:
- setattr(self.target, self.attribute, self.temp_original)
- else:
- delattr(self.target, self.attribute)
- del self.temp_original
-
-
-def patch_object(target, attribute, new=DEFAULT, spec=None, create=False):
- return _patch(target, attribute, new, spec, create)
-
-
-def patch(target, new=DEFAULT, spec=None, create=False):
- try:
- target, attribute = target.rsplit('.', 1)
- except (TypeError, ValueError):
- raise TypeError("Need a valid target to patch. You supplied: %r" % (target,))
- target = _importer(target)
- return _patch(target, attribute, new, spec, create)
-
-
-
-def _has_local_attr(obj, name):
- try:
- return name in vars(obj)
- except TypeError:
- # objects without a __dict__
- return hasattr(obj, name)
+# mock.py
+# Test tools for mocking and patching.
+# Copyright (C) 2007-2011 Michael Foord & the mock team
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+
+# mock 0.7.1
+# http://www.voidspace.org.uk/python/mock/
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# Comments, suggestions and bug reports welcome.
+
+
+__all__ = (
+ 'Mock',
+ 'MagicMock',
+ 'mocksignature',
+ 'patch',
+ 'patch_object',
+ 'sentinel',
+ 'DEFAULT'
+)
+
+__version__ = '0.7.1'
+
+__unittest = True
+
+
+import sys
+import warnings
+
+try:
+ import inspect
+except ImportError:
+ # for alternative platforms that
+ # may not have inspect
+ inspect = None
+
+try:
+ BaseException
+except NameError:
+ # Python 2.4 compatibility
+ BaseException = Exception
+
+try:
+ from functools import wraps
+except ImportError:
+ # Python 2.4 compatibility
+ def wraps(original):
+ def inner(f):
+ f.__name__ = original.__name__
+ f.__doc__ = original.__doc__
+ f.__module__ = original.__module__
+ return f
+ return inner
+
+try:
+ unicode
+except NameError:
+ # Python 3
+ basestring = unicode = str
+
+try:
+ long
+except NameError:
+ # Python 3
+ long = int
+
+inPy3k = sys.version_info[0] == 3
+
+if inPy3k:
+ self = '__self__'
+else:
+ self = 'im_self'
+
+
+# getsignature and mocksignature heavily "inspired" by
+# the decorator module: http://pypi.python.org/pypi/decorator/
+# by Michele Simionato
+
+def _getsignature(func, skipfirst):
+ if inspect is None:
+ raise ImportError('inspect module not available')
+
+ if inspect.isclass(func):
+ func = func.__init__
+ # will have a self arg
+ skipfirst = True
+ elif not (inspect.ismethod(func) or inspect.isfunction(func)):
+ func = func.__call__
+
+ regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
+
+ # instance methods need to lose the self argument
+ if getattr(func, self, None) is not None:
+ regargs = regargs[1:]
+
+ _msg = "_mock_ is a reserved argument name, can't mock signatures using _mock_"
+ assert '_mock_' not in regargs, _msg
+ if varargs is not None:
+ assert '_mock_' not in varargs, _msg
+ if varkwargs is not None:
+ assert '_mock_' not in varkwargs, _msg
+ if skipfirst:
+ regargs = regargs[1:]
+ signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults,
+ formatvalue=lambda value: "")
+ return signature[1:-1], func
+
+
+def _copy_func_details(func, funcopy):
+ funcopy.__name__ = func.__name__
+ funcopy.__doc__ = func.__doc__
+ funcopy.__dict__.update(func.__dict__)
+ funcopy.__module__ = func.__module__
+ if not inPy3k:
+ funcopy.func_defaults = func.func_defaults
+ else:
+ funcopy.__defaults__ = func.__defaults__
+ funcopy.__kwdefaults__ = func.__kwdefaults__
+
+
+def mocksignature(func, mock=None, skipfirst=False):
+ """
+ mocksignature(func, mock=None, skipfirst=False)
+
+ Create a new function with the same signature as `func` that delegates
+ to `mock`. If `skipfirst` is True the first argument is skipped, useful
+ for methods where `self` needs to be omitted from the new function.
+
+ If you don't pass in a `mock` then one will be created for you.
+
+ The mock is set as the `mock` attribute of the returned function for easy
+ access.
+
+ `mocksignature` can also be used with classes. It copies the signature of
+ the `__init__` method.
+
+ When used with callable objects (instances) it copies the signature of the
+ `__call__` method.
+ """
+ if mock is None:
+ mock = Mock()
+ signature, func = _getsignature(func, skipfirst)
+ src = "lambda %(signature)s: _mock_(%(signature)s)" % {
+ 'signature': signature
+ }
+
+ funcopy = eval(src, dict(_mock_=mock))
+ _copy_func_details(func, funcopy)
+ funcopy.mock = mock
+ return funcopy
+
+
+def _is_magic(name):
+ return '__%s__' % name[2:-2] == name
+
+
+class SentinelObject(object):
+ "A unique, named, sentinel object."
+ def __init__(self, name):
+ self.name = name
+
+ def __repr__(self):
+ return '<SentinelObject "%s">' % self.name
+
+
+class Sentinel(object):
+ """Access attributes to return a named object, usable as a sentinel."""
+ def __init__(self):
+ self._sentinels = {}
+
+ def __getattr__(self, name):
+ if name == '__bases__':
+ # Without this help(mock) raises an exception
+ raise AttributeError
+ return self._sentinels.setdefault(name, SentinelObject(name))
+
+
+sentinel = Sentinel()
+
+DEFAULT = sentinel.DEFAULT
+
+
+class OldStyleClass:
+ pass
+ClassType = type(OldStyleClass)
+
+
+def _copy(value):
+ if type(value) in (dict, list, tuple, set):
+ return type(value)(value)
+ return value
+
+
+if inPy3k:
+ class_types = type
+else:
+ class_types = (type, ClassType)
+
+
+class Mock(object):
+ """
+ Create a new ``Mock`` object. ``Mock`` takes several optional arguments
+ that specify the behaviour of the Mock object:
+
+ * ``spec``: This can be either a list of strings or an existing object (a
+ class or instance) that acts as the specification for the mock object. If
+ you pass in an object then a list of strings is formed by calling dir on
+ the object (excluding unsupported magic attributes and methods). Accessing
+ any attribute not in this list will raise an ``AttributeError``.
+
+ If ``spec`` is an object (rather than a list of strings) then
+ `mock.__class__` returns the class of the spec object. This allows mocks
+ to pass `isinstance` tests.
+
+ * ``spec_set``: A stricter variant of ``spec``. If used, attempting to *set*
+ or get an attribute on the mock that isn't on the object passed as
+ ``spec_set`` will raise an ``AttributeError``.
+
+ * ``side_effect``: A function to be called whenever the Mock is called. See
+ the :attr:`Mock.side_effect` attribute. Useful for raising exceptions or
+ dynamically changing return values. The function is called with the same
+ arguments as the mock, and unless it returns :data:`DEFAULT`, the return
+ value of this function is used as the return value.
+
+ Alternatively ``side_effect`` can be an exception class or instance. In
+ this case the exception will be raised when the mock is called.
+
+ * ``return_value``: The value returned when the mock is called. By default
+ this is a new Mock (created on first access). See the
+ :attr:`Mock.return_value` attribute.
+
+ * ``wraps``: Item for the mock object to wrap. If ``wraps`` is not None
+ then calling the Mock will pass the call through to the wrapped object
+ (returning the real result and ignoring ``return_value``). Attribute
+ access on the mock will return a Mock object that wraps the corresponding
+ attribute of the wrapped object (so attempting to access an attribute that
+ doesn't exist will raise an ``AttributeError``).
+
+ If the mock has an explicit ``return_value`` set then calls are not passed
+ to the wrapped object and the ``return_value`` is returned instead.
+
+ * ``name``: If the mock has a name then it will be used in the repr of the
+ mock. This can be useful for debugging. The name is propagated to child
+ mocks.
+ """
+ def __new__(cls, *args, **kw):
+ # every instance has its own class
+ # so we can create magic methods on the
+ # class without stomping on other mocks
+ new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__})
+ return object.__new__(new)
+
+
+ def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
+ wraps=None, name=None, spec_set=None, parent=None):
+ self._parent = parent
+ self._name = name
+ _spec_class = None
+ if spec_set is not None:
+ spec = spec_set
+ spec_set = True
+
+ if spec is not None and not isinstance(spec, list):
+ if isinstance(spec, class_types):
+ _spec_class = spec
+ else:
+ _spec_class = spec.__class__
+ spec = dir(spec)
+
+ self._spec_class = _spec_class
+ self._spec_set = spec_set
+ self._methods = spec
+ self._children = {}
+ self._return_value = return_value
+ self.side_effect = side_effect
+ self._wraps = wraps
+
+ self.reset_mock()
+
+
+ @property
+ def __class__(self):
+ if self._spec_class is None:
+ return type(self)
+ return self._spec_class
+
+
+ def reset_mock(self):
+ "Restore the mock object to its initial state."
+ self.called = False
+ self.call_args = None
+ self.call_count = 0
+ self.call_args_list = []
+ self.method_calls = []
+ for child in self._children.values():
+ child.reset_mock()
+ if isinstance(self._return_value, Mock):
+ if not self._return_value is self:
+ self._return_value.reset_mock()
+
+
+ def __get_return_value(self):
+ if self._return_value is DEFAULT:
+ self._return_value = self._get_child_mock()
+ return self._return_value
+
+ def __set_return_value(self, value):
+ self._return_value = value
+
+ __return_value_doc = "The value to be returned when the mock is called."
+ return_value = property(__get_return_value, __set_return_value,
+ __return_value_doc)
+
+
+ def __call__(self, *args, **kwargs):
+ self.called = True
+ self.call_count += 1
+ self.call_args = callargs((args, kwargs))
+ self.call_args_list.append(callargs((args, kwargs)))
+
+ parent = self._parent
+ name = self._name
+ while parent is not None:
+ parent.method_calls.append(callargs((name, args, kwargs)))
+ if parent._parent is None:
+ break
+ name = parent._name + '.' + name
+ parent = parent._parent
+
+ ret_val = DEFAULT
+ if self.side_effect is not None:
+ if (isinstance(self.side_effect, BaseException) or
+ isinstance(self.side_effect, class_types) and
+ issubclass(self.side_effect, BaseException)):
+ raise self.side_effect
+
+ ret_val = self.side_effect(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+
+ if self._wraps is not None and self._return_value is DEFAULT:
+ return self._wraps(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+ return ret_val
+
+
+ def __getattr__(self, name):
+ if name == '_methods':
+ raise AttributeError(name)
+ elif self._methods is not None:
+ if name not in self._methods or name in _all_magics:
+ raise AttributeError("Mock object has no attribute '%s'" % name)
+ elif _is_magic(name):
+ raise AttributeError(name)
+
+ if name not in self._children:
+ wraps = None
+ if self._wraps is not None:
+ wraps = getattr(self._wraps, name)
+ self._children[name] = self._get_child_mock(parent=self, name=name, wraps=wraps)
+
+ return self._children[name]
+
+
+ def __repr__(self):
+ if self._name is None and self._spec_class is None:
+ return object.__repr__(self)
+
+ name_string = ''
+ spec_string = ''
+ if self._name is not None:
+ def get_name(name):
+ if name is None:
+ return 'mock'
+ return name
+ parent = self._parent
+ name = self._name
+ while parent is not None:
+ name = get_name(parent._name) + '.' + name
+ parent = parent._parent
+ name_string = ' name=%r' % name
+ if self._spec_class is not None:
+ spec_string = ' spec=%r'
+ if self._spec_set:
+ spec_string = ' spec_set=%r'
+ spec_string = spec_string % self._spec_class.__name__
+ return "<%s%s%s id='%s'>" % (type(self).__name__,
+ name_string,
+ spec_string,
+ id(self))
+
+
+ def __setattr__(self, name, value):
+ if not 'method_calls' in self.__dict__:
+ # allow all attribute setting until initialisation is complete
+ return object.__setattr__(self, name, value)
+ if (self._spec_set and self._methods is not None and name not in
+ self._methods and name not in self.__dict__ and
+ name != 'return_value'):
+ raise AttributeError("Mock object has no attribute '%s'" % name)
+ if name in _unsupported_magics:
+ msg = 'Attempting to set unsupported magic method %r.' % name
+ raise AttributeError(msg)
+ elif name in _all_magics:
+ if self._methods is not None and name not in self._methods:
+ raise AttributeError("Mock object has no attribute '%s'" % name)
+
+ if not isinstance(value, Mock):
+ setattr(type(self), name, _get_method(name, value))
+ original = value
+ real = lambda *args, **kw: original(self, *args, **kw)
+ value = mocksignature(value, real, skipfirst=True)
+ else:
+ setattr(type(self), name, value)
+ return object.__setattr__(self, name, value)
+
+
+ def __delattr__(self, name):
+ if name in _all_magics and name in type(self).__dict__:
+ delattr(type(self), name)
+ return object.__delattr__(self, name)
+
+
+ def assert_called_with(self, *args, **kwargs):
+ """
+ assert that the mock was called with the specified arguments.
+
+ Raises an AssertionError if the args and keyword args passed in are
+ different to the last call to the mock.
+ """
+ if self.call_args is None:
+ raise AssertionError('Expected: %s\nNot called' % ((args, kwargs),))
+ if not self.call_args == (args, kwargs):
+ raise AssertionError(
+ 'Expected: %s\nCalled with: %s' % ((args, kwargs), self.call_args)
+ )
+
+
+ def assert_called_once_with(self, *args, **kwargs):
+ """
+ assert that the mock was called exactly once and with the specified
+ arguments.
+ """
+ if not self.call_count == 1:
+ msg = ("Expected to be called once. Called %s times." %
+ self.call_count)
+ raise AssertionError(msg)
+ return self.assert_called_with(*args, **kwargs)
+
+
+ def _get_child_mock(self, **kw):
+ klass = type(self).__mro__[1]
+ return klass(**kw)
+
+
+
+class callargs(tuple):
+ """
+ A tuple for holding the results of a call to a mock, either in the form
+ `(args, kwargs)` or `(name, args, kwargs)`.
+
+ If args or kwargs are empty then a callargs tuple will compare equal to
+ a tuple without those values. This makes comparisons less verbose::
+
+ callargs('name', (), {}) == ('name',)
+ callargs('name', (1,), {}) == ('name', (1,))
+ callargs((), {'a': 'b'}) == ({'a': 'b'},)
+ """
+ def __eq__(self, other):
+ if len(self) == 3:
+ if other[0] != self[0]:
+ return False
+ args_kwargs = self[1:]
+ other_args_kwargs = other[1:]
+ else:
+ args_kwargs = tuple(self)
+ other_args_kwargs = other
+
+ if len(other_args_kwargs) == 0:
+ other_args, other_kwargs = (), {}
+ elif len(other_args_kwargs) == 1:
+ if isinstance(other_args_kwargs[0], tuple):
+ other_args = other_args_kwargs[0]
+ other_kwargs = {}
+ else:
+ other_args = ()
+ other_kwargs = other_args_kwargs[0]
+ else:
+ other_args, other_kwargs = other_args_kwargs
+
+ return tuple(args_kwargs) == (other_args, other_kwargs)
+
+
+def _dot_lookup(thing, comp, import_path):
+ try:
+ return getattr(thing, comp)
+ except AttributeError:
+ __import__(import_path)
+ return getattr(thing, comp)
+
+
+def _importer(target):
+ components = target.split('.')
+ import_path = components.pop(0)
+ thing = __import__(import_path)
+
+ for comp in components:
+ import_path += ".%s" % comp
+ thing = _dot_lookup(thing, comp, import_path)
+ return thing
+
+
+class _patch(object):
+ def __init__(self, target, attribute, new, spec, create,
+ mocksignature, spec_set):
+ self.target = target
+ self.attribute = attribute
+ self.new = new
+ self.spec = spec
+ self.create = create
+ self.has_local = False
+ self.mocksignature = mocksignature
+ self.spec_set = spec_set
+
+
+ def copy(self):
+ return _patch(self.target, self.attribute, self.new, self.spec,
+ self.create, self.mocksignature, self.spec_set)
+
+
+ def __call__(self, func):
+ if isinstance(func, class_types):
+ return self.decorate_class(func)
+ else:
+ return self.decorate_callable(func)
+
+
+ def decorate_class(self, klass):
+ for attr in dir(klass):
+ attr_value = getattr(klass, attr)
+ if attr.startswith("test") and hasattr(attr_value, "__call__"):
+ setattr(klass, attr, self.copy()(attr_value))
+ return klass
+
+
+ def decorate_callable(self, func):
+ if hasattr(func, 'patchings'):
+ func.patchings.append(self)
+ return func
+
+ @wraps(func)
+ def patched(*args, **keywargs):
+ # don't use a with here (backwards compatability with 2.5)
+ extra_args = []
+ for patching in patched.patchings:
+ arg = patching.__enter__()
+ if patching.new is DEFAULT:
+ extra_args.append(arg)
+ args += tuple(extra_args)
+ try:
+ return func(*args, **keywargs)
+ finally:
+ for patching in reversed(getattr(patched, 'patchings', [])):
+ patching.__exit__()
+
+ patched.patchings = [self]
+ if hasattr(func, 'func_code'):
+ # not in Python 3
+ patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno",
+ func.func_code.co_firstlineno)
+ return patched
+
+
+ def get_original(self):
+ target = self.target
+ name = self.attribute
+
+ original = DEFAULT
+ local = False
+
+ try:
+ original = target.__dict__[name]
+ except (AttributeError, KeyError):
+ original = getattr(target, name, DEFAULT)
+ else:
+ local = True
+
+ if not self.create and original is DEFAULT:
+ raise AttributeError("%s does not have the attribute %r" % (target, name))
+ return original, local
+
+
+ def __enter__(self):
+ """Perform the patch."""
+ new, spec, spec_set = self.new, self.spec, self.spec_set
+ original, local = self.get_original()
+ if new is DEFAULT:
+ # XXXX what if original is DEFAULT - shouldn't use it as a spec
+ inherit = False
+ if spec_set == True:
+ spec_set = original
+ if isinstance(spec_set, class_types):
+ inherit = True
+ elif spec == True:
+ # set spec to the object we are replacing
+ spec = original
+ if isinstance(spec, class_types):
+ inherit = True
+ new = Mock(spec=spec, spec_set=spec_set)
+ if inherit:
+ new.return_value = Mock(spec=spec, spec_set=spec_set)
+ new_attr = new
+ if self.mocksignature:
+ new_attr = mocksignature(original, new)
+
+ self.temp_original = original
+ self.is_local = local
+ setattr(self.target, self.attribute, new_attr)
+ return new
+
+
+ def __exit__(self, *_):
+ """Undo the patch."""
+ if self.is_local and self.temp_original is not DEFAULT:
+ setattr(self.target, self.attribute, self.temp_original)
+ else:
+ delattr(self.target, self.attribute)
+ if not self.create and not hasattr(self.target, self.attribute):
+ # needed for proxy objects like django settings
+ setattr(self.target, self.attribute, self.temp_original)
+
+ del self.temp_original
+ del self.is_local
+
+ start = __enter__
+ stop = __exit__
+
+
+def _patch_object(target, attribute, new=DEFAULT, spec=None, create=False,
+ mocksignature=False, spec_set=None):
+ """
+ patch.object(target, attribute, new=DEFAULT, spec=None, create=False,
+ mocksignature=False, spec_set=None)
+
+ patch the named member (`attribute`) on an object (`target`) with a mock
+ object.
+
+ Arguments new, spec, create, mocksignature and spec_set have the same
+ meaning as for patch.
+ """
+ return _patch(target, attribute, new, spec, create, mocksignature,
+ spec_set)
+
+
+def patch_object(*args, **kwargs):
+ "A deprecated form of patch.object(...)"
+ warnings.warn(('Please use patch.object instead.'), DeprecationWarning, 2)
+ return _patch_object(*args, **kwargs)
+
+
+def patch(target, new=DEFAULT, spec=None, create=False,
+ mocksignature=False, spec_set=None):
+ """
+ ``patch`` acts as a function decorator, class decorator or a context
+ manager. Inside the body of the function or with statement, the ``target``
+ (specified in the form `'PackageName.ModuleName.ClassName'`) is patched
+ with a ``new`` object. When the function/with statement exits the patch is
+ undone.
+
+ The ``target`` is imported and the specified attribute patched with the new
+ object, so it must be importable from the environment you are calling the
+ decorator from.
+
+ If ``new`` is omitted, then a new ``Mock`` is created and passed in as an
+ extra argument to the decorated function.
+
+ The ``spec`` and ``spec_set`` keyword arguments are passed to the ``Mock``
+ if patch is creating one for you.
+
+ In addition you can pass ``spec=True`` or ``spec_set=True``, which causes
+ patch to pass in the object being mocked as the spec/spec_set object.
+
+ If ``mocksignature`` is True then the patch will be done with a function
+ created by mocking the one being replaced. If the object being replaced is
+ a class then the signature of `__init__` will be copied. If the object
+ being replaced is a callable object then the signature of `__call__` will
+ be copied.
+
+ By default ``patch`` will fail to replace attributes that don't exist. If
+ you pass in 'create=True' and the attribute doesn't exist, patch will
+ create the attribute for you when the patched function is called, and
+ delete it again afterwards. This is useful for writing tests against
+ attributes that your production code creates at runtime. It is off by by
+ default because it can be dangerous. With it switched on you can write
+ passing tests against APIs that don't actually exist!
+
+ Patch can be used as a TestCase class decorator. It works by
+ decorating each test method in the class. This reduces the boilerplate
+ code when your test methods share a common patchings set.
+
+ Patch can be used with the with statement, if this is available in your
+ version of Python. Here the patching applies to the indented block after
+ the with statement. If you use "as" then the patched object will be bound
+ to the name after the "as"; very useful if `patch` is creating a mock
+ object for you.
+
+ `patch.dict(...)` and `patch.object(...)` are available for alternate
+ use-cases.
+ """
+ try:
+ target, attribute = target.rsplit('.', 1)
+ except (TypeError, ValueError):
+ raise TypeError("Need a valid target to patch. You supplied: %r" %
+ (target,))
+ target = _importer(target)
+ return _patch(target, attribute, new, spec, create, mocksignature, spec_set)
+
+
+class _patch_dict(object):
+ """
+ Patch a dictionary and restore the dictionary to its original state after
+ the test.
+
+ `in_dict` can be a dictionary or a mapping like container. If it is a
+ mapping then it must at least support getting, setting and deleting items
+ plus iterating over keys.
+
+ `in_dict` can also be a string specifying the name of the dictionary, which
+ will then be fetched by importing it.
+
+ `values` can be a dictionary of values to set in the dictionary. `values`
+ can also be an iterable of ``(key, value)`` pairs.
+
+ If `clear` is True then the dictionary will be cleared before the new
+ values are set.
+ """
+
+ def __init__(self, in_dict, values=(), clear=False):
+ if isinstance(in_dict, basestring):
+ in_dict = _importer(in_dict)
+ self.in_dict = in_dict
+ # support any argument supported by dict(...) constructor
+ self.values = dict(values)
+ self.clear = clear
+ self._original = None
+
+
+ def __call__(self, f):
+ if isinstance(f, class_types):
+ return self.decorate_class(f)
+ @wraps(f)
+ def _inner(*args, **kw):
+ self._patch_dict()
+ try:
+ return f(*args, **kw)
+ finally:
+ self._unpatch_dict()
+
+ return _inner
+
+
+ def decorate_class(self, klass):
+ for attr in dir(klass):
+ attr_value = getattr(klass, attr)
+ if attr.startswith("test") and hasattr(attr_value, "__call__"):
+ decorator = _patch_dict(self.in_dict, self.values, self.clear)
+ decorated = decorator(attr_value)
+ setattr(klass, attr, decorated)
+ return klass
+
+
+ def __enter__(self):
+ """Patch the dict."""
+ self._patch_dict()
+
+
+ def _patch_dict(self):
+ """Unpatch the dict."""
+ values = self.values
+ in_dict = self.in_dict
+ clear = self.clear
+
+ try:
+ original = in_dict.copy()
+ except AttributeError:
+ # dict like object with no copy method
+ # must support iteration over keys
+ original = {}
+ for key in in_dict:
+ original[key] = in_dict[key]
+ self._original = original
+
+ if clear:
+ _clear_dict(in_dict)
+
+ try:
+ in_dict.update(values)
+ except AttributeError:
+ # dict like object with no update method
+ for key in values:
+ in_dict[key] = values[key]
+
+
+ def _unpatch_dict(self):
+ in_dict = self.in_dict
+ original = self._original
+
+ _clear_dict(in_dict)
+
+ try:
+ in_dict.update(original)
+ except AttributeError:
+ for key in original:
+ in_dict[key] = original[key]
+
+
+ def __exit__(self, *args):
+ self._unpatch_dict()
+ return False
+
+ start = __enter__
+ stop = __exit__
+
+
+def _clear_dict(in_dict):
+ try:
+ in_dict.clear()
+ except AttributeError:
+ keys = list(in_dict)
+ for key in keys:
+ del in_dict[key]
+
+
+patch.object = _patch_object
+patch.dict = _patch_dict
+
+
+magic_methods = (
+ "lt le gt ge eq ne "
+ "getitem setitem delitem "
+ "len contains iter "
+ "hash str sizeof "
+ "enter exit "
+ "divmod neg pos abs invert "
+ "complex int float index "
+ "trunc floor ceil "
+)
+
+numerics = "add sub mul div truediv floordiv mod lshift rshift and xor or pow "
+inplace = ' '.join('i%s' % n for n in numerics.split())
+right = ' '.join('r%s' % n for n in numerics.split())
+extra = ''
+if inPy3k:
+ extra = 'bool next '
+else:
+ extra = 'unicode long nonzero oct hex '
+# __truediv__ and __rtruediv__ not available in Python 3 either
+
+# not including __prepare__, __instancecheck__, __subclasscheck__
+# (as they are metaclass methods)
+# __del__ is not supported at all as it causes problems if it exists
+
+_non_defaults = set('__%s__' % method for method in [
+ 'cmp', 'getslice', 'setslice', 'coerce', 'subclasses',
+ 'dir', 'format', 'get', 'set', 'delete', 'reversed',
+ 'missing', 'reduce', 'reduce_ex', 'getinitargs',
+ 'getnewargs', 'getstate', 'setstate', 'getformat',
+ 'setformat', 'repr'
+])
+
+
+def _get_method(name, func):
+ "Turns a callable object (like a mock) into a real function"
+ def method(self, *args, **kw):
+ return func(self, *args, **kw)
+ method.__name__ = name
+ return method
+
+
+_magics = set(
+ '__%s__' % method for method in
+ ' '.join([magic_methods, numerics, inplace, right, extra]).split()
+)
+
+_all_magics = _magics | _non_defaults
+
+_unsupported_magics = set([
+ '__getattr__', '__setattr__',
+ '__init__', '__new__', '__prepare__'
+ '__instancecheck__', '__subclasscheck__',
+ '__del__'
+])
+
+_calculate_return_value = {
+ '__hash__': lambda self: object.__hash__(self),
+ '__str__': lambda self: object.__str__(self),
+ '__sizeof__': lambda self: object.__sizeof__(self),
+ '__unicode__': lambda self: unicode(object.__str__(self)),
+}
+
+_return_values = {
+ '__int__': 1,
+ '__contains__': False,
+ '__len__': 0,
+ '__iter__': iter([]),
+ '__exit__': False,
+ '__complex__': 1j,
+ '__float__': 1.0,
+ '__bool__': True,
+ '__nonzero__': True,
+ '__oct__': '1',
+ '__hex__': '0x1',
+ '__long__': long(1),
+ '__index__': 1,
+}
+
+
+def _set_return_value(mock, method, name):
+ return_value = DEFAULT
+ if name in _return_values:
+ return_value = _return_values[name]
+ elif name in _calculate_return_value:
+ try:
+ return_value = _calculate_return_value[name](mock)
+ except AttributeError:
+ return_value = AttributeError(name)
+ if return_value is not DEFAULT:
+ method.return_value = return_value
+
+
+class MagicMock(Mock):
+ """
+ MagicMock is a subclass of :Mock with default implementations
+ of most of the magic methods. You can use MagicMock without having to
+ configure the magic methods yourself.
+
+ If you use the ``spec`` or ``spec_set`` arguments then *only* magic
+ methods that exist in the spec will be created.
+
+ Attributes and the return value of a `MagicMock` will also be `MagicMocks`.
+ """
+ def __init__(self, *args, **kw):
+ Mock.__init__(self, *args, **kw)
+
+ these_magics = _magics
+ if self._methods is not None:
+ these_magics = _magics.intersection(self._methods)
+
+ for entry in these_magics:
+ # could specify parent?
+ m = Mock()
+ setattr(self, entry, m)
+ _set_return_value(self, m, entry)
Please sign in to comment.
Something went wrong with that request. Please try again.