test_dashboards.py
1 import json 2 from typing import Dict 3 4 import pytest 5 6 from evidently._pydantic_compat import parse_obj_as 7 from evidently.legacy.base_metric import ColumnName 8 from evidently.legacy.base_metric import InputData 9 from evidently.legacy.base_metric import Metric 10 from evidently.legacy.base_metric import MetricResult 11 from evidently.legacy.base_metric import TResult 12 from evidently.legacy.descriptors import OOV 13 from evidently.legacy.ui.dashboards import PanelValue 14 from evidently.legacy.ui.dashboards.utils import _get_hover_params 15 from evidently.legacy.ui.dashboards.utils import getattr_nested 16 from evidently.pydantic_utils import EvidentlyBaseModel 17 18 19 class A(MetricResult): 20 class Config: 21 alias_required = False 22 23 f: str 24 25 26 class B(MetricResult): 27 class Config: 28 alias_required = False 29 30 f: Dict[str, A] 31 f1: A 32 33 34 @pytest.mark.parametrize( 35 "obj,path,value", 36 [(A(f="a"), "f", "a"), (B(f={}, f1=A(f="a")), "f1.f", "a"), (B(f={"a": A(f="a")}, f1=A(f="b")), "f.a.f", "a")], 37 ) 38 def test_getattr_nested(obj, path: str, value): 39 assert getattr_nested(obj, path.split(".")) == value 40 41 42 def test_panel_value_metric_args_ser(): 43 pv = PanelValue(field_path="", metric_args={"col": OOV(display_name="OOV").for_column("Review_Text")}) 44 45 pl = json.dumps(pv.dict()) 46 pv2 = parse_obj_as(PanelValue, json.loads(pl)) 47 48 assert pv2 == pv 49 50 51 def test_panel_value_methic_hash_filter(): 52 class MyMetric(Metric[A]): 53 class Config: 54 alias_required = False 55 56 arg: str 57 58 def calculate(self, data: InputData) -> TResult: 59 return A(f=self.arg) 60 61 metric1 = MyMetric(arg="1") 62 metric2 = MyMetric(arg="2") 63 pv = PanelValue(field_path="value", metric_fingerprint=metric1.get_fingerprint()) 64 65 assert pv.metric_matched(metric1) 66 assert not pv.metric_matched(metric2) 67 68 69 def test_metric_hover_template(): 70 class Nested(EvidentlyBaseModel): 71 class Config: 72 alias_required = False 73 74 f: str 75 76 class MyMetric(Metric[A]): 77 class Config: 78 alias_required = False 79 80 arg: str 81 n: Nested 82 83 def calculate(self, data: InputData) -> TResult: 84 return A(f=self.arg) 85 86 m1 = MyMetric(arg="1", n=Nested(f="1")) 87 m2 = MyMetric(arg="1", n=Nested(f="2")) 88 m3 = MyMetric(arg="2", n=Nested(f="1")) 89 90 assert _get_hover_params({m1}) == {m1: []} 91 assert _get_hover_params({m1, m2}) == {m1: ["n.f: 1"], m2: ["n.f: 2"]} 92 triple = _get_hover_params({m1, m2, m3}) 93 assert {m: set(lines) for m, lines in triple.items()} == { 94 m1: { 95 "n.f: 1", 96 "arg: 1", 97 }, 98 m2: { 99 "n.f: 2", 100 "arg: 1", 101 }, 102 m3: { 103 "n.f: 1", 104 "arg: 2", 105 }, 106 } 107 108 109 def test_metric_hover_template_column_name(): 110 class MyMetric(Metric[A]): 111 class Config: 112 alias_required = False 113 114 column_name: ColumnName 115 116 def calculate(self, data: InputData) -> TResult: 117 return A(f="") 118 119 m1 = MyMetric(column_name=ColumnName.from_any("col1")) 120 m2 = MyMetric(column_name=ColumnName.from_any("col2")) 121 122 assert _get_hover_params({m1, m2}) == {m1: ["column_name: col1"], m2: ["column_name: col2"]}