Source code for metawards.utils._safe_eval


from typing import Union as _Union

__all__ = ["safe_eval_number"]


[docs]def safe_eval_number(s: _Union[float, int, str]) -> float: """Convert 's' to a number. This supports normal floats, but also simple maths expressions like 1/1.2, plus anything that ends with a "%" is recognised as a percentage Examples -------- safe_eval_number(0.3) -> 0.3 safe_eval_number("5%") -> 0.05 safe_eval_number("1/4") -> 0.25 safe_eval_number("(30+100)%) -> 1.3 """ if isinstance(s, float) or isinstance(s, int): return s if not isinstance(s, str): s = str(s) try: # this is about as save as eval gets in python # (and we allow math so that "sqrt(3)" and "2 * pi" will work) import math x = eval(s, {"__builtins__": math}, {}) v = float(x) if v.is_integer(): return int(x) else: return v except Exception: pass if isinstance(s, str): s = s.strip() if s.endswith("%"): try: return safe_eval_number(s[0:-1]) / 100.0 except Exception: pass raise ValueError(f"Cannot interpret '{s}' as a float")