Skip to content

Instantly share code, notes, and snippets.

@anfedorov
Created June 18, 2009 09:42

Revisions

  1. anfedorov created this gist Jun 18, 2009.
    77 changes: 77 additions & 0 deletions decorations.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,77 @@
    from functools import wraps, partial
    from inspect import getargspec

    def _param_update(old_params, new_params):
    args, kwargs = old_params

    if type(new_params) == tuple:
    if len(new_params) == 2 and type(new_params[0]) == tuple and type(new_params[1]) == dict:
    args = new_params[0]
    kwargs.update(new_params[1])
    else:
    args = new_params
    elif type(new_params) == dict:
    kwargs.update(new_params)

    return (args, kwargs)

    def filter_dict(d, fltr):
    return dict( (x, d[x]) for x in fltr if x in d )

    def apply_some(f, *args, **kwargs):
    fspec = getargspec(f)
    return f(*args, **kwargs) if fspec.keywords else f( *args, **filter_dict(kwargs, fspec.args) )

    def _metadecorator(decoration, params="maybe"):
    "Takes a decoration to pre-apply to a decoratee"
    def cap_params(*dec_params, **dec_kwargs):
    "Captures decoration parameters"
    @wraps(decoration)
    def decorator(decoratee):
    "The decorator - takes a decoratee to decorate"
    @wraps(decoratee)
    def decorated(*args, **kwargs):
    "The decorated decoratee"
    # the decoration will be passed the decoratee and (optionally) two sets of arguments
    return apply_some(decoration, decoratee, args=args, kwargs=kwargs, dec_params=dec_params, dec_kwargs=dec_kwargs)
    return decorated

    if params=="maybe" and not dec_kwargs and len(dec_params)==1 and callable(dec_params[0]):
    decoratee = dec_params[0]
    dec_params = ()
    return decorator(decoratee)
    else:
    return decorator

    return cap_params

    def decoration(decoration=None, has_params="maybe"):
    "Meta-decorates"
    if decoration:
    dec_args = getargspec(decoration).args
    if 'dec_params' in dec_args or 'dec_kwargs' in dec_args:
    return _metadecorator(decoration, params=has_params)
    else:
    return _metadecorator(decoration, params=has_params)()
    else:
    return partial(decoration, params=has_params)

    @decoration
    def predecoration(f, args, kwargs):
    "Declares something as a predecoration"
    def predecorator(g, **kwds):
    # at this point, `f` will be our predecoration and `g` will be our decoratee.
    update = apply_some(f, g, **kwds)
    gargs, gkwargs = _param_update((kwds['args'], kwds['kwargs']), update)
    return g(*gargs, **gkwargs)
    return _metadecorator(predecorator)(*args, **kwargs)

    @decoration
    def postdecoration(f, args, kwargs, dec_kwargs):
    "Declares something as a postdecoration"
    def postdecorator(g, **kwds):
    # at this point, `f` will be our postdecoration and `g` will be our decoratee.
    res = g(*kwds['args'], **kwds['kwargs'])
    return apply_some(f, res, *kwds['dec_params'], **kwds['dec_kwargs'])
    return _metadecorator(postdecorator, dec_kwargs.get('has_params', 'maybe'))(*args, **kwargs)