diff --git a/sohstationviewer/view/db_config/value_color_helper/__init__.py b/sohstationviewer/view/db_config/value_color_helper/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/sohstationviewer/view/db_config/value_color_helper/functions.py b/sohstationviewer/view/db_config/value_color_helper/functions.py new file mode 100644 index 0000000000000000000000000000000000000000..da6aeb07198191c6a5b49c3405ecfbad77d95c24 --- /dev/null +++ b/sohstationviewer/view/db_config/value_color_helper/functions.py @@ -0,0 +1,111 @@ +from typing import Optional + +from sohstationviewer.view.util.color import clr + +from sohstationviewer.view.util.plot_func_names import plot_functions + + +def convert_value_color_str( + plot_type: str, old_value_color_str: Optional[str]) -> str: + """ + Convert value_color str to new format. This will be removed after + value_colors in database changed + linesDots: L:G|D:G => Line:#00FF00|Dot:#00FF00 + upDownDots: 0:R|1:G => Down:#FF0000|Up:#00FF00 + multiColorDotsEqualOnUpperBound: + 0:_|1:Y|2:G|+2:M => <=0:not plot|<=1:#FFFF00|<=2:#00FF00|2<:#FF00FF + multiColorDotsEqualOnLowerBound: + 3:R|3.3:Y|=3.3:G => <3:#FF0000|<3.3:#FFFF00|=3.3:#00FF00 + triColorLines: + -1:M|0:R|1:G => -1:#FF00FF|0:#FF0000|1:#00FF00 + :param plot_type: type of channel's plot + :param old_value_color_str: value_color_str in old format + :return: value_color_str in new format + """ + if old_value_color_str is None: + return "" + value_color_list = [] + if old_value_color_str == '' and plot_type == 'linesDots': + old_value_color_str = "L:G" + value_color_parts = old_value_color_str.split('|') + for c_str in value_color_parts: + val, color = c_str.split(':') + val = convert_value(plot_type, val) + if color == '_': + color = "not plot" + else: + if color in clr.keys(): + color = clr[color] + value_color_list.append(f"{val}:{color}") + return '|'.join(value_color_list) + + +def convert_value(plot_type: str, old_value: str): + """ + Convert value part in value color str to new format + :param plot_type: type of channel's plot + :param old_value: value in old format + :return: value in new format + """ + if not plot_functions[plot_type]['value_pattern'].match(old_value): + return "unrecognized:" + old_value + + if old_value in ['L', 'Line'] and plot_type == 'linesDots': + new_value = 'Line' + elif old_value in ['D', 'Dot'] and plot_type == 'linesDots': + new_value = 'Dot' + elif old_value in ['1', 'Up'] and plot_type == 'upDownDots': + new_value = 'Up' + elif old_value in ['0', 'Down'] and plot_type == 'upDownDots': + new_value = 'Down' + elif plot_type == "multiColorDotsEqualOnUpperBound": + if old_value.startswith('+'): + new_value = old_value[1:] + '<' + elif old_value.startswith('<=') or old_value.endswith('<'): + new_value = old_value + else: + new_value = '<=' + old_value + elif plot_type == "multiColorDotsEqualOnLowerBound": + if old_value.startswith('=') or old_value.startswith('<'): + new_value = old_value + else: + new_value = '<' + old_value + elif plot_type == 'triColorLines': + new_value = old_value + else: + new_value = "Sth wrong:" + old_value + return new_value + + +def prepare_value_color_html(value_colors: Optional[str]) -> str: + """ + Change value_color with hex color to html to square with actual color from + hex color. + :param value_colors: string for value color to be saved in DB. + Possible formats + Line:color|Dot:color + Up:color|Down:color + <=value:color|value<:color + (color can be hex color '#00FFF' or 'not plot') + :return: value color in html + Ex: <p>Line:<span style='#00FFFF; font-size:25px;'>∎</span>| + Dot:<span style='#FF0000; font-size:25px;'>∎</span></p> + """ + if value_colors in [None, ""]: + return "" + html_color_parts = [] + color_parts = value_colors.split('|') + for c_str in color_parts: + value, color = c_str.split(':') + value = value.replace('<=', '≤').replace('<', '<') + if color == 'not plot': + c_html = f"{value}:not plot" + else: + c_html = ( + f"{value}:" + f"<span style='color: {color}; font-size:25px;'>∎" + f"</span>") + + html_color_parts.append(c_html) + value_color_html = f"<p>{'|'.join(html_color_parts)}</p>" + return value_color_html diff --git a/sohstationviewer/view/util/plot_func_names.py b/sohstationviewer/view/util/plot_func_names.py index adac47907de55038023a2ab5285829bcea0b15b2..236917c658d559734d030ae51b4c663a62b1ea51 100644 --- a/sohstationviewer/view/util/plot_func_names.py +++ b/sohstationviewer/view/util/plot_func_names.py @@ -1,3 +1,5 @@ +import re + plot_functions = { 'linesDots': { "description": ( @@ -8,7 +10,8 @@ plot_functions = { "\tDots are plotted with color W\n" "If D is not defined, dots won't be displayed.\n" "If L is not defined, lines will be plotted with color G"), - "plot_function": "plot_lines_dots" + "plot_function": "plot_lines_dots", + "value_pattern": re.compile('^(L|D|Line|Dot)$') }, 'linesSRate': { "description": "Lines, one color dots, bitweight info. ", @@ -21,7 +24,8 @@ plot_functions = { 'triColorLines': { "description": "Three lines with three different colors for " "values -1, 0, 1.", - "plot_function": "plot_tri_colors" + "plot_function": "plot_tri_colors", + "value_pattern": re.compile('^-?[10]?$') }, 'dotForTime': { "description": ( @@ -41,7 +45,8 @@ plot_functions = { "\tvalue <= 0 => plot with R color\n" "\t0 < value <= 2.3 => plot with Y color\n" "\t2.3 < value => plot with G color\n"), - "plot_function": "plot_multi_color_dots_equal_on_upper_bound" + "plot_function": "plot_multi_color_dots_equal_on_upper_bound", + "value_pattern": re.compile('^(\+|<=)?[0-9]+\.?[0-9]?<?$') # noqa: W605,E501 }, 'multiColorDotsEqualOnLowerBound': { "description": ( @@ -53,12 +58,14 @@ plot_functions = { "\tvalue < 3. => plot with R color\n" "\t3. <= value < 3.3 => plot with Y color\n" "\tvalue = 3.3 => plot with G color\n"), - "plot_function": "plot_multi_color_dots_equal_on_lower_bound" + "plot_function": "plot_multi_color_dots_equal_on_lower_bound", + "value_pattern": re.compile('^[=<]?[0-9]\.?[0-9]?$') # noqa: W605 }, 'upDownDots': { "description": ( "Show data with 2 different values: first down/ second up. " "Colors defined by ValueColors.\nEx: 1:R|0:Y"), - "plot_function": 'plot_up_down_dots' + "plot_function": 'plot_up_down_dots', + "value_pattern": re.compile("^(0|1|Up|Down)$") } } diff --git a/tests/view/db_config/__init__.py b/tests/view/db_config/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/view/db_config/value_color_helper/__init__.py b/tests/view/db_config/value_color_helper/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/view/db_config/value_color_helper/test_functions.py b/tests/view/db_config/value_color_helper/test_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..c07285c61acbe7422d43663f65c18839810806e1 --- /dev/null +++ b/tests/view/db_config/value_color_helper/test_functions.py @@ -0,0 +1,200 @@ +from sohstationviewer.view.db_config.value_color_helper.functions import ( + convert_value_color_str, prepare_value_color_html +) + +from tests.base_test_case import BaseTestCase + + +class TestConvertValueColorStr(BaseTestCase): + def test_lines_dots(self): + with self.subTest("Old format of both line and dot value"): + expected_value_colors = "Line:#00FF00|Dot:#00FF00" + result = convert_value_color_str('linesDots', 'L:G|D:G') + self.assertEqual(result, expected_value_colors) + with self.subTest("Old format of line value"): + expected_value_colors = "Line:#00FF00" + result = convert_value_color_str('linesDots', 'L:G') + self.assertEqual(result, expected_value_colors) + with self.subTest("Old format of default value which is empty string"): + expected_value_colors = "Line:#00FF00" + result = convert_value_color_str('linesDots', '') + self.assertEqual(result, expected_value_colors) + with self.subTest("New format of both line and dot value"): + expected_value_colors = "Line:#00FF00|Dot:#00FF00" + result = convert_value_color_str('linesDots', + "Line:#00FF00|Dot:#00FF00") + self.assertEqual(result, expected_value_colors) + with self.subTest("New format of line value"): + expected_value_colors = "Line:#00FF00" + result = convert_value_color_str('linesDots', "Line:#00FF00") + self.assertEqual(result, expected_value_colors) + + def test_up_down_dots(self): + with self.subTest("Old format"): + expected_value_colors = "Down:#FF0000|Up:#00FF00" + result = convert_value_color_str('upDownDots', '0:R|1:G') + self.assertEqual(result, expected_value_colors) + with self.subTest("New format"): + expected_value_colors = "Down:#FF0000|Up:#00FF00" + result = convert_value_color_str('upDownDots', + "Down:#FF0000|Up:#00FF00") + self.assertEqual(result, expected_value_colors) + + def test_multi_color_dots_equal_on_upper_bound(self): + with self.subTest("Old format"): + expected_value_colors = ('<=0:not plot|<=1:#FFFF00|<=2:#00FF00' + '|2<:#FF00FF') + result = convert_value_color_str( + 'multiColorDotsEqualOnUpperBound', + '0:_|1:Y|2:G|+2:M') + self.assertEqual(result, expected_value_colors) + with self.subTest("New format"): + expected_value_colors = ('<=0:not plot|<=1:#FFFF00|<=2:#00FF00' + '|2<:#FF00FF') + result = convert_value_color_str( + 'multiColorDotsEqualOnUpperBound', + '<=0:not plot|<=1:#FFFF00|<=2:#00FF00|2<:#FF00FF') + self.assertEqual(result, expected_value_colors) + + def test_multi_color_dots_equal_on_lower_bound(self): + with self.subTest("Old format"): + expected_value_colors = '<3:#FF0000|<3.3:#FFFF00|=3.3:#00FF00' + result = convert_value_color_str( + 'multiColorDotsEqualOnLowerBound', + '3:R|3.3:Y|=3.3:G') + self.assertEqual(result, expected_value_colors) + with self.subTest("New format"): + expected_value_colors = '<3:#FF0000|<3.3:#FFFF00|=3.3:#00FF00' + result = convert_value_color_str( + 'multiColorDotsEqualOnLowerBound', + '<3:#FF0000|<3.3:#FFFF00|=3.3:#00FF00') + self.assertEqual(result, expected_value_colors) + + def test_tri_color_lines(self): + with self.subTest("Old format"): + expected_value_colors = '-1:#FF00FF|0:#FF0000|1:#00FF00' + result = convert_value_color_str( + 'triColorLines', + '-1:M|0:R|1:G') + self.assertEqual(result, expected_value_colors) + with self.subTest("New format"): + expected_value_colors = '-1:#FF00FF|0:#FF0000|1:#00FF00' + result = convert_value_color_str( + 'triColorLines', + '-1:#FF00FF|0:#FF0000|1:#00FF00') + self.assertEqual(result, expected_value_colors) + + def test_incorrect_format(self): + with self.subTest("triColorLines"): + expected_value_colors = ('unrecognized:=1:#FF00FF' + '|unrecognized:*0:#FF0000' + '|unrecognized:1.1:#00FF00') + result = convert_value_color_str( + 'triColorLines', + '=1:M|*0:R|1.1:G') + self.assertEqual(result, expected_value_colors) + with self.subTest("upDownDots"): + expected_value_colors = ('unrecognized:2:#FF00FF' + '|unrecognized:Line:#FF0000' + '|unrecognized:1.1:#00FF00' + '|unrecognized:L:#FFFF00') + result = convert_value_color_str( + 'upDownDots', + '2:M|Line:R|1.1:G|L:Y') + self.assertEqual(result, expected_value_colors) + with self.subTest("linesDots"): + expected_value_colors = ('unrecognized:1:#FF00FF' + '|unrecognized:Up:#FF0000' + '|unrecognized:1.1:#00FF00' + '|Line:#FFFF00') + result = convert_value_color_str( + 'linesDots', + '1:M|Up:R|1.1:G|L:Y') + self.assertEqual(result, expected_value_colors) + with self.subTest("multiColorDotsEqualOnUpperBound"): + expected_value_colors = ('unrecognized:*3:#FF0000' + '|unrecognized:<3.3:#FFFF00' + '|unrecognized:=3.3:#00FF00') + result = convert_value_color_str( + 'multiColorDotsEqualOnUpperBound', + '*3:#FF0000|<3.3:#FFFF00|=3.3:#00FF00') + self.assertEqual(result, expected_value_colors) + with self.subTest("multiColorDotsEqualOnLowerBound"): + expected_value_colors = ('unrecognized:+0:#FF0000' + '|unrecognized:-1:#FFFF00' + '|unrecognized:<=2:#00FF00' + '|unrecognized:2<:#FF00FF') + result = convert_value_color_str( + 'multiColorDotsEqualOnLowerBound', + '+0:R|-1:Y|<=2:G|2<:M') + self.assertEqual(result, expected_value_colors) + + def test_old_value_color_str_is_none(self): + result = convert_value_color_str('linesSRate', None) + self.assertEqual(result, '') + + +class TestPrepareValueColorHTML(BaseTestCase): + def test_lines_dots(self): + with self.subTest("Line and dot values"): + expected_value_colors = ( + "<p>Line:" + "<span style='color: #00FF00; font-size:25px;'>∎</span>" + "|Dot:" + "<span style='color: #00FF00; font-size:25px;'>∎</span>" + "</p>") + result = prepare_value_color_html("Line:#00FF00|Dot:#00FF00") + self.assertEqual(result, expected_value_colors) + with self.subTest("Line value"): + expected_value_colors = ( + "<p>Line:<span style='color: #00FF00; font-size:25px;'>∎" + "</span></p>") + result = prepare_value_color_html("Line:#00FF00") + self.assertEqual(result, expected_value_colors) + + def test_up_down_dots(self): + expected_value_colors = ( + "<p>Down:" + "<span style='color: #FF0000; font-size:25px;'>∎</span>" + "|Up:" + "<span style='color: #00FF00; font-size:25px;'>∎</span>" + "</p>") + result = prepare_value_color_html("Down:#FF0000|Up:#00FF00") + self.assertEqual(result, expected_value_colors) + + def test_multi_color_dots_equal_on_upper_bound(self): + expected_value_colors = ( + "<p>≤0:not plot" + "|≤1:" + "<span style='color: #FFFF00; font-size:25px;'>∎</span>" + "|≤2:" + "<span style='color: #00FF00; font-size:25px;'>∎</span>" + "|2<:" + "<span style='color: #FF00FF; font-size:25px;'>∎</span>" + "</p>") + result = prepare_value_color_html( + '<=0:not plot|<=1:#FFFF00|<=2:#00FF00|2<:#FF00FF') + self.assertEqual(result, expected_value_colors) + + def test_multi_color_dots_equal_on_lower_bound(self): + expected_value_colors = ( + "<p><3:not plot" + "|<3.3:" + "<span style='color: #FFFF00; font-size:25px;'>∎</span>" + "|=3.3:" + "<span style='color: #00FF00; font-size:25px;'>∎</span>" + "</p>") + result = prepare_value_color_html( + '<3:not plot|<3.3:#FFFF00|=3.3:#00FF00') + self.assertEqual(result, expected_value_colors) + + def test_tri_color_lines(self): + expected_value_colors = ( + "<p>-1:" + "<span style='color: #FF00FF; font-size:25px;'>∎</span>" + "|0:<span style='color: #FF0000; font-size:25px;'>∎</span>" + "|1:<span style='color: #00FF00; font-size:25px;'>∎</span>" + "</p>" + ) + result = prepare_value_color_html('-1:#FF00FF|0:#FF0000|1:#00FF00') + self.assertEqual(result, expected_value_colors)