From bbbfca2d97290abf8b77173c7d2c9c935d00ce14 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Tue, 15 Oct 2019 11:37:03 +0000 Subject: [PATCH] [FIX] web, tools: static inheritance supports replace in debug mode Have a parent template Have a child, in extension inherit mode of the parent The child has a xpath like `` Before this commit, there was a crash. That was because the Comment (which indicates which templates modified the parent) was taken as the replacer node instead of the actual content of the xpath After this commit, there is no crash, and it works as expected closes odoo/odoo#39453 X-original-commit: 02d790e1d21b78395e489f57bf30c82f728cbee6 Signed-off-by: Lucas Perais (lpe) --- addons/web/tests/test_serving_base.py | 267 ++++++++++++++++++++++++++ odoo/tools/template_inheritance.py | 15 +- 2 files changed, 281 insertions(+), 1 deletion(-) diff --git a/addons/web/tests/test_serving_base.py b/addons/web/tests/test_serving_base.py index a91834f03e0..31be8bfa89e 100644 --- a/addons/web/tests/test_serving_base.py +++ b/addons/web/tests/test_serving_base.py @@ -450,3 +450,270 @@ class TestStaticInheritance(BaseCase): after = datetime.now() self.assertLessEqual(after - before, timedelta(milliseconds=1000)) + + def test_replace_in_debug_mode(self): + """ + Replacing a template's meta definition in place doesn't keep the original attrs of the template + """ + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
And I grew strong
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+ And I grew strong +
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_in_debug_mode2(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+ And so you're back +
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+ And I grew strong +

And I learned how to get along

+ And so you're back +
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_in_debug_mode3(self): + """Text outside of a div which will replace a whole template + becomes outside of the template + This doesn't mean anything in terms of the business of template inheritance + But it is in the XPATH specs""" + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+
+ And so you're back +
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+ + And I grew strong +

And I learned how to get along

+
+ And so you're back +
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_root_node_tag(self): + """ + Root node is not targeted by //NODE_TAG in xpath + """ + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+ Inner Form
+ + + +
+ Form replacer +
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+ +
Form replacer
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_root_node_tag_in_primary(self): + """ + Root node is not targeted by //NODE_TAG in xpath + """ + self.maxDiff = None + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+ Inner Form
+ + + +
Form replacer
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+ Inner Form
+ +
+
At first I was afraid
+
Form replacer
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_inherit_primary_replace_debug(self): + """ + The inheriting template has got both its own defining attrs + and new ones if one is to replace its defining root node + """ + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
+
+ And I grew strong +

And I learned how to get along

+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_in_nodebug_mode1(self): + """Comments already in the arch are ignored""" + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ + And I grew strong +

And I learned how to get along

+ And so you're back +
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=False) + expected = b""" + +
+ And I grew strong +

And I learned how to get along

+ And so you're back +
+
+ """ + + self.assertXMLEqual(contents, expected) diff --git a/odoo/tools/template_inheritance.py b/odoo/tools/template_inheritance.py index 7f84f97d225..e025cd32712 100644 --- a/odoo/tools/template_inheritance.py +++ b/odoo/tools/template_inheritance.py @@ -129,7 +129,20 @@ def apply_inheritance_specs(source, specs_tree, inherit_branding=False, pre_loca loc.text = '' loc.append(copy.deepcopy(node)) if node.getparent() is None: - source = copy.deepcopy(spec[0]) + spec_content = None + comment = None + for content in spec: + if content.tag is not etree.Comment: + spec_content = content + break + else: + comment = content + source = copy.deepcopy(spec_content) + if comment is not None: + text = source.text + source.text = None + comment.tail = text + source.insert(0, comment) else: replaced_node_tag = None for child in spec: