14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""functools.py - Tools for working with functions and callable objects
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""
34adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Python module wrapper for _functools C module
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# to allow utilities written in Python to be added
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# to the functools module.
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Written by Nick Coghlan <ncoghlan at gmail.com>
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#   Copyright (C) 2006 Python Software Foundation.
84adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# See C source code for _functools credits/copyright
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom _functools import partial, reduce
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# update_wrapper() and wraps() are tools to help write
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# wrapper functions that can handle naive introspection
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
154adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoWRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
164adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoWRAPPER_UPDATES = ('__dict__',)
174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef update_wrapper(wrapper,
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   wrapped,
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   assigned = WRAPPER_ASSIGNMENTS,
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   updated = WRAPPER_UPDATES):
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Update a wrapper function to look like the wrapped function
224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       wrapper is the function to be updated
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       wrapped is the original function
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       assigned is a tuple naming the attributes assigned directly
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       from the wrapped function to the wrapper function (defaults to
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       functools.WRAPPER_ASSIGNMENTS)
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       updated is a tuple naming the attributes of the wrapper that
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       are updated with the corresponding attribute from the wrapped
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       function (defaults to functools.WRAPPER_UPDATES)
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    for attr in assigned:
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        setattr(wrapper, attr, getattr(wrapped, attr))
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    for attr in updated:
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # Return the wrapper so this can be used as a decorator via partial()
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return wrapper
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef wraps(wrapped,
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao          assigned = WRAPPER_ASSIGNMENTS,
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao          updated = WRAPPER_UPDATES):
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Decorator factory to apply update_wrapper() to a wrapper function
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       Returns a decorator that invokes update_wrapper() with the decorated
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       function as the wrapper argument and the arguments to wraps() as the
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       remaining arguments. Default arguments are as for update_wrapper().
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       This is a convenience function to simplify applying partial() to
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       update_wrapper().
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return partial(update_wrapper, wrapped=wrapped,
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   assigned=assigned, updated=updated)
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef total_ordering(cls):
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Class decorator that fills in missing ordering methods"""
554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    convert = {
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '__lt__': [('__gt__', lambda self, other: not (self < other or self == other)),
574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   ('__le__', lambda self, other: self < other or self == other),
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   ('__ge__', lambda self, other: not self < other)],
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '__le__': [('__ge__', lambda self, other: not self <= other or self == other),
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   ('__lt__', lambda self, other: self <= other and not self == other),
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   ('__gt__', lambda self, other: not self <= other)],
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '__gt__': [('__lt__', lambda self, other: not (self > other or self == other)),
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   ('__ge__', lambda self, other: self > other or self == other),
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   ('__le__', lambda self, other: not self > other)],
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        '__ge__': [('__le__', lambda self, other: (not self >= other) or self == other),
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   ('__gt__', lambda self, other: self >= other and not self == other),
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   ('__lt__', lambda self, other: not self >= other)]
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    }
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    roots = set(dir(cls)) & set(convert)
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if not roots:
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise ValueError('must define at least one ordering operation: < > <= >=')
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    root = max(roots)       # prefer __lt__ to __le__ to __gt__ to __ge__
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    for opname, opfunc in convert[root]:
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if opname not in roots:
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            opfunc.__name__ = opname
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            opfunc.__doc__ = getattr(int, opname).__doc__
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            setattr(cls, opname, opfunc)
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return cls
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef cmp_to_key(mycmp):
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Convert a cmp= function into a key= function"""
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    class K(object):
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        __slots__ = ['obj']
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __init__(self, obj, *args):
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.obj = obj
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __lt__(self, other):
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return mycmp(self.obj, other.obj) < 0
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __gt__(self, other):
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return mycmp(self.obj, other.obj) > 0
904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __eq__(self, other):
914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return mycmp(self.obj, other.obj) == 0
924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __le__(self, other):
934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return mycmp(self.obj, other.obj) <= 0
944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __ge__(self, other):
954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return mycmp(self.obj, other.obj) >= 0
964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __ne__(self, other):
974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return mycmp(self.obj, other.obj) != 0
984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        def __hash__(self):
994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise TypeError('hash not implemented')
1004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return K
101