Fix for Python V3.7
parent
ba7b0b26c9
commit
357c96c057
|
|
@ -9,9 +9,12 @@ import textwrap
|
|||
import uuid
|
||||
from datetime import datetime
|
||||
from subprocess import Popen, PIPE
|
||||
from collections import OrderedDict
|
||||
from odoo import fields, tools
|
||||
from odoo.tools.pycompat import string_types, to_text
|
||||
from odoo.http import request
|
||||
from odoo.modules.module import get_resource_path
|
||||
from odoo.addons.base.ir.ir_qweb.qweb import escape
|
||||
import psycopg2
|
||||
from odoo.tools import func, misc
|
||||
|
||||
|
|
@ -65,7 +68,6 @@ def rjsmin(script):
|
|||
).strip()
|
||||
return result
|
||||
|
||||
|
||||
class AssetError(Exception):
|
||||
pass
|
||||
|
||||
|
|
@ -79,17 +81,16 @@ class AssetsBundle(object):
|
|||
rx_preprocess_imports = re.compile("""(@import\s?['"]([^'"]+)['"](;?))""")
|
||||
rx_css_split = re.compile("\/\*\! ([a-f0-9-]+) \*\/")
|
||||
|
||||
def __init__(self, name, files, remains, env=None):
|
||||
# remains attribute is depreciated and will remove after v11
|
||||
def __init__(self, name, files, remains=None, env=None):
|
||||
self.name = name
|
||||
self.env = request.env if env is None else env
|
||||
self.max_css_rules = self.env.context.get('max_css_rules', MAX_CSS_RULES)
|
||||
self.javascripts = []
|
||||
self.stylesheets = []
|
||||
self.css_errors = []
|
||||
self.remains = []
|
||||
self._checksum = None
|
||||
self.files = files
|
||||
self.remains = remains
|
||||
for f in files:
|
||||
if f['atype'] == 'text/sass':
|
||||
self.stylesheets.append(SassStylesheetAsset(self, url=f['url'], filename=f['filename'], inline=f['content'], media=f['media']))
|
||||
|
|
@ -100,10 +101,37 @@ class AssetsBundle(object):
|
|||
elif f['atype'] == 'text/javascript':
|
||||
self.javascripts.append(JavascriptAsset(self, url=f['url'], filename=f['filename'], inline=f['content']))
|
||||
|
||||
def to_html(self, sep=None, css=True, js=True, debug=False, async=False, url_for=(lambda url: url)):
|
||||
# depreciated and will remove after v11
|
||||
def to_html(self, sep=None, css=True, js=True, debug=False, async_load=False, url_for=(lambda url: url), **kw):
|
||||
if 'async' in kw:
|
||||
_logger.warning("Using deprecated argument 'async' in to_html call, use 'async_load' instead.")
|
||||
async_load = kw['async']
|
||||
nodes = self.to_node(css=css, js=js, debug=debug, async_load=async_load)
|
||||
|
||||
if sep is None:
|
||||
sep = u'\n '
|
||||
response = []
|
||||
for tagName, attributes, content in nodes:
|
||||
html = u"<%s " % tagName
|
||||
for name, value in attributes.items():
|
||||
if value or isinstance(value, string_types):
|
||||
html += u' %s="%s"' % (name, escape(to_text(value)))
|
||||
if content is None:
|
||||
html += u'/>'
|
||||
else:
|
||||
html += u'>%s</%s>' % (escape(to_text(content)), tagName)
|
||||
response.append(html)
|
||||
|
||||
return sep + sep.join(response)
|
||||
|
||||
def to_node(self, css=True, js=True, debug=False, async_load=False, **kw):
|
||||
"""
|
||||
:returns [(tagName, attributes, content)] if the tag is auto close
|
||||
"""
|
||||
if 'async' in kw:
|
||||
_logger.warning("Using deprecated argument 'async' in to_node call, use 'async_load' instead.")
|
||||
async_load = kw['async']
|
||||
response = []
|
||||
if debug == 'assets':
|
||||
if css and self.stylesheets:
|
||||
is_css_preprocessed, old_attachments = self.is_css_preprocessed()
|
||||
|
|
@ -111,28 +139,37 @@ class AssetsBundle(object):
|
|||
self.preprocess_css(debug=debug, old_attachments=old_attachments)
|
||||
if self.css_errors:
|
||||
msg = '\n'.join(self.css_errors)
|
||||
response.append(JavascriptAsset(self, inline=self.dialog_message(msg)).to_html())
|
||||
response.append(StylesheetAsset(self, url="/web/static/lib/bootstrap/css/bootstrap.css").to_html())
|
||||
response.append(JavascriptAsset(self, inline=self.dialog_message(msg)).to_node())
|
||||
response.append(StylesheetAsset(self, url="/web/static/lib/bootstrap/css/bootstrap.css").to_node())
|
||||
if not self.css_errors:
|
||||
for style in self.stylesheets:
|
||||
response.append(style.to_html())
|
||||
response.append(style.to_node())
|
||||
|
||||
if js:
|
||||
for jscript in self.javascripts:
|
||||
response.append(jscript.to_html())
|
||||
response.append(jscript.to_node())
|
||||
else:
|
||||
if css and self.stylesheets:
|
||||
css_attachments = self.css() or []
|
||||
for attachment in css_attachments:
|
||||
response.append(u'<link href="%s" rel="stylesheet"/>' % url_for(attachment.url))
|
||||
attr = OrderedDict([
|
||||
["type", "text/css"],
|
||||
["rel", "stylesheet"],
|
||||
["href", attachment.url],
|
||||
])
|
||||
response.append(("link", attr, None))
|
||||
if self.css_errors:
|
||||
msg = '\n'.join(self.css_errors)
|
||||
response.append(JavascriptAsset(self, inline=self.dialog_message(msg)).to_html())
|
||||
response.append(JavascriptAsset(self, inline=self.dialog_message(msg)).to_node())
|
||||
if js and self.javascripts:
|
||||
response.append(u'<script %s type="text/javascript" src="%s"></script>' % (async and u'async="async"' or '', url_for(self.js().url)))
|
||||
response.extend(self.remains)
|
||||
attr = OrderedDict([
|
||||
["async", "async" if async_load else None],
|
||||
["type", "text/javascript"],
|
||||
["src", self.js().url],
|
||||
])
|
||||
response.append(("script", attr, None))
|
||||
|
||||
return sep + sep.join(response)
|
||||
return response
|
||||
|
||||
@func.lazy_property
|
||||
def last_modified(self):
|
||||
|
|
@ -152,17 +189,15 @@ class AssetsBundle(object):
|
|||
Not really a full checksum.
|
||||
We compute a SHA1 on the rendered bundle + max linked files last_modified date
|
||||
"""
|
||||
check = u"%s%s%s" % (json.dumps(self.files, sort_keys=True), u",".join(self.remains), self.last_modified)
|
||||
check = u"%s%s" % (json.dumps(self.files, sort_keys=True), self.last_modified)
|
||||
return hashlib.sha1(check.encode('utf-8')).hexdigest()
|
||||
|
||||
def clean_attachments(self, type):
|
||||
""" Takes care of deleting any outdated ir.attachment records associated to a bundle before
|
||||
saving a fresh one.
|
||||
|
||||
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
|
||||
the same bundle's version.
|
||||
|
||||
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
|
||||
call to `clean_attachments ` is made at the end of the method in order to avoid the rollback
|
||||
|
|
@ -278,22 +313,16 @@ class AssetsBundle(object):
|
|||
(function (message) {
|
||||
if (window.__assetsBundleErrorSeen) return;
|
||||
window.__assetsBundleErrorSeen = true;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
var alertTimeout = setTimeout(alert.bind(window, message), 0);
|
||||
if (typeof odoo === "undefined") return;
|
||||
|
||||
odoo.define("AssetsBundle.ErrorMessage", function (require) {
|
||||
"use strict";
|
||||
|
||||
var base = require("web_editor.base");
|
||||
var core = require("web.core");
|
||||
var Dialog = require("web.Dialog");
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
clearTimeout(alertTimeout);
|
||||
|
||||
base.ready().then(function () {
|
||||
new Dialog(null, {
|
||||
title: _t("Style error"),
|
||||
|
|
@ -314,7 +343,7 @@ class AssetsBundle(object):
|
|||
outdated = False
|
||||
assets = dict((asset.html_url, asset) for asset in self.stylesheets if isinstance(asset, atype))
|
||||
if assets:
|
||||
assets_domain = [('url', 'in', list(assets))]
|
||||
assets_domain = [('url', 'in', list(assets.keys()))]
|
||||
attachments = self.env['ir.attachment'].sudo().search(assets_domain)
|
||||
for attachment in attachments:
|
||||
asset = assets[attachment.url]
|
||||
|
|
@ -474,7 +503,20 @@ class WebAsset(object):
|
|||
except Exception:
|
||||
raise AssetNotFound("Could not find %s" % self.name)
|
||||
|
||||
# depreciated and will remove after v11
|
||||
def to_html(self):
|
||||
tagName, attributes, content = self.to_node()
|
||||
html = u"<%s " % tagName
|
||||
for name, value in attributes.items():
|
||||
if value or isinstance(value, string_types):
|
||||
html += u' %s="%s"' % (name, escape(to_text(value)))
|
||||
if content is None:
|
||||
html += u'/>'
|
||||
else:
|
||||
html += u'>%s</%s>' % (escape(to_text(content)), tagName)
|
||||
return html
|
||||
|
||||
def to_node(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@func.lazy_property
|
||||
|
|
@ -533,13 +575,19 @@ class JavascriptAsset(WebAsset):
|
|||
try:
|
||||
return super(JavascriptAsset, self)._fetch_content()
|
||||
except AssetError as e:
|
||||
return "console.error(%s);" % json.dumps(str(e))
|
||||
return u"console.error(%s);" % json.dumps(to_text(e))
|
||||
|
||||
def to_html(self):
|
||||
def to_node(self):
|
||||
if self.url:
|
||||
return '<script type="text/javascript" src="%s"></script>' % (self.html_url)
|
||||
return ("script", OrderedDict([
|
||||
["type", "text/javascript"],
|
||||
["src", self.html_url],
|
||||
]), None)
|
||||
else:
|
||||
return '<script type="text/javascript" charset="utf-8">%s</script>' % self.with_header()
|
||||
return ("script", OrderedDict([
|
||||
["type", "text/javascript"],
|
||||
["charset", "utf-8"],
|
||||
]), self.with_header())
|
||||
|
||||
|
||||
class StylesheetAsset(WebAsset):
|
||||
|
|
@ -595,13 +643,21 @@ class StylesheetAsset(WebAsset):
|
|||
content = re.sub(r' *([{}]) *', r'\1', content)
|
||||
return self.with_header(content)
|
||||
|
||||
def to_html(self):
|
||||
media = (' media="%s"' % misc.html_escape(self.media)) if self.media else ''
|
||||
def to_node(self):
|
||||
if self.url:
|
||||
href = self.html_url
|
||||
return '<link rel="stylesheet" href="%s" type="text/css"%s/>' % (href, media)
|
||||
attr = OrderedDict([
|
||||
["type", "text/css"],
|
||||
["rel", "stylesheet"],
|
||||
["href", self.html_url],
|
||||
["media", escape(to_text(self.media)) if self.media else None]
|
||||
])
|
||||
return ("link", attr, None)
|
||||
else:
|
||||
return '<style type="text/css"%s>%s</style>' % (media, self.with_header())
|
||||
attr = OrderedDict([
|
||||
["type", "text/css"],
|
||||
["media", escape(to_text(self.media)) if self.media else None]
|
||||
])
|
||||
return ("style", attr, self.with_header())
|
||||
|
||||
|
||||
class PreprocessedCSS(StylesheetAsset):
|
||||
|
|
@ -666,4 +722,4 @@ class LessStylesheetAsset(PreprocessedCSS):
|
|||
except IOError:
|
||||
lessc = 'lessc'
|
||||
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]
|
||||
|
|
@ -37,9 +37,7 @@ class IrQWeb(models.AbstractModel, QWeb):
|
|||
@api.model
|
||||
def render(self, id_or_xml_id, values=None, **options):
|
||||
""" render(id_or_xml_id, values, **options)
|
||||
|
||||
Render the template specified by the given name.
|
||||
|
||||
:param id_or_xml_id: name or etree (see get_template)
|
||||
: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)
|
||||
|
|
@ -125,35 +123,122 @@ class IrQWeb(models.AbstractModel, QWeb):
|
|||
if len(el):
|
||||
raise SyntaxError("t-call-assets cannot contain children nodes")
|
||||
|
||||
# self._get_asset(xmlid, options, css=css, js=js, debug=values.get('debug'), async=async, values=values)
|
||||
# nodes = self._get_asset(xmlid, options, css=css, js=js, debug=values.get('debug'), async=async, values=values)
|
||||
#
|
||||
# for index, (tagName, t_attrs, content) in enumerate(nodes):
|
||||
# if index:
|
||||
# append('\n ')
|
||||
# append('<')
|
||||
# append(tagName)
|
||||
#
|
||||
# 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'"')
|
||||
#
|
||||
# if not content and tagName in self._void_elements:
|
||||
# append('/>')
|
||||
# else:
|
||||
# append('>')
|
||||
# if content:
|
||||
# append(content)
|
||||
# append('</')
|
||||
# append(tagName)
|
||||
# append('>')
|
||||
#
|
||||
space = el.getprevious() is not None and el.getprevious().tail or el.getparent().text
|
||||
sep = u'\n' + space.rsplit('\n').pop()
|
||||
return [
|
||||
self._append(ast.Call(
|
||||
func=ast.Attribute(
|
||||
value=ast.Name(id='self', ctx=ast.Load()),
|
||||
attr='_get_asset',
|
||||
ctx=ast.Load()
|
||||
ast.Assign(
|
||||
targets=[ast.Name(id='nodes', ctx=ast.Store())],
|
||||
value=ast.Call(
|
||||
func=ast.Attribute(
|
||||
value=ast.Name(id='self', ctx=ast.Load()),
|
||||
attr='_get_asset_nodes',
|
||||
ctx=ast.Load()
|
||||
),
|
||||
args=[
|
||||
ast.Str(el.get('t-call-assets')),
|
||||
ast.Name(id='options', ctx=ast.Load()),
|
||||
],
|
||||
keywords=[
|
||||
ast.keyword('css', self._get_attr_bool(el.get('t-css', True))),
|
||||
ast.keyword('js', self._get_attr_bool(el.get('t-js', True))),
|
||||
ast.keyword('debug', ast.Call(
|
||||
func=ast.Attribute(
|
||||
value=ast.Name(id='values', ctx=ast.Load()),
|
||||
attr='get',
|
||||
ctx=ast.Load()
|
||||
),
|
||||
args=[ast.Str('debug')],
|
||||
keywords=[], starargs=None, kwargs=None
|
||||
)),
|
||||
ast.keyword('async', self._get_attr_bool(el.get('async', False))),
|
||||
ast.keyword('values', ast.Name(id='values', ctx=ast.Load())),
|
||||
],
|
||||
starargs=None, kwargs=None
|
||||
)
|
||||
),
|
||||
ast.For(
|
||||
target=ast.Tuple(elts=[
|
||||
ast.Name(id='index', ctx=ast.Store()),
|
||||
ast.Tuple(elts=[
|
||||
ast.Name(id='tagName', ctx=ast.Store()),
|
||||
ast.Name(id='t_attrs', ctx=ast.Store()),
|
||||
ast.Name(id='content', ctx=ast.Store())
|
||||
], ctx=ast.Store())
|
||||
], ctx=ast.Store()),
|
||||
iter=ast.Call(
|
||||
func=ast.Name(id='enumerate', ctx=ast.Load()),
|
||||
args=[ast.Name(id='nodes', ctx=ast.Load())],
|
||||
keywords=[],
|
||||
starargs=None, kwargs=None
|
||||
),
|
||||
args=[
|
||||
ast.Str(el.get('t-call-assets')),
|
||||
ast.Name(id='options', ctx=ast.Load()),
|
||||
],
|
||||
keywords=[
|
||||
ast.keyword('css', self._get_attr_bool(el.get('t-css', True))),
|
||||
ast.keyword('js', self._get_attr_bool(el.get('t-js', True))),
|
||||
ast.keyword('debug', ast.Call(
|
||||
func=ast.Attribute(
|
||||
value=ast.Name(id='values', ctx=ast.Load()),
|
||||
attr='get',
|
||||
ctx=ast.Load()
|
||||
body=[
|
||||
ast.If(
|
||||
test=ast.Name(id='index', ctx=ast.Load()),
|
||||
body=[self._append(ast.Str(sep))],
|
||||
orelse=[]
|
||||
),
|
||||
self._append(ast.Str(u'<')),
|
||||
self._append(ast.Name(id='tagName', ctx=ast.Load())),
|
||||
] + self._append_attributes() + [
|
||||
ast.If(
|
||||
test=ast.BoolOp(
|
||||
op=ast.And(),
|
||||
values=[
|
||||
ast.UnaryOp(ast.Not(), ast.Name(id='content', ctx=ast.Load()), lineno=0, col_offset=0),
|
||||
ast.Compare(
|
||||
left=ast.Name(id='tagName', ctx=ast.Load()),
|
||||
ops=[ast.In()],
|
||||
comparators=[ast.Attribute(
|
||||
value=ast.Name(id='self', ctx=ast.Load()),
|
||||
attr='_void_elements',
|
||||
ctx=ast.Load()
|
||||
)]
|
||||
),
|
||||
]
|
||||
),
|
||||
args=[ast.Str('debug')],
|
||||
keywords=[], starargs=None, kwargs=None
|
||||
)),
|
||||
ast.keyword('async', self._get_attr_bool(el.get('async', False))),
|
||||
ast.keyword('values', ast.Name(id='values', ctx=ast.Load())),
|
||||
body=[self._append(ast.Str(u'/>'))],
|
||||
orelse=[
|
||||
self._append(ast.Str(u'>')),
|
||||
ast.If(
|
||||
test=ast.Name(id='content', ctx=ast.Load()),
|
||||
body=[self._append(ast.Name(id='content', ctx=ast.Load()))],
|
||||
orelse=[]
|
||||
),
|
||||
self._append(ast.Str(u'</')),
|
||||
self._append(ast.Name(id='tagName', ctx=ast.Load())),
|
||||
self._append(ast.Str(u'>')),
|
||||
]
|
||||
)
|
||||
],
|
||||
starargs=None, kwargs=None
|
||||
))
|
||||
orelse=[]
|
||||
)
|
||||
]
|
||||
|
||||
# for backward compatibility to remove after v10
|
||||
|
|
@ -185,16 +270,34 @@ class IrQWeb(models.AbstractModel, QWeb):
|
|||
|
||||
# method called by computing code
|
||||
|
||||
def get_asset_bundle(self, xmlid, files, remains=None, env=None):
|
||||
return AssetsBundle(xmlid, files, remains=remains, env=env)
|
||||
|
||||
# compatibility to remove after v11 - DEPRECATED
|
||||
@tools.conditional(
|
||||
'xml' not in tools.config['dev_mode'],
|
||||
tools.ormcache_context('xmlid', 'options.get("lang", "en_US")', 'css', 'js', 'debug', 'kw.get("async")', 'async_load', keys=("website_id",)),
|
||||
)
|
||||
def _get_asset(self, xmlid, options, css=True, js=True, debug=False, async_load=False, values=None, **kw):
|
||||
if 'async' in kw:
|
||||
async_load = kw['async']
|
||||
files, remains = self._get_asset_content(xmlid, options)
|
||||
asset = self.get_asset_bundle(xmlid, files, remains, env=self.env)
|
||||
return asset.to_html(css=css, js=js, debug=debug, async_load=async_load, url_for=(values or {}).get('url_for', lambda url: url))
|
||||
|
||||
@tools.conditional(
|
||||
# in non-xml-debug mode we want assets to be cached forever, and the admin can force a cache clear
|
||||
# by restarting the server after updating the source code (or using the "Clear server cache" in debug tools)
|
||||
'xml' not in tools.config['dev_mode'],
|
||||
tools.ormcache_context('xmlid', 'options.get("lang", "en_US")', 'css', 'js', 'debug', 'async', keys=("website_id",)),
|
||||
tools.ormcache_context('xmlid', 'options.get("lang", "en_US")', 'css', 'js', 'debug', 'kw.get("async")', 'async_load', keys=("website_id",)),
|
||||
)
|
||||
def _get_asset(self, xmlid, options, css=True, js=True, debug=False, async=False, values=None):
|
||||
def _get_asset_nodes(self, xmlid, options, css=True, js=True, debug=False, async_load=False, values=None, **kw):
|
||||
if 'async' in kw:
|
||||
async_load = kw['async']
|
||||
files, remains = self._get_asset_content(xmlid, options)
|
||||
asset = AssetsBundle(xmlid, files, remains, env=self.env)
|
||||
return asset.to_html(css=css, js=js, debug=debug, async=async, url_for=(values or {}).get('url_for', lambda url: url))
|
||||
asset = self.get_asset_bundle(xmlid, files, env=self.env)
|
||||
remains = [node for node in remains if (css and node[0] == 'link') or (js and node[0] != 'link')]
|
||||
return remains + asset.to_node(css=css, js=js, debug=debug, async_load=async_load)
|
||||
|
||||
@tools.ormcache_context('xmlid', 'options.get("lang", "en_US")', keys=("website_id",))
|
||||
def _get_asset_content(self, xmlid, options):
|
||||
|
|
@ -205,6 +308,9 @@ class IrQWeb(models.AbstractModel, QWeb):
|
|||
|
||||
env = self.env(context=options)
|
||||
|
||||
def can_aggregate(url):
|
||||
return not urls.url_parse(url).scheme and not urls.url_parse(url).netloc and not url.startswith('/web/content')
|
||||
|
||||
# TODO: This helper can be used by any template that wants to embedd the backend.
|
||||
# It is currently necessary because the ir.ui.view bundle inheritance does not
|
||||
# match the module dependency graph.
|
||||
|
|
@ -218,16 +324,13 @@ class IrQWeb(models.AbstractModel, QWeb):
|
|||
files = []
|
||||
remains = []
|
||||
for el in html.fragments_fromstring(template):
|
||||
if isinstance(el, pycompat.string_types):
|
||||
remains.append(pycompat.to_text(el))
|
||||
elif isinstance(el, html.HtmlElement):
|
||||
if isinstance(el, html.HtmlElement):
|
||||
href = el.get('href', '')
|
||||
src = el.get('src', '')
|
||||
atype = el.get('type')
|
||||
media = el.get('media')
|
||||
|
||||
can_aggregate = not urls.url_parse(href).netloc and not href.startswith('/web/content')
|
||||
if el.tag == 'style' or (el.tag == 'link' and el.get('rel') == 'stylesheet' and can_aggregate):
|
||||
if can_aggregate(href) and (el.tag == 'style' or (el.tag == 'link' and el.get('rel') == 'stylesheet')):
|
||||
if href.endswith('.sass'):
|
||||
atype = 'text/sass'
|
||||
elif href.endswith('.less'):
|
||||
|
|
@ -237,25 +340,26 @@ class IrQWeb(models.AbstractModel, QWeb):
|
|||
path = [segment for segment in href.split('/') if segment]
|
||||
filename = get_resource_path(*path) if path else None
|
||||
files.append({'atype': atype, 'url': href, 'filename': filename, 'content': el.text, 'media': media})
|
||||
elif el.tag == 'script':
|
||||
elif can_aggregate(src) and el.tag == 'script':
|
||||
atype = 'text/javascript'
|
||||
path = [segment for segment in src.split('/') if segment]
|
||||
path = [segment for segment in href.split('/') if segment]
|
||||
filename = get_resource_path(*path) if path else None
|
||||
files.append({'atype': atype, 'url': src, 'filename': filename, 'content': el.text, 'media': media})
|
||||
else:
|
||||
remains.append(html.tostring(el, encoding='unicode'))
|
||||
remains.append((el.tag, OrderedDict(el.attrib), el.text))
|
||||
else:
|
||||
try:
|
||||
remains.append(html.tostring(el, encoding='unicode'))
|
||||
except Exception:
|
||||
# notYETimplementederror
|
||||
raise NotImplementedError
|
||||
# the other cases are ignored
|
||||
pass
|
||||
|
||||
return (files, remains)
|
||||
|
||||
def _get_field(self, record, field_name, expression, tagName, field_options, options, values):
|
||||
field = record._fields[field_name]
|
||||
|
||||
# adds template compile options for rendering fields
|
||||
field_options['template_options'] = options
|
||||
|
||||
# adds generic field options
|
||||
field_options['tagName'] = tagName
|
||||
field_options['expression'] = expression
|
||||
field_options['type'] = field_options.get('widget', field.type)
|
||||
|
|
@ -275,6 +379,9 @@ class IrQWeb(models.AbstractModel, QWeb):
|
|||
return (attributes, content, inherit_branding or translate)
|
||||
|
||||
def _get_widget(self, value, expression, tagName, field_options, options, values):
|
||||
# adds template compile options for rendering fields
|
||||
field_options['template_options'] = options
|
||||
|
||||
field_options['type'] = field_options['widget']
|
||||
field_options['tagName'] = tagName
|
||||
field_options['expression'] = expression
|
||||
|
|
@ -319,4 +426,4 @@ class IrQWeb(models.AbstractModel, QWeb):
|
|||
return ast.Name(id='False', ctx=ast.Load())
|
||||
elif attr in ('true', '1'):
|
||||
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())
|
||||
|
|
@ -101,6 +101,8 @@ _SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [
|
|||
'CALL_FUNCTION_EX',
|
||||
# Already in P2 but apparently the first one is used more aggressively in P3
|
||||
'CALL_FUNCTION_KW', 'CALL_FUNCTION_VAR', 'CALL_FUNCTION_VAR_KW',
|
||||
# Added in P3.7 https://bugs.python.org/issue26110
|
||||
'CALL_METHOD', 'LOAD_METHOD',
|
||||
'GET_ITER', 'FOR_ITER', 'YIELD_VALUE',
|
||||
'JUMP_FORWARD', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_ABSOLUTE',
|
||||
# New in Python 2.7 - http://bugs.python.org/issue4715 :
|
||||
|
|
|
|||
Loading…
Reference in New Issue