diff --git a/openerp/addons/test_new_api/__openerp__.py b/openerp/addons/test_new_api/__openerp__.py
index 9c859de4445..89355ac19ee 100644
--- a/openerp/addons/test_new_api/__openerp__.py
+++ b/openerp/addons/test_new_api/__openerp__.py
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
{
- 'name': 'Test New API',
+ 'name': 'Test API',
'version': '1.0',
'category': 'Tests',
- 'description': """A module to test the new API.""",
+ 'description': """A module to test the API.""",
'author': 'OpenERP SA',
'maintainer': 'OpenERP SA',
'website': 'http://www.openerp.com',
diff --git a/openerp/addons/test_new_api/demo_data.xml b/openerp/addons/test_new_api/demo_data.xml
index acb53a7b07f..1715b024cd7 100644
--- a/openerp/addons/test_new_api/demo_data.xml
+++ b/openerp/addons/test_new_api/demo_data.xml
@@ -26,5 +26,7 @@
This is a much longer message
+
+
diff --git a/openerp/addons/test_new_api/ir.model.access.csv b/openerp/addons/test_new_api/ir.model.access.csv
index 5b62045ae08..2bbd1adf12d 100644
--- a/openerp/addons/test_new_api/ir.model.access.csv
+++ b/openerp/addons/test_new_api/ir.model.access.csv
@@ -3,3 +3,5 @@ access_category,test_new_api_category,test_new_api.model_test_new_api_category,,
access_discussion,test_new_api_discussion,test_new_api.model_test_new_api_discussion,,1,1,1,1
access_message,test_new_api_message,test_new_api.model_test_new_api_message,,1,1,1,1
access_mixed,test_new_api_mixed,test_new_api.model_test_new_api_mixed,,1,1,1,1
+access_test_function_noinfiniterecursion,access_test_function_noinfiniterecursion,model_test_old_api_function_noinfiniterecursion,,1,1,1,1
+access_test_function_counter,access_test_function_counter,model_test_old_api_function_counter,,1,1,1,1
diff --git a/openerp/addons/test_new_api/models.py b/openerp/addons/test_new_api/models.py
index 4399cb0ed49..173935a8985 100644
--- a/openerp/addons/test_new_api/models.py
+++ b/openerp/addons/test_new_api/models.py
@@ -19,9 +19,17 @@
#
##############################################################################
+import datetime
from openerp.exceptions import AccessError
+
+##############################################################################
+#
+# OLD API
+#
+##############################################################################
from openerp.osv import osv, fields
+
class res_partner(osv.Model):
_inherit = 'res.partner'
@@ -41,6 +49,48 @@ class res_partner(osv.Model):
}
+class TestFunctionCounter(osv.Model):
+ _name = 'test_old_api.function_counter'
+
+ def _compute_cnt(self, cr, uid, ids, fname, arg, context=None):
+ res = {}
+ for cnt in self.browse(cr, uid, ids, context=context):
+ res[cnt.id] = cnt.access and cnt.cnt + 1 or 0
+ return res
+
+ _columns = {
+ 'access': fields.datetime('Datetime Field'),
+ 'cnt': fields.function(
+ _compute_cnt, type='integer', string='Function Field', store=True),
+ }
+
+
+class TestFunctionNoInfiniteRecursion(osv.Model):
+ _name = 'test_old_api.function_noinfiniterecursion'
+
+ def _compute_f1(self, cr, uid, ids, fname, arg, context=None):
+ res = {}
+ for tf in self.browse(cr, uid, ids, context=context):
+ res[tf.id] = 'create' in tf.f0 and 'create' or 'write'
+ cntobj = self.pool['test_old_api.function_counter']
+ cnt_id = self.pool['ir.model.data'].xmlid_to_res_id(
+ cr, uid, 'test_new_api.c1')
+ cntobj.write(
+ cr, uid, cnt_id, {'access': datetime.datetime.now()},
+ context=context)
+ return res
+
+ _columns = {
+ 'f0': fields.char('Char Field'),
+ 'f1': fields.function(
+ _compute_f1, type='char', string='Function Field', store=True),
+ }
+
+##############################################################################
+#
+# NEW API
+#
+##############################################################################
from openerp import models, fields, api, _
diff --git a/openerp/addons/test_new_api/tests/__init__.py b/openerp/addons/test_new_api/tests/__init__.py
index 790ad9c9a59..f4803bd4837 100644
--- a/openerp/addons/test_new_api/tests/__init__.py
+++ b/openerp/addons/test_new_api/tests/__init__.py
@@ -5,3 +5,4 @@ from . import test_new_fields
from . import test_onchange
from . import test_field_conversions
from . import test_attributes
+from . import test_no_infinite_recursion
diff --git a/openerp/addons/test_new_api/tests/test_no_infinite_recursion.py b/openerp/addons/test_new_api/tests/test_no_infinite_recursion.py
new file mode 100644
index 00000000000..68ef3fcf3b9
--- /dev/null
+++ b/openerp/addons/test_new_api/tests/test_no_infinite_recursion.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+from openerp.tests import common
+
+
+class test_no_infinite_recursion(common.TransactionCase):
+
+ def setUp(self):
+ super(test_no_infinite_recursion, self).setUp()
+ self.tstfct = self.registry['test_old_api.function_noinfiniterecursion']
+
+ def test_00_create_and_update(self):
+ """
+ Check that computing old api function field does not cycle infinitely
+ See https://github.com/odoo/odoo/pull/7558
+ """
+ cr, uid, context, tstfct = self.cr, self.uid, {}, self.tstfct
+
+ vals = {
+ 'f0': 'Test create',
+ }
+ idnew = tstfct.create(cr, uid, vals, context=context)
+ tst = tstfct.browse(cr, uid, idnew, context=context)
+
+ self.assertEqual(tst.f1, 'create')
+
+ vals = {
+ 'f0': 'Test write',
+ }
+ tstfct.write(cr, uid, idnew, vals, context=context)
+
+ self.assertEqual(tst.f1, 'write')
diff --git a/openerp/models.py b/openerp/models.py
index 35944ff4873..b0c7762bbd7 100644
--- a/openerp/models.py
+++ b/openerp/models.py
@@ -4007,18 +4007,22 @@ class BaseModel(object):
done = {}
recs.env.recompute_old.extend(result)
- for order, model_name, ids_to_update, fields_to_recompute in sorted(recs.env.recompute_old):
- key = (model_name, tuple(fields_to_recompute))
- done.setdefault(key, {})
- # avoid to do several times the same computation
- todo = []
- for id in ids_to_update:
- if id not in done[key]:
- done[key][id] = True
- if id not in deleted_related[model_name]:
- todo.append(id)
- self.pool[model_name]._store_set_values(cr, user, todo, fields_to_recompute, context)
- recs.env.clear_recompute_old()
+ while recs.env.recompute_old:
+ sorted_recompute_old = sorted(recs.env.recompute_old)
+ recs.env.clear_recompute_old()
+ for __, model_name, ids_to_update, fields_to_recompute in \
+ sorted_recompute_old:
+ key = (model_name, tuple(fields_to_recompute))
+ done.setdefault(key, {})
+ # avoid to do several times the same computation
+ todo = []
+ for id in ids_to_update:
+ if id not in done[key]:
+ done[key][id] = True
+ if id not in deleted_related[model_name]:
+ todo.append(id)
+ self.pool[model_name]._store_set_values(
+ cr, user, todo, fields_to_recompute, context)
# recompute new-style fields
if recs.env.recompute and context.get('recompute', True):
@@ -4275,11 +4279,15 @@ class BaseModel(object):
if recs.env.recompute and context.get('recompute', True):
done = []
- for order, model_name, ids, fields2 in sorted(recs.env.recompute_old):
- if not (model_name, ids, fields2) in done:
- self.pool[model_name]._store_set_values(cr, user, ids, fields2, context)
- done.append((model_name, ids, fields2))
- recs.env.clear_recompute_old()
+ while recs.env.recompute_old:
+ sorted_recompute_old = sorted(recs.env.recompute_old)
+ recs.env.clear_recompute_old()
+ for __, model_name, ids, fields2 in sorted_recompute_old:
+ if not (model_name, ids, fields2) in done:
+ self.pool[model_name]._store_set_values(
+ cr, user, ids, fields2, context)
+ done.append((model_name, ids, fields2))
+
# recompute new-style fields
recs.recompute()