From d65ef2776788cbcbf1de1f5b6756ae03d1109141 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Fri, 29 Mar 2024 20:25:02 +0100 Subject: [PATCH] Accept `datasource` attribute on `DatasourceItem`, but don't process it > When I try to explore datasources it always fail with a TypeError. > No idea why this happens. Exception: TypeError: DatasourceItem.__init__() got an unexpected keyword argument 'datasource' --- CHANGES.rst | 6 +++-- grafana_wtf/model.py | 27 ++++++++++++++++++++- tests/test_model.py | 57 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 tests/test_model.py diff --git a/CHANGES.rst b/CHANGES.rst index 440cddf..e13ec51 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,8 +6,10 @@ grafana-wtf changelog in progress =========== - CI: Verify support for Grafana 11 -- AMG compatibility: Fetch Grafana version from `/api/frontend/settings` - instead of `/api/health`. Thanks, @squadgazzz. +- AMG compatibility: Fetch Grafana version from ``/api/frontend/settings`` + instead of ``/api/health``. Thanks, @squadgazzz. +- Accept ``datasource`` attribute on ``DatasourceItem``, but + ignore it for the time being. Thanks, @apepojken. 2024-04-20 0.19.1 ================= diff --git a/grafana_wtf/model.py b/grafana_wtf/model.py index fd27fe4..15fbe67 100644 --- a/grafana_wtf/model.py +++ b/grafana_wtf/model.py @@ -3,8 +3,9 @@ # License: GNU Affero General Public License, Version 3 import dataclasses import logging +import warnings from collections import OrderedDict -from typing import Dict, List, Optional +from typing import Any, Dict, List, Optional from urllib.parse import urljoin from munch import Munch @@ -158,6 +159,10 @@ def transform(section): @dataclasses.dataclass class DatasourceItem: + """ + Represent a datasource reference within a panel, annotation, or templating (variable). + """ + uid: Optional[str] = None name: Optional[str] = None type: Optional[str] = None @@ -168,11 +173,31 @@ def from_payload(cls, payload: any): if isinstance(payload, Munch): payload = dict(payload) if isinstance(payload, dict): + cls.validate(payload) return cls(**payload) if isinstance(payload, str): return cls(name=payload) raise TypeError(f"Unknown payload type for DatasourceItem: {type(payload)}") + @classmethod + def validate(cls, data: dict): + if "datasource" in data: + warnings.warn( + f""" +The `datasource` attribute is ignored for the time being. + +See also: https://github.com/panodata/grafana-wtf/issues/110 + +Please report back this occurrence to the grafana-wtf issue tracker, +so the maintainers can improve the situation. + +The context of this error is in `DatasourceItem`, using this ingress data: +{data} +""".strip(), + UserWarning, + ) + del data["datasource"] + @dataclasses.dataclass class DatasourceExplorationItem: diff --git a/tests/test_model.py b/tests/test_model.py new file mode 100644 index 0000000..fa51313 --- /dev/null +++ b/tests/test_model.py @@ -0,0 +1,57 @@ +import re + +import pytest +from munch import Munch + +from grafana_wtf.model import DatasourceItem + +DATA = dict(uid="foo", name="bar", type="baz", url="qux") + + +def test_datasource_item_basic(): + item = DatasourceItem(**DATA) + assert item.uid == "foo" + + +def test_datasource_item_dict_success(): + item = DatasourceItem.from_payload(DATA) + assert item.uid == "foo" + + +def test_datasource_item_munch(): + item = DatasourceItem.from_payload(Munch(**DATA)) + assert item.uid == "foo" + + +def test_datasource_item_str(): + item = DatasourceItem.from_payload("Hotzenplotz") + assert item.uid is None + assert item.name == "Hotzenplotz" + + +def test_datasource_item_dict_unknown_attribute(): + mydata = DATA.copy() + mydata.update({"more": "data"}) + with pytest.raises(TypeError) as ex: + DatasourceItem.from_payload(mydata) + assert ex.match(re.escape("__init__() got an unexpected keyword argument 'more'")) + + +def test_datasource_item_dict_compensate_datasource(): + """ + Validate that the `datasource` attribute is ignored. + + TypeError: DatasourceItem.__init__() got an unexpected keyword argument 'datasource' + https://github.com/panodata/grafana-wtf/issues/110 + """ + mydata = DATA.copy() + mydata.update({"datasource": "unknown"}) + with pytest.warns(UserWarning) as record: + item = DatasourceItem.from_payload(mydata) + assert item.uid == "foo" + + # Check that only one warning was raised. + assert len(record) == 1 + + # Check that the message matches. + assert "The `datasource` attribute is ignored for the time being" in record[0].message.args[0]