Edit on GitHub

vse_sim.decorators

  1import time
  2from functools import update_wrapper, wraps
  3from inspect import getfullargspec, isfunction
  4from itertools import starmap
  5
  6_missing = object()
  7
  8
  9def decorator(d):
 10    "Make function d a decorator: d wraps a function fn."
 11
 12    def _d(fn):
 13        return update_wrapper(d(fn), fn)
 14
 15    return _d
 16
 17
 18decorator = decorator(decorator)(decorator)
 19
 20
 21def setdefaultattr(obj, name, value):
 22    try:
 23        return getattr(obj, name)
 24    except AttributeError:
 25        setattr(obj, name, value)
 26    return value
 27
 28
 29def autoassign(*names, **kwargs):
 30    """
 31    autoassign(function) -> method
 32    autoassign(*argnames) -> decorator
 33    autoassign(exclude=argnames) -> decorator
 34
 35    allow a method to assign (some of) its arguments as attributes of
 36    'self' automatically.  E.g.
 37
 38    >>> class Foo(object):
 39    ...     @autoassign
 40    ...     def __init__(self, foo, bar): pass
 41    ...
 42    >>> breakfast = Foo('spam', 'eggs')
 43    >>> breakfast.foo, breakfast.bar
 44    ('spam', 'eggs')
 45
 46    To restrict autoassignment to 'bar' and 'baz', write:
 47
 48        @autoassign('bar', 'baz')
 49        def method(self, foo, bar, baz): ...
 50
 51    To prevent 'foo' and 'baz' from being autoassigned, use:
 52
 53        @autoassign(exclude=('foo', 'baz'))
 54        def method(self, foo, bar, baz): ...
 55    """
 56    if kwargs:
 57        exclude, f = set(kwargs["exclude"]), None
 58        sieve = lambda l: filter(lambda nv: nv[0] not in exclude, l)
 59    elif len(names) == 1 and isfunction(names[0]):
 60        f = names[0]
 61        sieve = lambda l: l
 62    else:
 63        names, f = set(names), None
 64        sieve = lambda l: [nv for nv in l if nv[0] in names]
 65
 66    def decorator(f):
 67        spec = getfullargspec(f)
 68        fargnames, fdefaults = spec.args, spec.defaults
 69        # Remove self from fargnames and make sure fdefault is a tuple
 70        fargnames, fdefaults = fargnames[1:], fdefaults or ()
 71        defaults = list(sieve(zip(reversed(fargnames), reversed(fdefaults))))
 72
 73        @wraps(f)
 74        def decorated(self, *args, **kwargs):
 75            assigned = dict(sieve(zip(fargnames, args)))
 76            assigned.update(sieve(kwargs.items()))
 77            for _ in starmap(assigned.setdefault, defaults):
 78                pass
 79            self.__dict__.update(assigned)
 80            return f(self, *args, **kwargs)
 81
 82        return decorated
 83
 84    return f and decorator(f) or decorator
 85
 86
 87import functools
 88
 89
 90@decorator
 91class memoized(object):
 92    """Decorator. Caches a function's return value each time it is called.
 93    If called later with the same arguments, the cached value is returned
 94    (not reevaluated).
 95    """
 96
 97    def __init__(self, func):
 98        self.func = func
 99        self.cache = {}
