diff options
| author | Raphael Collet <rco@odoo.com> | 2020-08-28 14:11:21 +0000 |
|---|---|---|
| committer | Raphael Collet <rco@odoo.com> | 2020-09-03 09:05:21 +0000 |
| commit | d4b2e9224839aed8fc160ebe5a89e0f7d4c6a5bb (patch) | |
| tree | 1d69605221a479b1cf9406b69a8acf4ac94964c6 /odoo/addons/base/tests | |
| parent | 800c55db56689baa9b67b7243e494246a98b3484 (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/addons/base/tests')
| -rw-r--r-- | odoo/addons/base/tests/test_misc.py | 56 |
1 files changed, 37 insertions, 19 deletions
diff --git a/odoo/addons/base/tests/test_misc.py b/odoo/addons/base/tests/test_misc.py index 2cf2ebc7842..0c25a5e1669 100644 --- a/odoo/addons/base/tests/test_misc.py +++ b/odoo/addons/base/tests/test_misc.py @@ -272,36 +272,54 @@ class TestFormatLangDate(TransactionCase): self.assertEqual(misc.format_time(lang.with_context(lang='zh_CN').env, time_part, time_format='medium', lang_code='fr_FR'), '16:30:22') -class TestGroupCalls(BaseCase): - def test_callbacks(self): +class TestCallbacks(BaseCase): + def test_callback(self): log = [] + callbacks = misc.Callbacks() + # add foo def foo(): log.append("foo") - def bar(items): - log.extend(items) - callbacks.add(baz) + callbacks.add(foo) - def baz(): - log.append("baz") + # add bar + @callbacks.add + def bar(): + log.append("bar") - callbacks = misc.GroupCalls() + # add foo again callbacks.add(foo) - callbacks.add(bar, list)[0].append(1) - callbacks.add(bar, list)[0].append(2) - self.assertEqual(log, []) - callbacks() - self.assertEqual(log, ["foo", 1, 2, "baz"]) + # this should call foo(), bar(), foo() + callbacks.run() + self.assertEqual(log, ["foo", "bar", "foo"]) + + # this should do nothing + callbacks.run() + self.assertEqual(log, ["foo", "bar", "foo"]) + + def test_aggregate(self): + log = [] + callbacks = misc.Callbacks() + + # register foo once + @callbacks.add + def foo(): + log.append(callbacks.data["foo"]) + + # aggregate data + callbacks.data.setdefault("foo", []).append(1) + callbacks.data.setdefault("foo", []).append(2) + callbacks.data.setdefault("foo", []).append(3) - callbacks() - self.assertEqual(log, ["foo", 1, 2, "baz"]) + # foo() is called once + callbacks.run() + self.assertEqual(log, [[1, 2, 3]]) + self.assertFalse(callbacks.data) - callbacks.add(bar, list)[0].append(3) - callbacks.clear() - callbacks() - self.assertEqual(log, ["foo", 1, 2, "baz"]) + callbacks.run() + self.assertEqual(log, [[1, 2, 3]]) class TestRemoveAccents(BaseCase): |
