Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AOP in Python With Decorators

novoland
September 29, 2013

AOP in Python With Decorators

novoland

September 29, 2013
Tweet

More Decks by novoland

Other Decks in Programming

Transcript

  1. Case • BioBench: ◦ Application for biogas installations • Enter

    measurements • Normalize data • Calculate plant performance
  2. Problem description • Large code-base • A lot of calculations

    • Django web-interface • Make calculations available via an API
  3. Problem description • Is there a library/framework? • Are the

    alternatives? • What is the actual impact of the feature? • What aspects to take into account?
  4. Problem description def add(lhs, rhs): return lhs + rhs def

    api_add(request): return add(request.args['lhs'], request.args['rhs'])
  5. Problem description def add(lhs, rhs): return lhs + rhs def

    api_add(request): if request.args['token'] == valid: return add(request.args['lhs'], request.args['rhs']) raise Exception('Security error')
  6. Problem description def add(lhs, rhs): return lhs + rhs def

    api_add(request): if request.args['token'] == valid: database.query().alter usage counter return add(request.args['lhs'], request.args['rhs']) raise Exception('Security error')
  7. Problem description def add(lhs, rhs): return lhs + rhs def

    api_add(request): if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')
  8. Problem description def add(lhs, rhs): return lhs + rhs def

    api_add(request): if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')
  9. Problem description def add(lhs, rhs): return lhs + rhs def

    api_add(request): if request.args['token'] == valid: database.query().alter usage counter result = add(request.args['lhs'], request.args['rhs']) return '<xml>{0}</xml>'.format(result) raise Exception('Security error')
  10. Aspect Oriented Programming • What is AOP? • Separation of

    concerns (aspects) • Avoid scattering / tangling
  11. Aspect Oriented Programming • Aspect: ◦ Pointcuts ◦ Join points

    ◦ Advices ▪ Before advices ▪ After advices ▪ Around advices
  12. Aspect Oriented Programming • Before advice ◦ Must execute the

    function (no side-effects) def aspect(function): def advice(*args, **kwargs): do something here return function(*args, **kwargs) return advice
  13. Aspect Oriented Programming • After advice ◦ Must execute the

    function (no side-effects) def aspect(function): def advice(*args, **kwargs): result = function(*args, **kwargs) do something here return result return advice
  14. Aspect Oriented Programming • Around advice ◦ Allowed to bypass

    the function def aspect(function): def advice(*args, **kwargs): do something here result = function(*args, **kwargs) do something here return result return advice
  15. Implementation • Security aspect ◦ Around advice def secure(function): def

    advice(*args, **kwargs): if valid token in request object: return function(*args, **kwargs) raise Exception('No valid token provided') return advice
  16. Implementation • Statistics aspect ◦ Before advice def statistics(function): def

    advice(*args, **kwargs): increase API usage count for the user logged in return function(*args, **kwargs) return advice
  17. Implementation • Serialization aspect ◦ Around advice def serialize(function): def

    advice(format, *args, **kwargs): if not format in ['html', 'xml', 'json']: raise exception result = function(*args, **kwargs) make a http response of 'result' in the right format return advice
  18. Implementation • Dispatcher aspect ◦ Around advice def dispatch(function): def

    advice(*args, **kwargs): proxy the API call to a call to the core system return advice
  19. Implementation def dispatch(function): def advice(*args, **kwargs): if API call in

    proxy mapping: core_function, params = mapping[API call] kwargs.update(extract(params, request)) return function(proxy=core_function, params=params, *args, **kwargs) raise exception return advice
  20. Implementation @secure @serialize @statistics @dispatch def api_call(*args, **kwargs): proxy_function =

    kwargs['proxy'] params = kwargs['params'] return proxy_function(extract params from kwargs)
  21. Conclusion • AOP offers some brilliant concepts in software engineering

    • Separate your concerns / aspects ◦ Avoid classical scattering and tangling