summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2018-08-16 11:19:49 +0200
committerRaphael Collet <rco@odoo.com>2018-08-16 16:39:20 +0200
commit2a2ff6eb5c746acec46ebc7fee382dfa78ec8c14 (patch)
treeab8617d0003d04c342436770816b940a349e6788
parent49fb7a4682bf57165f1964a36dca477ff86e2ae7 (diff)
[FIX] tools: serialize lazy to json
-rw-r--r--odoo/addons/test_performance/tests/test_performance.py4
-rw-r--r--odoo/tools/func.py50
2 files changed, 35 insertions, 19 deletions
diff --git a/odoo/addons/test_performance/tests/test_performance.py b/odoo/addons/test_performance/tests/test_performance.py
index 3e38fd6f5b9..a4e7b0481c2 100644
--- a/odoo/addons/test_performance/tests/test_performance.py
+++ b/odoo/addons/test_performance/tests/test_performance.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
+import json
from odoo.tests.common import TransactionCase, users, warmup
from odoo.tools import pycompat
@@ -138,3 +139,6 @@ class TestPerformance(TransactionCase):
self.assertEqual(res['partner_id'][0], exp['partner_id'][0])
self.assertEqual(res['partner_id_count'], exp['partner_id_count'])
self.assertEqual(res['value'], exp['value'])
+ # now serialize to json, which should force evaluation
+ with self.assertQueryCount(admin=1, demo=1):
+ json.dumps(result)
diff --git a/odoo/tools/func.py b/odoo/tools/func.py
index ed1305a5590..424b6879aba 100644
--- a/odoo/tools/func.py
+++ b/odoo/tools/func.py
@@ -4,8 +4,9 @@
__all__ = ['synchronized', 'lazy_classproperty', 'lazy_property',
'classproperty', 'conditional', 'lazy']
-from functools import wraps, partial
+from functools import wraps
from inspect import getsourcefile
+from json import JSONEncoder
class lazy_property(object):
@@ -122,27 +123,27 @@ class lazy(object):
baz = foo + 2 # use result of func(arg) and add 2
"""
- __slots__ = ['_func', '_value']
+ __slots__ = ['_func', '_args', '_kwargs', '_cached_value']
def __init__(self, func, *args, **kwargs):
- self._func = partial(func, *args, **kwargs)
+ # bypass own __setattr__
+ object.__setattr__(self, '_func', func)
+ object.__setattr__(self, '_args', args)
+ object.__setattr__(self, '_kwargs', kwargs)
- def __getattr__(self, name):
- if name == '_value':
- self._value = value = self._func()
- self._func = None
- return value
- return getattr(self._value, name)
-
- def __setattr__(self, name, value):
- if name in ('_func', '_value'):
- return object.__setattr__(self, name, value)
- return setattr(self._value, name, value)
-
- def __delattr__(self, name):
- if name in ('_func', '_value'):
- return object.__delattr__(self, name)
- return delattr(self._value, name)
+ @property
+ def _value(self):
+ if self._func is not None:
+ value = self._func(*self._args, **self._kwargs)
+ object.__setattr__(self, '_func', None)
+ object.__setattr__(self, '_args', None)
+ object.__setattr__(self, '_kwargs', None)
+ object.__setattr__(self, '_cached_value', value)
+ return self._cached_value
+
+ def __getattr__(self, name): return getattr(self._value, name)
+ def __setattr__(self, name, value): return setattr(self._value, name, value)
+ def __delattr__(self, name): return delattr(self._value, name)
def __repr__(self):
return repr(self._value) if self._func is None else object.__repr__(self)
@@ -241,3 +242,14 @@ class lazy(object):
def __aenter__(self): return self._value.__aenter__()
def __aexit__(self, exc_type, exc_value, traceback):
return self._value.__aexit__(exc_type, exc_value, traceback)
+
+
+# patch serialization of lazy
+def default(self, o):
+ if isinstance(o, lazy):
+ return o._value
+ return json_encoder_default(self, o)
+
+
+json_encoder_default = JSONEncoder.default
+JSONEncoder.default = default