Changeset 259

Show
Ignore:
Timestamp:
12/01/05 13:33:18 (3 years ago)
Author:
kevin
Message:

test fixes
implemented implicit transaction handling. each exposed method is
wrapped in a transaction. The transaction actually begins even earlier
than expose, so filters should still go through the transaction as well.
this takes care of ticket #80
it should also take care of ticket #85 - since every request goes through
a transaction, they each get their own cache.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/turbogears/controllers.py

    r199 r259  
    1212from turbogears.util import setlike 
    1313import turbogears 
     14from turbogears import database 
    1415from turbogears.widgets import js_location 
    1516 
     
    192193                    except turbogearsvalid.Invalid, error: 
    193194                        errors.update(error.error_dict) 
    194             if errors: 
    195                 if errorhandler: 
    196                     output = _call_with_errors(func, self, *args, **kw) 
    197                 elif hasattr(self, "validation_error"): 
    198                     output = self.validation_error(func.func_name, kw, errors) 
    199                 else: 
    200                     raise turbogearsvalid.Invalid(str(errors), kw, None) 
     195            if not hasattr(cherrypy.request, "in_transaction"): 
     196                cherrypy.request.in_transaction = True 
     197                output = database.run_with_transaction(_execute_func, self, 
     198                        errors, errorhandler, func, *args, **kw) 
    201199            else: 
    202                 if errorhandler: 
    203                     output = func(self, has_errors=False, *args, **kw) 
    204                 else: 
    205                     output = func(self, *args, **kw) 
     200                output = _execute_func(self, errors, errorhandler, func, 
     201                            *args, **kw) 
    206202            return controllers._process_output(tg_format, output, html) 
    207203             
     
    214210         
    215211    return decorator 
     212 
     213def _execute_func(self, errors, errorhandler, func, *args, **kw): 
     214    if errors: 
     215        if errorhandler: 
     216            output = _call_with_errors(func, self, *args, **kw) 
     217        elif hasattr(self, "validation_error"): 
     218            output = self.validation_error(func.func_name, kw, errors) 
     219        else: 
     220            raise turbogearsvalid.Invalid(str(errors), kw, None) 
     221    else: 
     222        if errorhandler: 
     223            output = func(self, has_errors=False, *args, **kw) 
     224        else: 
     225            output = func(self, *args, **kw) 
     226    return output 
     227     
    216228 
    217229def flash(message): 
  • trunk/turbogears/database.py

    r68 r259  
    44from sqlobject.dbconnection import ConnectionHub, Transaction, TheURIOpener 
    55import cherrypy 
     6from sets import Set 
     7 
     8hub_registry = Set() 
    69 
    710class AutoConnectHub(ConnectionHub): 
     
    1518            uri = cherrypy.config.get("sqlobject.dburi") 
    1619        self.uri = uri 
     20        hub_registry.add(self) 
    1721        ConnectionHub.__init__(self) 
    1822     
     
    2024        try: 
    2125            conn = self.threadingLocal.connection 
    22             return conn 
     26            return self.begin(conn) 
    2327        except AttributeError: 
    2428            if self.uri: 
     
    3034                    TheURIOpener.cachedURIs = {} 
    3135                self.threadingLocal.connection = conn 
    32                 return conn 
     36                return self.begin(conn) 
    3337            try: 
    3438                return self.processConnection 
     
    4347        self.threadingLocal = threading_local() 
    4448         
    45     def begin(self): 
     49    def begin(self, conn=None): 
    4650        "Starts a transaction." 
    47         conn = self.getConnection() 
     51        if not conn: 
     52            conn = self.getConnection() 
    4853        if isinstance(conn, Transaction): 
    4954            if conn._obsolete: 
    5055                conn.begin() 
    51             return 
     56            return conn 
    5257        self.threadingLocal.old_conn = conn 
    53         self.threadingLocal.connection = conn.transaction() 
     58        trans = conn.transaction() 
     59        self.threadingLocal.connection = trans 
     60        return trans 
    5461         
    5562    def commit(self): 
    5663        "Commits the current transaction." 
    57         conn = self.threadingLocal.connection 
     64        try: 
     65            conn = self.threadingLocal.connection 
     66        except AttributeError: 
     67            return 
    5868        if isinstance(conn, Transaction): 
    5969            self.threadingLocal.connection.commit() 
     
    6171    def rollback(self): 
    6272        "Rolls back the current transaction." 
    63         conn = self.threadingLocal.connection 
     73        try: 
     74            conn = self.threadingLocal.connection 
     75        except AttributeError: 
     76            return 
    6477        if isinstance(conn, Transaction) and not conn._obsolete: 
    6578            self.threadingLocal.connection.rollback() 
     
    6780    def end(self): 
    6881        "Ends the transaction, returning to a standard connection." 
    69         conn = self.threadingLocal.connection 
     82        try: 
     83            conn = self.threadingLocal.connection 
     84        except AttributeError: 
     85            return 
    7086        if not isinstance(conn, Transaction): 
    7187            return 
     
    137153            {"sqlobject.dburi" : dburi} 
    138154        }) 
    139          
    140 __all__ = ["PackageHub", "AutoConnectHub", "set_db_uri"] 
     155 
     156def commit_all(): 
     157    "Commits the Transactions in all registered hubs (for this thread)" 
     158    for hub in hub_registry: 
     159        hub.commit() 
     160 
     161def rollback_all(): 
     162    "Rolls back the Transactions in all registered hubs (for this thread)" 
     163    for hub in hub_registry: 
     164        hub.rollback() 
     165 
     166def end_all(): 
     167    "Ends the Transactions in all registered hubs (for this thread)" 
     168    for hub in hub_registry: 
     169        hub.end() 
     170     
     171def run_with_transaction(func, *args, **kw): 
     172    try: 
     173        try: 
     174            retval = func(*args, **kw) 
     175            commit_all() 
     176            return retval 
     177        except cherrypy.HTTPRedirect: 
     178            commit_all() 
     179            raise 
     180        except cherrypy.InternalRedirect: 
     181            commit_all() 
     182            raise 
     183        except: 
     184            rollback_all() 
     185            raise 
     186    finally: 
     187        end_all() 
     188     
     189__all__ = ["PackageHub", "AutoConnectHub", "set_db_uri",  
     190           "commit_all", "rollback_all", "end_all"] 
  • trunk/turbogears/tests/test_controllers.py

    r189 r259  
    44from turbogears import url 
    55from turbogears import validators 
     6from turbogears import database 
    67import cherrypy 
    78from turbogears.tests import util 
     
    4041    istrue = turbogears.expose( 
    4142            validators={'value': validators.StringBoolean()})(istrue) 
     43     
     44    def callsanother(self): 
     45        return self.istrue(True) 
     46    callsanother = turbogears.expose()(callsanother) 
    4247         
    4348    def returnjson(self): 
     
    8691        return dict(tg_template="turbogears.tests.othertemplate") 
    8792    useother = turbogears.expose(html="turbogears.tests.simple")(useother) 
     93     
     94    rwt_called = 0 
     95    def rwt(self, func, *args, **kw): 
     96        self.rwt_called += 1 
     97        func(*args, **kw) 
    8898 
    8999class TestRoot(unittest.TestCase): 
     
    200210        util.createRequest("/useother") 
    201211        assert "This is the other template" in cherrypy.response.body[0] 
     212     
     213    def test_runwithtrans(self): 
     214        "run_with_transaction is called only on topmost exposed method" 
     215        oldrwt = database.run_with_transaction 
     216        database.run_with_transaction = cherrypy.root.rwt 
     217        util.createRequest("/callsanother") 
     218        database.run_with_transaction = oldrwt 
     219        assert cherrypy.root.value 
     220        assert cherrypy.root.rwt_called == 1 
    202221        
    203222class TestURLs(unittest.TestCase): 
  • trunk/turbogears/tests/test_i18n.py

    r247 r259  
    1010dt = datetime(2005, 2, 5) # Saturday, 5rd Feb 2005 
    1111def get_test_locale(): 
    12  
     12    import cherrypy 
    1313    return cherrypy.config.get('i18n.defaultLocale', 'en') 
    1414     
  • trunk/turbogears/validators.py

    r92 r259  
    66from formencode.validators import * 
    77from formencode.compound import * 
     8from formencode.api import Invalid