Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow query parameters on endpoints. Fix various endpoints. #172

Merged
merged 6 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions grafana_client/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
AsyncDatasource,
AsyncFolder,
AsyncHealth,
AsyncLibraryElement,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this was missing, right? Thanks for spotting, and fixing per 4144e92!

Maybe we can come up with an idea and routine to prevent such details slipping through on future occasions, on behalf of script/generate_async.py, if it's not too much of a hassle?

/cc @Ousret

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be easy to implement, yes.
There's another option, a bit more straightforward (without generate_async.py): "getattr + module async inspect" on init to check if one api is missing in both sync and async. then raise a warning or error.

regards,

AsyncNotifications,
AsyncOrganization,
AsyncOrganizations,
Expand Down Expand Up @@ -235,6 +236,7 @@ def __init__(
self.notifications = AsyncNotifications(self.client)
self.plugin = AsyncPlugin(self.client)
self.serviceaccount = AsyncServiceAccount(self.client)
self.libraryelement = AsyncLibraryElement(self.client, self)

self._grafana_info = None

Expand Down
6 changes: 4 additions & 2 deletions grafana_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def _extract_from_response(r, accept_empty_json):
raise

def __getattr__(self, item):
def __request_runner(url, json=None, data=None, headers=None, accept_empty_json=False):
def __request_runner(url, json=None, data=None, params=None, headers=None, accept_empty_json=False):
__url = self._make_url(url)
# Sanity checks.
self._ensure_valid_json_arg(json)
Expand All @@ -200,6 +200,7 @@ def __request_runner(url, json=None, data=None, headers=None, accept_empty_json=
__url,
json=json,
data=data,
params=params,
headers=headers,
auth=self.auth,
verify=self.verify,
Expand Down Expand Up @@ -244,7 +245,7 @@ def __init__(
self.s.headers.setdefault("Connection", "keep-alive")

def __getattr__(self, item):
async def __request_runner(url, json=None, data=None, headers=None, accept_empty_json=False):
async def __request_runner(url, json=None, data=None, params=None, headers=None, accept_empty_json=False):
__url = self._make_url(url)
# Sanity checks.
self._ensure_valid_json_arg(json)
Expand All @@ -255,6 +256,7 @@ async def __request_runner(url, json=None, data=None, headers=None, accept_empty
__url,
json=json,
data=data,
params=params,
headers=headers,
auth=self.auth,
verify=self.verify,
Expand Down
6 changes: 3 additions & 3 deletions grafana_client/elements/_async/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ async def get_all_folders(self, parent_uid=None):
:return:
"""
path = "/folders"
data = {}
params = {}
if parent_uid:
data["parentUid"] = parent_uid
return await self.client.GET(path, data=data)
params["parentUid"] = parent_uid
return await self.client.GET(path, params=params)

async def get_folder(self, uid):
"""
Expand Down
33 changes: 21 additions & 12 deletions grafana_client/elements/_async/search.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from grafana_client.util import format_param_value

from ..base import Base


Expand All @@ -12,7 +14,9 @@ async def search_dashboards(
tag=None,
type_=None,
dashboard_ids=None,
dashboard_uids=None,
folder_ids=None,
folder_uids=None,
starred=None,
limit=None,
):
Expand All @@ -22,36 +26,41 @@ async def search_dashboards(
:param tag:
:param type_:
:param dashboard_ids:
:param dashboard_uids:
:param folder_ids:
:param folder_uids:
:param starred:
:param limit:
:return:
"""
list_dashboard_path = "/search"
params = []
params = {}

if query:
params.append("query=%s" % query)
params["query"] = query

if tag:
params.append("tag=%s" % tag)
params["tag"] = format_param_value(tag)

if type_:
params.append("type=%s" % type_)
params["type"] = type_

if dashboard_ids:
params.append("dashboardIds=%s" % dashboard_ids)
params["dashboardIds"] = format_param_value(dashboard_ids)

if dashboard_uids:
params["dashboardUIDs"] = format_param_value(dashboard_uids)

if folder_ids:
params.append("folderIds=%s" % folder_ids)
params["folderIds"] = format_param_value(folder_ids)

if folder_uids:
params["folderUIDs"] = format_param_value(folder_uids)

if starred:
params.append("starred=%s" % starred)
params["starred"] = starred

if limit:
params.append("limit=%s" % limit)

list_dashboard_path += "?"
list_dashboard_path += "&".join(params)
params["limit"] = limit

return await self.client.GET(list_dashboard_path)
return await self.client.GET(list_dashboard_path, params=params)
17 changes: 17 additions & 0 deletions grafana_client/elements/_async/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ async def get_user_organisations(self, user_id):
get_user_organisations_path = "/users/%s/orgs" % user_id
return await self.client.GET(get_user_organisations_path)

async def get_user_teams(self, user_id):
"""

:param user_id:
:return:
"""
get_user_teams_path = "/users/%s/teams" % user_id
return await self.client.GET(get_user_teams_path)


class User(Base):
def __init__(self, client):
Expand Down Expand Up @@ -145,6 +154,14 @@ async def get_actual_user_organisations(self):
get_actual_user_organisations_path = "/user/orgs"
return await self.client.GET(get_actual_user_organisations_path)

async def get_actual_user_teams(self):
"""

:return:
"""
get_actual_user_teams_path = "/user/teams"
return await self.client.GET(get_actual_user_teams_path)

async def star_actual_user_dashboard(self, dashboard_id):
"""

Expand Down
6 changes: 3 additions & 3 deletions grafana_client/elements/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ def get_all_folders(self, parent_uid=None):
:return:
"""
path = "/folders"
data = {}
params = {}
if parent_uid:
data["parentUid"] = parent_uid
return self.client.GET(path, data=data)
params["parentUid"] = parent_uid
return self.client.GET(path, params=params)

def get_folder(self, uid):
"""
Expand Down
33 changes: 21 additions & 12 deletions grafana_client/elements/search.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from grafana_client.util import format_param_value

from .base import Base


Expand All @@ -12,7 +14,9 @@
tag=None,
type_=None,
dashboard_ids=None,
dashboard_uids=None,
folder_ids=None,
folder_uids=None,
starred=None,
limit=None,
):
Expand All @@ -22,36 +26,41 @@
:param tag:
:param type_:
:param dashboard_ids:
:param dashboard_uids:
:param folder_ids:
:param folder_uids:
:param starred:
:param limit:
:return:
"""
list_dashboard_path = "/search"
params = []
params = {}

if query:
params.append("query=%s" % query)
params["query"] = query

if tag:
params.append("tag=%s" % tag)
params["tag"] = format_param_value(tag)

if type_:
params.append("type=%s" % type_)
params["type"] = type_

if dashboard_ids:
params.append("dashboardIds=%s" % dashboard_ids)
params["dashboardIds"] = format_param_value(dashboard_ids)

if dashboard_uids:
params["dashboardUIDs"] = format_param_value(dashboard_uids)

Check warning on line 52 in grafana_client/elements/search.py

View check run for this annotation

Codecov / codecov/patch

grafana_client/elements/search.py#L52

Added line #L52 was not covered by tests

if folder_ids:
params.append("folderIds=%s" % folder_ids)
params["folderIds"] = format_param_value(folder_ids)

if folder_uids:
params["folderUIDs"] = format_param_value(folder_uids)

Check warning on line 58 in grafana_client/elements/search.py

View check run for this annotation

Codecov / codecov/patch

grafana_client/elements/search.py#L58

Added line #L58 was not covered by tests

if starred:
params.append("starred=%s" % starred)
params["starred"] = starred

if limit:
params.append("limit=%s" % limit)

list_dashboard_path += "?"
list_dashboard_path += "&".join(params)
params["limit"] = limit

return self.client.GET(list_dashboard_path)
return self.client.GET(list_dashboard_path, params=params)
17 changes: 17 additions & 0 deletions grafana_client/elements/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@
get_user_organisations_path = "/users/%s/orgs" % user_id
return self.client.GET(get_user_organisations_path)

def get_user_teams(self, user_id):
"""

:param user_id:
:return:
"""
get_user_teams_path = "/users/%s/teams" % user_id
return self.client.GET(get_user_teams_path)

Check warning on line 95 in grafana_client/elements/user.py

View check run for this annotation

Codecov / codecov/patch

grafana_client/elements/user.py#L94-L95

Added lines #L94 - L95 were not covered by tests


class User(Base):
def __init__(self, client):
Expand Down Expand Up @@ -145,6 +154,14 @@
get_actual_user_organisations_path = "/user/orgs"
return self.client.GET(get_actual_user_organisations_path)

def get_actual_user_teams(self):
"""

:return:
"""
get_actual_user_teams_path = "/user/teams"
return self.client.GET(get_actual_user_teams_path)

Check warning on line 163 in grafana_client/elements/user.py

View check run for this annotation

Codecov / codecov/patch

grafana_client/elements/user.py#L162-L163

Added lines #L162 - L163 were not covered by tests

def star_actual_user_dashboard(self, dashboard_id):
"""

Expand Down
7 changes: 7 additions & 0 deletions grafana_client/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,10 @@
return _STR_BOOLEAN_MAPPING[value.lower()]
except KeyError:
raise ValueError(f"invalid truth value {value}")


def format_param_value(maybe_list):
if isinstance(maybe_list, list):
return ",".join([str(x) for x in maybe_list])

Check warning on line 46 in grafana_client/util.py

View check run for this annotation

Codecov / codecov/patch

grafana_client/util.py#L46

Added line #L46 was not covered by tests
else:
return maybe_list
4 changes: 3 additions & 1 deletion test/test_grafana_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from grafana_client.api import GrafanaApi
from grafana_client.client import (
GrafanaClientError,
GrafanaServerError,
GrafanaTimeoutError,
HeaderAuth,
TokenAuth,
Expand Down Expand Up @@ -95,6 +96,7 @@ def test_grafana_client_no_verify(self):
auth=basic_auth,
headers=None,
json=None,
params=None,
data=None,
verify=False,
timeout=5.0,
Expand Down Expand Up @@ -160,7 +162,7 @@ def test_grafana_client_version(self, mock_get):

def test_grafana_client_non_json_response(self):
grafana = GrafanaApi.from_url("https://example.org/")
self.assertRaises(GrafanaClientError, lambda: grafana.connect())
self.assertRaises((GrafanaClientError, GrafanaServerError), lambda: grafana.connect())
Comment on lines -163 to +165
Copy link
Contributor

@amotl amotl Apr 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, the issue with the tests failing seems to be on line 163 of test_grafana_client.py and the behavior (?) of https://example.org/.

Indeed, example.org, on its /api endpoint, seems to respond with both 500 and 404 status codes now, specifically with HTTP 500 on /api/health.

HTTP/1.1 404 Not Found

http HEAD https://example.org/api/foo
http HEAD https://example.org/api/hello

HTTP/1.1 500 Internal Server Error

http HEAD https://example.org/api/bar
http HEAD https://example.org/api/world
http HEAD https://example.org/api/health

It's weird, but c'est la vie, right?


def test_grafana_client_204_no_content_response(self):
grafana = GrafanaApi.from_url()
Expand Down