Ticket #9536: 9536-db-context-manager-r10102.patch
| File 9536-db-context-manager-r10102.patch, 4.0 KB (added by cboos, 21 months ago) |
|---|
-
trac/db/api.py
# HG changeset patch # Parent 6b65e6ec7bc777a8635ec1a19162e39c81b7c877 db: introduce context managers for accessing `Connection` instances. This continues the work started in #8751. Part of #9636. diff -r 6b65e6ec7bc7 trac/db/api.py
a b _transaction_local = ThreadLocal(db=None 30 30 def with_transaction(env, db=None): 31 31 """Function decorator to emulate a context manager for database 32 32 transactions. 33 34 :deprecated: use `env.db_{query|transaction}` 33 35 34 36 >>> def api_method(p1, p2): 35 37 >>> result[0] = value1 … … def get_read_db(env): 90 92 return _transaction_local.db or DatabaseManager(env).get_connection() 91 93 92 94 95 class TransactionContextMgr(object): 96 """Transactioned Database Context Manager 97 98 The outermost such context manager will either commit or rollback, 99 depending on the context being exited normally or after an exception. 100 """ 101 def __init__(self, env): 102 self._env = env 103 104 def __enter__(self): 105 db = _transaction_local.db 106 if not db: 107 _transaction_local.db = self._db = db = self._env.get_db_cnx() 108 self._env = None # we own the _transaction_local.db 109 return db 110 111 def __exit__(self, et, ev, tb): 112 if self._env is None: 113 _transaction_local.db = None 114 if et is None: 115 self._db.commit() 116 else: 117 self._db.rollback() 118 119 class ReadOnlyConnection(object): 120 """Wrapper around connection objects suppressing commit/rollback methods. 121 122 :since 0.13: 123 """ 124 __slots__ = ('cnx', 'log') 125 126 def __init__(self, cnx, log=None): 127 self.cnx, self.log = cnx, log 128 129 def __getattr__(self, name): 130 if name in ('commit', 'rollback'): 131 raise AttributeError 132 return getattr(self.cnx, name) 133 134 class QueryContextMgr(object): 135 """Database Context Manager for retrieving a Connection wrapper 136 with no commit or rollback""" 137 def __init__(self, env): 138 self._env = env 139 140 def __enter__(self): 141 db = _transaction_local.db 142 if not db: 143 db = self._env.get_db_cnx() 144 return ReadOnlyConnection(db) 145 146 def __exit__(self, et, ev, tb): 147 pass 148 149 93 150 class IDatabaseConnector(Interface): 94 151 """Extension point interface for components that support the connection to 95 152 relational databases.""" -
trac/env.py
diff -r 6b65e6ec7bc7 trac/env.py
a b from trac.cache import CacheManager 25 25 from trac.config import * 26 26 from trac.core import Component, ComponentManager, implements, Interface, \ 27 27 ExtensionPoint, TracError 28 from trac.db.api import DatabaseManager, get_read_db, with_transaction 28 from trac.db.api import (DatabaseManager, QueryContextMgr, 29 TransactionContextMgr, get_read_db, with_transaction) 29 30 from trac.util import copytree, create_file, get_pkginfo, makedirs 30 31 from trac.util.compat import any 31 32 from trac.util.concurrency import threading … … class Environment(Component, ComponentMa 326 327 return get_read_db(self) 327 328 328 329 def with_transaction(self, db=None): 329 """Decorator for transaction functions. 330 331 See `trac.db.api.with_transaction` for detailed documentation.""" 330 """Decorator for transaction functions (deprecated)""" 332 331 return with_transaction(self, db) 333 332 334 333 def get_read_db(self): … … class Environment(Component, ComponentMa 337 336 See `trac.db.api.get_read_db` for detailed documentation.""" 338 337 return get_read_db(self) 339 338 339 @property 340 def db_query(self): 341 return QueryContextMgr(self) 342 343 @property 344 def db_transaction(self): 345 return TransactionContextMgr(self) 346 340 347 def shutdown(self, tid=None): 341 348 """Close the environment.""" 342 349 RepositoryManager(self).shutdown(tid)
