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"),
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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