Aspect oriented programming for Python. Patch everything!
Badges? We ain’t got no badges! We don’t need no badges! I don’t have to show you any stinking badges!
Features:
TODO:
__init__
and __new__
.
import aop
def multiply(context):
print(context.aspect, context.args, context.kwargs)
yield
context.result *= 100
aop.register(
handler=multiply,
modules=aop.match(equals='math'),
targets=aop.match(regexp='(sin|cos)')
)
Ok, let’s check:
import math
math.cos(0)
# prints: cos (0,) {}
# returns: 100.0
Register new advice:
aop.register(
handler=some_handler,
modules=aop.match(equals='math'),
targets=aop.match(regexp='(sin|cos)')
)
Parameters for aop.register
:
handler
— advice for joinpoint processing.paths
— expression for path to module.modules
— expression for module name.targets
— expression for object name.methods
— expression for called object’s method. It’s __call__
for functions.Available kwargs for aop.match
:
regexp
— object name fully match to regular expression.startswith
— object name starts with specified string.endswith
— object name ends with specified string.contains
— object contains specified string.equals
— object name equal to specified string.Handler looks like:
def multiply(context):
... # before aspect call
yield
... # after aspect call
Context’s properties:
aspect
— name of target.method
— name of called method or __call__
for functions.module
— name of module where aspect defined.path
— path to module where aspect defined.args
— tuple of passed positional argskwargs
— dict of passed keyword argsresult
— target’s method responseRegister all advices or just enable patching before all other imports in project:
import aop
aop.enable()
... # all other imports
Also it’s recommend finally enable patching after register last advice:
aop.register(...)
aop.register(...)
aop.enable(final=True)
If you want to disable patching:
aop.disable()
Inspect object:
aop.inspect(math.isclose, print=True)
Now this package can’t patch modules that imported before aop.enable()
or aop.register(...)
:
$ python3 special_cases/2_after.py
...
AssertionError: not patched
Although you can run your script via aop runner:
$ python3 -m aop special_cases/2_after.py
cos (0,) {}