summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2019-02-14 12:59:04 +0000
committerRaphael Collet <rco@odoo.com>2019-03-22 16:42:14 +0000
commitd87443a21337bcc3d785ae23e19f66b11ba8bb9e (patch)
tree0a10e803beca0026560ecb32c18b492c7323de22
parent1ced3bfca457ac50845637bcd42a8e53bd7f088d (diff)
[FIX] convert: enable kwargs in tag <function>
closes odoo/odoo#31417 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
-rw-r--r--addons/crm/data/crm_lead_demo.xml12
-rw-r--r--addons/mass_mailing/data/mass_mailing_demo.xml23
-rw-r--r--addons/stock/data/stock_data.xml20
-rw-r--r--odoo/addons/test_convert/__init__.py12
-rw-r--r--odoo/addons/test_convert/models.py20
-rw-r--r--odoo/addons/test_convert/tests/test_convert.py114
-rw-r--r--odoo/import_xml.rng1
-rw-r--r--odoo/tools/convert.py36
8 files changed, 177 insertions, 61 deletions
diff --git a/addons/crm/data/crm_lead_demo.xml b/addons/crm/data/crm_lead_demo.xml
index 4f638a42f0e..0e73640175a 100644
--- a/addons/crm/data/crm_lead_demo.xml
+++ b/addons/crm/data/crm_lead_demo.xml
@@ -368,8 +368,8 @@ Andrew</p>]]></field>
<!-- Call Function to Cancel the leads (set as Dead) -->
<function model="crm.lead" name="action_set_lost"
- eval="[ref('crm_case_7'), ref('crm_case_9'), ref('crm_case_11'), ref('crm_case_12')],
- {'install_mode': True}"/>
+ eval="[[ref('crm_case_7'), ref('crm_case_9'), ref('crm_case_11'), ref('crm_case_12')]]"
+ context="{'install_mode': True}"/>
<!-- Demo Opportunities -->
<record id="crm_case_13" model="crm.lead">
@@ -1161,13 +1161,13 @@ Andrew</p>]]></field>
<!-- Call Function to set dome opportunities as Lost -->
<function model="crm.lead" name="action_set_lost"
- eval="[ref('crm_case_28')],
- {'install_mode': True}"/>
+ eval="[[ref('crm_case_28')]]"
+ context="{'install_mode': True}"/>
<!-- Call Function to set some opportunities as Won -->
<function model="crm.lead" name="action_set_won"
- eval="[ref('crm_case_20'), ref('crm_case_23'), ref('crm_case_27')],
- {'install_mode': True}"/>
+ eval="[[ref('crm_case_20'), ref('crm_case_23'), ref('crm_case_27')]]"
+ context="{'install_mode': True}"/>
<!-- Activities -->
<record id="activity_1" model="mail.activity">
diff --git a/addons/mass_mailing/data/mass_mailing_demo.xml b/addons/mass_mailing/data/mass_mailing_demo.xml
index 19957054c66..e9df5daaa35 100644
--- a/addons/mass_mailing/data/mass_mailing_demo.xml
+++ b/addons/mass_mailing/data/mass_mailing_demo.xml
@@ -264,34 +264,41 @@
<value model="link.tracker.code"
search="[('link_id.url', '=', 'http://www.example.com')]"
use="code"/>
- <value eval="{'ip': '100.01.02.03', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_0')}"/>
+ <value name="ip">100.01.02.03</value>
+ <value name="country_code">BE</value>
+ <value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/>
</function>
<function model="link.tracker.click" name="add_click">
<value model="link.tracker.code"
search="[('link_id.url', '=', 'http://www.example.net/page/contactus')]"
use="code"/>
- <value eval="{'ip': '100.01.02.03', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_0')}"/>
+ <value name="ip">100.01.02.03</value>
+ <value name="country_code">BE</value>
+ <value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/>
</function>
<function model="link.tracker.click" name="add_click">
<value model="link.tracker.code"
search="[('link_id.url', '=', 'http://www.example.com')]"
use="code"/>
- <value eval="{'ip': '100.01.02.04', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_1')}"/>
+ <value name="ip">100.01.02.04</value>
+ <value name="country_code">BE</value>
+ <value name="mail_stat_id" eval="ref('mass_mail_1_stat_1')"/>
</function>
<function model="link.tracker.click" name="add_click">
<value model="link.tracker.code"
search="[('link_id.url', '=', 'http://www.example.net/page/contactus')]"
use="code"/>
- <value eval="{'ip': '100.01.02.04', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_0')}"/>
- <value eval="'100.01.02.04'"/>
- <value eval="'BE'"/>
- <value eval="ref('mass_mail_1_stat_0')"/>
+ <value name="ip">100.01.02.04</value>
+ <value name="country_code">BE</value>
+ <value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/>
</function>
<function model="link.tracker.click" name="add_click">
<value model="link.tracker.code"
search="[('link_id.url', '=', 'http://www.example.com')]"
use="code"/>
- <value eval="{'ip': '100.01.02.05', 'country_code': 'BE', 'mail_stat_id': ref('mass_mail_1_stat_2')}"/>
+ <value name="ip">100.01.02.05</value>
+ <value name="country_code">BE</value>
+ <value name="mail_stat_id" eval="ref('mass_mail_1_stat_2')"/>
</function>
</data>
diff --git a/addons/stock/data/stock_data.xml b/addons/stock/data/stock_data.xml
index d522f76d9c6..34693a1c29f 100644
--- a/addons/stock/data/stock_data.xml
+++ b/addons/stock/data/stock_data.xml
@@ -143,20 +143,10 @@
</function>
<!-- create the transit location for each company existing -->
- <function model="res.company" name="create_missing_transit_location">
- <value model="res.company" eval="obj()"/>
- </function>
- <function model="res.company" name="create_missing_warehouse">
- <value model="res.company" eval="obj()"/>
- </function>
- <function model="res.company" name="create_missing_inventory_loss_location">
- <value model="res.company" eval="obj()"/>
- </function>
- <function model="res.company" name="create_missing_production_location">
- <value model="res.company" eval="obj()"/>
- </function>
- <function model="res.company" name="create_missing_scrap_location">
- <value model="res.company" eval="obj()"/>
- </function>
+ <function model="res.company" name="create_missing_transit_location"/>
+ <function model="res.company" name="create_missing_warehouse"/>
+ <function model="res.company" name="create_missing_inventory_loss_location"/>
+ <function model="res.company" name="create_missing_production_location"/>
+ <function model="res.company" name="create_missing_scrap_location"/>
</data>
</odoo>
diff --git a/odoo/addons/test_convert/__init__.py b/odoo/addons/test_convert/__init__.py
index a301ab24b52..dc5e6b693d1 100644
--- a/odoo/addons/test_convert/__init__.py
+++ b/odoo/addons/test_convert/__init__.py
@@ -1,10 +1,4 @@
-from odoo import fields, models
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
-
-class Usered(models.Model):
- _name = 'test_convert.usered'
- _description = "z test model ignore"
-
- name = fields.Char()
- user_id = fields.Many2one('res.users', default=lambda self: self.env.user)
- tz = fields.Char(default=lambda self: self.env.context.get('tz') or self.env.user.tz)
+from . import models
diff --git a/odoo/addons/test_convert/models.py b/odoo/addons/test_convert/models.py
new file mode 100644
index 00000000000..e48ac2d1e7f
--- /dev/null
+++ b/odoo/addons/test_convert/models.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, fields, api
+
+
+class Usered(models.Model):
+ _name = 'test_convert.usered'
+ _description = "z test model ignore"
+
+ name = fields.Char()
+ user_id = fields.Many2one('res.users', default=lambda self: self.env.user)
+ tz = fields.Char(default=lambda self: self.env.context.get('tz') or self.env.user.tz)
+
+ @api.model
+ def model_method(self, *args, **kwargs):
+ return self, args, kwargs
+
+ def method(self, *args, **kwargs):
+ return self, args, kwargs
diff --git a/odoo/addons/test_convert/tests/test_convert.py b/odoo/addons/test_convert/tests/test_convert.py
index e81526dd43c..709a5eeab10 100644
--- a/odoo/addons/test_convert/tests/test_convert.py
+++ b/odoo/addons/test_convert/tests/test_convert.py
@@ -7,7 +7,7 @@ import unittest
from lxml.builder import E
from odoo.tests import common
-from odoo.tools.convert import _eval_xml
+from odoo.tools.convert import xml_import, _eval_xml
Field = E.field
Value = E.value
@@ -74,6 +74,118 @@ class TestEvalXML(common.TransactionCase):
with self.assertRaises(IOError):
self.eval_xml(Field('test_nofile.txt', type='file'), obj)
+ def test_function(self):
+ obj = xml_import(self.cr, 'test_convert', None, 'init')
+
+ # pass args in eval
+ xml = E.function(
+ model="test_convert.usered",
+ name="model_method",
+ eval="[1, 2]",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, self.env.context)
+ self.assertEqual(rec.ids, [])
+ self.assertEqual(args, (1, 2))
+ self.assertEqual(kwargs, {})
+
+ xml = E.function(
+ model="test_convert.usered",
+ name="method",
+ eval="[1, 2]",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, self.env.context)
+ self.assertEqual(rec.ids, [1])
+ self.assertEqual(args, (2,))
+ self.assertEqual(kwargs, {})
+
+ # pass args in child elements
+ xml = E.function(
+ E.value(eval="1"), E.value(eval="2"),
+ model="test_convert.usered",
+ name="model_method",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, self.env.context)
+ self.assertEqual(rec.ids, [])
+ self.assertEqual(args, (1, 2))
+ self.assertEqual(kwargs, {})
+
+ xml = E.function(
+ E.value(eval="1"), E.value(eval="2"),
+ model="test_convert.usered",
+ name="method",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, self.env.context)
+ self.assertEqual(rec.ids, [1])
+ self.assertEqual(args, (2,))
+ self.assertEqual(kwargs, {})
+
+ def test_function_kwargs(self):
+ obj = xml_import(self.cr, 'test_convert', None, 'init')
+
+ # pass args and kwargs in child elements
+ xml = E.function(
+ E.value(eval="1"), E.value(name="foo", eval="2"),
+ model="test_convert.usered",
+ name="model_method",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, self.env.context)
+ self.assertEqual(rec.ids, [])
+ self.assertEqual(args, (1,))
+ self.assertEqual(kwargs, {'foo': 2})
+
+ xml = E.function(
+ E.value(eval="1"), E.value(name="foo", eval="2"),
+ model="test_convert.usered",
+ name="method",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, self.env.context)
+ self.assertEqual(rec.ids, [1])
+ self.assertEqual(args, ())
+ self.assertEqual(kwargs, {'foo': 2})
+
+ # pass args and context in kwargs
+ xml = E.function(
+ E.value(eval="1"), E.value(name="context", eval="{'foo': 2}"),
+ model="test_convert.usered",
+ name="model_method",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, {'foo': 2})
+ self.assertEqual(rec.ids, [])
+ self.assertEqual(args, (1,))
+ self.assertEqual(kwargs, {})
+
+ xml = E.function(
+ E.value(eval="1"), E.value(name="context", eval="{'foo': 2}"),
+ model="test_convert.usered",
+ name="method",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, {'foo': 2})
+ self.assertEqual(rec.ids, [1])
+ self.assertEqual(args, ())
+ self.assertEqual(kwargs, {})
+
+ def test_function_function(self):
+ obj = xml_import(self.cr, 'test_convert', None, 'init')
+
+ xml = E.function(
+ E.function(model="test_convert.usered", name="search", eval="[[]]"),
+ model="test_convert.usered",
+ name="method",
+ )
+ rec, args, kwargs = self.eval_xml(xml, obj)
+ self.assertEqual(rec.env.context, {})
+ self.assertEqual(rec.ids, [])
+ self.assertEqual(args, ())
+ self.assertEqual(kwargs, {})
+
@unittest.skip("not tested")
def test_xml(self):
pass
diff --git a/odoo/import_xml.rng b/odoo/import_xml.rng
index 953cac69e42..83324f379a9 100644
--- a/odoo/import_xml.rng
+++ b/odoo/import_xml.rng
@@ -23,6 +23,7 @@
<rng:define name="value">
<rng:element name="value">
+ <rng:optional><rng:attribute name="name" /></rng:optional>
<rng:optional><rng:attribute name="model" /></rng:optional>
<rng:choice>
<rng:attribute name="search" />
diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py
index e677560979e..7a3ff444cce 100644
--- a/odoo/tools/convert.py
+++ b/odoo/tools/convert.py
@@ -177,32 +177,24 @@ def _eval_xml(self, node, env):
return tuple(res)
return res
elif node.tag == "function":
+ model = env[node.get('model')]
+ method_name = node.get('name')
+ # determine arguments
+ args = []
+ kwargs = {}
a_eval = node.get('eval')
if a_eval:
self.idref['ref'] = self.id_get
- # ensure the args are a list (sometimes folks eval a tuple which
- # is inconvenient when trying to concatenate w/ a list)
args = list(safe_eval(a_eval, self.idref))
- else:
- args = [
- r for r in (_eval_xml(self, n, env) for n in node)
- if r is not None
- ]
-
- model = env[node.get('model')]
- method_name = node.get('name')
- method = getattr(model, method_name)
-
- # this mess is necessary to merge @context and a possible positional
- # context parameter, as <function> works on the old API so ids and
- # context are just args
- ids, args = [], list(args)
- if getattr(method, '_api', None) not in ('model', 'model_create'):
- ids, args = args[:1], args[1:]
- context, args, kwargs = api.split_context(method, args, {})
- kwargs['context'] = {**env.context, **(context or {})}
-
- return odoo.api.call_kw(model, method_name, ids + args, kwargs)
+ for child in node:
+ if child.tag == 'value' and child.get('name'):
+ kwargs[child.get('name')] = _eval_xml(self, child, env)
+ else:
+ args.append(_eval_xml(self, child, env))
+ # merge current context with context in kwargs
+ kwargs['context'] = {**env.context, **kwargs.get('context', {})}
+ # invoke method
+ return odoo.api.call_kw(model, method_name, args, kwargs)
elif node.tag == "test":
return node.text