fix for Python 3.7
							parent
							
								
									357c96c057
								
							
						
					
					
						commit
						7267c6aee6
					
				|  | @ -195,9 +195,11 @@ class AssetsBundle(object): | ||||||
|     def clean_attachments(self, type): |     def clean_attachments(self, type): | ||||||
|         """ Takes care of deleting any outdated ir.attachment records associated to a bundle before |         """ Takes care of deleting any outdated ir.attachment records associated to a bundle before | ||||||
|         saving a fresh one. |         saving a fresh one. | ||||||
|  | 
 | ||||||
|         When `type` is css we need to check that we are deleting a different version (and not *any* |         When `type` is css we need to check that we are deleting a different version (and not *any* | ||||||
|         version) because css may be paginated and, therefore, may produce multiple attachments for |         version) because css may be paginated and, therefore, may produce multiple attachments for | ||||||
|         the same bundle's version. |         the same bundle's version. | ||||||
|  | 
 | ||||||
|         When `type` is js we need to check that we are deleting a different version (and not *any* |         When `type` is js we need to check that we are deleting a different version (and not *any* | ||||||
|         version) because, as one of the creates in `save_attachment` can trigger a rollback, the |         version) because, as one of the creates in `save_attachment` can trigger a rollback, the | ||||||
|         call to `clean_attachments ` is made at the end of the method in order to avoid the rollback |         call to `clean_attachments ` is made at the end of the method in order to avoid the rollback | ||||||
|  | @ -313,16 +315,22 @@ class AssetsBundle(object): | ||||||
|             (function (message) { |             (function (message) { | ||||||
|                 if (window.__assetsBundleErrorSeen) return; |                 if (window.__assetsBundleErrorSeen) return; | ||||||
|                 window.__assetsBundleErrorSeen = true; |                 window.__assetsBundleErrorSeen = true; | ||||||
|  | 
 | ||||||
|                 document.addEventListener("DOMContentLoaded", function () { |                 document.addEventListener("DOMContentLoaded", function () { | ||||||
|                     var alertTimeout = setTimeout(alert.bind(window, message), 0); |                     var alertTimeout = setTimeout(alert.bind(window, message), 0); | ||||||
|                     if (typeof odoo === "undefined") return; |                     if (typeof odoo === "undefined") return; | ||||||
|  | 
 | ||||||
|                     odoo.define("AssetsBundle.ErrorMessage", function (require) { |                     odoo.define("AssetsBundle.ErrorMessage", function (require) { | ||||||
|                         "use strict"; |                         "use strict"; | ||||||
|  | 
 | ||||||
|                         var base = require("web_editor.base"); |                         var base = require("web_editor.base"); | ||||||
|                         var core = require("web.core"); |                         var core = require("web.core"); | ||||||
|                         var Dialog = require("web.Dialog"); |                         var Dialog = require("web.Dialog"); | ||||||
|  | 
 | ||||||
|                         var _t = core._t; |                         var _t = core._t; | ||||||
|  | 
 | ||||||
|                         clearTimeout(alertTimeout); |                         clearTimeout(alertTimeout); | ||||||
|  | 
 | ||||||
|                         base.ready().then(function () { |                         base.ready().then(function () { | ||||||
|                             new Dialog(null, { |                             new Dialog(null, { | ||||||
|                                 title: _t("Style error"), |                                 title: _t("Style error"), | ||||||
|  | @ -722,4 +730,4 @@ class LessStylesheetAsset(PreprocessedCSS): | ||||||
|         except IOError: |         except IOError: | ||||||
|             lessc = 'lessc' |             lessc = 'lessc' | ||||||
|         lesspath = get_resource_path('web', 'static', 'lib', 'bootstrap', 'less') |         lesspath = get_resource_path('web', 'static', 'lib', 'bootstrap', 'less') | ||||||
|         return [lessc, '-', '--no-js', '--no-color', '--include-path=%s' % lesspath] |         return [lessc, '-', '--no-js', '--no-color', '--include-path=%s' % lesspath] | ||||||
|  |  | ||||||
|  | @ -6,6 +6,8 @@ from io import BytesIO | ||||||
| from odoo import api, fields, models, _ | from odoo import api, fields, models, _ | ||||||
| from PIL import Image | from PIL import Image | ||||||
| import babel | import babel | ||||||
|  | from lxml import etree | ||||||
|  | 
 | ||||||
| from odoo.tools import html_escape as escape, posix_to_ldml, safe_eval, float_utils, format_date, pycompat | from odoo.tools import html_escape as escape, posix_to_ldml, safe_eval, float_utils, format_date, pycompat | ||||||
| 
 | 
 | ||||||
| import logging | import logging | ||||||
|  | @ -252,7 +254,17 @@ class HTMLConverter(models.AbstractModel): | ||||||
| 
 | 
 | ||||||
|     @api.model |     @api.model | ||||||
|     def value_to_html(self, value, options): |     def value_to_html(self, value, options): | ||||||
|         return pycompat.to_text(value) |         irQweb = self.env['ir.qweb'] | ||||||
|  |         # wrap value inside a body and parse it as HTML | ||||||
|  |         body = etree.fromstring("<body>%s</body>" % value, etree.HTMLParser(encoding='utf-8'))[0] | ||||||
|  |         # use pos processing for all nodes with attributes | ||||||
|  |         for element in body.iter(): | ||||||
|  |             if element.attrib: | ||||||
|  |                 attrib = OrderedDict(element.attrib) | ||||||
|  |                 attrib = irQweb._post_processing_att(element.tag, attrib, options.get('template_options')) | ||||||
|  |                 element.attrib.clear() | ||||||
|  |                 element.attrib.update(attrib) | ||||||
|  |         return etree.tostring(body, encoding='unicode', method='html')[6:-7] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ImageConverter(models.AbstractModel): | class ImageConverter(models.AbstractModel): | ||||||
|  | @ -476,7 +488,7 @@ class Contact(models.AbstractModel): | ||||||
|             'object': value, |             'object': value, | ||||||
|             'options': options |             'options': options | ||||||
|         } |         } | ||||||
|         return self.env['ir.qweb'].render('base.contact', val) |         return self.env['ir.qweb'].render('base.contact', val, **options.get('template_options')) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class QwebView(models.AbstractModel): | class QwebView(models.AbstractModel): | ||||||
|  |  | ||||||
|  | @ -37,7 +37,9 @@ class IrQWeb(models.AbstractModel, QWeb): | ||||||
|     @api.model |     @api.model | ||||||
|     def render(self, id_or_xml_id, values=None, **options): |     def render(self, id_or_xml_id, values=None, **options): | ||||||
|         """ render(id_or_xml_id, values, **options) |         """ render(id_or_xml_id, values, **options) | ||||||
|  | 
 | ||||||
|         Render the template specified by the given name. |         Render the template specified by the given name. | ||||||
|  | 
 | ||||||
|         :param id_or_xml_id: name or etree (see get_template) |         :param id_or_xml_id: name or etree (see get_template) | ||||||
|         :param dict values: template values to be used for rendering |         :param dict values: template values to be used for rendering | ||||||
|         :param options: used to compile the template (the dict available for the rendering is frozen) |         :param options: used to compile the template (the dict available for the rendering is frozen) | ||||||
|  | @ -426,4 +428,4 @@ class IrQWeb(models.AbstractModel, QWeb): | ||||||
|                 return ast.Name(id='False', ctx=ast.Load()) |                 return ast.Name(id='False', ctx=ast.Load()) | ||||||
|             elif attr in ('true', '1'): |             elif attr in ('true', '1'): | ||||||
|                 return ast.Name(id='True', ctx=ast.Load()) |                 return ast.Name(id='True', ctx=ast.Load()) | ||||||
|         return ast.Name(id=str(attr if attr is False else default), ctx=ast.Load()) |         return ast.Name(id=str(attr if attr is False else default), ctx=ast.Load()) | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ import os.path | ||||||
| import re | import re | ||||||
| import traceback | import traceback | ||||||
| 
 | 
 | ||||||
| from collections import OrderedDict, Sized, Mapping, defaultdict | from collections import OrderedDict, Sized, Mapping | ||||||
| from functools import reduce | from functools import reduce | ||||||
| from itertools import tee, count | from itertools import tee, count | ||||||
| from textwrap import dedent | from textwrap import dedent | ||||||
|  | @ -308,8 +308,9 @@ class QWeb(object): | ||||||
|             raise e |             raise e | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|             path = _options['last_path_node'] |             path = _options['last_path_node'] | ||||||
|             node = element.getroottree().xpath(path) |             element, document = self.get_template(template, options) | ||||||
|             raise QWebException("Error when compiling AST", e, path, etree.tostring(node[0], encoding='unicode'), name) |             node = element.getroottree().xpath(path) if ':' not in path else None | ||||||
|  |             raise QWebException("Error when compiling AST", e, path, node and etree.tostring(node[0], encoding='unicode'), name) | ||||||
|         astmod.body.extend(_options['ast_calls']) |         astmod.body.extend(_options['ast_calls']) | ||||||
| 
 | 
 | ||||||
|         if 'profile' in options: |         if 'profile' in options: | ||||||
|  | @ -344,7 +345,7 @@ class QWeb(object): | ||||||
|             except Exception as e: |             except Exception as e: | ||||||
|                 path = log['last_path_node'] |                 path = log['last_path_node'] | ||||||
|                 element, document = self.get_template(template, options) |                 element, document = self.get_template(template, options) | ||||||
|                 node = element.getroottree().xpath(path) |                 node = element.getroottree().xpath(path) if ':' not in path else None | ||||||
|                 raise QWebException("Error to render compiling AST", e, path, node and etree.tostring(node[0], encoding='unicode'), name) |                 raise QWebException("Error to render compiling AST", e, path, node and etree.tostring(node[0], encoding='unicode'), name) | ||||||
| 
 | 
 | ||||||
|         return _compiled_fn |         return _compiled_fn | ||||||
|  | @ -694,6 +695,80 @@ class QWeb(object): | ||||||
|             ctx=ctx |             ctx=ctx | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  |     def _append_attributes(self): | ||||||
|  |         # t_attrs = self._post_processing_att(tagName, t_attrs, options) | ||||||
|  |         # for name, value in t_attrs.items(): | ||||||
|  |         #     if value or isinstance(value, string_types)): | ||||||
|  |         #         append(u' ') | ||||||
|  |         #         append(name) | ||||||
|  |         #         append(u'="') | ||||||
|  |         #         append(escape(pycompat.to_text((value))) | ||||||
|  |         #         append(u'"') | ||||||
|  |         return [ | ||||||
|  |             ast.Assign( | ||||||
|  |                 targets=[ast.Name(id='t_attrs', ctx=ast.Store())], | ||||||
|  |                 value=ast.Call( | ||||||
|  |                     func=ast.Attribute( | ||||||
|  |                         value=ast.Name(id='self', ctx=ast.Load()), | ||||||
|  |                         attr='_post_processing_att', | ||||||
|  |                         ctx=ast.Load() | ||||||
|  |                     ), | ||||||
|  |                     args=[ | ||||||
|  |                         ast.Name(id='tagName', ctx=ast.Load()), | ||||||
|  |                         ast.Name(id='t_attrs', ctx=ast.Load()), | ||||||
|  |                         ast.Name(id='options', ctx=ast.Load()), | ||||||
|  |                     ], keywords=[], | ||||||
|  |                     starargs=None, kwargs=None | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |             ast.For( | ||||||
|  |                 target=ast.Tuple(elts=[ast.Name(id='name', ctx=ast.Store()), ast.Name(id='value', ctx=ast.Store())], ctx=ast.Store()), | ||||||
|  |                 iter=ast.Call( | ||||||
|  |                     func=ast.Attribute( | ||||||
|  |                         value=ast.Name(id='t_attrs', ctx=ast.Load()), | ||||||
|  |                         attr='items', | ||||||
|  |                         ctx=ast.Load() | ||||||
|  |                         ), | ||||||
|  |                     args=[], keywords=[], | ||||||
|  |                     starargs=None, kwargs=None | ||||||
|  |                 ), | ||||||
|  |                 body=[ast.If( | ||||||
|  |                     test=ast.BoolOp( | ||||||
|  |                         op=ast.Or(), | ||||||
|  |                         values=[ | ||||||
|  |                             ast.Name(id='value', ctx=ast.Load()), | ||||||
|  |                             ast.Call( | ||||||
|  |                                 func=ast.Name(id='isinstance', ctx=ast.Load()), | ||||||
|  |                                 args=[ | ||||||
|  |                                     ast.Name(id='value', ctx=ast.Load()), | ||||||
|  |                                     ast.Name(id='string_types', ctx=ast.Load()) | ||||||
|  |                                 ], | ||||||
|  |                                 keywords=[], | ||||||
|  |                                 starargs=None, kwargs=None | ||||||
|  |                             ) | ||||||
|  |                         ] | ||||||
|  |                     ), | ||||||
|  |                     body=[ | ||||||
|  |                         self._append(ast.Str(u' ')), | ||||||
|  |                         self._append(ast.Name(id='name', ctx=ast.Load())), | ||||||
|  |                         self._append(ast.Str(u'="')), | ||||||
|  |                         self._append(ast.Call( | ||||||
|  |                             func=ast.Name(id='escape', ctx=ast.Load()), | ||||||
|  |                             args=[ast.Call( | ||||||
|  |                                 func=ast.Name(id='to_text', ctx=ast.Load()), | ||||||
|  |                                 args=[ast.Name(id='value', ctx=ast.Load())], keywords=[], | ||||||
|  |                                 starargs=None, kwargs=None | ||||||
|  |                             )], keywords=[], | ||||||
|  |                             starargs=None, kwargs=None | ||||||
|  |                         )), | ||||||
|  |                         self._append(ast.Str(u'"')), | ||||||
|  |                     ], | ||||||
|  |                     orelse=[] | ||||||
|  |                 )], | ||||||
|  |                 orelse=[] | ||||||
|  |             ) | ||||||
|  |         ] | ||||||
|  | 
 | ||||||
|     # order |     # order | ||||||
| 
 | 
 | ||||||
|     def _directives_eval_order(self): |     def _directives_eval_order(self): | ||||||
|  | @ -732,7 +807,7 @@ class QWeb(object): | ||||||
|         if not el.nsmap: |         if not el.nsmap: | ||||||
|             unqualified_el_tag = el_tag = el.tag |             unqualified_el_tag = el_tag = el.tag | ||||||
|             content = self._compile_directive_content(el, options) |             content = self._compile_directive_content(el, options) | ||||||
|             attrib = el.attrib |             attrib = self._post_processing_att(el.tag, el.attrib, options) | ||||||
|         else: |         else: | ||||||
|             # Etree will remove the ns prefixes indirection by inlining the corresponding |             # Etree will remove the ns prefixes indirection by inlining the corresponding | ||||||
|             # nsmap definition into the tag attribute. Restore the tag and prefix here. |             # nsmap definition into the tag attribute. Restore the tag and prefix here. | ||||||
|  | @ -762,6 +837,8 @@ class QWeb(object): | ||||||
|                 else: |                 else: | ||||||
|                     attrib[key] = value |                     attrib[key] = value | ||||||
| 
 | 
 | ||||||
|  |             attrib = self._post_processing_att(el.tag, attrib, options) | ||||||
|  | 
 | ||||||
|             # Update the dict of inherited namespaces before continuing the recursion. Note: |             # Update the dict of inherited namespaces before continuing the recursion. Note: | ||||||
|             # since `options['nsmap']` is a dict (and therefore mutable) and we do **not** |             # since `options['nsmap']` is a dict (and therefore mutable) and we do **not** | ||||||
|             # want changes done in deeper recursion to bevisible in earlier ones, we'll pass |             # want changes done in deeper recursion to bevisible in earlier ones, we'll pass | ||||||
|  | @ -870,59 +947,12 @@ class QWeb(object): | ||||||
|                     ))) |                     ))) | ||||||
| 
 | 
 | ||||||
|         if attr_already_created: |         if attr_already_created: | ||||||
|             # for name, value in t_attrs.items(): |             # tagName = $el.tag | ||||||
|             #     if value or isinstance(value, basestring)): |             body.append(ast.Assign( | ||||||
|             #         append(u' ') |                 targets=[ast.Name(id='tagName', ctx=ast.Store())], | ||||||
|             #         append(name) |                 value=ast.Str(el.tag)) | ||||||
|             #         append(u'="') |             ) | ||||||
|             #         append(escape(to_text((value))) |             body.extend(self._append_attributes()) | ||||||
|             #         append(u'"') |  | ||||||
|             body.append(ast.For( |  | ||||||
|                 target=ast.Tuple(elts=[ast.Name(id='name', ctx=ast.Store()), ast.Name(id='value', ctx=ast.Store())], ctx=ast.Store()), |  | ||||||
|                 iter=ast.Call( |  | ||||||
|                     func=ast.Attribute( |  | ||||||
|                         value=ast.Name(id='t_attrs', ctx=ast.Load()), |  | ||||||
|                         attr='items', |  | ||||||
|                         ctx=ast.Load() |  | ||||||
|                         ), |  | ||||||
|                     args=[], keywords=[], |  | ||||||
|                     starargs=None, kwargs=None |  | ||||||
|                 ), |  | ||||||
|                 body=[ast.If( |  | ||||||
|                     test=ast.BoolOp( |  | ||||||
|                         op=ast.Or(), |  | ||||||
|                         values=[ |  | ||||||
|                             ast.Name(id='value', ctx=ast.Load()), |  | ||||||
|                             ast.Call( |  | ||||||
|                                 func=ast.Name(id='isinstance', ctx=ast.Load()), |  | ||||||
|                                 args=[ |  | ||||||
|                                     ast.Name(id='value', ctx=ast.Load()), |  | ||||||
|                                     ast.Name(id='string_types', ctx=ast.Load()) |  | ||||||
|                                 ], |  | ||||||
|                                 keywords=[], |  | ||||||
|                                 starargs=None, kwargs=None |  | ||||||
|                             ) |  | ||||||
|                         ] |  | ||||||
|                     ), |  | ||||||
|                     body=[ |  | ||||||
|                         self._append(ast.Str(u' ')), |  | ||||||
|                         self._append(ast.Name(id='name', ctx=ast.Load())), |  | ||||||
|                         self._append(ast.Str(u'="')), |  | ||||||
|                         self._append(ast.Call( |  | ||||||
|                             func=ast.Name(id='escape', ctx=ast.Load()), |  | ||||||
|                             args=[ast.Call( |  | ||||||
|                                 func=ast.Name(id='to_text', ctx=ast.Load()), |  | ||||||
|                                 args=[ast.Name(id='value', ctx=ast.Load())], keywords=[], |  | ||||||
|                                 starargs=None, kwargs=None |  | ||||||
|                             )], keywords=[], |  | ||||||
|                             starargs=None, kwargs=None |  | ||||||
|                         )), |  | ||||||
|                         self._append(ast.Str(u'"')), |  | ||||||
|                     ], |  | ||||||
|                     orelse=[] |  | ||||||
|                 )], |  | ||||||
|                 orelse=[] |  | ||||||
|             )) |  | ||||||
| 
 | 
 | ||||||
|         return body |         return body | ||||||
| 
 | 
 | ||||||
|  | @ -1512,6 +1542,14 @@ class QWeb(object): | ||||||
|             atts = OrderedDict(atts) |             atts = OrderedDict(atts) | ||||||
|         return atts |         return atts | ||||||
| 
 | 
 | ||||||
|  |     def _post_processing_att(self, tagName, atts, options): | ||||||
|  |         """ Method called by the compiled code. This method may be overwrited | ||||||
|  |             to filter or modify the attributes after they are compiled. | ||||||
|  | 
 | ||||||
|  |             @returns OrderedDict | ||||||
|  |         """ | ||||||
|  |         return atts | ||||||
|  | 
 | ||||||
|     def _get_field(self, record, field_name, expression, tagName, field_options, options, values): |     def _get_field(self, record, field_name, expression, tagName, field_options, options, values): | ||||||
|         """ |         """ | ||||||
|         :returns: tuple: |         :returns: tuple: | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue