adding after_rollback functionality

This commit is contained in:
Mark McClain
2011-10-27 13:38:59 -04:00
parent 76925401c8
commit da61da0d50
3 changed files with 87 additions and 13 deletions

View File

@@ -2,7 +2,7 @@ from inspect import getargspec, getmembers, isclass, ismethod
from util import _cfg from util import _cfg
__all__ = [ __all__ = [
'expose', 'transactional', 'accept_noncanonical', 'after_commit' 'expose', 'transactional', 'accept_noncanonical', 'after_commit', 'after_rollback'
] ]
@@ -105,6 +105,24 @@ def transactional(ignore_redirects=True):
return deco return deco
def after_action(action_type, action):
'''
If utilizing the :mod:`pecan.hooks` ``TransactionHook``, allows you
to flag a controller method to perform a callable action after the
action_type is successfully issued.
:param action: The callable to call after the commit is successfully issued.
'''
if action_type not in ('commit', 'rollback'):
raise Exception, 'action_type (%s) is not valid' % action_type
def deco(func):
_cfg(func).setdefault('after_%s' % action_type, []).append(action)
return func
return deco
def after_commit(action): def after_commit(action):
''' '''
If utilizing the :mod:`pecan.hooks` ``TransactionHook``, allows you If utilizing the :mod:`pecan.hooks` ``TransactionHook``, allows you
@@ -113,10 +131,18 @@ def after_commit(action):
:param action: The callable to call after the commit is successfully issued. :param action: The callable to call after the commit is successfully issued.
''' '''
def deco(func): return after_action('commit', action)
_cfg(func).setdefault('after_commit', []).append(action)
return func
return deco def after_rollback(action):
'''
If utilizing the :mod:`pecan.hooks` ``TransactionHook``, allows you
to flag a controller method to perform a callable action after the
rollback is successfully issued.
:param action: The callable to call after the rollback is successfully issued.
'''
return after_action('rollback', action)
def accept_noncanonical(func): def accept_noncanonical(func):

View File

@@ -156,19 +156,23 @@ class TransactionHook(PecanHook):
def after(self, state): def after(self, state):
if state.request.transactional: if state.request.transactional:
action_name = None
if state.request.error: if state.request.error:
action_name = 'after_rollback'
self.rollback() self.rollback()
else: else:
action_name = 'after_commit'
self.commit() self.commit()
# #
# If a controller was routed to, find any # If a controller was routed to, find any
# after_commit actions it may have registered, and perform # after_* actions it may have registered, and perform
# them. # them.
# #
if action_name:
controller = getattr(state, 'controller', None) controller = getattr(state, 'controller', None)
if controller is not None: if controller is not None:
actions = _cfg(controller).get('after_commit', []) actions = _cfg(controller).get(action_name, [])
for action in actions: for action in actions:
action() action()

View File

@@ -1,9 +1,9 @@
from cStringIO import StringIO from cStringIO import StringIO
from pecan import make_app, expose, request, redirect from pecan import make_app, expose, request, redirect, abort
from pecan.core import state from pecan.core import state
from pecan.hooks import PecanHook, TransactionHook, HookController, RequestViewerHook from pecan.hooks import PecanHook, TransactionHook, HookController, RequestViewerHook
from pecan.configuration import Config from pecan.configuration import Config
from pecan.decorators import transactional, after_commit from pecan.decorators import transactional, after_commit, after_rollback
from copy import copy from copy import copy
from formencode import Schema, validators from formencode import Schema, validators
from webtest import TestApp from webtest import TestApp
@@ -560,6 +560,17 @@ class TestTransactionHook(object):
run_hook.append('inside') run_hook.append('inside')
return 'Decorated Method!' return 'Decorated Method!'
@expose()
@after_rollback(action('action-three'))
def rollback(self):
abort(500)
@expose()
@transactional()
@after_rollback(action('action-four'))
def rollback_decorated(self):
abort(500)
def gen(event): def gen(event):
return lambda: run_hook.append(event) return lambda: run_hook.append(event)
@@ -612,6 +623,39 @@ class TestTransactionHook(object):
run_hook = [] run_hook = []
response = app.get('/rollback', expect_errors=True)
assert response.status_int == 500
assert len(run_hook) == 2
assert run_hook[0] == 'start_ro'
assert run_hook[1] == 'clear'
run_hook = []
response = app.post('/rollback', expect_errors=True)
assert response.status_int == 500
assert len(run_hook) == 4
assert run_hook[0] == 'start'
assert run_hook[1] == 'rollback'
assert run_hook[2] == 'action-three'
assert run_hook[3] == 'clear'
run_hook = []
response = app.get('/rollback_decorated', expect_errors=True)
assert response.status_int == 500
assert len(run_hook) == 6
assert run_hook[0] == 'start_ro'
assert run_hook[1] == 'clear'
assert run_hook[2] == 'start'
assert run_hook[3] == 'rollback'
assert run_hook[4] == 'action-four'
assert run_hook[5] == 'clear'
run_hook = []
response = app.get('/fourohfour', status=404) response = app.get('/fourohfour', status=404)
assert response.status_int == 404 assert response.status_int == 404