/ tests / ui / test_dashboards.py
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"]}