Created
June 18, 2009 09:42
-
-
Save anfedorov/131829 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment