File size: 2,076 Bytes
7885a28 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# Adapted from https://stackoverflow.com/a/9558001/2536294
import ast
import operator as op
from dataclasses import dataclass
from ._multiprocessing_helpers import mp
if mp is not None:
from .externals.loky.process_executor import _ExceptionWithTraceback
# supported operators
operators = {
ast.Add: op.add,
ast.Sub: op.sub,
ast.Mult: op.mul,
ast.Div: op.truediv,
ast.FloorDiv: op.floordiv,
ast.Mod: op.mod,
ast.Pow: op.pow,
ast.USub: op.neg,
}
def eval_expr(expr):
"""
>>> eval_expr('2*6')
12
>>> eval_expr('2**6')
64
>>> eval_expr('1 + 2*3**(4) / (6 + -7)')
-161.0
"""
try:
return eval_(ast.parse(expr, mode="eval").body)
except (TypeError, SyntaxError, KeyError) as e:
raise ValueError(
f"{expr!r} is not a valid or supported arithmetic expression."
) from e
def eval_(node):
if isinstance(node, ast.Constant): # <constant>
return node.value
elif isinstance(node, ast.BinOp): # <left> <operator> <right>
return operators[type(node.op)](eval_(node.left), eval_(node.right))
elif isinstance(node, ast.UnaryOp): # <operator> <operand> e.g., -1
return operators[type(node.op)](eval_(node.operand))
else:
raise TypeError(node)
@dataclass(frozen=True)
class _Sentinel:
"""A sentinel to mark a parameter as not explicitly set"""
default_value: object
def __repr__(self):
return f"default({self.default_value!r})"
class _TracebackCapturingWrapper:
"""Protect function call and return error with traceback."""
def __init__(self, func):
self.func = func
def __call__(self, **kwargs):
try:
return self.func(**kwargs)
except BaseException as e:
return _ExceptionWithTraceback(e)
def _retrieve_traceback_capturing_wrapped_call(out):
if isinstance(out, _ExceptionWithTraceback):
rebuild, args = out.__reduce__()
out = rebuild(*args)
if isinstance(out, BaseException):
raise out
return out
|