Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f00ff30 authored by Nivesh Krishna's avatar Nivesh Krishna
Browse files

Merge branch 'fix-calculator' into 'master'

Fix calculator

See merge request !122
parents 4cc35605 5f0de8f9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -20,3 +20,4 @@ linuxdoc==20211220
aiounittest==1.4.1
numexpr==2.8.1
werkzeug==2.0.3
wrapt-timeout-decorator==1.3.8
+1 −0
Original line number Diff line number Diff line
@@ -18,3 +18,4 @@ redis==3.4.1
ring==0.7.3
numexpr==2.8.1
werkzeug==2.0.3
wrapt-timeout-decorator==1.3.8
 No newline at end of file
+15 −14
Original line number Diff line number Diff line
from searx import logger
from numexpr import evaluate
from flask_babel import gettext

from wrapt_timeout_decorator import timeout

name = gettext('Calculator')
description = gettext('This plugin extends results when the query is a mathematical expression')
@@ -13,12 +13,10 @@ def check_if_loaded():
    logger.debug("initializing calculator plugin")


def is_really_big(query):
    # For cases like 2**99999**9999
    if len(query.split("**")) >= 3:
        return True
    # Add more cases if needed
    return False
# Set timeout so that the plugin doesn't hang for long computations
@timeout(5)
def calculate(query):
    return evaluate(query).item()


def post_search(request, search):
@@ -27,8 +25,11 @@ def post_search(request, search):
    try:
        query = search.search_query.query.lower()
        unmodified_query = query

        # Replace all frequently used substitutes
        query = query.replace("x", "*")
        query = query.replace("^", "**")
        query = query.replace("%", "*0.01")

        # Not going to compute if only one number is present
        try:
@@ -45,18 +46,18 @@ def post_search(request, search):
        if len(query) > 30:
            return

        # Not going to compute the result if the query is not within permissible range
        if is_really_big(query):
            raise OverflowError
        # Multiply by float to upcast all numbers to floats
        # https://numexpr.readthedocs.io/projects/NumExpr3/en/latest/user_guide.html#casting-rules
        query += "*1.0"

        value = evaluate(query).item()
        value = calculate(query)
        if type(value) in (int, float):
            search.result_container.answers.clear()
            answer = "{} = {}".format(unmodified_query, value)
            search.result_container.answers[answer] = {'answer': answer, 'calculator': True}
    except (ZeroDivisionError, ValueError, FloatingPointError, MemoryError, OverflowError) as e:
            search.result_container.answers['calculator'] = {'answer': answer, 'calculator': True}
    except (ZeroDivisionError, ValueError, FloatingPointError, MemoryError, OverflowError, TimeoutError) as e:
        answer = gettext('Error')
        search.result_container.answers[answer] = {'answer': answer, 'calculator': True}
        search.result_container.answers['calculator'] = {'answer': answer, 'calculator': True}
    except Exception as e:
        logger.debug(e)

+48 −0
Original line number Diff line number Diff line
@@ -137,3 +137,51 @@ class HashPluginTest(SearxTestCase):
        self.assertTrue('sha512 hash digest: ee26b0dd4af7e749aa1a8ee3c10ae9923f6'
                        '18980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5'
                        'fa9ad8e6f57f50028a8ff' in search.result_container.answers['hash']['answer'])


class CalculatorPluginTest(SearxTestCase):

    def test_PluginStore_init(self):
        store = plugins.PluginStore()
        store.register(plugins.calculator)

        self.assertTrue(len(store.plugins) == 1)

        request = Mock(remote_addr='127.0.0.1')
        request.headers.getlist.return_value = []

        # True addition test
        search = get_search_mock(query='2+2', pageno=1)
        store.call(store.plugins, 'post_search', request, search)
        self.assertTrue('4'
                        in search.result_container.answers['calculator']['answer'])

        # False addition test
        search = get_search_mock(query='2+2', pageno=1)
        store.call(store.plugins, 'post_search', request, search)
        self.assertFalse('4' not
                         in search.result_container.answers['calculator']['answer'])

        # no result test
        search = get_search_mock(query='2+2', pageno=2)
        store.call(store.plugins, 'post_search', request, search)
        self.assertFalse('calculator'
                         in search.result_container.answers)

        # no result test
        search = get_search_mock(query='2+2/sdf', pageno=1)
        store.call(store.plugins, 'post_search', request, search)
        self.assertFalse('calculator'
                         in search.result_container.answers)

        # error result test
        search = get_search_mock(query='2+2/0', pageno=1)
        store.call(store.plugins, 'post_search', request, search)
        self.assertTrue('Error'
                        in search.result_container.answers['calculator']['answer'])

        # error result test
        search = get_search_mock(query='2**999999999**99999999', pageno=1)
        store.call(store.plugins, 'post_search', request, search)
        self.assertTrue('Error'
                        in search.result_container.answers['calculator']['answer'])