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
__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
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):
'''
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.
'''
def deco(func):
_cfg(func).setdefault('after_commit', []).append(action)
return func
return deco
return after_action('commit', action)
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):

View File

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

View File

@@ -1,9 +1,9 @@
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.hooks import PecanHook, TransactionHook, HookController, RequestViewerHook
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 formencode import Schema, validators
from webtest import TestApp
@@ -559,6 +559,17 @@ class TestTransactionHook(object):
def decorated(self):
run_hook.append('inside')
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):
return lambda: run_hook.append(event)
@@ -612,6 +623,39 @@ class TestTransactionHook(object):
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)
assert response.status_int == 404