Skip to content
Snippets Groups Projects
mock.py 73 KiB
Newer Older
# mock.py
# Test tools for mocking and patching.
# Copyright (C) 2007-2012 Michael Foord & the mock team
# E-mail: fuzzyman AT voidspace DOT org DOT uk

# mock 1.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',
    'MagicMock',
    'patch',
    'sentinel',
    'DEFAULT',
    'ANY',
    'call',
    'create_autospec',
    'FILTER_DIR',
    'NonCallableMock',
    'NonCallableMagicMock',
Michael Foord's avatar
Michael Foord committed
    'mock_open',
Michael Foord's avatar
Michael Foord committed
    'PropertyMock',


import pprint
import sys

try:
    import inspect
except ImportError:
    # for alternative platforms that
    # may not have inspect
    inspect = None

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

try:
    BaseException
except NameError:
    # Python 2.4 compatibility
    BaseException = Exception

try:
    next
except NameError:
    def next(obj):
        return obj.next()


BaseExceptions = (BaseException,)
if 'java' in sys.platform:
    # jython
    import java
    BaseExceptions = (BaseException, java.lang.Throwable)

try:
    _isidentifier = str.isidentifier
except AttributeError:
    # Python 2.X
    import keyword
    import re
    regex = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
    def _isidentifier(string):
        if string in keyword.kwlist:
            return False
        return regex.match(string)


inPy3k = sys.version_info[0] == 3

# Needed to work around Python 3 bug where use of "super" interferes with
# defining __class__ as a descriptor
_super = super

self = 'im_self'
builtin = '__builtin__'
if inPy3k:
    self = '__self__'
    builtin = 'builtins'

FILTER_DIR = True


def _is_instance_mock(obj):
    # can't use isinstance on Mock objects because they override __class__
    # The base class for all mocks is NonCallableMock
    return issubclass(type(obj), NonCallableMock)


def _is_exception(obj):
    return (
        isinstance(obj, BaseExceptions) or
        isinstance(obj, ClassTypes) and issubclass(obj, BaseExceptions)
    )


class _slotted(object):
    __slots__ = ['a']


DescriptorTypes = (
    type(_slotted.a),
    property,
)


def _getsignature(func, skipfirst, instance=False):
    if inspect is None:
        raise ImportError('inspect module not available')

    if isinstance(func, ClassTypes) and not instance:
        try:
            func = func.__init__
        except AttributeError:
            return
        skipfirst = True
    elif not isinstance(func, FunctionTypes):
        # for classes where instance is True we end up here too
        try:
            func = func.__call__
        except AttributeError:
            return

    if inPy3k:
        try:
            argspec = inspect.getfullargspec(func)
        except TypeError:
            # C function / method, possibly inherited object().__init__
            return
        regargs, varargs, varkw, defaults, kwonly, kwonlydef, ann = argspec
    else:
        try:
            regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
        except TypeError:
            # C function / method, possibly inherited object().__init__
            return

    # instance methods and classmethods need to lose the self argument
    if getattr(func, self, None) is not None:
        regargs = regargs[1:]
    if skipfirst:
        # this condition and the above one are never both True - why?
        regargs = regargs[1:]

    if inPy3k:
        signature = inspect.formatargspec(
            regargs, varargs, varkw, defaults,
            kwonly, kwonlydef, ann, formatvalue=lambda value: "")
    else:
        signature = inspect.formatargspec(
            regargs, varargs, varkwargs, defaults,
            formatvalue=lambda value: "")
    return signature[1:-1], func


def _check_signature(func, mock, skipfirst, instance=False):
    if not _callable(func):
        return

    result = _getsignature(func, skipfirst, instance)
    if result is None:
        return
    signature, func = result

    # can't use self because "self" is common as an argument name
    # unfortunately even not in the first place
    src = "lambda _mock_self, %s: None" % signature
Loading
Loading full blame...