mirror of
https://github.com/searxng/searxng
synced 2024-01-01 19:24:07 +01:00

call Python directly with -S and -I parameters to skip loading of the standard library and the SearXNG module. The actual calculator is moved to a standalone script: calculator_process.py
58 lines
1.2 KiB
Python
58 lines
1.2 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""Standalone script to actually calculate mathematical expressions using ast
|
|
|
|
This is not a module, the SearXNG modules are not available here
|
|
"""
|
|
|
|
import ast
|
|
import sys
|
|
import operator
|
|
from typing import Callable
|
|
|
|
|
|
operators: dict[type, Callable] = {
|
|
ast.Add: operator.add,
|
|
ast.Sub: operator.sub,
|
|
ast.Mult: operator.mul,
|
|
ast.Div: operator.truediv,
|
|
ast.Pow: operator.pow,
|
|
ast.BitXor: operator.xor,
|
|
ast.USub: operator.neg,
|
|
}
|
|
|
|
|
|
def _eval_expr(expr):
|
|
"""
|
|
>>> _eval_expr('2^6')
|
|
4
|
|
>>> _eval_expr('2**6')
|
|
64
|
|
>>> _eval_expr('1 + 2*3**(4^5) / (6 + -7)')
|
|
-5.0
|
|
"""
|
|
try:
|
|
return _eval(ast.parse(expr, mode='eval').body)
|
|
except ZeroDivisionError:
|
|
# This is undefined
|
|
return ""
|
|
|
|
|
|
def _eval(node):
|
|
if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
|
|
return node.value
|
|
|
|
if isinstance(node, ast.BinOp):
|
|
return operators[type(node.op)](_eval(node.left), _eval(node.right))
|
|
|
|
if isinstance(node, ast.UnaryOp):
|
|
return operators[type(node.op)](_eval(node.operand))
|
|
|
|
raise TypeError(node)
|
|
|
|
|
|
def main():
|
|
print(_eval_expr(sys.argv[1]), end="")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|