def test_unhashable_star_empty():
    '''Test `ArgumentsProfile` hashing and handling of `*()`.'''
    def func(a, b, c=3, d=4, **kwargs):
        pass

    a2 = ArgumentsProfile(func,
                          7, ({
                              'a': 'b'
                          }, ), {1, (3, 4)},
                          meow=[1, 2, {
                              1: [1, 2]
                          }])
    assert a2.args == (7, ({'a': 'b'}, ), {1, (3, 4)})
    assert a2.kwargs == OrderedDict((('meow', [1, 2, {1: [1, 2]}]), ))

    a3 = ArgumentsProfile(func,
                          *(),
                          b=({
                              'a': 'b'
                          }, ),
                          c={1, (3, 4)},
                          a=7,
                          meow=[1, 2, {
                              1: [1, 2]
                          }])
    assert a3.args == (7, ({'a': 'b'}, ), {1, (3, 4)})
    assert a3.kwargs == OrderedDict((('meow', [1, 2, {1: [1, 2]}]), ))
    assert hash(a2) == hash(a3)
def test_many_defaultfuls_some_long_2():
    '''
    Test `ArgumentsProfile` with many defaultful arguments, some of them long.
    '''
    def func(a, b, c=3, dragon=4, e=5, f=6, glide=7, human=8, iris=9):
        pass

    a1 = ArgumentsProfile(func, 1, 2, glide='boom')
    assert a1.args == (1, 2)
    assert a1.kwargs == OrderedDict((('glide', 'boom'), ))

    a2 = ArgumentsProfile(func, 1, 2, 3, 4, 5, 6, 'boom')
    a3 = ArgumentsProfile(func, 1, 2, 3, glide='boom')
    assert a1 == a2 == a3

    a4 = ArgumentsProfile(func,
                          1,
                          2,
                          glide='boom',
                          human='pow',
                          iris='badabang')
    a5 = ArgumentsProfile(func, 1, 2, 3, 4, 5, 6, 'boom', 'pow', 'badabang')
    assert a4 == a5
    assert a4.args == (1, 2, 3, 4, 5, 6, 'boom', 'pow', 'badabang')
    assert not a4.kwargs
def test_many_defaultfuls_and_star_args():
    '''Test `ArgumentsProfile` with many defaultful arguments and `*args`.'''
    def func(a, b, c='three', d='four', e='five', f='six', *args):
        pass

    a1 = ArgumentsProfile(func, 'one', 'two', f='roar')
    assert a1.args == ('one', 'two')
    assert a1.kwargs == OrderedDict((('f', 'roar'), ))

    a2 = ArgumentsProfile(func, 'one', 'two', 'three', 'four', 'five', 'roar')
    assert a1 == a2

    # Specifying `*args`, so can't specify pre-`*args` arguments by keyword:
    a3 = ArgumentsProfile(func, 'one', 'two', 'three', 'four', 'five', 'roar',
                          'meow_frr')
    assert a3.args == ('one', 'two', 'three', 'four', 'five', 'roar',
                       'meow_frr')
    assert not a3.kwargs

    a4 = ArgumentsProfile(func, 'one', 'two', 'three', 'four', 'five', 'six',
                          3, 1, 4, 1, 5, 9, 2)
    assert a4.args == ('one', 'two', 'three', 'four', 'five', 'six', 3, 1, 4,
                       1, 5, 9, 2)
    assert not a4.kwargs
    assert a4['*'] == (3, 1, 4, 1, 5, 9, 2)
Beispiel #4
0
def get_default_args_dict(function):
    '''
    Get ordered dict from arguments which have a default to their default.
    
    Example:
    
        >>> def f(a, b, c=1, d='meow'): pass
        >>> get_default_args_dict(f)
        OrderedDict([('c', 1), ('d', 'meow')])
        
    '''
    arg_spec = cute_inspect.getargspec(function)
    (s_args, s_star_args, s_star_kwargs, s_defaults) = arg_spec

    # `getargspec` has a weird policy, when inspecting a function with no
    # defaults, to give a `defaults` of `None` instead of the more consistent
    # `()`. We fix that here:
    if s_defaults is None:
        s_defaults = ()

    # The number of args which have default values:
    n_defaultful_args = len(s_defaults)

    defaultful_args = s_args[-n_defaultful_args:] if n_defaultful_args \
                       else []

    return OrderedDict(zip(defaultful_args, s_defaults))
def test_empty():
    '''Test `get_default_args_dict` on a function with no defaultful args.'''
    def f(a, b, c, *args, **kwargs):
        pass

    assert get_default_args_dict(f) == \
        OrderedDict()
def test_generator():
    '''Test `get_default_args_dict` on a generator function.'''
    def f(a, meow='frr', d={}):
        yield None

    assert get_default_args_dict(f) == \
        OrderedDict((('meow', 'frr'), ('d', {})))
def test():
    '''Test the basic workings of `get_default_args_dict`.'''
    def f(a, b, c=3, d=4):
        pass

    assert get_default_args_dict(f) == \
        OrderedDict((('c', 3), ('d', 4)))
def test_many_defaultfuls_some_long():
    '''
    Test `ArgumentsProfile` with many defaultful arguments, some of them long.
    '''
    def func(a, b, c=3, dragon=4, e=5, f=6, glide=7, human=8):
        pass

    a1 = ArgumentsProfile(func, 1, 2, glide='boom')
    assert a1.args == (1, 2)
    assert a1.kwargs == OrderedDict((('glide', 'boom'), ))

    a2 = ArgumentsProfile(func, 1, 2, 3, 4, 5, 6, 'boom')
    a3 = ArgumentsProfile(func, 1, 2, 3, glide='boom')
    assert a1 == a2 == a3

    a4 = ArgumentsProfile(func, 1, 2, glide='boom', human='pow')
    a5 = ArgumentsProfile(func, 1, 2, 3, 4, 5, 6, 'boom', 'pow')
    # edge case, second priority
    assert a4.args == (1, 2)
    assert a4.kwargs == OrderedDict((('glide', 'boom'), ('human', 'pow')))
    assert a4 == a5
