Merge lp:~openerp-dev/openobject-server/trunk-test_cursor-rco into lp:openobject-server
- trunk-test_cursor-rco
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 5169 |
Proposed branch: | lp:~openerp-dev/openobject-server/trunk-test_cursor-rco |
Merge into: | lp:openobject-server |
Diff against target: |
718 lines (+163/-123) 17 files modified
openerp/addons/base/res/res_users.py (+4/-5) openerp/addons/base/tests/test_db_cursor.py (+1/-1) openerp/addons/base/tests/test_ir_sequence.py (+1/-1) openerp/addons/base/tests/test_uninstall.py (+1/-1) openerp/addons/base/tests/test_views.py (+1/-1) openerp/cli/server.py (+2/-2) openerp/http.py (+5/-13) openerp/modules/registry.py (+68/-32) openerp/pooler.py (+2/-2) openerp/service/model.py (+2/-13) openerp/service/report.py (+2/-2) openerp/sql_db.py (+57/-0) openerp/tests/common.py (+13/-37) openerp/tools/mail.py (+1/-1) openerpcommand/module.py (+1/-4) openerpcommand/read.py (+1/-4) openerpcommand/uninstall.py (+1/-4) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-server/trunk-test_cursor-rco |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+214925@code.launchpad.net |
Commit message
Description of the change
Change implementation of the "test" cursor used mainly for js tests:
- change the lock on registry to allow concurrent accesses during tests only
- implement a "test" cursor that is used across multiple requests;
this cursor simulates commit and rollback with a savepoint
- always use a registry method to retrieve a cursor on the database;
when in test mode, this method returns a test cursor and serializes requests
- in unittest classes, make self.registry the registry (not just a function)
Christophe Simonis (OpenERP) (kangol) wrote : | # |
- 5169. By Raphael Collet (OpenERP)
-
[IMP] sql_db: simplify TestCursor, given that method execute() does not need overriding
- 5170. By Raphael Collet (OpenERP)
-
[IMP] registry: avoid every direct access registry.db, and rename attribute as registry._db
Raphael Collet (OpenERP) (rco-openerp) wrote : | # |
openerp/
openerp/sql_db.py: removed overriding of execute()
In Registry, I renamed registry.db into registry._db, and rewrote every call to registry.
- 5171. By Raphael Collet (OpenERP)
-
[FIX] registry: stupid typo
Preview Diff
1 | === modified file 'openerp/addons/base/res/res_users.py' | |||
2 | --- openerp/addons/base/res/res_users.py 2014-04-07 12:50:50 +0000 | |||
3 | +++ openerp/addons/base/res/res_users.py 2014-04-09 13:52:38 +0000 | |||
4 | @@ -388,14 +388,13 @@ | |||
5 | 388 | if not password: | 388 | if not password: |
6 | 389 | return False | 389 | return False |
7 | 390 | user_id = False | 390 | user_id = False |
9 | 391 | cr = self.pool.db.cursor() | 391 | cr = self.pool.cursor() |
10 | 392 | try: | 392 | try: |
11 | 393 | # autocommit: our single update request will be performed atomically. | 393 | # autocommit: our single update request will be performed atomically. |
12 | 394 | # (In this way, there is no opportunity to have two transactions | 394 | # (In this way, there is no opportunity to have two transactions |
13 | 395 | # interleaving their cr.execute()..cr.commit() calls and have one | 395 | # interleaving their cr.execute()..cr.commit() calls and have one |
14 | 396 | # of them rolled back due to a concurrent access.) | 396 | # of them rolled back due to a concurrent access.) |
17 | 397 | if not openerp.tools.config['test_enable']: | 397 | cr.autocommit(True) |
16 | 398 | cr.autocommit(True) | ||
18 | 399 | # check if user exists | 398 | # check if user exists |
19 | 400 | res = self.search(cr, SUPERUSER_ID, [('login','=',login)]) | 399 | res = self.search(cr, SUPERUSER_ID, [('login','=',login)]) |
20 | 401 | if res: | 400 | if res: |
21 | @@ -440,7 +439,7 @@ | |||
22 | 440 | # Successfully logged in as admin! | 439 | # Successfully logged in as admin! |
23 | 441 | # Attempt to guess the web base url... | 440 | # Attempt to guess the web base url... |
24 | 442 | if user_agent_env and user_agent_env.get('base_location'): | 441 | if user_agent_env and user_agent_env.get('base_location'): |
26 | 443 | cr = self.pool.db.cursor() | 442 | cr = self.pool.cursor() |
27 | 444 | try: | 443 | try: |
28 | 445 | base = user_agent_env['base_location'] | 444 | base = user_agent_env['base_location'] |
29 | 446 | ICP = self.pool['ir.config_parameter'] | 445 | ICP = self.pool['ir.config_parameter'] |
30 | @@ -461,7 +460,7 @@ | |||
31 | 461 | raise openerp.exceptions.AccessDenied() | 460 | raise openerp.exceptions.AccessDenied() |
32 | 462 | if self._uid_cache.get(db, {}).get(uid) == passwd: | 461 | if self._uid_cache.get(db, {}).get(uid) == passwd: |
33 | 463 | return | 462 | return |
35 | 464 | cr = self.pool.db.cursor() | 463 | cr = self.pool.cursor() |
36 | 465 | try: | 464 | try: |
37 | 466 | self.check_credentials(cr, uid, passwd) | 465 | self.check_credentials(cr, uid, passwd) |
38 | 467 | if self._uid_cache.has_key(db): | 466 | if self._uid_cache.has_key(db): |
39 | 468 | 467 | ||
40 | === modified file 'openerp/addons/base/tests/test_db_cursor.py' | |||
41 | --- openerp/addons/base/tests/test_db_cursor.py 2014-02-09 00:37:45 +0000 | |||
42 | +++ openerp/addons/base/tests/test_db_cursor.py 2014-04-09 13:52:38 +0000 | |||
43 | @@ -21,7 +21,7 @@ | |||
44 | 21 | """ | 21 | """ |
45 | 22 | Try to use iterable but non-list or int params in query parameters. | 22 | Try to use iterable but non-list or int params in query parameters. |
46 | 23 | """ | 23 | """ |
48 | 24 | with registry().cursor(auto_commit=False) as cr: | 24 | with registry().cursor() as cr: |
49 | 25 | with self.assertRaises(ValueError): | 25 | with self.assertRaises(ValueError): |
50 | 26 | cr.execute("SELECT id FROM res_users WHERE login=%s", 'admin') | 26 | cr.execute("SELECT id FROM res_users WHERE login=%s", 'admin') |
51 | 27 | with self.assertRaises(ValueError): | 27 | with self.assertRaises(ValueError): |
52 | 28 | 28 | ||
53 | === modified file 'openerp/addons/base/tests/test_ir_sequence.py' | |||
54 | --- openerp/addons/base/tests/test_ir_sequence.py 2014-03-18 12:41:12 +0000 | |||
55 | +++ openerp/addons/base/tests/test_ir_sequence.py 2014-04-09 13:52:38 +0000 | |||
56 | @@ -21,7 +21,7 @@ | |||
57 | 21 | return openerp.modules.registry.RegistryManager.get(DB)[model] | 21 | return openerp.modules.registry.RegistryManager.get(DB)[model] |
58 | 22 | 22 | ||
59 | 23 | def cursor(): | 23 | def cursor(): |
61 | 24 | return openerp.modules.registry.RegistryManager.get(DB).db.cursor() | 24 | return openerp.modules.registry.RegistryManager.get(DB).cursor() |
62 | 25 | 25 | ||
63 | 26 | 26 | ||
64 | 27 | def drop_sequence(code): | 27 | def drop_sequence(code): |
65 | 28 | 28 | ||
66 | === modified file 'openerp/addons/base/tests/test_uninstall.py' | |||
67 | --- openerp/addons/base/tests/test_uninstall.py 2014-02-09 00:37:45 +0000 | |||
68 | +++ openerp/addons/base/tests/test_uninstall.py 2014-04-09 13:52:38 +0000 | |||
69 | @@ -13,7 +13,7 @@ | |||
70 | 13 | return openerp.modules.registry.RegistryManager.get(DB)[model] | 13 | return openerp.modules.registry.RegistryManager.get(DB)[model] |
71 | 14 | 14 | ||
72 | 15 | def cursor(): | 15 | def cursor(): |
74 | 16 | return openerp.modules.registry.RegistryManager.get(DB).db.cursor() | 16 | return openerp.modules.registry.RegistryManager.get(DB).cursor() |
75 | 17 | 17 | ||
76 | 18 | def get_module(module_name): | 18 | def get_module(module_name): |
77 | 19 | registry = openerp.modules.registry.RegistryManager.get(DB) | 19 | registry = openerp.modules.registry.RegistryManager.get(DB) |
78 | 20 | 20 | ||
79 | === modified file 'openerp/addons/base/tests/test_views.py' | |||
80 | --- openerp/addons/base/tests/test_views.py 2014-02-25 11:47:06 +0000 | |||
81 | +++ openerp/addons/base/tests/test_views.py 2014-04-09 13:52:38 +0000 | |||
82 | @@ -28,7 +28,7 @@ | |||
83 | 28 | self.assertTreesEqual(c1, c2, msg) | 28 | self.assertTreesEqual(c1, c2, msg) |
84 | 29 | 29 | ||
85 | 30 | 30 | ||
87 | 31 | class TestNodeLocator(common.BaseCase): | 31 | class TestNodeLocator(common.TransactionCase): |
88 | 32 | """ | 32 | """ |
89 | 33 | The node locator returns None when it can not find a node, and the first | 33 | The node locator returns None when it can not find a node, and the first |
90 | 34 | match when it finds something (no jquery-style node sets) | 34 | match when it finds something (no jquery-style node sets) |
91 | 35 | 35 | ||
92 | === modified file 'openerp/cli/server.py' | |||
93 | --- openerp/cli/server.py 2014-04-07 16:05:48 +0000 | |||
94 | +++ openerp/cli/server.py 2014-04-09 13:52:38 +0000 | |||
95 | @@ -111,7 +111,7 @@ | |||
96 | 111 | fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower() | 111 | fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower() |
97 | 112 | buf = file(config["translate_out"], "w") | 112 | buf = file(config["translate_out"], "w") |
98 | 113 | registry = openerp.modules.registry.RegistryManager.new(dbname) | 113 | registry = openerp.modules.registry.RegistryManager.new(dbname) |
100 | 114 | cr = registry.db.cursor() | 114 | cr = registry.cursor() |
101 | 115 | openerp.tools.trans_export(config["language"], | 115 | openerp.tools.trans_export(config["language"], |
102 | 116 | config["translate_modules"] or ["all"], buf, fileformat, cr) | 116 | config["translate_modules"] or ["all"], buf, fileformat, cr) |
103 | 117 | cr.close() | 117 | cr.close() |
104 | @@ -125,7 +125,7 @@ | |||
105 | 125 | dbname = config['db_name'] | 125 | dbname = config['db_name'] |
106 | 126 | 126 | ||
107 | 127 | registry = openerp.modules.registry.RegistryManager.new(dbname) | 127 | registry = openerp.modules.registry.RegistryManager.new(dbname) |
109 | 128 | cr = registry.db.cursor() | 128 | cr = registry.cursor() |
110 | 129 | openerp.tools.trans_load( cr, config["translate_in"], config["language"], | 129 | openerp.tools.trans_load( cr, config["translate_in"], config["language"], |
111 | 130 | context=context) | 130 | context=context) |
112 | 131 | cr.commit() | 131 | cr.commit() |
113 | 132 | 132 | ||
114 | === modified file 'openerp/http.py' | |||
115 | --- openerp/http.py 2014-04-07 16:05:48 +0000 | |||
116 | +++ openerp/http.py 2014-04-09 13:52:38 +0000 | |||
117 | @@ -235,10 +235,7 @@ | |||
118 | 235 | """ | 235 | """ |
119 | 236 | # some magic to lazy create the cr | 236 | # some magic to lazy create the cr |
120 | 237 | if not self._cr: | 237 | if not self._cr: |
125 | 238 | # Test cursors | 238 | self._cr = self.registry.cursor() |
122 | 239 | self._cr = openerp.tests.common.acquire_test_cursor(self.session_id) | ||
123 | 240 | if not self._cr: | ||
124 | 241 | self._cr = self.registry.db.cursor() | ||
126 | 242 | return self._cr | 239 | return self._cr |
127 | 243 | 240 | ||
128 | 244 | def __enter__(self): | 241 | def __enter__(self): |
129 | @@ -249,14 +246,9 @@ | |||
130 | 249 | _request_stack.pop() | 246 | _request_stack.pop() |
131 | 250 | 247 | ||
132 | 251 | if self._cr: | 248 | if self._cr: |
141 | 252 | # Dont close test cursors | 249 | if exc_type is None and not self._failed: |
142 | 253 | if not openerp.tests.common.release_test_cursor(self._cr): | 250 | self._cr.commit() |
143 | 254 | if exc_type is None and not self._failed: | 251 | self._cr.close() |
136 | 255 | self._cr.commit() | ||
137 | 256 | else: | ||
138 | 257 | # just to be explicit - happens at close() anyway | ||
139 | 258 | self._cr.rollback() | ||
140 | 259 | self._cr.close() | ||
144 | 260 | # just to be sure no one tries to re-use the request | 252 | # just to be sure no one tries to re-use the request |
145 | 261 | self.disable_db = True | 253 | self.disable_db = True |
146 | 262 | self.uid = None | 254 | self.uid = None |
147 | @@ -294,7 +286,7 @@ | |||
148 | 294 | def checked_call(___dbname, *a, **kw): | 286 | def checked_call(___dbname, *a, **kw): |
149 | 295 | # The decorator can call us more than once if there is an database error. In this | 287 | # The decorator can call us more than once if there is an database error. In this |
150 | 296 | # case, the request cursor is unusable. Rollback transaction to create a new one. | 288 | # case, the request cursor is unusable. Rollback transaction to create a new one. |
152 | 297 | if self._cr and not openerp.tools.config['test_enable']: | 289 | if self._cr: |
153 | 298 | self._cr.rollback() | 290 | self._cr.rollback() |
154 | 299 | return self.endpoint(*a, **kw) | 291 | return self.endpoint(*a, **kw) |
155 | 300 | 292 | ||
156 | 301 | 293 | ||
157 | === modified file 'openerp/modules/registry.py' | |||
158 | --- openerp/modules/registry.py 2014-02-16 21:22:22 +0000 | |||
159 | +++ openerp/modules/registry.py 2014-04-09 13:52:38 +0000 | |||
160 | @@ -58,7 +58,10 @@ | |||
161 | 58 | self._init_modules = set() | 58 | self._init_modules = set() |
162 | 59 | 59 | ||
163 | 60 | self.db_name = db_name | 60 | self.db_name = db_name |
165 | 61 | self.db = openerp.sql_db.db_connect(db_name) | 61 | self._db = openerp.sql_db.db_connect(db_name) |
166 | 62 | |||
167 | 63 | # special cursor for test mode; None means "normal" mode | ||
168 | 64 | self.test_cr = None | ||
169 | 62 | 65 | ||
170 | 63 | # Indicates that the registry is | 66 | # Indicates that the registry is |
171 | 64 | self.ready = False | 67 | self.ready = False |
172 | @@ -75,7 +78,7 @@ | |||
173 | 75 | # Useful only in a multi-process context. | 78 | # Useful only in a multi-process context. |
174 | 76 | self._any_cache_cleared = False | 79 | self._any_cache_cleared = False |
175 | 77 | 80 | ||
177 | 78 | cr = self.db.cursor() | 81 | cr = self.cursor() |
178 | 79 | has_unaccent = openerp.modules.db.has_unaccent(cr) | 82 | has_unaccent = openerp.modules.db.has_unaccent(cr) |
179 | 80 | if openerp.tools.config['unaccent'] and not has_unaccent: | 83 | if openerp.tools.config['unaccent'] and not has_unaccent: |
180 | 81 | _logger.warning("The option --unaccent was given but no unaccent() function was found in database.") | 84 | _logger.warning("The option --unaccent was given but no unaccent() function was found in database.") |
181 | @@ -102,6 +105,10 @@ | |||
182 | 102 | """ Return the model with the given name or raise KeyError if it doesn't exist.""" | 105 | """ Return the model with the given name or raise KeyError if it doesn't exist.""" |
183 | 103 | return self.models[model_name] | 106 | return self.models[model_name] |
184 | 104 | 107 | ||
185 | 108 | def __call__(self, model_name): | ||
186 | 109 | """ Same as ``self[model_name]``. """ | ||
187 | 110 | return self.models[model_name] | ||
188 | 111 | |||
189 | 105 | def do_parent_store(self, cr): | 112 | def do_parent_store(self, cr): |
190 | 106 | for o in self._init_parent: | 113 | for o in self._init_parent: |
191 | 107 | self.get(o)._parent_store_compute(cr) | 114 | self.get(o)._parent_store_compute(cr) |
192 | @@ -183,27 +190,38 @@ | |||
193 | 183 | r, c) | 190 | r, c) |
194 | 184 | return r, c | 191 | return r, c |
195 | 185 | 192 | ||
209 | 186 | @contextmanager | 193 | def enter_test_mode(self): |
210 | 187 | def cursor(self, auto_commit=True): | 194 | """ Enter the 'test' mode, where one cursor serves several requests. """ |
211 | 188 | cr = self.db.cursor() | 195 | assert self.test_cr is None |
212 | 189 | try: | 196 | self.test_cr = self._db.test_cursor() |
213 | 190 | yield cr | 197 | RegistryManager.enter_test_mode() |
214 | 191 | if auto_commit: | 198 | |
215 | 192 | cr.commit() | 199 | def leave_test_mode(self): |
216 | 193 | finally: | 200 | """ Leave the test mode. """ |
217 | 194 | cr.close() | 201 | assert self.test_cr is not None |
218 | 195 | 202 | self.test_cr.close(force=True) # close the cursor for real | |
219 | 196 | class TestRLock(object): | 203 | self.test_cr = None |
220 | 197 | def __init__(self): | 204 | RegistryManager.leave_test_mode() |
221 | 198 | self._lock = threading.RLock() | 205 | |
222 | 206 | def cursor(self): | ||
223 | 207 | """ Return a new cursor for the database. The cursor itself may be used | ||
224 | 208 | as a context manager to commit/rollback and close automatically. | ||
225 | 209 | """ | ||
226 | 210 | if self.test_cr is not None: | ||
227 | 211 | # While in test mode, we use one special cursor across requests. The | ||
228 | 212 | # test cursor uses a reentrant lock to serialize accesses. The lock | ||
229 | 213 | # is granted here by cursor(), and automatically released by the | ||
230 | 214 | # cursor itself in its method close(). | ||
231 | 215 | self.test_cr.acquire() | ||
232 | 216 | return self.test_cr | ||
233 | 217 | return self._db.cursor() | ||
234 | 218 | |||
235 | 219 | class DummyRLock(object): | ||
236 | 220 | """ Dummy reentrant lock, to be used while running rpc and js tests """ | ||
237 | 199 | def acquire(self): | 221 | def acquire(self): |
241 | 200 | if openerp.tools.config['test_enable']: | 222 | pass |
239 | 201 | return | ||
240 | 202 | return self._lock.acquire() | ||
242 | 203 | def release(self): | 223 | def release(self): |
246 | 204 | if openerp.tools.config['test_enable']: | 224 | pass |
244 | 205 | return | ||
245 | 206 | return self._lock.release() | ||
247 | 207 | def __enter__(self): | 225 | def __enter__(self): |
248 | 208 | self.acquire() | 226 | self.acquire() |
249 | 209 | def __exit__(self, type, value, traceback): | 227 | def __exit__(self, type, value, traceback): |
250 | @@ -219,12 +237,30 @@ | |||
251 | 219 | # Mapping between db name and model registry. | 237 | # Mapping between db name and model registry. |
252 | 220 | # Accessed through the methods below. | 238 | # Accessed through the methods below. |
253 | 221 | registries = {} | 239 | registries = {} |
255 | 222 | registries_lock = TestRLock() | 240 | _lock = threading.RLock() |
256 | 241 | _saved_lock = None | ||
257 | 242 | |||
258 | 243 | @classmethod | ||
259 | 244 | def lock(cls): | ||
260 | 245 | """ Return the current registry lock. """ | ||
261 | 246 | return cls._lock | ||
262 | 247 | |||
263 | 248 | @classmethod | ||
264 | 249 | def enter_test_mode(cls): | ||
265 | 250 | """ Enter the 'test' mode, where the registry is no longer locked. """ | ||
266 | 251 | assert cls._saved_lock is None | ||
267 | 252 | cls._lock, cls._saved_lock = DummyRLock(), cls._lock | ||
268 | 253 | |||
269 | 254 | @classmethod | ||
270 | 255 | def leave_test_mode(cls): | ||
271 | 256 | """ Leave the 'test' mode. """ | ||
272 | 257 | assert cls._saved_lock is not None | ||
273 | 258 | cls._lock, cls._saved_lock = cls._saved_lock, None | ||
274 | 223 | 259 | ||
275 | 224 | @classmethod | 260 | @classmethod |
276 | 225 | def get(cls, db_name, force_demo=False, status=None, update_module=False): | 261 | def get(cls, db_name, force_demo=False, status=None, update_module=False): |
277 | 226 | """ Return a registry for a given database name.""" | 262 | """ Return a registry for a given database name.""" |
279 | 227 | with cls.registries_lock: | 263 | with cls.lock(): |
280 | 228 | try: | 264 | try: |
281 | 229 | return cls.registries[db_name] | 265 | return cls.registries[db_name] |
282 | 230 | except KeyError: | 266 | except KeyError: |
283 | @@ -244,7 +280,7 @@ | |||
284 | 244 | 280 | ||
285 | 245 | """ | 281 | """ |
286 | 246 | import openerp.modules | 282 | import openerp.modules |
288 | 247 | with cls.registries_lock: | 283 | with cls.lock(): |
289 | 248 | registry = Registry(db_name) | 284 | registry = Registry(db_name) |
290 | 249 | 285 | ||
291 | 250 | # Initializing a registry will call general code which will in turn | 286 | # Initializing a registry will call general code which will in turn |
292 | @@ -259,7 +295,7 @@ | |||
293 | 259 | registry.base_registry_signaling_sequence = seq_registry | 295 | registry.base_registry_signaling_sequence = seq_registry |
294 | 260 | registry.base_cache_signaling_sequence = seq_cache | 296 | registry.base_cache_signaling_sequence = seq_cache |
295 | 261 | # This should be a method on Registry | 297 | # This should be a method on Registry |
297 | 262 | openerp.modules.load_modules(registry.db, force_demo, status, update_module) | 298 | openerp.modules.load_modules(registry._db, force_demo, status, update_module) |
298 | 263 | except Exception: | 299 | except Exception: |
299 | 264 | del cls.registries[db_name] | 300 | del cls.registries[db_name] |
300 | 265 | raise | 301 | raise |
301 | @@ -269,7 +305,7 @@ | |||
302 | 269 | # Yeah, crazy. | 305 | # Yeah, crazy. |
303 | 270 | registry = cls.registries[db_name] | 306 | registry = cls.registries[db_name] |
304 | 271 | 307 | ||
306 | 272 | cr = registry.db.cursor() | 308 | cr = registry.cursor() |
307 | 273 | try: | 309 | try: |
308 | 274 | registry.do_parent_store(cr) | 310 | registry.do_parent_store(cr) |
309 | 275 | cr.commit() | 311 | cr.commit() |
310 | @@ -286,7 +322,7 @@ | |||
311 | 286 | @classmethod | 322 | @classmethod |
312 | 287 | def delete(cls, db_name): | 323 | def delete(cls, db_name): |
313 | 288 | """Delete the registry linked to a given database. """ | 324 | """Delete the registry linked to a given database. """ |
315 | 289 | with cls.registries_lock: | 325 | with cls.lock(): |
316 | 290 | if db_name in cls.registries: | 326 | if db_name in cls.registries: |
317 | 291 | cls.registries[db_name].clear_caches() | 327 | cls.registries[db_name].clear_caches() |
318 | 292 | del cls.registries[db_name] | 328 | del cls.registries[db_name] |
319 | @@ -294,7 +330,7 @@ | |||
320 | 294 | @classmethod | 330 | @classmethod |
321 | 295 | def delete_all(cls): | 331 | def delete_all(cls): |
322 | 296 | """Delete all the registries. """ | 332 | """Delete all the registries. """ |
324 | 297 | with cls.registries_lock: | 333 | with cls.lock(): |
325 | 298 | for db_name in cls.registries.keys(): | 334 | for db_name in cls.registries.keys(): |
326 | 299 | cls.delete(db_name) | 335 | cls.delete(db_name) |
327 | 300 | 336 | ||
328 | @@ -309,7 +345,7 @@ | |||
329 | 309 | This method is given to spare you a ``RegistryManager.get(db_name)`` | 345 | This method is given to spare you a ``RegistryManager.get(db_name)`` |
330 | 310 | that would loads the given database if it was not already loaded. | 346 | that would loads the given database if it was not already loaded. |
331 | 311 | """ | 347 | """ |
333 | 312 | with cls.registries_lock: | 348 | with cls.lock(): |
334 | 313 | if db_name in cls.registries: | 349 | if db_name in cls.registries: |
335 | 314 | cls.registries[db_name].clear_caches() | 350 | cls.registries[db_name].clear_caches() |
336 | 315 | 351 | ||
337 | @@ -325,7 +361,7 @@ | |||
338 | 325 | changed = False | 361 | changed = False |
339 | 326 | if openerp.multi_process and db_name in cls.registries: | 362 | if openerp.multi_process and db_name in cls.registries: |
340 | 327 | registry = cls.get(db_name) | 363 | registry = cls.get(db_name) |
342 | 328 | cr = registry.db.cursor() | 364 | cr = registry.cursor() |
343 | 329 | try: | 365 | try: |
344 | 330 | cr.execute(""" | 366 | cr.execute(""" |
345 | 331 | SELECT base_registry_signaling.last_value, | 367 | SELECT base_registry_signaling.last_value, |
346 | @@ -371,7 +407,7 @@ | |||
347 | 371 | registry = cls.get(db_name) | 407 | registry = cls.get(db_name) |
348 | 372 | if registry.any_cache_cleared(): | 408 | if registry.any_cache_cleared(): |
349 | 373 | _logger.info("At least one model cache has been cleared, signaling through the database.") | 409 | _logger.info("At least one model cache has been cleared, signaling through the database.") |
351 | 374 | cr = registry.db.cursor() | 410 | cr = registry.cursor() |
352 | 375 | r = 1 | 411 | r = 1 |
353 | 376 | try: | 412 | try: |
354 | 377 | cr.execute("select nextval('base_cache_signaling')") | 413 | cr.execute("select nextval('base_cache_signaling')") |
355 | @@ -386,7 +422,7 @@ | |||
356 | 386 | if openerp.multi_process and db_name in cls.registries: | 422 | if openerp.multi_process and db_name in cls.registries: |
357 | 387 | _logger.info("Registry changed, signaling through the database") | 423 | _logger.info("Registry changed, signaling through the database") |
358 | 388 | registry = cls.get(db_name) | 424 | registry = cls.get(db_name) |
360 | 389 | cr = registry.db.cursor() | 425 | cr = registry.cursor() |
361 | 390 | r = 1 | 426 | r = 1 |
362 | 391 | try: | 427 | try: |
363 | 392 | cr.execute("select nextval('base_registry_signaling')") | 428 | cr.execute("select nextval('base_registry_signaling')") |
364 | 393 | 429 | ||
365 | === modified file 'openerp/pooler.py' | |||
366 | --- openerp/pooler.py 2013-03-27 14:16:53 +0000 | |||
367 | +++ openerp/pooler.py 2014-04-09 13:52:38 +0000 | |||
368 | @@ -36,7 +36,7 @@ | |||
369 | 36 | assert openerp.conf.deprecation.openerp_pooler | 36 | assert openerp.conf.deprecation.openerp_pooler |
370 | 37 | _logger.warning('openerp.pooler.get_db_and_pool() is deprecated.') | 37 | _logger.warning('openerp.pooler.get_db_and_pool() is deprecated.') |
371 | 38 | registry = RegistryManager.get(db_name, force_demo, status, update_module) | 38 | registry = RegistryManager.get(db_name, force_demo, status, update_module) |
373 | 39 | return registry.db, registry | 39 | return registry._db, registry |
374 | 40 | 40 | ||
375 | 41 | 41 | ||
376 | 42 | def restart_pool(db_name, force_demo=False, status=None, update_module=False): | 42 | def restart_pool(db_name, force_demo=False, status=None, update_module=False): |
377 | @@ -44,7 +44,7 @@ | |||
378 | 44 | _logger.warning('openerp.pooler.restart_pool() is deprecated.') | 44 | _logger.warning('openerp.pooler.restart_pool() is deprecated.') |
379 | 45 | assert openerp.conf.deprecation.openerp_pooler | 45 | assert openerp.conf.deprecation.openerp_pooler |
380 | 46 | registry = RegistryManager.new(db_name, force_demo, status, update_module) | 46 | registry = RegistryManager.new(db_name, force_demo, status, update_module) |
382 | 47 | return registry.db, registry | 47 | return registry._db, registry |
383 | 48 | 48 | ||
384 | 49 | def get_db(db_name): | 49 | def get_db(db_name): |
385 | 50 | """Return a database connection. The corresponding registry is initialized.""" | 50 | """Return a database connection. The corresponding registry is initialized.""" |
386 | 51 | 51 | ||
387 | === modified file 'openerp/service/model.py' | |||
388 | --- openerp/service/model.py 2014-02-09 00:40:05 +0000 | |||
389 | +++ openerp/service/model.py 2014-04-09 13:52:38 +0000 | |||
390 | @@ -161,21 +161,10 @@ | |||
391 | 161 | def execute_kw(db, uid, obj, method, args, kw=None): | 161 | def execute_kw(db, uid, obj, method, args, kw=None): |
392 | 162 | return execute(db, uid, obj, method, *args, **kw or {}) | 162 | return execute(db, uid, obj, method, *args, **kw or {}) |
393 | 163 | 163 | ||
394 | 164 | @contextmanager | ||
395 | 165 | def closing_cr_and_commit(cr): | ||
396 | 166 | try: | ||
397 | 167 | yield cr | ||
398 | 168 | cr.commit() | ||
399 | 169 | except Exception: | ||
400 | 170 | cr.rollback() | ||
401 | 171 | raise | ||
402 | 172 | finally: | ||
403 | 173 | cr.close() | ||
404 | 174 | |||
405 | 175 | @check | 164 | @check |
406 | 176 | def execute(db, uid, obj, method, *args, **kw): | 165 | def execute(db, uid, obj, method, *args, **kw): |
407 | 177 | threading.currentThread().dbname = db | 166 | threading.currentThread().dbname = db |
409 | 178 | with closing_cr_and_commit(openerp.registry(db).db.cursor()) as cr: | 167 | with openerp.registry(db).cursor() as cr: |
410 | 179 | if method.startswith('_'): | 168 | if method.startswith('_'): |
411 | 180 | raise except_orm('Access Denied', 'Private methods (such as %s) cannot be called remotely.' % (method,)) | 169 | raise except_orm('Access Denied', 'Private methods (such as %s) cannot be called remotely.' % (method,)) |
412 | 181 | res = execute_cr(cr, uid, obj, method, *args, **kw) | 170 | res = execute_cr(cr, uid, obj, method, *args, **kw) |
413 | @@ -190,7 +179,7 @@ | |||
414 | 190 | 179 | ||
415 | 191 | @check | 180 | @check |
416 | 192 | def exec_workflow(db, uid, obj, signal, *args): | 181 | def exec_workflow(db, uid, obj, signal, *args): |
418 | 193 | with closing_cr_and_commit(openerp.registry(db).db.cursor()) as cr: | 182 | with openerp.registry(db).cursor() as cr: |
419 | 194 | return exec_workflow_cr(cr, uid, obj, signal, *args) | 183 | return exec_workflow_cr(cr, uid, obj, signal, *args) |
420 | 195 | 184 | ||
421 | 196 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: | 185 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
422 | 197 | 186 | ||
423 | === modified file 'openerp/service/report.py' | |||
424 | --- openerp/service/report.py 2013-03-27 16:40:45 +0000 | |||
425 | +++ openerp/service/report.py 2014-04-09 13:52:38 +0000 | |||
426 | @@ -49,7 +49,7 @@ | |||
427 | 49 | 49 | ||
428 | 50 | self_reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} | 50 | self_reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} |
429 | 51 | 51 | ||
431 | 52 | cr = openerp.registry(db).db.cursor() | 52 | cr = openerp.registry(db).cursor() |
432 | 53 | try: | 53 | try: |
433 | 54 | result, format = openerp.report.render_report(cr, uid, ids, object, datas, context) | 54 | result, format = openerp.report.render_report(cr, uid, ids, object, datas, context) |
434 | 55 | if not result: | 55 | if not result: |
435 | @@ -87,7 +87,7 @@ | |||
436 | 87 | self_reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} | 87 | self_reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} |
437 | 88 | 88 | ||
438 | 89 | def go(id, uid, ids, datas, context): | 89 | def go(id, uid, ids, datas, context): |
440 | 90 | cr = openerp.registry(db).db.cursor() | 90 | cr = openerp.registry(db).cursor() |
441 | 91 | try: | 91 | try: |
442 | 92 | result, format = openerp.report.render_report(cr, uid, ids, object, datas, context) | 92 | result, format = openerp.report.render_report(cr, uid, ids, object, datas, context) |
443 | 93 | if not result: | 93 | if not result: |
444 | 94 | 94 | ||
445 | === modified file 'openerp/sql_db.py' | |||
446 | --- openerp/sql_db.py 2014-03-17 12:43:43 +0000 | |||
447 | +++ openerp/sql_db.py 2014-04-09 13:52:38 +0000 | |||
448 | @@ -347,6 +347,23 @@ | |||
449 | 347 | """ | 347 | """ |
450 | 348 | return self._cnx.rollback() | 348 | return self._cnx.rollback() |
451 | 349 | 349 | ||
452 | 350 | def __enter__(self): | ||
453 | 351 | """ Using the cursor as a contextmanager automatically commits and | ||
454 | 352 | closes it:: | ||
455 | 353 | |||
456 | 354 | with cr: | ||
457 | 355 | cr.execute(...) | ||
458 | 356 | |||
459 | 357 | # cr is committed if no failure occurred | ||
460 | 358 | # cr is closed in any case | ||
461 | 359 | """ | ||
462 | 360 | return self | ||
463 | 361 | |||
464 | 362 | def __exit__(self, exc_type, exc_value, traceback): | ||
465 | 363 | if exc_type is None: | ||
466 | 364 | self.commit() | ||
467 | 365 | self.close() | ||
468 | 366 | |||
469 | 350 | @contextmanager | 367 | @contextmanager |
470 | 351 | @check | 368 | @check |
471 | 352 | def savepoint(self): | 369 | def savepoint(self): |
472 | @@ -364,6 +381,41 @@ | |||
473 | 364 | def __getattr__(self, name): | 381 | def __getattr__(self, name): |
474 | 365 | return getattr(self._obj, name) | 382 | return getattr(self._obj, name) |
475 | 366 | 383 | ||
476 | 384 | class TestCursor(Cursor): | ||
477 | 385 | """ A cursor to be used for tests. It keeps the transaction open across | ||
478 | 386 | several requests, and simulates committing, rolling back, and closing. | ||
479 | 387 | """ | ||
480 | 388 | def __init__(self, *args, **kwargs): | ||
481 | 389 | # in order to simulate commit and rollback, the cursor maintains a | ||
482 | 390 | # savepoint at its last commit | ||
483 | 391 | super(TestCursor, self).__init__(*args, **kwargs) | ||
484 | 392 | self.execute("SAVEPOINT test_cursor") | ||
485 | 393 | self._lock = threading.RLock() | ||
486 | 394 | |||
487 | 395 | def acquire(self): | ||
488 | 396 | self._lock.acquire() | ||
489 | 397 | |||
490 | 398 | def release(self): | ||
491 | 399 | self._lock.release() | ||
492 | 400 | |||
493 | 401 | def close(self, force=False): | ||
494 | 402 | if force: | ||
495 | 403 | super(TestCursor, self).close() | ||
496 | 404 | elif not self._closed: | ||
497 | 405 | self.rollback() # for stuff that has not been committed | ||
498 | 406 | self.release() | ||
499 | 407 | |||
500 | 408 | def autocommit(self, on): | ||
501 | 409 | _logger.debug("TestCursor.autocommit(%r) does nothing", on) | ||
502 | 410 | |||
503 | 411 | def commit(self): | ||
504 | 412 | self.execute("RELEASE SAVEPOINT test_cursor") | ||
505 | 413 | self.execute("SAVEPOINT test_cursor") | ||
506 | 414 | |||
507 | 415 | def rollback(self): | ||
508 | 416 | self.execute("ROLLBACK TO SAVEPOINT test_cursor") | ||
509 | 417 | self.execute("SAVEPOINT test_cursor") | ||
510 | 418 | |||
511 | 367 | class PsycoConnection(psycopg2.extensions.connection): | 419 | class PsycoConnection(psycopg2.extensions.connection): |
512 | 368 | pass | 420 | pass |
513 | 369 | 421 | ||
514 | @@ -491,6 +543,11 @@ | |||
515 | 491 | _logger.debug('create %scursor to %r', cursor_type, self.dbname) | 543 | _logger.debug('create %scursor to %r', cursor_type, self.dbname) |
516 | 492 | return Cursor(self._pool, self.dbname, serialized=serialized) | 544 | return Cursor(self._pool, self.dbname, serialized=serialized) |
517 | 493 | 545 | ||
518 | 546 | def test_cursor(self, serialized=True): | ||
519 | 547 | cursor_type = serialized and 'serialized ' or '' | ||
520 | 548 | _logger.debug('create test %scursor to %r', cursor_type, self.dbname) | ||
521 | 549 | return TestCursor(self._pool, self.dbname, serialized=serialized) | ||
522 | 550 | |||
523 | 494 | # serialized_cursor is deprecated - cursors are serialized by default | 551 | # serialized_cursor is deprecated - cursors are serialized by default |
524 | 495 | serialized_cursor = cursor | 552 | serialized_cursor = cursor |
525 | 496 | 553 | ||
526 | 497 | 554 | ||
527 | === modified file 'openerp/tests/common.py' | |||
528 | --- openerp/tests/common.py 2014-04-03 13:41:09 +0000 | |||
529 | +++ openerp/tests/common.py 2014-04-09 13:52:38 +0000 | |||
530 | @@ -20,6 +20,7 @@ | |||
531 | 20 | import werkzeug | 20 | import werkzeug |
532 | 21 | 21 | ||
533 | 22 | import openerp | 22 | import openerp |
534 | 23 | from openerp.modules.registry import RegistryManager | ||
535 | 23 | 24 | ||
536 | 24 | _logger = logging.getLogger(__name__) | 25 | _logger = logging.getLogger(__name__) |
537 | 25 | 26 | ||
538 | @@ -37,25 +38,6 @@ | |||
539 | 37 | # Useless constant, tests are aware of the content of demo data | 38 | # Useless constant, tests are aware of the content of demo data |
540 | 38 | ADMIN_USER_ID = openerp.SUPERUSER_ID | 39 | ADMIN_USER_ID = openerp.SUPERUSER_ID |
541 | 39 | 40 | ||
542 | 40 | # Magic session_id, unfortunately we have to serialize access to the cursors to | ||
543 | 41 | # serialize requests. We first tried to duplicate the database for each tests | ||
544 | 42 | # but this proved too slow. Any idea to improve this is welcome. | ||
545 | 43 | HTTP_SESSION = {} | ||
546 | 44 | |||
547 | 45 | def acquire_test_cursor(session_id): | ||
548 | 46 | if openerp.tools.config['test_enable']: | ||
549 | 47 | cr = HTTP_SESSION.get(session_id) | ||
550 | 48 | if cr: | ||
551 | 49 | cr._test_lock.acquire() | ||
552 | 50 | return cr | ||
553 | 51 | |||
554 | 52 | def release_test_cursor(cr): | ||
555 | 53 | if openerp.tools.config['test_enable']: | ||
556 | 54 | if hasattr(cr, '_test_lock'): | ||
557 | 55 | cr._test_lock.release() | ||
558 | 56 | return True | ||
559 | 57 | return False | ||
560 | 58 | |||
561 | 59 | def at_install(flag): | 41 | def at_install(flag): |
562 | 60 | """ Sets the at-install state of a test, the flag is a boolean specifying | 42 | """ Sets the at-install state of a test, the flag is a boolean specifying |
563 | 61 | whether the test should (``True``) or should not (``False``) run during | 43 | whether the test should (``True``) or should not (``False``) run during |
564 | @@ -67,6 +49,7 @@ | |||
565 | 67 | obj.at_install = flag | 49 | obj.at_install = flag |
566 | 68 | return obj | 50 | return obj |
567 | 69 | return decorator | 51 | return decorator |
568 | 52 | |||
569 | 70 | def post_install(flag): | 53 | def post_install(flag): |
570 | 71 | """ Sets the post-install state of a test. The flag is a boolean | 54 | """ Sets the post-install state of a test. The flag is a boolean |
571 | 72 | specifying whether the test should or should not run after a set of | 55 | specifying whether the test should or should not run after a set of |
572 | @@ -83,18 +66,13 @@ | |||
573 | 83 | """ | 66 | """ |
574 | 84 | Subclass of TestCase for common OpenERP-specific code. | 67 | Subclass of TestCase for common OpenERP-specific code. |
575 | 85 | 68 | ||
577 | 86 | This class is abstract and expects self.cr and self.uid to be initialized by subclasses. | 69 | This class is abstract and expects self.registry, self.cr and self.uid to be |
578 | 70 | initialized by subclasses. | ||
579 | 87 | """ | 71 | """ |
580 | 88 | 72 | ||
581 | 89 | @classmethod | ||
582 | 90 | def cursor(self): | 73 | def cursor(self): |
590 | 91 | return openerp.modules.registry.RegistryManager.get(DB).db.cursor() | 74 | return self.registry.cursor() |
591 | 92 | 75 | ||
585 | 93 | @classmethod | ||
586 | 94 | def registry(self, model): | ||
587 | 95 | return openerp.modules.registry.RegistryManager.get(DB)[model] | ||
588 | 96 | |||
589 | 97 | @classmethod | ||
592 | 98 | def ref(self, xid): | 76 | def ref(self, xid): |
593 | 99 | """ Returns database ID corresponding to a given identifier. | 77 | """ Returns database ID corresponding to a given identifier. |
594 | 100 | 78 | ||
595 | @@ -106,7 +84,6 @@ | |||
596 | 106 | _, id = self.registry('ir.model.data').get_object_reference(self.cr, self.uid, module, xid) | 84 | _, id = self.registry('ir.model.data').get_object_reference(self.cr, self.uid, module, xid) |
597 | 107 | return id | 85 | return id |
598 | 108 | 86 | ||
599 | 109 | @classmethod | ||
600 | 110 | def browse_ref(self, xid): | 87 | def browse_ref(self, xid): |
601 | 111 | """ Returns a browsable record for the given identifier. | 88 | """ Returns a browsable record for the given identifier. |
602 | 112 | 89 | ||
603 | @@ -125,10 +102,9 @@ | |||
604 | 125 | """ | 102 | """ |
605 | 126 | 103 | ||
606 | 127 | def setUp(self): | 104 | def setUp(self): |
611 | 128 | # Store cr and uid in class variables, to allow ref() and browse_ref to be BaseCase @classmethods | 105 | self.registry = RegistryManager.get(DB) |
612 | 129 | # and still access them | 106 | self.cr = self.cursor() |
613 | 130 | TransactionCase.cr = self.cursor() | 107 | self.uid = openerp.SUPERUSER_ID |
610 | 131 | TransactionCase.uid = openerp.SUPERUSER_ID | ||
614 | 132 | 108 | ||
615 | 133 | def tearDown(self): | 109 | def tearDown(self): |
616 | 134 | self.cr.rollback() | 110 | self.cr.rollback() |
617 | @@ -143,7 +119,8 @@ | |||
618 | 143 | 119 | ||
619 | 144 | @classmethod | 120 | @classmethod |
620 | 145 | def setUpClass(cls): | 121 | def setUpClass(cls): |
622 | 146 | cls.cr = cls.cursor() | 122 | cls.registry = RegistryManager.get(DB) |
623 | 123 | cls.cr = cls.registry.cursor() | ||
624 | 147 | cls.uid = openerp.SUPERUSER_ID | 124 | cls.uid = openerp.SUPERUSER_ID |
625 | 148 | 125 | ||
626 | 149 | @classmethod | 126 | @classmethod |
627 | @@ -166,16 +143,15 @@ | |||
628 | 166 | 143 | ||
629 | 167 | def setUp(self): | 144 | def setUp(self): |
630 | 168 | super(HttpCase, self).setUp() | 145 | super(HttpCase, self).setUp() |
631 | 146 | self.registry.enter_test_mode() | ||
632 | 169 | # setup a magic session_id that will be rollbacked | 147 | # setup a magic session_id that will be rollbacked |
633 | 170 | self.session = openerp.http.root.session_store.new() | 148 | self.session = openerp.http.root.session_store.new() |
634 | 171 | self.session_id = self.session.sid | 149 | self.session_id = self.session.sid |
635 | 172 | self.session.db = DB | 150 | self.session.db = DB |
636 | 173 | openerp.http.root.session_store.save(self.session) | 151 | openerp.http.root.session_store.save(self.session) |
637 | 174 | self.cr._test_lock = threading.RLock() | ||
638 | 175 | HTTP_SESSION[self.session_id] = self.cr | ||
639 | 176 | 152 | ||
640 | 177 | def tearDown(self): | 153 | def tearDown(self): |
642 | 178 | del HTTP_SESSION[self.session_id] | 154 | self.registry.leave_test_mode() |
643 | 179 | super(HttpCase, self).tearDown() | 155 | super(HttpCase, self).tearDown() |
644 | 180 | 156 | ||
645 | 181 | def url_open(self, url, data=None, timeout=10): | 157 | def url_open(self, url, data=None, timeout=10): |
646 | 182 | 158 | ||
647 | === modified file 'openerp/tools/mail.py' | |||
648 | --- openerp/tools/mail.py 2014-02-19 14:06:17 +0000 | |||
649 | +++ openerp/tools/mail.py 2014-04-09 13:52:38 +0000 | |||
650 | @@ -625,7 +625,7 @@ | |||
651 | 625 | if not cr: | 625 | if not cr: |
652 | 626 | db_name = getattr(threading.currentThread(), 'dbname', None) | 626 | db_name = getattr(threading.currentThread(), 'dbname', None) |
653 | 627 | if db_name: | 627 | if db_name: |
655 | 628 | local_cr = cr = openerp.registry(db_name).db.cursor() | 628 | local_cr = cr = openerp.registry(db_name).cursor() |
656 | 629 | else: | 629 | else: |
657 | 630 | raise Exception("No database cursor found, please pass one explicitly") | 630 | raise Exception("No database cursor found, please pass one explicitly") |
658 | 631 | 631 | ||
659 | 632 | 632 | ||
660 | === modified file 'openerpcommand/module.py' | |||
661 | --- openerpcommand/module.py 2013-01-11 13:46:57 +0000 | |||
662 | +++ openerpcommand/module.py 2014-04-09 13:52:38 +0000 | |||
663 | @@ -33,12 +33,9 @@ | |||
664 | 33 | 33 | ||
665 | 34 | xs = [] | 34 | xs = [] |
666 | 35 | ir_module_module = registry.get('ir.module.module') | 35 | ir_module_module = registry.get('ir.module.module') |
669 | 36 | cr = registry.db.cursor() # TODO context manager | 36 | with registry.cursor() as cr: |
668 | 37 | try: | ||
670 | 38 | ids = ir_module_module.search(cr, openerp.SUPERUSER_ID, [], {}) | 37 | ids = ir_module_module.search(cr, openerp.SUPERUSER_ID, [], {}) |
671 | 39 | xs = ir_module_module.read(cr, openerp.SUPERUSER_ID, ids, [], {}) | 38 | xs = ir_module_module.read(cr, openerp.SUPERUSER_ID, ids, [], {}) |
672 | 40 | finally: | ||
673 | 41 | cr.close() | ||
674 | 42 | 39 | ||
675 | 43 | if xs: | 40 | if xs: |
676 | 44 | print "Modules (database `%s`):" % (args.database,) | 41 | print "Modules (database `%s`):" % (args.database,) |
677 | 45 | 42 | ||
678 | === modified file 'openerpcommand/read.py' | |||
679 | --- openerpcommand/read.py 2013-03-29 14:07:23 +0000 | |||
680 | +++ openerpcommand/read.py 2014-04-09 13:52:38 +0000 | |||
681 | @@ -20,15 +20,12 @@ | |||
682 | 20 | registry = openerp.modules.registry.RegistryManager.get( | 20 | registry = openerp.modules.registry.RegistryManager.get( |
683 | 21 | args.database, update_module=False) | 21 | args.database, update_module=False) |
684 | 22 | model = registry[args.model] | 22 | model = registry[args.model] |
685 | 23 | cr = registry.db.cursor() # TODO context manager | ||
686 | 24 | field_names = [args.field] if args.field else [] | 23 | field_names = [args.field] if args.field else [] |
687 | 25 | if args.short: | 24 | if args.short: |
688 | 26 | # ignore --field | 25 | # ignore --field |
689 | 27 | field_names = ['name'] | 26 | field_names = ['name'] |
691 | 28 | try: | 27 | with registry.cursor() as cr: |
692 | 29 | xs = model.read(cr, 1, args.id, field_names, {}) | 28 | xs = model.read(cr, 1, args.id, field_names, {}) |
693 | 30 | finally: | ||
694 | 31 | cr.close() | ||
695 | 32 | 29 | ||
696 | 33 | if xs: | 30 | if xs: |
697 | 34 | print "Records (model `%s`, database `%s`):" % (args.model, args.database) | 31 | print "Records (model `%s`, database `%s`):" % (args.model, args.database) |
698 | 35 | 32 | ||
699 | === modified file 'openerpcommand/uninstall.py' | |||
700 | --- openerpcommand/uninstall.py 2013-02-09 06:02:46 +0000 | |||
701 | +++ openerpcommand/uninstall.py 2014-04-09 13:52:38 +0000 | |||
702 | @@ -43,15 +43,12 @@ | |||
703 | 43 | args.database, update_module=False) | 43 | args.database, update_module=False) |
704 | 44 | 44 | ||
705 | 45 | ir_module_module = registry.get('ir.module.module') | 45 | ir_module_module = registry.get('ir.module.module') |
708 | 46 | cr = registry.db.cursor() # TODO context manager | 46 | with registry.cursor() as cr: |
707 | 47 | try: | ||
709 | 48 | ids = ir_module_module.search(cr, openerp.SUPERUSER_ID, [('name', 'in', args.module), ('state', '=', 'installed')], {}) | 47 | ids = ir_module_module.search(cr, openerp.SUPERUSER_ID, [('name', 'in', args.module), ('state', '=', 'installed')], {}) |
710 | 49 | if len(ids) == len(args.module): | 48 | if len(ids) == len(args.module): |
711 | 50 | ir_module_module.button_immediate_uninstall(cr, openerp.SUPERUSER_ID, ids, {}) | 49 | ir_module_module.button_immediate_uninstall(cr, openerp.SUPERUSER_ID, ids, {}) |
712 | 51 | else: | 50 | else: |
713 | 52 | print "At least one module not found (database `%s`)." % (args.database,) | 51 | print "At least one module not found (database `%s`)." % (args.database,) |
714 | 53 | finally: | ||
715 | 54 | cr.close() | ||
716 | 55 | 52 | ||
717 | 56 | def add_parser(subparsers): | 53 | def add_parser(subparsers): |
718 | 57 | parser = subparsers.add_parser('uninstall', | 54 | parser = subparsers.add_parser('uninstall', |
in file openerp/ addons/ base/tests/ test_db_ cursor. py, you can keep the context manager.
in file openerp/sql_db.py: in TestCursor() no need to ovewrite method execute to just call super()
more generally, I'm pretty sure there is still addons that call `registry. db.cursor( )`.
To forbid that, can you rename the `db` variable to `__db` (it's private after all)