From f8a6daa4301b38c0c689758bbf7cc55ed413fe11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Fri, 6 May 2016 14:27:19 +0200 Subject: [PATCH] [IMP] make SimpleArray produce DataError in memberwise operations Put DataError and mis_safe_eval in their own files --- mis_builder/models/data_error.py | 11 +++++++++ mis_builder/models/mis_safe_eval.py | 38 +++++++++++++++++++++++++++++ mis_builder/models/simple_array.py | 19 +++++++++++++-- mis_builder/tests/__init__.py | 1 + 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 mis_builder/models/data_error.py create mode 100644 mis_builder/models/mis_safe_eval.py diff --git a/mis_builder/models/data_error.py b/mis_builder/models/data_error.py new file mode 100644 index 00000000..ccc1dc6e --- /dev/null +++ b/mis_builder/models/data_error.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +# © 2016 ACSONE SA/NV () +# © 2016 Akretion () +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + + +class DataError(Exception): + + def __init__(self, name, msg): + self.name = name + self.msg = msg diff --git a/mis_builder/models/mis_safe_eval.py b/mis_builder/models/mis_safe_eval.py new file mode 100644 index 00000000..981e9a62 --- /dev/null +++ b/mis_builder/models/mis_safe_eval.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# © 2016 ACSONE SA/NV () +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +import traceback + +from openerp.tools.safe_eval import test_expr, _SAFE_OPCODES, _BUILTINS + +from .data_error import DataError + + +__all__ = ['mis_safe_eval'] + + +def mis_safe_eval(expr, locals_dict): + """ Evaluate an expression using safe_eval + + Returns the evaluated value or DataError. + + Raises NameError if the evaluation depends on a variable that is not + present in local_dict. + """ + try: + c = test_expr(expr, _SAFE_OPCODES, mode='eval') + globals_dict = {'__builtins__': _BUILTINS} + val = eval(c, globals_dict, locals_dict) + except NameError: + raise + except ZeroDivisionError: + val = DataError('#DIV/0', traceback.format_exc()) + except: + val = DataError('#ERR', traceback.format_exc()) + return val + + +if __name__ == '__main__': + import doctest + doctest.testmod() diff --git a/mis_builder/models/simple_array.py b/mis_builder/models/simple_array.py index 39534206..e6a51395 100644 --- a/mis_builder/models/simple_array.py +++ b/mis_builder/models/simple_array.py @@ -46,9 +46,16 @@ SimpleArray((2.0, 2.5, 3.0)) SimpleArray((8.0, 10.0, 12.0)) >>> b += 2 ; b SimpleArray((6.0, 7.0, 8.0)) +>>> a / ((1.0, 0.0, 1.0)) +SimpleArray((1.0, DataError(), 3.0)) +>>> a / 0.0 +SimpleArray((DataError(), DataError(), DataError())) """ import operator +import traceback + +from .data_error import DataError __all__ = ['SimpleArray'] @@ -57,12 +64,20 @@ __all__ = ['SimpleArray'] class SimpleArray(tuple): def _op(self, op, other): + def _o2(x, y): + try: + return op(x, y) + except ZeroDivisionError: + return DataError('#DIV/0', traceback.format_exc()) + except: + return DataError('#ERR', traceback.format_exc()) + if isinstance(other, tuple): if len(other) != len(self): raise TypeError("tuples must have same length for %s" % op) - return SimpleArray(map(op, self, other)) + return SimpleArray(map(_o2, self, other)) else: - return SimpleArray(map(lambda x: op(x, other), self)) + return SimpleArray(map(lambda z: _o2(z, other), self)) def __add__(self, other): return self._op(operator.add, other) diff --git a/mis_builder/tests/__init__.py b/mis_builder/tests/__init__.py index 8335944d..e2db2cba 100644 --- a/mis_builder/tests/__init__.py +++ b/mis_builder/tests/__init__.py @@ -6,4 +6,5 @@ from . import test_accounting_none from . import test_aep from . import test_aggregate from . import test_mis_builder +from . import test_mis_safe_eval from . import test_simple_array