From 1942119c4da58015fe4c3245527b55da9bc1c122 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 12 Apr 2022 11:07:13 +0530 Subject: [PATCH 1/8] replace ^ with ** --- searx/plugins/calculator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index aa7a8b5c0..7d6475356 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -27,6 +27,7 @@ def post_search(request, search): try: query = search.search_query.query.lower() query = query.replace("x", "*") + query = query.replace("^", "**") # Not going to compute if only one number is present try: -- GitLab From 38fb37cf3e83541184e64fbfcb2dec6770dd4696 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 12 Apr 2022 11:14:59 +0530 Subject: [PATCH 2/8] show unmodified query --- searx/plugins/calculator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index 7d6475356..f8a7eefa6 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -26,6 +26,7 @@ def post_search(request, search): return try: query = search.search_query.query.lower() + unmodified_query = query query = query.replace("x", "*") query = query.replace("^", "**") @@ -51,7 +52,7 @@ def post_search(request, search): value = evaluate(query).item() if type(value) in (int, float): search.result_container.answers.clear() - answer = "{} = {}".format(query, value) + answer = "{} = {}".format(unmodified_query, value) search.result_container.answers[answer] = {'answer': answer, 'calculator': True} except (ZeroDivisionError, ValueError, FloatingPointError, MemoryError, OverflowError) as e: answer = gettext('Error') -- GitLab From f0b4a54b22166e4ed28f48bd54dd19ee1f3f5175 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 12 Apr 2022 15:04:41 +0530 Subject: [PATCH 3/8] set timeout to calculator --- requirements-dev.txt | 1 + requirements.txt | 1 + searx/plugins/calculator.py | 21 +++++++-------------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index bfc4244dd..e1cb212da 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -20,3 +20,4 @@ linuxdoc==20211220 aiounittest==1.4.1 numexpr==2.8.1 werkzeug==2.0.3 +wrapt-timeout-decorator==1.3.8 diff --git a/requirements.txt b/requirements.txt index a91f92fc0..31f48c269 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index f8a7eefa6..970144f59 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -1,7 +1,7 @@ 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,13 +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): if search.search_query.pageno > 1: @@ -45,16 +42,12 @@ 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 - - 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: + except (ZeroDivisionError, ValueError, FloatingPointError, MemoryError, OverflowError, TimeoutError) as e: answer = gettext('Error') search.result_container.answers[answer] = {'answer': answer, 'calculator': True} except Exception as e: -- GitLab From 3c6b3f77ba1ed9cfae077b2b683373a75eceb0f9 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 12 Apr 2022 15:08:57 +0530 Subject: [PATCH 4/8] fix pep8 --- searx/plugins/calculator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index 970144f59..abde98768 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -18,6 +18,7 @@ def check_if_loaded(): def calculate(query): return evaluate(query).item() + def post_search(request, search): if search.search_query.pageno > 1: return -- GitLab From 5fac5628e8dacbddfa3809eb5c121afae56b452f Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 12 Apr 2022 15:39:06 +0530 Subject: [PATCH 5/8] add tests for calculator plugin --- searx/plugins/calculator.py | 4 ++-- tests/unit/test_plugins.py | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index abde98768..17f87d68f 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -47,10 +47,10 @@ def post_search(request, search): 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} + 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) diff --git a/tests/unit/test_plugins.py b/tests/unit/test_plugins.py index 9ef4cd692..c4438f6d9 100644 --- a/tests/unit/test_plugins.py +++ b/tests/unit/test_plugins.py @@ -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']) \ No newline at end of file -- GitLab From 53ff36e75a103686543d8ed3501f42267bc5e1b2 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 12 Apr 2022 15:39:27 +0530 Subject: [PATCH 6/8] fix pep --- tests/unit/test_plugins.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/unit/test_plugins.py b/tests/unit/test_plugins.py index c4438f6d9..c4f323c25 100644 --- a/tests/unit/test_plugins.py +++ b/tests/unit/test_plugins.py @@ -159,29 +159,29 @@ class CalculatorPluginTest(SearxTestCase): # 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']) + 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) + 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) + 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' + 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']) \ No newline at end of file + self.assertTrue('Error' + in search.result_container.answers['calculator']['answer']) -- GitLab From 955413c336589f5280e06bfad525060f6e2fb144 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 12 Apr 2022 16:05:45 +0530 Subject: [PATCH 7/8] replace % with 0.01 --- searx/plugins/calculator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index 17f87d68f..329276818 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -27,6 +27,7 @@ def post_search(request, search): unmodified_query = query query = query.replace("x", "*") query = query.replace("^", "**") + query = query.replace("%", "*0.01") # Not going to compute if only one number is present try: -- GitLab From 2995ee63724a5d87822ff502fa140ca30d2f7e59 Mon Sep 17 00:00:00 2001 From: Nivesh Krishna Date: Tue, 12 Apr 2022 17:38:12 +0530 Subject: [PATCH 8/8] upcast all value to float --- searx/plugins/calculator.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/searx/plugins/calculator.py b/searx/plugins/calculator.py index 329276818..c0b5499f6 100644 --- a/searx/plugins/calculator.py +++ b/searx/plugins/calculator.py @@ -25,6 +25,8 @@ 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") @@ -44,6 +46,10 @@ def post_search(request, search): if len(query) > 30: return + # 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 = calculate(query) if type(value) in (int, float): search.result_container.answers.clear() -- GitLab