def test_only_defaultless():
    '''
    Test `ArgumentsProfile` on a function with defaultless arguments only.
    '''
    def func(a, b, c):
        pass

    a1 = ArgumentsProfile(func, 1, 2, 3)
    assert a1.args == (1, 2, 3)
    assert not a1.kwargs

    a2 = ArgumentsProfile(func, 1, c=3, b=2)
    a3 = ArgumentsProfile(func, c=3, a=1, b=2)
    a4 = ArgumentsProfile(func, 1, **{'c': 3, 'b': 2})
    a5 = ArgumentsProfile(func, **OrderedDict((('c', 3), ('b', 2), ('a', 1))))
    assert a1 == a2 == a3 == a4 == a5

    for arg_prof in [a1, a2, a3, a4, a5]:

        ### Testing `.iteritems`: #############################################
        #                                                                     #
        assert dict(arg_prof) == {'a': 1, 'b': 2, 'c': 3}
        assert OrderedDict(arg_prof) == \
            OrderedDict((('a', 1), ('b', 2), ('c', 3)))
        #                                                                     #
        ### Finished testing `.iteritems`. ####################################

        ### Testing `.__getitem__`: ###########################################
        #                                                                     #
        assert (arg_prof['a'], arg_prof['b'], arg_prof['c']) == (1, 2, 3)
        with cute_testing.RaiseAssertor(KeyError):
            arg_prof['non_existing_key']
        #                                                                     #
        ### Finished testing `.__getitem__`. ##################################

        ### Testing `.get`: ###################################################
        #                                                                     #
        assert arg_prof.get('a') == arg_prof.get('a', 'asdfasdf') == 1
        assert arg_prof.get('non_existing_key', 7) == 7
        assert arg_prof.get('non_existing_key') is None
Beispiel #10
0
    def __init__(self,
                 parameters=None,
                 return_annotation=_empty,
                 __validate_parameters__=True):
        '''Constructs Signature from the given list of Parameter
        objects and 'return_annotation'.  All arguments are optional.
        '''

        if parameters is None:
            params = OrderedDict()
        else:
            if __validate_parameters__:
                params = OrderedDict()
                top_kind = _POSITIONAL_ONLY

                for idx, param in enumerate(parameters):
                    kind = param.kind
                    if kind < top_kind:
                        msg = 'wrong parameter order: {0} before {1}'
                        msg = msg.format(top_kind, param.kind)
                        raise ValueError(msg)
                    else:
                        top_kind = kind

                    name = param.name
                    if name is None:
                        name = str(idx)
                        param = param.replace(name=name)

                    if name in params:
                        msg = 'duplicate parameter name: {0!r}'.format(name)
                        raise ValueError(msg)
                    params[name] = param
            else:
                params = OrderedDict(
                    ((param.name, param) for param in parameters))

        self._parameters = params
        self._return_annotation = return_annotation
Beispiel #11
0
 def test_only_positive_ints_or_zero(self):
     assert self.bag_type(
         OrderedDict([('a', 0), ('b', 0.0), ('c', 1), ('d', 2.0),
                      ('e', decimal_module.Decimal('3.0'))])) == \
                                                     self.bag_type('cddeee')
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': 1.1,
         })
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': -2,
         })
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': -3,
         })
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': decimal_module.Decimal('-3'),
         })
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': infinity,
         })
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': -infinity,
         })
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': 'whatever',
         })
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': b'whateva',
         })
     with cute_testing.RaiseAssertor(TypeError):
         self.bag_type({
             'a': ('still', 'nope'),
         })
def test_simplest_defaultful():
    '''
    Test `ArgumentsProfile` on a function with defaultful arguments.
    '''
    def func(a, b, c='three', d='four'):
        pass

    a1 = ArgumentsProfile(func, 'one', 'two')
    assert a1.args == ('one', 'two')
    assert not a1.kwargs

    a2 = ArgumentsProfile(func, 'one', 'two', 'three')
    a3 = ArgumentsProfile(func, 'one', 'two', 'three', 'four')
    assert a1 == a2 == a3

    a4 = ArgumentsProfile(func, 'one', 'two', 'dynamite')
    assert a1 != a4
    assert a4.args == ('one', 'two', 'dynamite')
    assert not a4.kwargs

    a5 = ArgumentsProfile(func, 'one', 'two', c='dynamite')
    a6 = ArgumentsProfile(func, 'one', 'two', 'dynamite', 'four')
    a7 = ArgumentsProfile(func, 'one', 'two', c='dynamite', d='four')
    a8 = ArgumentsProfile(func, 'one', 'two', 'dynamite', d='four')
    a9 = ArgumentsProfile(func, a='one', b='two', c='dynamite', d='four')
    a10 = ArgumentsProfile(func, d='four', c='dynamite', b='two', a='one')
    a11 = ArgumentsProfile(func, 'one', c='dynamite', d='four', b='two')
    assert a4 == a5 == a6 == a7 == a8 == a9 == a10 == a11

    a12 = ArgumentsProfile(func, 'one', 'two', d='bang')
    assert a12.args == ('one', 'two')
    assert a12.kwargs == OrderedDict((('d', 'bang'), ))

    a13 = ArgumentsProfile(func, 'one', 'two', 'three', d='bang')
    a14 = ArgumentsProfile(func, 'one', 'two', c='three', d='bang')
    a15 = ArgumentsProfile(func, 'one', 'two', 'three', 'bang')
    a16 = ArgumentsProfile(func, a='one', b='two', c='three', d='bang')
    a17 = ArgumentsProfile(func, b='two', c='three', d='bang', a='one')
    assert a13 == a14 == a15 == a16 == a17
def test_unhashable():
    '''Test hashing of `ArgumentsProfile` that has unhashable arguments.'''
    def func(a, b, c=3, d=4, **kwargs):
        pass

    a1 = ArgumentsProfile(func, 7, {1: 2})
    assert a1.args == (7, {1: 2})
    assert not a1.kwargs
    hash(a1)

    a2 = ArgumentsProfile(func,
                          7, ({
                              'a': 'b'
                          }, ), {1, (3, 4)},
                          meow=[1, 2, {
                              1: [1, 2]
                          }])
    assert a2.args == (7, ({'a': 'b'}, ), {1, (3, 4)})
    assert a2.kwargs == OrderedDict((('meow', [1, 2, {1: [1, 2]}]), ))

    d = {a1: 1, a2: 2}
    assert d[a1] == 1
    assert d[a2] == 2
