项目作者: orsinium-labs

项目描述 :
Aspect oriented programming for Python. Patch everything!
高级语言: Python
项目地址: git://github.com/orsinium-labs/aop.git
创建时间: 2018-08-15T14:27:42Z
项目社区:https://github.com/orsinium-labs/aop

开源协议:

下载


" class="reference-link">AOP

Badges? We ain’t got no badges! We don’t need no badges! I don’t have to show you any stinking badges!

Aspect-oriented programming

Features:

  1. Patch any module: your project, stdlib, built-ins.
  2. Patch any object: functions, class instances.
  3. Pure Python implementation: run it on CPython or PyPy.

TODO:

  1. Patch already imported objects
  2. Patch __init__ and __new__.
  3. Test PyPy

Example

  1. import aop
  2. def multiply(context):
  3. print(context.aspect, context.args, context.kwargs)
  4. yield
  5. context.result *= 100
  6. aop.register(
  7. handler=multiply,
  8. modules=aop.match(equals='math'),
  9. targets=aop.match(regexp='(sin|cos)')
  10. )

Ok, let’s check:

  1. import math
  2. math.cos(0)
  3. # prints: cos (0,) {}
  4. # returns: 100.0

Usage

Register

Register new advice:

  1. aop.register(
  2. handler=some_handler,
  3. modules=aop.match(equals='math'),
  4. targets=aop.match(regexp='(sin|cos)')
  5. )

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.

Match

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 and context

Handler looks like:

  1. def multiply(context):
  2. ... # before aspect call
  3. yield
  4. ... # 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 args
  • kwargs — dict of passed keyword args
  • result — target’s method response

Enable and disable

Register all advices or just enable patching before all other imports in project:

  1. import aop
  2. aop.enable()
  3. ... # all other imports

Also it’s recommend finally enable patching after register last advice:

  1. aop.register(...)
  2. aop.register(...)
  3. aop.enable(final=True)

If you want to disable patching:

  1. aop.disable()

Inspect

Inspect object:

  1. aop.inspect(math.isclose, print=True)

Patch import system automatically

Now this package can’t patch modules that imported before aop.enable() or aop.register(...):

  1. $ python3 special_cases/2_after.py
  2. ...
  3. AssertionError: not patched

Although you can run your script via aop runner:

  1. $ python3 -m aop special_cases/2_after.py
  2. cos (0,) {}