diff --git a/odoo/addons/base/models/qweb.py b/odoo/addons/base/models/qweb.py index e83236240bf..cd10dbfb026 100644 --- a/odoo/addons/base/models/qweb.py +++ b/odoo/addons/base/models/qweb.py @@ -295,7 +295,6 @@ class QWeb(object): globals_dict['Mapping'] = Mapping globals_dict['Markup'] = Markup globals_dict['escape'] = escape - globals_dict['type'] = type globals_dict['compile_options'] = options globals_dict.update(self._available_objects) return globals_dict @@ -410,7 +409,7 @@ class QWeb(object): code += f'.format({", ".join(values)})' return code - def _compile_expr_tokens(self, tokens, allowed_keys, raise_on_missing=False): + def _compile_expr_tokens(self, tokens, allowed_keys, argument_names=None, raise_on_missing=False): """ Transform the list of token coming into a python instruction in textual form by adding the namepaces for the dynamic values. @@ -436,6 +435,10 @@ class QWeb(object): index = 0 open_bracket_index = -1 bracket_depth = 0 + + argument_name = '_arg_%s__' + argument_names = argument_names or [] + while index < len(tokens): t = tokens[index] if t.exact_type in [token.LPAR, token.LSQB, token.LBRACE]: @@ -449,7 +452,7 @@ class QWeb(object): while i < len(tokens): t = tokens[i] if t.exact_type == token.NAME: - allowed_keys.append(t.string) + argument_names.append(t.string) elif t.exact_type == token.COMMA: pass elif t.exact_type == token.COLON: @@ -466,7 +469,7 @@ class QWeb(object): if t.exact_type == token.NAME: if t.string == 'in': break - allowed_keys.append(t.string) + argument_names.append(t.string) elif t.exact_type in [token.COMMA, token.LPAR, token.RPAR]: pass else: @@ -495,7 +498,12 @@ class QWeb(object): elif t.exact_type in [token.RPAR, token.RSQB, token.RBRACE]: bracket_depth -= 1 if bracket_depth == 0: - code = self._compile_expr_tokens(tokens[open_bracket_index + 1:index], list(allowed_keys), raise_on_missing) + code = self._compile_expr_tokens( + tokens[open_bracket_index + 1:index], + list(allowed_keys), + list(argument_names), + raise_on_missing, + ) code = tokens[open_bracket_index].string + code + t.string tokens[open_bracket_index:index + 1] = [tokenize.TokenInfo(token.QWEB, code, tokens[open_bracket_index].start, t.end, '')] index = open_bracket_index @@ -526,7 +534,9 @@ class QWeb(object): index += 1 while index < len(tokens): t = tokens[index] - if t.exact_type in [token.COMMA, token.NAME, token.COLON]: + if t.exact_type == token.NAME and t.string in argument_names: + code.append(argument_name % t.string) + if t.exact_type in [token.COMMA, token.COLON]: code.append(t.string) if t.exact_type == token.COLON: break @@ -535,6 +545,8 @@ class QWeb(object): pos = (t.end[0], 0) else: pos = t.end + elif string in argument_names: + code.append(argument_name % t.string) elif string in allowed_keys: code.append(string) elif index + 1 < len(tokens) and tokens[index + 1].exact_type == token.EQUAL: # function kw @@ -1048,7 +1060,7 @@ class QWeb(object): {t_foreach} = {self._compile_expr(expr_foreach)} or [] if isinstance({t_foreach}, Sized): values[{repr(expr_as + '_size')}] = {size} = len({t_foreach}) - elif type({t_foreach}) == int: + elif ({t_foreach}).__class__ == int: values[{repr(expr_as + '_size')}] = {size} = {t_foreach} {t_foreach} = range({size}) else: diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py index f0d26e443c3..1d6d6e90d08 100644 --- a/odoo/addons/base/tests/test_qweb.py +++ b/odoo/addons/base/tests/test_qweb.py @@ -684,6 +684,7 @@ class TestQWebBasic(TransactionCase): ("fn(a=11, b=22) or a", {'a': 1, 'fn': lambda a,b: b}, 22), ("(lambda a: a)(5)", {}, 5), ("(lambda a: a[0])([5])", {}, 5), + ("(lambda test: len(test))('aaa')", {}, 3), ("{'a': lambda a: a[0], 'b': 3}['a']([5])", {}, 5), ("list(map(lambda a: a[0], r))", {'r': [(1,11), (2,22)]}, [1, 2]), ("z + (head or 'z')", {'z': 'a'}, "az"), @@ -693,8 +694,10 @@ class TestQWebBasic(TransactionCase): ("any({x == 5 for x in [1,2,3]})", {}, False), ("{x:y for x,y in [('a', 11),('b', 22)]}", {}, {'a': 11, 'b': 22}), ("[(y,x) for x,y in [(1, 11),(2, 22)]]", {}, [(11, 1), (22, 2)]), - ("(lambda a: a + 5)(a=x)", {'x': 10}, 15), + ("(lambda a: a + 5)(x)", {'x': 10}, 15), + ("(lambda a: a + x)(5)", {'x': 10}, 15), ("sum(x for x in range(4)) + ((x))", {'x': 10}, 16), + ("['test_' + x for x in ['a', 'b']]", {}, ['test_a', 'test_b']) ] IrQweb = self.env['ir.qweb'] diff --git a/odoo/tools/safe_eval.py b/odoo/tools/safe_eval.py index f60bb5e91b6..591659faf26 100644 --- a/odoo/tools/safe_eval.py +++ b/odoo/tools/safe_eval.py @@ -37,7 +37,7 @@ __all__ = ['test_expr', 'safe_eval', 'const_eval'] # lp:703841), does import time. _ALLOWED_MODULES = ['_strptime', 'math', 'time'] -_UNSAFE_ATTRIBUTES = ['f_builtins', 'f_globals', 'f_locals', 'gi_frame', +_UNSAFE_ATTRIBUTES = ['f_builtins', 'f_globals', 'f_locals', 'gi_frame', 'gi_code', 'co_code', 'func_globals'] def to_opcodes(opnames, _opmap=opmap):