def test_defaultful_long_first():
    '''
    Test `ArgumentsProfile` on function with long first defaultful argument.
    '''
    def func(a, b, creativity=3, d=4):
        pass

    a1 = ArgumentsProfile(func, 1, 2)
    assert a1.args == (1, 2)
    assert not a1.kwargs

    a2 = ArgumentsProfile(func, 1, 2, 3, 4)
    a3 = ArgumentsProfile(func, a=1, b=2, creativity=3, d=4)
    a4 = ArgumentsProfile(func, creativity=3, d=4, a=1, b=2)
    a5 = ArgumentsProfile(func, 1, 2, creativity=3, d=4)
    assert a1 == a2 == a3 == a4 == a5

    a6 = ArgumentsProfile(func, 1, 2, d='booyeah')
    assert a6.args == (1, 2)
    assert a6.kwargs == OrderedDict((('d', 'booyeah'), ))

    a7 = ArgumentsProfile(func, 1, 2, 3, 'booyeah')
    a8 = ArgumentsProfile(func, 1, 2, creativity=3, d='booyeah')
    assert a6 == a7 == a8
Beispiel #15
0
    def test_operations(self):
        bag_0 = self.bag_type('abbccc')
        bag_1 = self.bag_type('bcc')
        bag_2 = self.bag_type('cddddd')

        assert bag_0 + bag_1 == self.bag_type('abbccc' + 'bcc')
        assert bag_1 + bag_0 == self.bag_type('bcc' + 'abbccc')
        assert bag_0 + bag_2 == self.bag_type('abbccc' + 'cddddd')
        assert bag_2 + bag_0 == self.bag_type('cddddd' + 'abbccc')
        assert bag_1 + bag_2 == self.bag_type('bcc' + 'cddddd')
        assert bag_2 + bag_1 == self.bag_type('cddddd' + 'bcc')

        assert bag_0 - bag_1 == self.bag_type('abc')
        assert bag_1 - bag_0 == self.bag_type()
        assert bag_0 - bag_2 == self.bag_type('abbcc')
        assert bag_2 - bag_0 == self.bag_type('ddddd')
        assert bag_1 - bag_2 == self.bag_type('bc')
        assert bag_2 - bag_1 == self.bag_type('ddddd')

        assert bag_0 * 2 == self.bag_type('abbccc' * 2)
        assert bag_1 * 2 == self.bag_type('bcc' * 2)
        assert bag_2 * 2 == self.bag_type('cddddd' * 2)
        assert 3 * bag_0 == self.bag_type('abbccc' * 3)
        assert 3 * bag_1 == self.bag_type('bcc' * 3)
        assert 3 * bag_2 == self.bag_type('cddddd' * 3)

        # We only allow floor division on bags, not regular divison, because a
        # decimal bag is unheard of.
        with cute_testing.RaiseAssertor(TypeError):
            bag_0 / 2
        with cute_testing.RaiseAssertor(TypeError):
            bag_1 / 2
        with cute_testing.RaiseAssertor(TypeError):
            bag_2 / 2
        with cute_testing.RaiseAssertor(TypeError):
            bag_0 / self.bag_type('ab')
        with cute_testing.RaiseAssertor(TypeError):
            bag_1 / self.bag_type('ab')
        with cute_testing.RaiseAssertor(TypeError):
            bag_2 / self.bag_type('ab')

        assert bag_0 // 2 == self.bag_type('bc')
        assert bag_1 // 2 == self.bag_type('c')
        assert bag_2 // 2 == self.bag_type('dd')
        assert bag_0 // self.bag_type('ab') == 1
        assert bag_1 // self.bag_type('ab') == 0
        assert bag_2 // self.bag_type('ab') == 0

        with cute_testing.RaiseAssertor(ZeroDivisionError):
            bag_0 // 0
        with cute_testing.RaiseAssertor(ZeroDivisionError):
            bag_0 // self.bag_type()

        assert bag_0 % 2 == self.bag_type('ac') == bag_0 - ((bag_0 // 2) * 2) \
               == self.bag_type(OrderedDict((key, count % 2) for (key, count)
                                                             in bag_0.items()))
        assert bag_1 % 2 == self.bag_type('b') == bag_1 - ((bag_1 // 2) * 2) \
               == self.bag_type(OrderedDict((key, count % 2) for (key, count)
                                                             in bag_1.items()))
        assert bag_2 % 2 == self.bag_type('cd') == bag_2 - ((bag_2 // 2) * 2)\
               == self.bag_type(OrderedDict((key, count % 2) for (key, count)
                                                             in bag_2.items()))
        assert bag_0 % self.bag_type('ac') == self.bag_type('bbcc')
        assert bag_1 % self.bag_type('b') == self.bag_type('cc')
        assert bag_2 % self.bag_type('cd') == self.bag_type('dddd')

        assert bag_0**2 == pow(bag_0, 2) == self.bag_type('abbbbccccccccc')
        assert bag_1**2 == pow(bag_1, 2) == self.bag_type('bcccc')
        assert bag_2 ** 2 == pow(bag_2, 2) == \
                                    self.bag_type('cddddddddddddddddddddddddd')
        assert pow(bag_0, 2, 3) == self.bag_type('ab')
        assert pow(bag_1, 2, 3) == self.bag_type('bc')
        assert pow(bag_2, 2, 3) == self.bag_type('cd')

        assert divmod(bag_0, 3) == (bag_0 // 3, bag_0 % 3)
        assert divmod(bag_1, 3) == (bag_1 // 3, bag_1 % 3)
        assert divmod(bag_2, 3) == (bag_2 // 3, bag_2 % 3)
        assert divmod(bag_0, self.bag_type('cd')) == \
                    (bag_0 // self.bag_type('cd'), bag_0 % self.bag_type('cd'))
        assert divmod(bag_1, self.bag_type('cd')) == \
                    (bag_1 // self.bag_type('cd'), bag_1 % self.bag_type('cd'))
        assert divmod(bag_2, self.bag_type('cd')) == \
                    (bag_2 // self.bag_type('cd'), bag_2 % self.bag_type('cd'))
Beispiel #16
0
    def _bind(self, args, kwargs, partial=False):
        '''Private method.  Don't use directly.'''

        arguments = OrderedDict()

        parameters = iter(self.parameters.values())
        parameters_ex = ()
        arg_vals = iter(args)

        if partial:
            # Support for binding arguments to 'functools.partial' objects.
            # See 'functools.partial' case in 'signature()' implementation
            # for details.
            for param_name, param in self.parameters.items():
                if (param._partial_kwarg and param_name not in kwargs):
                    # Simulating 'functools.partial' behavior
                    kwargs[param_name] = param.default

        while True:
            # Let's iterate through the positional arguments and corresponding
            # parameters
            try:
                arg_val = next(arg_vals)
            except StopIteration:
                # No more positional arguments
                try:
                    param = next(parameters)
                except StopIteration:
                    # No more parameters. That's it. Just need to check that
                    # we have no `kwargs` after this while loop
                    break
                else:
                    if param.kind == _VAR_POSITIONAL:
                        # That's OK, just empty *args.  Let's start parsing
                        # kwargs
                        break
                    elif param.name in kwargs:
                        if param.kind == _POSITIONAL_ONLY:
                            msg = '{arg!r} parameter is positional only, ' \
                                  'but was passed as a keyword'
                            msg = msg.format(arg=param.name)
                            raise TypeError(msg)
                        parameters_ex = (param, )
                        break
                    elif (param.kind == _VAR_KEYWORD
                          or param.default is not _empty):
                        # That's fine too - we have a default value for this
                        # parameter.  So, lets start parsing `kwargs`, starting
                        # with the current parameter
                        parameters_ex = (param, )
                        break
                    else:
                        if partial:
                            parameters_ex = (param, )
                            break
                        else:
                            msg = '{arg!r} parameter lacking default value'
                            msg = msg.format(arg=param.name)
                            raise TypeError(msg)
            else:
                # We have a positional argument to process
                try:
                    param = next(parameters)
                except StopIteration:
                    raise TypeError('too many positional arguments')
                else:
                    if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
                        # Looks like we have no parameter for this positional
                        # argument
                        raise TypeError('too many positional arguments')

                    if param.kind == _VAR_POSITIONAL:
                        # We have an '*args'-like argument, let's fill it with
                        # all positional arguments we have left and move on to
                        # the next phase
                        values = [arg_val]
                        values.extend(arg_vals)
                        arguments[param.name] = tuple(values)
                        break

                    if param.name in kwargs:
                        raise TypeError('multiple values for argument '
                                        '{arg!r}'.format(arg=param.name))

                    arguments[param.name] = arg_val

        # Now, we iterate through the remaining parameters to process
        # keyword arguments
        kwargs_param = None
        for param in itertools.chain(parameters_ex, parameters):
            if param.kind == _POSITIONAL_ONLY:
                # This should never happen in case of a properly built
                # Signature object (but let's have this check here
                # to ensure correct behaviour just in case)
                raise TypeError('{arg!r} parameter is positional only, '
                                'but was passed as a keyword'. \
                                format(arg=param.name))

            if param.kind == _VAR_KEYWORD:
                # Memorize that we have a '**kwargs'-like parameter
                kwargs_param = param
                continue

            param_name = param.name
            try:
                arg_val = kwargs.pop(param_name)
            except KeyError:
                # We have no value for this parameter.  It's fine though,
                # if it has a default value, or it is an '*args'-like
                # parameter, left alone by the processing of positional
                # arguments.
                if (not partial and param.kind != _VAR_POSITIONAL
                        and param.default is _empty):
                    raise TypeError('{arg!r} parameter lacking default value'. \
                                    format(arg=param_name))

            else:
                arguments[param_name] = arg_val

        if kwargs:
            if kwargs_param is not None:
                # Process our '**kwargs'-like parameter
                arguments[kwargs_param.name] = kwargs
            else:
                raise TypeError('too many keyword arguments')

        return self._bound_arguments_cls(self, arguments)
Beispiel #17
0
 def parameters(self):
     try:
         return types.MappingProxyType(self._parameters)
     except AttributeError:
         return OrderedDict(self._parameters.items())
def test_many_defaultfuls_and_star_args_and_star_kwargs():
    '''
    Test `ArgumentsProfile` with defaultful arguments, `*args` and `**kwargs`.
    '''
    def func(a, b, c='three', d='four', e='five', f='six', *args, **kwargs):
        pass

    func(None, None)

    a1 = ArgumentsProfile(func,
                          'one',
                          'two',
                          f='boomboomboom',
                          __awesome=True,
                          big=True)
    assert a1.args == ('one', 'two')
    assert a1.kwargs == OrderedDict(
        (('f', 'boomboomboom'), ('big', True), ('__awesome', True)))

    a2 = ArgumentsProfile(func,
                          'one',
                          'two',
                          'three',
                          'four',
                          'five',
                          'bombastic',
                          'meow_frr',
                          __funky=None,
                          zany=True,
                          _wet=False,
                          blue=True)
    assert a2.args == ('one', 'two', 'three', 'four', 'five', 'bombastic',
                       'meow_frr')
    assert a2.kwargs == OrderedDict(
        (('blue', True), ('zany', True), ('_wet', False), ('__funky', None)))

    a3 = ArgumentsProfile(func,
                          'one',
                          'two',
                          'three',
                          'four',
                          'five',
                          'bombastic',
                          'meow_frr',
                          zany=True,
                          __funky=None,
                          blue=True,
                          _wet=False,
                          **OrderedDict())
    assert a2 == a3

    for arg_prof in [a2, a3]:
        # Testing `.iteritems`:
        assert OrderedDict(arg_prof) == OrderedDict(
            (('a', 'one'), ('b', 'two'), ('c', 'three'), ('d', 'four'),
             ('e', 'five'), ('f', 'bombastic'), ('*', ('meow_frr', )),
             ('blue', True), ('zany', True), ('_wet', False), ('__funky',
                                                               None)))

        ### Testing `.__getitem__`: ###########################################
        #                                                                     #
        assert (arg_prof['a'], arg_prof['b'], arg_prof['c'], arg_prof['d'],
                arg_prof['e'], arg_prof['f'], arg_prof['*'], arg_prof['blue'],
                arg_prof['zany'],  arg_prof['_wet'], arg_prof['__funky']) == \
               ('one', 'two', 'three', 'four', 'five', 'bombastic',
                ('meow_frr',), True, True, False, None)

        with cute_testing.RaiseAssertor(KeyError):
            arg_prof['non_existing_key']
        #                                                                     #
        ### Finished testing `.__getitem__`. ##################################

        ### Testing `.get`: ###################################################
        #                                                                     #
        assert arg_prof.get('d') == arg_prof.get('d', 7) == 'four'
        assert arg_prof.get('non_existing_key', 7) == 7
        assert arg_prof.get('non_existing_key') is None
        #                                                                     #
        ### Finished testing `.get`. ##########################################

        ### Testing `.iterkeys`, `.keys` and `__iter__`: ######################
        #                                                                     #
        assert list(arg_prof.iterkeys()) == list(arg_prof.keys()) == \
            list(arg_prof) == \
            ['a', 'b', 'c', 'd', 'e', 'f', '*', 'blue', 'zany', '_wet',
             '__funky']
        #                                                                     #
        ### Finished testing `.iterkeys`, `.keys` and `__iter__`. #############

        ### Testing `.itervalues` and `.values`: ##############################
        #                                                                     #
        assert list(arg_prof.itervalues()) == list(arg_prof.values()) == \
            ['one', 'two', 'three', 'four', 'five', 'bombastic', ('meow_frr',),
             True, True, False, None]
        #                                                                     #
        ### Finished testing `.itervalues` and `.values`. #####################

        ### Testing `.iteritems` and `.items`: ################################
        #                                                                     #
        items_1 = list(arg_prof.iteritems())
        items_2 = arg_prof.items()
        assert items_1 == items_2 == zip(arg_prof.keys(), arg_prof.values())
        #                                                                     #
        ### Finished testing `.iteritems` and `.items`. #######################

        ### Testing `.__contains__`: ##########################################
        #                                                                     #
        for key in arg_prof:
            assert key in arg_prof
    def __init__(self, function, *args, **kwargs):
        '''
        Construct the arguments profile.
        
        `*args` and `**kwargs` are the arguments that go into the `function`.
        '''

        if not callable(function):
            raise Exception('%s is not a callable object.' % function)
        self.function = function

        raw_args = args
        raw_kwargs = kwargs
        del args, kwargs

        self.args = ()
        '''Tuple of positional arguments.'''

        self.kwargs = OrderedDict()
        '''Ordered dict of keyword arguments.'''

        args_spec = cute_inspect.getargspec(function)

        (s_args, s_star_args, s_star_kwargs, s_defaults) = args_spec

        # `getargspec` has a weird policy, when inspecting a function with no
        # defaults, to give a `defaults` of `None` instead of the more
        # consistent `()`. We fix that here:
        if s_defaults is None:
            s_defaults = ()

        getcallargs_result = cute_inspect.getcallargs(function, *raw_args,
                                                      **raw_kwargs)
        self.getcallargs_result = getcallargs_result

        # The number of args which have default values:
        n_defaultful_args = len(s_defaults)
        # The word "defaultful" means "something which has a default."

        #######################################################################
        #######################################################################
        # Now we'll create the arguments profile, using a 4-phases algorithm. #
        #                                                                     #

        #######################################################################
        # Phase 1: We specify all the args that don't have a default as
        # positional args:
        defaultless_args = s_args[:-n_defaultful_args] if n_defaultful_args \
                           else s_args[:]
        self.args += tuple(
            dict_tools.get_list(getcallargs_result, defaultless_args))

        #######################################################################
        # Phase 2: We now have to deal with args that have a default. Some of
        # them, possibly none and possibly all of them, should be given
        # positionally. Some of them, possibly none, should be given by
        # keyword. And some of them, possibly none and possibly all of them,
        # should not be given at all. It is our job to figure out in which way
        # each argument should be given.

        # In this variable:
        n_defaultful_args_to_specify_positionally = None
        # We will put the number of defaultful arguments that should be
        # specified positionally.

        defaultful_args = s_args[-n_defaultful_args:] if n_defaultful_args \
                          else []

        # `dict` that maps from argument name to default value:
        defaults = OrderedDict(zip(defaultful_args, s_defaults))

        defaultful_args_differing_from_defaults = {
            defaultful_arg
            for defaultful_arg in defaultful_args
            if defaults[defaultful_arg] != getcallargs_result[defaultful_arg]
        }

        if s_star_args and getcallargs_result[s_star_args]:
            # We have some arguments that go into `*args`! This means that we
            # don't even need to think hard, we can already be sure that we're
            # going to have to specify *all* of the defaultful arguments
            # positionally, otherwise it will be impossible to put arguments in
            # `*args`.
            n_defaultful_args_to_specify_positionally = n_defaultful_args

        else:

            # `dict` mapping from each defaultful arg to the "price" of
            # specifying its value:
            prices_of_values = OrderedDict({
                defaultful_arg: len(repr(getcallargs_result[defaultful_arg]))
                for defaultful_arg in defaultful_args
            })
            # The price is simply the string length of the value's `repr`.

            # `dict` mapping from each defaultful arg to the "price" of
            # specifying it as a keyword (not including the length of the
            # value):
            prices_of_keyword_prefixes = OrderedDict({
                defaultful_arg: len(defaultful_arg) + 1
                for defaultful_arg in defaultful_args
            })
            # For example, if we have a defaultful arg "gravity_strength", then
            # specifiying it by keyword will require using the string
            # "gravity_strength=", which is 17 characters long, therefore the
            # price is 17.

            # Now we need to decide just how many defaultful args we are going
            # to specify positionally. The options are anything from `0` to
            # `n_defaultful_args`. We're going to go one by one, and calcluate
            # the price for each candidate, and put it in this dict:
            total_price_for_n_dasp_candidate = OrderedDict()
            # (The `n_dasp` here is an abbreivation of the
            # `n_defaultful_args_to_specify_positionally` variable defined
            # before.)
            #
            # After we have the price for each option, we'll select the one
            # with the lowest price.

            # One thing to do before iterating on the candidates is to find out
            # whether the "lonely comma discount" is in effect.
            #
            # The "lonely comma discount" is given when there's nothing but
            # defaultful arguments to this function, and therefore the number
            # of ", " strings needed here is not `candidate`, but `candidate -
            # 1`, unless of course candidate is zero.

            if not defaultless_args and \
                (not s_star_args or not getcallargs_result[s_star_args]) and \
                (not s_star_kwargs or not getcallargs_result[s_star_kwargs]):

                lonely_comma_discount_may_be_given = True

            else:

                lonely_comma_discount_may_be_given = False

            # Now we iterate on the candidates to find out which one has the
            # lowest price:

            for candidate in range(n_defaultful_args + 1):

                defaultful_args_to_specify_positionally = \
                    defaultful_args[:candidate]

                price_for_positionally_specified_defaultful_args = \
                    2 * candidate + \
                    sum(
                        dict_tools.get_list(
                            prices_of_values,
                            defaultful_args_to_specify_positionally
                        )
                    )
                # The `2 * candidate` addend is to account for the ", " parts
                # between the arguments.

                defaultful_args_to_specify_by_keyword = list(
                    filter(
                        defaultful_args_differing_from_defaults.__contains__,
                        defaultful_args[candidate:]))

                price_for_defaultful_args_specified_by_keyword = \
                    2 * len(defaultful_args_to_specify_by_keyword) + \
                    sum(
                        dict_tools.get_list(
                            prices_of_keyword_prefixes,
                            defaultful_args_to_specify_by_keyword
                        )
                    ) + \
                    sum(
                        dict_tools.get_list(
                            prices_of_values,
                            defaultful_args_to_specify_by_keyword
                        )
                    )
                # The `2 * len(...)` addend is to account for the ", " parts
                # between the arguments.

                # Now we need to figure out if this candidate gets the "lonely
                # comma discount".
                if lonely_comma_discount_may_be_given and \
                   (defaultful_args_to_specify_by_keyword or \
                    defaultful_args_to_specify_positionally):

                    lonely_comma_discount = -2

                else:
                    lonely_comma_discount = 0

                price = price_for_positionally_specified_defaultful_args + \
                        price_for_defaultful_args_specified_by_keyword + \
                        lonely_comma_discount

                total_price_for_n_dasp_candidate[candidate] = price

            # Finished iterating on candidates! Time to pick our winner.

            minimum_price = min(total_price_for_n_dasp_candidate.values())

            leading_candidates = [
                candidate
                for candidate in total_price_for_n_dasp_candidate.keys()
                if total_price_for_n_dasp_candidate[candidate] == minimum_price
            ]

            if len(leading_candidates) == 1:
                # We finished with one candidate which has the minimum price.
                # This is our winner.
                (winner, ) = leading_candidates
                n_defaultful_args_to_specify_positionally = winner

            else:
                # We have a draw! We're gonna have to settle it by picking the
                # lowest candidate, because in our definition of "canonical
                # arguments profile", our second priority after "as few
                # characters as possible" is "as many keyword arguments as
                # possible".
                winner = leading_candidates[0]

            n_defaultful_args_to_specify_positionally = winner

        # We have a winner! Now we know exactly which defaultful args should
        # be specified positionally and which should be specified by
        # keyword.

        # First we add the positionally specified:

        defaultful_args_to_specify_positionally = \
            defaultful_args[:n_defaultful_args_to_specify_positionally]
        self.args += tuple(
            (getcallargs_result[defaultful_arg]
             for defaultful_arg in defaultful_args_to_specify_positionally))

        # Now we add those specified by keyword:

        defaultful_args_to_specify_by_keyword = list(
            filter(
                defaultful_args_differing_from_defaults.__contains__,
                defaultful_args[n_defaultful_args_to_specify_positionally:]))
        for defaultful_arg in defaultful_args_to_specify_by_keyword:
            self.kwargs[defaultful_arg] = getcallargs_result[defaultful_arg]

        #######################################################################
        # Phase 3: Add the star args:

        if s_star_args and getcallargs_result[s_star_args]:

            assert not self.kwargs
            # Just making sure that no non-star args were specified by keyword,
            # which would make it impossible for us to put stuff in `*args`.

            self.args += getcallargs_result[s_star_args]

        #######################################################################
        # Phase 4: Add the star kwargs:

        if s_star_kwargs and getcallargs_result[s_star_kwargs]:

            # We can't just add the `**kwargs` as is; we need to add them
            # according to canonical ordering. So we need to sort them first.

            unsorted_star_kwargs_names = \
                list(getcallargs_result[s_star_kwargs].keys())
            sorted_star_kwargs_names = sorted(
                unsorted_star_kwargs_names,
                key=comparison_tools.underscore_hating_key)

            sorted_star_kwargs = OrderedDict(
                zip(
                    sorted_star_kwargs_names,
                    dict_tools.get_list(getcallargs_result[s_star_kwargs],
                                        sorted_star_kwargs_names)))

            self.kwargs.update(sorted_star_kwargs)

        # Our 4-phases algorithm is done! The argument profile is canonical.  #
        #######################################################################
        #######################################################################

        #######################################################################
        # Now a bit of post-processing:

        _arguments = OrderedDict()

        dict_of_positional_arguments = OrderedDict(
            dict_tools.filter_items(
                getcallargs_result,
                lambda key, value: ((key not in self.kwargs) and \
                                    (key != s_star_args) and \
                                    (key != s_star_kwargs))
            )
        )
        dict_of_positional_arguments.sort(key=s_args.index)
        _arguments.update(dict_of_positional_arguments)

        if s_star_args:
            _arguments['*'] = getcallargs_result[s_star_args]

        _arguments.update(self.kwargs)

        self._arguments = _arguments
        '''Ordered dict of arguments, both positional- and keyword-.'''

        # Caching the hash, since its computation can take a long time:
        self._hash = cheat_hashing.cheat_hash(
            (self.function, self.args, tuple(self.kwargs)))
def test_defaultfuls_and_star_kwargs():
    '''Test `ArgumentsProfile` with defaultful arguments and `**kwargs`.'''
    def func(a, b, c=3, d=4, **kwargs):
        pass

    a1 = ArgumentsProfile(func, 1, 2)
    assert a1.args == (1, 2)
    assert not a1.kwargs

    # Alphabetic ordering among the `**kwargs`, but `d` is first because it's a
    # non-star:
    a2 = ArgumentsProfile(func, 1, 2, d='bombastic', zany=True, blue=True)
    assert a2.args == (1, 2)
    assert a2.kwargs == OrderedDict(
        (('d', 'bombastic'), ('blue', True), ('zany', True)))

    a3 = ArgumentsProfile(func, 1, b=2, blue=True, d='bombastic', zany=True)
    a4 = ArgumentsProfile(func, zany=True, a=1, b=2, blue=True, d='bombastic')
    a5 = ArgumentsProfile(func, 1, 2, 3, 'bombastic', zany=True, blue=True)
    assert a2 == a3 == a4 == a5

    for arg_prof in [a2, a3, a4, a5]:
        # Testing `.iteritems`:
        assert OrderedDict(arg_prof) == OrderedDict(
            (('a', 1), ('b', 2), ('c', 3), ('d', 'bombastic'), ('blue', True),
             ('zany', True)))

        ### Testing `.__getitem__`: ###########################################
        #                                                                     #
        assert (arg_prof['a'], arg_prof['b'], arg_prof['c'], arg_prof['d'],
                arg_prof['blue'], arg_prof['zany']) == \
               (1, 2, 3, 'bombastic', True, True)

        with cute_testing.RaiseAssertor(KeyError):
            arg_prof['non_existing_key']
        #                                                                     #
        ### Finished testing `.__getitem__`. ##################################

        ### Testing `.get`: ###################################################
        #                                                                     #
        assert arg_prof.get('d') == arg_prof.get('d', 7) == 'bombastic'
        assert arg_prof.get('non_existing_key', 7) == 7
        assert arg_prof.get('non_existing_key') is None
        #                                                                     #
        ### Finished testing `.get`. ##########################################

        ### Testing `.iterkeys`, `.keys` and `__iter__`: ######################
        #                                                                     #
        assert list(arg_prof.iterkeys()) == list(arg_prof.keys()) == \
            list(arg_prof) == ['a', 'b', 'c', 'd', 'blue', 'zany']
        #                                                                     #
        ### Finished testing `.iterkeys`, `.keys` and `__iter__`. #############

        ### Testing `.itervalues` and `.values`: ##############################
        #                                                                     #
        assert list(arg_prof.itervalues()) == list(arg_prof.values()) == \
            [1, 2, 3, 'bombastic', True, True]
        #                                                                     #
        ### Finished testing `.itervalues` and `.values`. #####################

        ### Testing `.__contains__`: ##########################################
        #                                                                     #
        for key in arg_prof:
            assert key in arg_prof
        assert 'agaofgnafgadf' not in arg_prof
        assert '**' not in arg_prof
Beispiel #21
0
    def test_operations(self):
        bag_0 = self.bag_type('abbccc')
        bag_1 = self.bag_type('bcc')
        bag_2 = self.bag_type('cddddd')

        assert bag_0 + bag_1 == self.bag_type('abbccc' + 'bcc')
        assert bag_1 + bag_0 == self.bag_type('bcc' + 'abbccc')
        assert bag_0 + bag_2 == self.bag_type('abbccc' + 'cddddd')
        assert bag_2 + bag_0 == self.bag_type('cddddd' + 'abbccc')
        assert bag_1 + bag_2 == self.bag_type('bcc' + 'cddddd')
        assert bag_2 + bag_1 == self.bag_type('cddddd' + 'bcc')

        assert bag_0 - bag_1 == self.bag_type('abc')
        assert bag_1 - bag_0 == self.bag_type()
        assert bag_0 - bag_2 == self.bag_type('abbcc')
        assert bag_2 - bag_0 == self.bag_type('ddddd')
        assert bag_1 - bag_2 == self.bag_type('bc')
        assert bag_2 - bag_1 == self.bag_type('ddddd')

        assert bag_0 * 2 == self.bag_type('abbccc' * 2)
        assert bag_1 * 2 == self.bag_type('bcc' * 2)
        assert bag_2 * 2 == self.bag_type('cddddd' * 2)
        assert 3 * bag_0 == self.bag_type('abbccc' * 3)
        assert 3 * bag_1 == self.bag_type('bcc' * 3)
        assert 3 * bag_2 == self.bag_type('cddddd' * 3)

        assert bag_0 // 2 == self.bag_type('bc')
        assert bag_1 // 2 == self.bag_type('c')
        assert bag_2 // 2 == self.bag_type('dd')
        assert bag_0 // self.bag_type('ab') == 1
        assert bag_1 // self.bag_type('ab') == 0
        assert bag_2 // self.bag_type('ab') == 0

        with cute_testing.RaiseAssertor(ZeroDivisionError):
            bag_0 // 0
        with cute_testing.RaiseAssertor(ZeroDivisionError):
            bag_0 // self.bag_type()

        assert bag_0 % 2 == self.bag_type('ac') == bag_0 - ((bag_0 // 2) * 2) \
               == self.bag_type(OrderedDict((key, count % 2) for (key, count)
                                                             in bag_0.items()))
        assert bag_1 % 2 == self.bag_type('b') == bag_1 - ((bag_1 // 2) * 2) \
               == self.bag_type(OrderedDict((key, count % 2) for (key, count)
                                                             in bag_1.items()))
        assert bag_2 % 2 == self.bag_type('cd') == bag_2 - ((bag_2 // 2) * 2)\
               == self.bag_type(OrderedDict((key, count % 2) for (key, count)
                                                             in bag_2.items()))
        assert bag_0 % self.bag_type('ac') == self.bag_type('bbcc')
        assert bag_1 % self.bag_type('b') == self.bag_type('cc')
        assert bag_2 % self.bag_type('cd') == self.bag_type('dddd')

        assert bag_0**2 == pow(bag_0, 2) == self.bag_type('abbbbccccccccc')
        assert bag_1**2 == pow(bag_1, 2) == self.bag_type('bcccc')
        assert bag_2 ** 2 == pow(bag_2, 2) == \
                                    self.bag_type('cddddddddddddddddddddddddd')
        assert pow(bag_0, 2, 3) == self.bag_type('ab')
        assert pow(bag_1, 2, 3) == self.bag_type('bc')
        assert pow(bag_2, 2, 3) == self.bag_type('cd')

        assert divmod(bag_0, 3) == (bag_0 // 3, bag_0 % 3)
        assert divmod(bag_1, 3) == (bag_1 // 3, bag_1 % 3)
        assert divmod(bag_2, 3) == (bag_2 // 3, bag_2 % 3)
        assert divmod(bag_0, self.bag_type('cd')) == \
                    (bag_0 // self.bag_type('cd'), bag_0 % self.bag_type('cd'))
        assert divmod(bag_1, self.bag_type('cd')) == \
                    (bag_1 // self.bag_type('cd'), bag_1 % self.bag_type('cd'))
        assert divmod(bag_2, self.bag_type('cd')) == \
                    (bag_2 // self.bag_type('cd'), bag_2 % self.bag_type('cd'))
 def _asdict(self):
     '''
     Return a new `OrderedDict` which maps field names to their values.
     '''
     from python_toolbox.nifty_collections import OrderedDict
     return OrderedDict(zip(self._fields, self))
Beispiel #23
0
def signature(obj):
    '''Get a signature object for the passed callable.'''

    if not callable(obj):
        raise TypeError('{0!r} is not a callable object'.format(obj))

    if isinstance(obj, types.MethodType):
        sig = signature(obj.__func__)
        if obj.__self__ is None:
            # Unbound method: the first parameter becomes positional-only
            if sig.parameters:
                first = sig.parameters.values()[0].replace(
                    kind=_POSITIONAL_ONLY)
                return sig.replace(parameters=(first, ) +
                                   tuple(sig.parameters.values())[1:])
            else:
                return sig
        else:
            # In this case we skip the first parameter of the underlying
            # function (usually `self` or `cls`).
            return sig.replace(parameters=tuple(sig.parameters.values())[1:])

    try:
        sig = obj.__signature__
    except AttributeError:
        pass
    else:
        if sig is not None:
            return sig

    try:
        # Was this function wrapped by a decorator?
        wrapped = obj.__wrapped__
    except AttributeError:
        pass
    else:
        return signature(wrapped)

    if isinstance(obj, types.FunctionType):
        return Signature.from_function(obj)

    if isinstance(obj, functools.partial):
        sig = signature(obj.func)

        new_params = OrderedDict(sig.parameters.items())

        partial_args = obj.args or ()
        partial_keywords = obj.keywords or {}
        try:
            ba = sig.bind_partial(*partial_args, **partial_keywords)
        except TypeError as ex:
            msg = 'partial object {0!r} has incorrect arguments'.format(obj)
            raise ValueError(msg)

        for arg_name, arg_value in ba.arguments.items():
            param = new_params[arg_name]
            if arg_name in partial_keywords:
                # We set a new default value, because the following code
                # is correct:
                #
                #   >>> def foo(a): print(a)
                #   >>> print(partial(partial(foo, a=10), a=20)())
                #   20
                #   >>> print(partial(partial(foo, a=10), a=20)(a=30))
                #   30
                #
                # So, with 'partial' objects, passing a keyword argument is
                # like setting a new default value for the corresponding
                # parameter
                #
                # We also mark this parameter with '_partial_kwarg'
                # flag.  Later, in '_bind', the 'default' value of this
                # parameter will be added to 'kwargs', to simulate
                # the 'functools.partial' real call.
                new_params[arg_name] = param.replace(default=arg_value,
                                                     _partial_kwarg=True)

            elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL)
                  and not param._partial_kwarg):
                new_params.pop(arg_name)

        return sig.replace(parameters=new_params.values())

    sig = None
    if isinstance(obj, type):
        # obj is a class or a metaclass

        # First, let's see if it has an overloaded __call__ defined
        # in its metaclass
        call = _get_user_defined_method(type(obj), '__call__')
        if call is not None:
            sig = signature(call)
        else:
            # Now we check if the 'obj' class has a '__new__' method
            new = _get_user_defined_method(obj, '__new__')
            if new is not None:
                sig = signature(new)
            else:
                # Finally, we should have at least __init__ implemented
                init = _get_user_defined_method(obj, '__init__')
                if init is not None:
                    sig = signature(init)
    elif not isinstance(obj, _NonUserDefinedCallables):
        # An object with __call__
        # We also check that the 'obj' is not an instance of
        # _WrapperDescriptor or _MethodWrapper to avoid
        # infinite recursion (and even potential segfault)
        call = _get_user_defined_method(type(obj), '__call__', 'im_func')
        if call is not None:
            sig = signature(call)

    if sig is not None:
        # For classes and objects we skip the first parameter of their
        # __call__, __new__, or __init__ methods
        return sig.replace(parameters=tuple(sig.parameters.values())[1:])

    if isinstance(obj, types.BuiltinFunctionType):
        # Raise a nicer error message for builtins
        msg = 'no signature found for builtin function {0!r}'.format(obj)
        raise ValueError(msg)

    raise ValueError(
        'callable {0!r} is not supported by signature'.format(obj))
Beispiel #24
0
    def decorator(function):

        # In case we're being given a function that is already cached:
        if getattr(function, 'is_cached', False): return function

        if max_size == infinity:

            if time_to_keep:

                sorting_key_function = lambda sleek_call_args: \
                                              cached._cache[sleek_call_args][1]

                def remove_expired_entries():
                    almost_cutting_point = \
                                          binary_search.binary_search_by_index(
                        list(cached._cache.keys()),
                        _get_now(),
                        sorting_key_function,
                        rounding=binary_search.LOW
                    )
                    if almost_cutting_point is not None:
                        cutting_point = almost_cutting_point + 1
                        for key in cached._cache.keys()[:cutting_point]:
                            del cached._cache[key]

                @misc_tools.set_attributes(_cache=OrderedDict())
                def cached(function, *args, **kwargs):
                    remove_expired_entries()
                    sleek_call_args = \
                        SleekCallArgs(cached._cache, function, *args, **kwargs)
                    try:
                        return cached._cache[sleek_call_args][0]
                    except KeyError:
                        value = function(*args, **kwargs)
                        cached._cache[sleek_call_args] = (value, _get_now() +
                                                          time_to_keep)
                        cached._cache.sort(key=sorting_key_function)
                        return value

            else:  # not time_to_keep

                @misc_tools.set_attributes(_cache={})
                def cached(function, *args, **kwargs):
                    sleek_call_args = \
                        SleekCallArgs(cached._cache, function, *args, **kwargs)
                    try:
                        return cached._cache[sleek_call_args]
                    except KeyError:
                        cached._cache[sleek_call_args] = value = \
                              function(*args, **kwargs)
                        return value

        else:  # max_size < infinity

            @misc_tools.set_attributes(_cache=OrderedDict())
            def cached(function, *args, **kwargs):
                sleek_call_args = \
                    SleekCallArgs(cached._cache, function, *args, **kwargs)
                try:
                    result = cached._cache[sleek_call_args]
                    cached._cache.move_to_end(sleek_call_args)
                    return result
                except KeyError:
                    cached._cache[sleek_call_args] = value = \
                        function(*args, **kwargs)
                    if len(cached._cache) > max_size:
                        cached._cache.popitem(last=False)
                    return value

        result = decorator_tools.decorator(cached, function)

        def cache_clear(key=CLEAR_ENTIRE_CACHE):
            if key is CLEAR_ENTIRE_CACHE:
                cached._cache.clear()
            else:
                try:
                    del cached._cache[key]
                except KeyError:
                    pass

        result.cache_clear = cache_clear

        result.is_cached = True

        return result