Skip to content

[IMP] adapt code to new simplified safe_eval API #265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions src/base/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

from odoo import modules
from odoo.tools import mute_logger
from odoo.tools.safe_eval import safe_eval

from odoo.addons.base.maintenance.migrations import util
from odoo.addons.base.maintenance.migrations.testing import UnitTestCase, parametrize
Expand Down Expand Up @@ -1690,11 +1689,11 @@ def test_expand_braces_failure(self, value):
]
)
def test_SelfPrint(self, value, expected):
evaluated = safe_eval(value, util.SelfPrintEvalContext(), nocopy=True)
evaluated = util.SelfPrintEvalContext().safe_eval(value)
self.assertEqual(str(evaluated), expected, "Self printed result differs")

replaced_value, ctx = util.SelfPrintEvalContext.preprocess(value)
evaluated = safe_eval(replaced_value, ctx, nocopy=True)
evaluated = ctx.safe_eval(replaced_value)
self.assertEqual(str(evaluated), expected, "Prepared self printed result differs")

@parametrize(
Expand All @@ -1714,7 +1713,7 @@ def test_SelfPrint(self, value, expected):
@unittest.skipUnless(util.ast_unparse is not None, "`ast.unparse` available from Python3.9")
def test_SelfPrint_prepare(self, value, expected):
replaced_value, ctx = util.SelfPrintEvalContext.preprocess(value)
evaluated = safe_eval(replaced_value, ctx, nocopy=True)
evaluated = ctx.safe_eval(replaced_value)
# extra fallback for old unparse from astunparse package
self.assertIn(str(evaluated), [expected, "({})".format(expected)])

Expand All @@ -1731,7 +1730,7 @@ def test_SelfPrint_prepare(self, value, expected):
def test_SelfPrint_failure(self, value):
# note: `safe_eval` will re-raise a ValueError
with self.assertRaises(ValueError):
safe_eval(value, util.SelfPrintEvalContext(), nocopy=True)
util.SelfPrintEvalContext().safe_eval(value)

@parametrize(
[
Expand Down
4 changes: 1 addition & 3 deletions src/util/domains.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@

try:
from odoo.tools import exception_to_unicode
from odoo.tools.safe_eval import safe_eval
except ImportError:
from openerp.tools import exception_to_unicode
from openerp.tools.safe_eval import safe_eval

from .const import NEARLYWARN
from .helpers import _dashboard_actions, _validate_model, resolve_model_fields_path
Expand Down Expand Up @@ -300,7 +298,7 @@ def _adapt_one_domain_old(cr, target_model, old, new, model, domain, adapter=Non
if isinstance(domain, basestring):
try:
replaced_domain, ctx = SelfPrintEvalContext.preprocess(domain)
eval_dom = normalize_domain(safe_eval(replaced_domain, ctx, nocopy=True))
eval_dom = normalize_domain(ctx.safe_eval(replaced_domain))
except Exception as e:
oops = exception_to_unicode(e)
_logger.log(NEARLYWARN, "Cannot evaluate %r domain: %r: %s", model, domain, oops)
Expand Down
11 changes: 5 additions & 6 deletions src/util/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import logging
import re
import warnings
from ast import literal_eval

import psycopg2
from psycopg2 import sql
Expand All @@ -25,11 +26,9 @@
try:
from odoo import release
from odoo.tools.misc import mute_logger
from odoo.tools.safe_eval import safe_eval
except ImportError:
from openerp import release
from openerp.tools.misc import mute_logger
from openerp.tools.safe_eval import safe_eval

from .domains import FALSE_LEAF, TRUE_LEAF

Expand Down Expand Up @@ -117,7 +116,7 @@ def _remove_field_from_filters(cr, model, field):
[model, r"\y{}\y".format(field)],
)
for id_, name, context_s in cr.fetchall():
context = safe_eval(context_s or "{}", SelfPrintEvalContext(), nocopy=True)
context = SelfPrintEvalContext().safe_eval(context_s or "{}")
changed = _remove_field_from_context(context, field)
cr.execute("UPDATE ir_filters SET context = %s WHERE id = %s", [unicode(context), id_])
if changed:
Expand Down Expand Up @@ -206,7 +205,7 @@ def remove_field(cr, model, fieldname, cascade=False, drop_column=True, skip_inh

# clean dashboard's contexts
for id_, action in _dashboard_actions(cr, r"\y{}\y".format(fieldname), model):
context = safe_eval(action.get("context", "{}"), SelfPrintEvalContext(), nocopy=True)
context = SelfPrintEvalContext().safe_eval(action.get("context", "{}"))
changed = _remove_field_from_context(context, fieldname)
action.set("context", unicode(context))
if changed:
Expand Down Expand Up @@ -350,7 +349,7 @@ def adapter(leaf, is_or, negated):
)
for alias_id, defaults_s in cr.fetchall():
try:
defaults = dict(safe_eval(defaults_s)) # XXX literal_eval should works.
defaults = dict(literal_eval(defaults_s))
except Exception:
continue
defaults.pop(fieldname, None)
Expand Down Expand Up @@ -1387,7 +1386,7 @@ def adapt_dict(d):
adapt_dict(d[vt])

for _, act in _dashboard_actions(cr, match, *only_models or ()):
context = safe_eval(act.get("context", "{}"), eval_context, nocopy=True)
context = eval_context.safe_eval(act.get("context", "{}"))
adapt_dict(context)

if def_old in context:
Expand Down
21 changes: 21 additions & 0 deletions src/util/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
from itertools import chain, islice

try:
import odoo.tools.safe_eval as _safe_eval
from odoo import release
from odoo.modules.module import get_module_path
from odoo.tools.parse_version import parse_version
except ImportError:
import openerp.tools.safe_eval as _safe_eval
from openerp import release
from openerp.modules.module import get_module_path
from openerp.tools.parse_version import parse_version
Expand Down Expand Up @@ -532,6 +534,25 @@ def visit_UnaryOp(self, node):
visited = replacer.visit(root)
return (ast_unparse(visited).strip(), SelfPrintEvalContext(replacer.replaces))

if version_gte("saas~18.3"):

def safe_eval(self, expr, mode="eval"):
assert isinstance(expr, (str, bytes))
c = _safe_eval.test_expr(expr, _safe_eval._SAFE_OPCODES, mode=mode, filename=None)
self["__builtins__"] = dict(_safe_eval._BUILTINS)
try:
return _safe_eval.unsafe_eval(c, self, None)
except _safe_eval._BUBBLEUP_EXCEPTIONS:
raise
except Exception as e:
raise ValueError("{!r} while evaluating\n{!r}".format(e, expr))
finally:
del self["__builtins__"]
else:

def safe_eval(self, expr, mode="eval"):
return _safe_eval.safe_eval(expr, self, nocopy=True)


class _Replacer(ast.NodeTransformer):
"""Replace literal nodes in an AST."""
Expand Down