100
101    def __call__(self, *args):
102        try:
103            return self.cache[args]
104        except KeyError:
105            pass
106        except TypeError:
107            return self.func(*args)
108        value = self.func(*args)
109        self.cache[args] = value
110        return value
111
112    def __repr__(self):
113        """Return the function's docstring."""
114        return self.func.__doc__
115
116    def __get__(self, obj, objtype):
117        """Support instance methods."""
118        return functools.partial(self.__call__, obj)
119
120
121@decorator
122class cached_property(object):
123    """A decorator that converts a function into a lazy property.  The
124    function wrapped is called the first time to retrieve the result
125    and then that calculated result is used the next time you access
126    the value::
127
128        class Foo(object):
129
130            @cached_property
131            def foo(self):
132                # calculate something important here
133                return 42
134
135    The class has to have a `__dict__` in order for this property to
136    work.
137    """
138
139    # implementation detail: this property is implemented as non-data
140    # descriptor.  non-data descriptors are only invoked if there is
141    # no entry with the same name in the instance's __dict__.
142    # this allows us to completely get rid of the access function call
143    # overhead.  If one choses to invoke __get__ by hand the property
144    # will still work as expected because the lookup logic is replicated
145    # in __get__ for manual invocation.
146
147    def __init__(self, func, name=None, doc=None):
148        self.__name__ = name or func.__name__
149        self.__module__ = func.__module__
150        self.__doc__ = doc or func.__doc__
151        self.func = func
152
153    def __get__(self, obj, type=None):
154        if obj is None:
155            return self
156        value = obj.__dict__.get(self.__name__, _missing)
157        if value is _missing:
158            value = self.func(obj)
159            obj.__dict__[self.__name__] = value
160        return value
161
162
163class curried(object):
164    """
165    Decorator that returns a function that keeps returning functions
166    until all arguments are supplied; then the original function is
167    evaluated.
168    """
169
170    def __init__(self, func, *a):
171        self.func = func
172        self.args = a
173
174    def __call__(self, *a):
175        args = self.args + a
176        if len(args) < self.func.__code__.co_argcount:
177            return curried(self.func, *args)
178        else:
179            return self.func(*args)
180
181
182@decorator
183def timeit(method):
184
185    def timed(*args, **kw):
186        ts = time.time()
187        result = method(*args, **kw)
188        te = time.time()
189
190        print("%r (%r, %r) %2.2f sec" % (method.__name__, args, kw, te - ts))
191        return result
192
193    return timed
194
195
196__all__ = [
197    "autoassign",
198    "cached_property",
199    "curried",
200    "decorator",
201    "memoized",
202    "setdefaultattr",
203    "timeit",
204]
def autoassign(*names, **kwargs):
30def autoassign(*names, **kwargs):
31    """
32    autoassign(function) -> method
33    autoassign(*argnames) -> decorator
34    autoassign(exclude=argnames) -> decorator
35
36    allow a method to assign (some of) its arguments as attributes of
37    'self' automatically.  E.g.
38
39    >>> class Foo(object):
40    ...     @autoassign
41    ...     def __init__(self, foo, bar): pass
42    ...
43    >>> breakfast = Foo('spam', 'eggs')
44    >>> breakfast.foo, breakfast.bar
45    ('spam', 'eggs')
46
47    To restrict autoassignment to 'bar' and 'baz', write:
48
49        @autoassign('bar', 'baz')
50        def method(self, foo, bar, baz): ...
51
52    To prevent 'foo' and 'baz' from being autoassigned, use:
53
54        @autoassign(exclude=('foo', 'baz'))
55        def method(self, foo, bar, baz): ...
56    """
57    if kwargs:
58        exclude, f = set(kwargs["exclude"]), None
59        sieve = lambda l: filter(lambda nv: nv[0] not in exclude, l)
60    elif len(names) == 1 and isfunction(names[0]):
61        f = names[0]
62        sieve = lambda l: l
63    else:
64        names, f = set(names), None
65        sieve = lambda l: [nv for nv in l if nv[0] in names]
66
67    def decorator(f):
68        spec = getfullargspec(f)
69        fargnames, fdefaults = spec.args, spec.defaults
70        # Remove self from fargnames and make sure fdefault is a tuple
71        fargnames, fdefaults = fargnames[1:], fdefaults or ()
72        defaults = list(sieve(zip(reversed(fargnames), reversed(fdefaults))))
73
74        @wraps(f)
75        def decorated(self, *args, **kwargs):
76            assigned = dict(sieve(zip(fargnames, args)))
77            assigned.update(sieve(kwargs.items()))
78            for _ in starmap(assigned.setdefault, defaults):
79                pass
80            self.__dict__.update(assigned)
81            return f(self, *args, **kwargs)
82
83        return decorated
84
85    return f and decorator(f) or decorator

autoassign(function) -> method autoassign(*argnames) -> decorator autoassign(exclude=argnames) -> decorator

allow a method to assign (some of) its arguments as attributes of 'self' automatically. E.g.

>>> class Foo(object):
...     @autoassign
...     def __init__(self, foo, bar): pass
...
>>> breakfast = Foo('spam', 'eggs')
>>> breakfast.foo, breakfast.bar
('spam', 'eggs')

