Repository: kangasta/fdbk

Issue:
Data tools should support custom warnings
Forked from #45.

Add option to status data tool to show warning instead of updating status. This could be a separate `warning` function.

Discussion:

Patch:
diff --git a/fdbk/data_tools/_run.py b/fdbk/data_tools/_run.py
index 442a1ef..7e7ec06 100644
--- a/fdbk/data_tools/_run.py
+++ b/fdbk/data_tools/_run.py
@@ -94,7 +94,7 @@ def run_data_tools(
                 instruction.get("field"),
                 instruction.get("parameters")
             )
-        except ValueError as error:
+        except (AssertionError, ValueError) as error:
             warnings.append(str(error))
             result = None
 
diff --git a/fdbk/data_tools/functions/_status_funcs.py b/fdbk/data_tools/functions/_status_funcs.py
index 3756fc4..6a49fd5 100644
--- a/fdbk/data_tools/functions/_status_funcs.py
+++ b/fdbk/data_tools/functions/_status_funcs.py
@@ -21,11 +21,14 @@ OPERATORS = {
 
 
 def _get_value(method, data, field, parameters=None):
+    if method not in functions:
+        raise ValueError(method_not_supported(method))
+
     value_d = functions.get(method)(data, field, parameters)
     return value_d.get("payload", {}).get("value")
 
 
-def _get_parameters(parameters=None):
+def _get_status_parameters(parameters=None):
     default = parameters.get("default")
     checks = parameters.get("checks", [])
     short_circuit = parameters.get("short_circuit", False)
@@ -34,6 +37,14 @@ def _get_parameters(parameters=None):
     return default, checks, short_circuit, method
 
 
+def _get_warning_parameters(parameters=None):
+    check = parameters.get("check")
+    message = parameters.get("message")
+    method = parameters.get("method", "latest")
+
+    return check, message, method
+
+
 def _run_assertion(assertion, value, other):
     if assertion not in ASSERTIONS:  # pragma: no cover
         raise RuntimeError(f"Assertion {assertion} was not recognized")
@@ -45,7 +56,7 @@ def _run_assertion(assertion, value, other):
 
 
 def _run_check(value, check):
-    status = check.get("status")
+    status = check.get("status", 'WARNING')
     operator = str(check.get("operator", 'or')).lower()
 
     result = False if operator == 'or' else True
@@ -72,13 +83,11 @@ def status(data, field, parameters=None):
 
     warnings = []
     try:
-        default, checks, short_circuit, method = _get_parameters(parameters)
+        default, checks, short_circuit, method = _get_status_parameters(
+            parameters)
     except BaseException:
         return None
 
-    if method not in functions:
-        raise ValueError(method_not_supported(method))
-
     value = _get_value(method, data, field, parameters)
 
     status_d = dict(field=field, status=default, reason=None)
@@ -104,6 +113,26 @@ def status(data, field, parameters=None):
     return status_dict(**status_d)
 
 
+def warning(data, field, parameters=None):
+    if not len(data):
+        return None
+
+    try:
+        check, message, method = _get_warning_parameters(parameters)
+    except BaseException:
+        return None
+
+    if not check or not message:
+        return None
+
+    value = _get_value(method, data, field, parameters)
+    warning = _run_check(value, check)
+
+    if warning:
+        raise AssertionError(message)
+
+
 STATUS_FUNCS = dict(
-    status=status
+    status=status,
+    warning=warning,
 )


Test patch:
diff --git a/tst/test_data_tools.py b/tst/test_data_tools.py
index bdd1200..3fc8b96 100644
--- a/tst/test_data_tools.py
+++ b/tst/test_data_tools.py
@@ -217,3 +217,29 @@ class DataToolsTest(TestCase):
         self.assertEqual(aggregated[0]["number"], 1)
         self.assertEqual(aggregated[1]["number"], 3)
         self.assertEqual(warnings, [])
+
+    def test_warning_functions(self):
+        topic_d = STATUS_TOPIC
+        data = generate_test_data()
+
+        for check, expected in [
+            (dict(operator='and', gte=4, lte=6), ["Test warning"]),
+            (dict(operator='and', gte=6, lte=4), []),
+        ]:
+            parameters=dict(
+                method="average",
+                message="Test warning",
+                check=check,
+            )
+
+            topic_d['data_tools'] = [
+                dict(field='number', method="warning", parameters=parameters),
+            ]
+
+            results, warnings = run_data_tools(topic_d, data)
+
+            self.assertEqual(len(results), 0)
+            self.assertEqual(len(warnings), len(expected))
+
+            if expected:
+                self.assertEqual(warnings[0], "Test warning")