From b7d9e3fc8eec667b47b929f9dd75e1c4808a042c Mon Sep 17 00:00:00 2001 From: Carsten Ehbrecht Date: Tue, 15 Sep 2020 09:59:03 +0200 Subject: [PATCH 1/3] process error with formatting --- pywps/app/exceptions.py | 61 ++++++++++++++++++++++-------------- tests/test_app_exceptions.py | 35 +++++++++++++++++++++ 2 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 tests/test_app_exceptions.py diff --git a/pywps/app/exceptions.py b/pywps/app/exceptions.py index a69cd64c7..1082c7224 100644 --- a/pywps/app/exceptions.py +++ b/pywps/app/exceptions.py @@ -7,42 +7,57 @@ Process exceptions raised intentionally in processes to provide information for users. """ +import re + +DEFAULT_ALLOWED_CHARS = ".:!?=,;_/" + +import logging + +LOGGER = logging.getLogger('PYWPS') + + +def format_message(text, min_length=3, max_length=300, allowed_chars=None): + allowed_chars = allowed_chars or DEFAULT_ALLOWED_CHARS + special = re.escape(allowed_chars) + pattern = rf'[\w{allowed_chars}]+' + msg = ' '.join(re.findall(pattern, text)) + msg.strip() + if len(msg) >= min_length: + msg = msg[:max_length] + else: + msg = '' + return msg + class ProcessError(Exception): """:class:`pywps.app.exceptions.ProcessError` is an :class:`Exception` you can intentionally raise in a process to provide a user-friendly error message. - The error message gets validated (3<= message length <=144) and only + The error message gets formatted (3<= message length <=300) and only alpha numeric characters and a few special characters are allowed. - The special characters are: `.`, `:`, `!`, `?`, `=`, `,`, `-`. """ - min_msg_length = 3 - max_msg_length = 144 - allowed_chars = ['.', ':', '!', '?', '=', ',', '-'] default_msg = 'Sorry, process failed. Please check server error log.' - def __init__(self, msg=None): + def __init__(self, msg=None, min_length=3, max_length=300, allowed_chars=None): self.msg = msg + self.min_length = min_length + self.max_length = max_length + self.allowed_chars = allowed_chars or DEFAULT_ALLOWED_CHARS def __str__(self): return self.message - def _validate_message(self): - valid = False - if self.msg and self.min_msg_length <= len(self.msg) <= self.max_msg_length: - # remove spaces - test_str = self.msg.replace(' ', '') - # remove allowed non alpha-numeric chars - for char in self.allowed_chars: - test_str = test_str.replace(char, '') - # only alpha numeric string accepted - valid = test_str.isalnum() - return valid - @property def message(self): - if self._validate_message(): - new_msg = "{}".format(self.msg) - else: - new_msg = self.default_msg - return new_msg + try: + msg = format_message( + self.msg, + min_length=self.min_length, + max_length=self.max_length, + allowed_chars=self.allowed_chars) + except Exception as e: + LOGGER.warning(f"process error formatting failed: {e}") + msg = None + if not msg: + msg = self.default_msg + return msg diff --git a/tests/test_app_exceptions.py b/tests/test_app_exceptions.py new file mode 100644 index 000000000..1fc9dc7d6 --- /dev/null +++ b/tests/test_app_exceptions.py @@ -0,0 +1,35 @@ +################################################################## +# Copyright 2018 Open Source Geospatial Foundation and others # +# licensed under MIT, Please consult LICENSE.txt for details # +################################################################## + +import unittest +from pywps.app.exceptions import format_message, ProcessError + + +class AppExceptionsTest(unittest.TestCase): + + def setUp(self): + pass + + def test_format_message(self): + assert format_message('no data available') == 'no data available' + assert format_message(' no data available! ') == 'no data available!' + assert format_message('no') == '' + assert format_message('no data available', max_length=7) == 'no data' + assert format_message('no &data% available') == 'no data available' + assert format_message(".:!?=,;_/") == ".:!?=,;_/" + + def test_process_error(self): + assert ProcessError(' no &data available!').message == 'no data available!' + assert ProcessError('no', min_length=2).message == 'no' + assert ProcessError('0 data available', max_length=6).message == '0 data' + assert ProcessError('no data? not available!', allowed_chars='?').message == 'no data? not available' + assert ProcessError('').message == 'Sorry, process failed. Please check server error log.' + assert ProcessError(1234).message == 'Sorry, process failed. Please check server error log.' + try: + raise ProcessError('no data!!') + except ProcessError as e: + assert f"{e}" == 'no data!!' + else: + assert False From baf10ab6b7f82bdb810a50e8e9925556de0aadb0 Mon Sep 17 00:00:00 2001 From: Carsten Ehbrecht Date: Tue, 15 Sep 2020 10:11:02 +0200 Subject: [PATCH 2/3] fix specials --- pywps/app/exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pywps/app/exceptions.py b/pywps/app/exceptions.py index 1082c7224..66e05bb00 100644 --- a/pywps/app/exceptions.py +++ b/pywps/app/exceptions.py @@ -9,7 +9,7 @@ import re -DEFAULT_ALLOWED_CHARS = ".:!?=,;_/" +DEFAULT_ALLOWED_CHARS = ".:!?=,;-_/" import logging @@ -19,7 +19,7 @@ def format_message(text, min_length=3, max_length=300, allowed_chars=None): allowed_chars = allowed_chars or DEFAULT_ALLOWED_CHARS special = re.escape(allowed_chars) - pattern = rf'[\w{allowed_chars}]+' + pattern = rf'[\w{special}]+' msg = ' '.join(re.findall(pattern, text)) msg.strip() if len(msg) >= min_length: From d266900458ebfcd9cfca56591e2e05ecffbc0f90 Mon Sep 17 00:00:00 2001 From: Carsten Ehbrecht Date: Tue, 15 Sep 2020 10:33:29 +0200 Subject: [PATCH 3/3] update test --- tests/test_app_exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_app_exceptions.py b/tests/test_app_exceptions.py index 1fc9dc7d6..c1fa00a67 100644 --- a/tests/test_app_exceptions.py +++ b/tests/test_app_exceptions.py @@ -4,7 +4,7 @@ ################################################################## import unittest -from pywps.app.exceptions import format_message, ProcessError +from pywps.app.exceptions import format_message, ProcessError, DEFAULT_ALLOWED_CHARS class AppExceptionsTest(unittest.TestCase): @@ -18,7 +18,7 @@ def test_format_message(self): assert format_message('no') == '' assert format_message('no data available', max_length=7) == 'no data' assert format_message('no &data% available') == 'no data available' - assert format_message(".:!?=,;_/") == ".:!?=,;_/" + assert format_message(DEFAULT_ALLOWED_CHARS) == DEFAULT_ALLOWED_CHARS def test_process_error(self): assert ProcessError(' no &data available!').message == 'no data available!'