summaryrefslogtreecommitdiff
path: root/odoo/sql_db.py
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2020-08-28 14:11:21 +0000
committerRaphael Collet <rco@odoo.com>2020-09-03 09:05:21 +0000
commitd4b2e9224839aed8fc160ebe5a89e0f7d4c6a5bb (patch)
tree1d69605221a479b1cf9406b69a8acf4ac94964c6 /odoo/sql_db.py
parent800c55db56689baa9b67b7243e494246a98b3484 (diff)
[FIX] core: cursor hooks API and implementation
Python 3.8 changed the equality rules for bound methods to be based on the *identity* of the receiver (`__self__`) rather than its *equality*. This means that in 3.7, methods from different instances will compare (and hash) equal, thereby landing in the same map "slot", but that isn't the case in 3.8. While it's usually not relevant, it's an issue for `GroupCalls` which is indexed by a function: in 3.7, that being a method from recordsets comparing equal will deduplicate them, but not anymore in 3.8, leading to duplicated callbacks (exactly the thing GroupCalls aims to avoid). Also, the API of `GroupCalls` turned out to be unusual and weird. The bug above is fixed by using a plain list for callbacks, thereby avoiding comparisons between registered functions. The API is now: callbacks.add(func) # add func to callbacks callbacks.run() # run all callbacks in addition order callbacks.clear() # remove all callbacks In order to handle aggregated data, the `callbacks` object provides a dictionary `callbacks.data` that any callback function can freely use. For the sake of consistency, the `callbacks.data` dict is automatically cleared upon execution of callbacks. Discovered by @william-andre Related to odoo#56583 References: * https://bugs.python.org/issue1617161 * python/cpython#7848 * https://docs.python.org/3/whatsnew/changelog.html#python-3-8-0-alpha-1 (no direct link because individual entries are not linkable, look for bpo-1617161) X-original-commit: a986f4929bab95759086cc77ca5e60795f82e91a
Diffstat (limited to 'odoo/sql_db.py')
-rw-r--r--odoo/sql_db.py34
1 files changed, 10 insertions, 24 deletions
diff --git a/odoo/sql_db.py b/odoo/sql_db.py
index 18f3633539d..e8426691cd1 100644
--- a/odoo/sql_db.py
+++ b/odoo/sql_db.py
@@ -96,13 +96,11 @@ def check(f, self, *args, **kwargs):
class BaseCursor:
- """ Base class for cursors that manages pre/post commit/rollback hooks. """
+ """ Base class for cursors that manage pre/post commit hooks. """
def __init__(self):
- self.precommit = tools.GroupCalls()
- self.postcommit = tools.GroupCalls()
- self.prerollback = tools.GroupCalls()
- self.postrollback = tools.GroupCalls()
+ self.precommit = tools.Callbacks()
+ self.postcommit = tools.Callbacks()
@contextmanager
@check
@@ -111,20 +109,17 @@ class BaseCursor:
name = uuid.uuid1().hex
if flush:
flush_env(self, clear=False)
- self.precommit()
- self.prerollback.clear()
+ self.precommit.run()
self.execute('SAVEPOINT "%s"' % name)
try:
yield
if flush:
flush_env(self, clear=False)
- self.precommit()
- self.prerollback.clear()
+ self.precommit.run()
except Exception:
if flush:
clear_env(self)
self.precommit.clear()
- self.prerollback()
self.execute('ROLLBACK TO SAVEPOINT "%s"' % name)
raise
else:
@@ -428,17 +423,15 @@ class Cursor(BaseCursor):
if event == 'commit':
self.postcommit.add(func)
elif event == 'rollback':
- self.postrollback.add(func)
+ raise NotImplementedError()
@check
def commit(self):
""" Perform an SQL `COMMIT` """
flush_env(self)
- self.precommit()
+ self.precommit.run()
result = self._cnx.commit()
- self.prerollback.clear()
- self.postrollback.clear()
- self.postcommit()
+ self.postcommit.run()
return result
@check
@@ -447,9 +440,7 @@ class Cursor(BaseCursor):
clear_env(self)
self.precommit.clear()
self.postcommit.clear()
- self.prerollback()
result = self._cnx.rollback()
- self.postrollback()
return result
@check
@@ -506,23 +497,18 @@ class TestCursor(BaseCursor):
def commit(self):
""" Perform an SQL `COMMIT` """
flush_env(self)
- self.precommit()
+ self.precommit.run()
self._cursor.execute('SAVEPOINT "%s"' % self._savepoint)
- self.prerollback.clear()
- # ignore post-commit/rollback hooks
+ # ignore post-commit hooks
self.postcommit.clear()
- self.postrollback.clear()
@check
def rollback(self):
""" Perform an SQL `ROLLBACK` """
clear_env(self)
self.precommit.clear()
- self.prerollback()
self._cursor.execute('ROLLBACK TO SAVEPOINT "%s"' % self._savepoint)
- # ignore post-commit/rollback hooks
self.postcommit.clear()
- self.postrollback.clear()
def __getattr__(self, name):
value = getattr(self._cursor, name)