Package: attach.me
A library for attaching additional functionality around existing functions, such as before or after execution, or given
a raised exception or specific return value.@attach(on_before=lambda:print('Initializing connection'),on_after=lambda:print('Connect successfully established'),on_error=lambdax:print('Erred establishing connection:%s'%x),on_return=lambdax:print('Returned connection:%s'%x))defconnection(conn_str,params):conn=db(conn_str,params)returndb.open()InstallationThe latest version of attach.me is available viapip:pipinstallattach.meAlternatively, you can download and install from source:pythonsetup.pyinstallGetting StartedTheattachfunction contains the following signature:@attach(on_before=None,on_after=None,on_error=None,on_return=None,override_error=False,override_return=False,before_has_kwargs=False)deffunc(...)...It serves as both a function decorator, and a runnable wrapper and is configurable through it’s dynamic parameters. Most
of which are function callbacks which allow the user to highly configure the additional behavior.Before / After ExecutionEither prior to the wrapped function being executed, or afterwards, another function can be called. The most simplistic
use case for this is logging the beginning and ending of execution of a function.@attach(on_before=lambda:logging.info('Execution began'),on_after=lambda:logging.info('Execution ended'))deffunc():...If an exception is raised by the wrapped function (or theon_beforefunction), theon_afterfunction isn’t
called.More complex usage comes from digesting the parameters meant for the wrapped function and transforming them in some way.
This is accomplished by simply returning an object from theon_beforefunction and the values will be used instead
of the ones passed in.defsanitize(string):# Do some stuffreturnnew_string@attach(on_before=lambdax:sanitize(x))deffunc(string):...If an iterable is returned, it is used as the args of the wrapped function. Thebefore_with_kwargsargument can be
set toTrueto specify that the return value be used as the kwargs of the wrapped function (which means it should
be a dictionary. If an iterable is returned and this parameter is set, the last value is used as the kwargs, and the
rest as the args.defsanitize(string):# Do some stuffreturnnew_string@attach(on_before=lambdax:sanitize(x),{'use_ssl':True})deffunc(string):...Error HandlingTheon_errorcan be used to execute a function if an exception is raised. By default, the original exception is
still raised after theon_errorcallback is called. This can be changed by settingoverride_errortoTrue.
This can be used to instead return a value or raise a different exception.defon_error(e):print('Caught error: '+str(e))ifisinstance(e,TypeError):return-1raise@attach(on_error=on_error,override_error=True)deffunc():raiseTypeError# -1 is returned instead of raising TypeErrorReturn Value HandlingLike raised exception, return values can consumed by aon_returnfunction in a similar manner. By default, the
original return value is still returned after theon_returncallback is called. This can be changed by settingoverride_returntoTrue. A common use case for this is when interacting with functions that yield a return value
that indicates a failed state (like-1orNone), while other values indicate a successful state (like0or
anobject). This behavior can be transformed into a simple boolTrueorFalsereturn value instead.defon_return(val):ifvalin(-1,None):returnFalsereturnTrue@attach(on_return=on_return,override_return=True)deffunc()return-1# False is returned instead of -1If an exception is raised by the wrapped function (or theon_beforeoron_afterfunctions), theon_returnfunction isn’t called.Advanced UsageInstead of using as a decorator,attachcan be used as an instead for wrapping an arbitrary number of function
calls. This can be achieved via therunmethod.deffunc_a():...deffunc_b():...attacher=attach(on_before=...,on_after=...,on_error=...,on_return=...)# Using same configured attach instanceattach.run(func_a,args,kwargs)attach.run(func_b,args,kwargs)Besides using the providedrunmethod, like any decorator functions can be locally wrapped, passed around, and
executed.deffunc():...attacher=attach(on_before=...,on_after=...,on_error=...,on_return=...)attach_func=attacher(func)attach_func(args,kwargs)# Or as a one-off like soattach(...)(func)(args,kwargs)Each of the function parameters that can be passed intoattach, can actually be configured to accepts different
number of parameters depending on the function. They can each either accept 0 parameters, the parameters that would be
typically passed in, or the wrapped function’s args and kwargs in addition to the parameters typically given.Optionally passing in the args and kwargs allows for building more complex callback functions. Each of the possible
function variations are shown below.defon_before():...defon_before(*args,**kwargs):...defon_after():...defon_after(*args,**kwargs):...defon_error():...defon_error(error):...defon_error(error,*args,**kwargs):...defon_return():...defon_return(value):...defon_return(value,*args,**kwargs):...ContributionContributions or suggestions are welcome! Feel free toopen an issueif a bug is found or an enhancement is desired,
or even apull request.ChangelogAll changes and versioning information can be found in theCHANGELOG.LicenseCopyright (c) 2018 Jared Gillespie. SeeLICENSEfor details.