To restrict autoassignment to 'bar' and 'baz', write:

@autoassign('bar', 'baz')
def method(self, foo, bar, baz): ...

To prevent 'foo' and 'baz' from being autoassigned, use:

@autoassign(exclude=('foo', 'baz'))
def method(self, foo, bar, baz): ...
@decorator
def cached_property(func, name=None, doc=None):
122@decorator
123class cached_property(object):
124    """A decorator that converts a function into a lazy property.  The
125    function wrapped is called the first time to retrieve the result
126    and then that calculated result is used the next time you access
127    the value::
128
129        class Foo(object):
130
131            @cached_property
132            def foo(self):
133                # calculate something important here
134                return 42
135
136    The class has to have a `__dict__` in order for this property to
137    work.
138    """
139
140    # implementation detail: this property is implemented as non-data
141    # descriptor.  non-data descriptors are only invoked if there is
142    # no entry with the same name in the instance's __dict__.
143    # this allows us to completely get rid of the access function call
144    # overhead.  If one choses to invoke __get__ by hand the property
145    # will still work as expected because the lookup logic is replicated
146    # in __get__ for manual invocation.
147
148    def __init__(self, func, name=None, doc=None):
149        self.__name__ = name or func.__name__
150        self.__module__ = func.__module__
151        self.__doc__ = doc or func.__doc__
152        self.func = func
153
154    def __get__(self, obj, type=None):
155        if obj is None:
156            return self
157        value = obj.__dict__.get(self.__name__, _missing)
158        if value is _missing:
159            value = self.func(obj)
160            obj.__dict__[self.__name__] = value
161        return value

A decorator that converts a function into a lazy property. The function wrapped is called the first time to retrieve the result and then that calculated result is used the next time you access the value::

class Foo(object):

    @cached_property
    def foo(self):
        # calculate something important here
        return 42

The class has to have a __dict__ in order for this property to work.

class curried:
164class curried(object):
165    """
166    Decorator that returns a function that keeps returning functions
167    until all arguments are supplied; then the original function is
168    evaluated.
169    """
170
171    def __init__(self, func, *a):
172        self.func = func
173        self.args = a
174
175    def __call__(self, *a):
176        args = self.args + a
177        if len(args) < self.func.__code__.co_argcount:
178            return curried(self.func, *args)
179        else:
180            return self.func(*args)

Decorator that returns a function that keeps returning functions until all arguments are supplied; then the original function is evaluated.

curried(func, *a)
171    def __init__(self, func, *a):
172        self.func = func
173        self.args = a
func
args
def decorator(d):
10def decorator(d):
11    "Make function d a decorator: d wraps a function fn."
12
13    def _d(fn):
14        return update_wrapper(d(fn), fn)
15
16    return _d

Make function d a decorator: d wraps a function fn.

@decorator
def memoized(func):
 91@decorator
 92class memoized(object):
 93    """Decorator. Caches a function's return value each time it is called.
 94    If called later with the same arguments, the cached value is returned
 95    (not reevaluated).
 96    """
 97
 98    def __init__(self, func):
 99        self.func = func
100        self.cache = {}
101
102    def __call__(self, *args):
103        try:
104            return self.cache[args]
105        except KeyError:
106            pass
107        except TypeError:
108            return self.func(*args)
109        value = self.func(*args)
110        self.cache[args] = value
111        return value
112
113    def __repr__(self):
114        """Return the function's docstring."""
115        return self.func.__doc__
116
117    def __get__(self, obj, objtype):
118        """Support instance methods."""
119        return functools.partial(self.__call__, obj)

Decorator. Caches a function's return value each time it is called. If called later with the same arguments, the cached value is returned (not reevaluated).

def setdefaultattr(obj, name, value):
22def setdefaultattr(obj, name, value):
23    try:
24        return getattr(obj, name)
25    except AttributeError:
26        setattr(obj, name, value)
27    return value
@decorator
def timeit(method):
183@decorator
184def timeit(method):
185
186    def timed(*args, **kw):
187        ts = time.time()
188        result = method(*args, **kw)
189        te = time.time()
190
191        print("%r (%r, %r) %2.2f sec" % (method.__name__, args, kw, te - ts))
192        return result
193
194    return timed