Ticket #1267 (closed defect: fixed)
[PATCH] auto commiting with SQLAlchemy does not work
|Reported by:||kov||Owned by:||anonymous|
Description (last modified by jorge.vargas) (diff)
"After executing a controller method to handle a page request, TurboGears is supposed to commit any changes that the controller made to the database. When using SQLAlchemy, it fails to do this. It's possible to work around this by modifying the controller to do the commit manually, but that's not something that the application should be doing. I'm calling this bug "important" because existing TurboGears-based web applications, as-written, will not work correctly on this release of TurboGears if they use SQLAlchemy.
TurboGears' database support (for both SQLObject and SQLAlchemy) is implemented in the file "turbogears/database.py". This file contains a generic "run_with_transaction" function:
[dispatch.generic(MultiorderGenericFunction)] def run_with_transaction(func, *args, **kw): pass
which is supposed to call either so_rwt() or sa_rwt() depending on whether SQLObject or SQLAlchemy is in use:
[run_with_transaction.when("not _use_sa()")] def so_rwt(func, *args, **kw): ... [run_with_transaction.when("_use_sa()")] def sa_rwt(func, *args, **kw): ...
The check for whether SQLAlchemy is in use is done by looking at a global variable:
def _use_sa(): return _engine is not None
The _engine variable is initialized to None near the top of this file, and a function called get_engine() is provided which may assign an object to it after reading some options from a config file.
The problem is that the so_rwt() and sa_rwt() functions get registered with the run_with_transaction() dispatcher at the same time as they're defined: while Python is executing turbogears/database.py in response to an import declaration. At this point the get_engine() function has been defined, but hasn't been run yet, so _engine is always going to be None, and run_with_transaction() always ends up calling so_rwt(), never sa_rwt().
How to reproduce this: use quickstart to create a new SQLAlchemy project, and then run "tg-admin shell" on it. Do the following:
import turbogears.database turbogears.database.run_with_transaction(None)
This will cause a TypeError? exception, and you'll see so_rwt() in the stack trace.
If I modify turbogears/database.py and put "print _use_sa()" just before the definition of the so_rwt() function, I see False printed when I start a shell, even though running turbogears.database._use_sa() from within the shell yields True. That False is what causes so_rwt() to become the function that the dispatcher uses, rather than sa_rwt() like it should." -- Mike Paul
- Priority changed from high to highest
- Description modified (diff)
- Summary changed from auto commiting with SQLAlchemy does not work to [PATCH] auto commiting with SQLAlchemy does not work