Skip to content
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: 1 addition & 1 deletion .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
run: export PYTHONPATH=$PWD && uv run --extra dev pytest --junitxml=pytest.xml --cov=perses_api --cov-report xml tests/unit/ | tee pytest-coverage.txt

- name: Execute the coverage checks
uses: MishaKav/pytest-coverage-comment@v1.10.0
uses: MishaKav/pytest-coverage-comment@v1.11.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
pytest-coverage-path: ./pytest-coverage.txt
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ client = APIModel(host="http://localhost:8080", username="admin", password="secr
client = APIModel(
host="http://localhost:8080",
token="<token>",
timeout=30.0, # request timeout in seconds (default: 10)
http2_support=False, # enable HTTP/2 (requires httpx[http2])
num_pools=10, # max concurrent connections
retries=False, # retry failed requests
timeout=30.0, # request timeout in seconds (default: 10)
http2_support=False, # enable HTTP/2 (requires httpx[http2])
num_pools=10, # max concurrent connections
retries=False, # retry failed requests
follow_redirects=True, # follow HTTP redirects
)
```
Expand Down
2 changes: 1 addition & 1 deletion docs/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 17 additions & 17 deletions perses_api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
from .model import APIModel
from .api import Api
from .project import Project
from .dashboard import Dashboard
from .datasource import GlobalDatasource, ProjectDatasource
from .ephemeral_dashboard import EphemeralDashboard
from .datasource import ProjectDatasource, GlobalDatasource
from .variable import ProjectVariable, GlobalVariable
from .role import ProjectRole, GlobalRole
from .role_binding import ProjectRoleBinding, GlobalRoleBinding
from .secret import ProjectSecret, GlobalSecret
from .user import User
from .plugin import Plugin
from .migrate import Migrate
from .model import APIModel
from .plugin import Plugin
from .project import Project
from .role import GlobalRole, ProjectRole
from .role_binding import GlobalRoleBinding, ProjectRoleBinding
from .secret import GlobalSecret, ProjectSecret
from .user import User
from .validate import Validate
from .variable import GlobalVariable, ProjectVariable

__all__ = [
"APIModel",
"Api",
"Project",
"Dashboard",
"EphemeralDashboard",
"ProjectDatasource",
"GlobalDatasource",
"ProjectVariable",
"GlobalRole",
"GlobalRoleBinding",
"GlobalSecret",
"GlobalVariable",
"Migrate",
"Plugin",
"Project",
"ProjectDatasource",
"ProjectRole",
"GlobalRole",
"ProjectRoleBinding",
"GlobalRoleBinding",
"ProjectSecret",
"GlobalSecret",
"ProjectVariable",
"User",
"Plugin",
"Migrate",
"Validate",
]
20 changes: 11 additions & 9 deletions perses_api/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import logging

from .api import Api

logger = logging.getLogger(__name__)
from .model import APIModel, RequestsMethods


Expand Down Expand Up @@ -30,7 +32,7 @@ def _base_path(self) -> str:
"""
raise NotImplementedError

def _get_all(self, name: str = None) -> list:
def _get_all(self, name: str | None = None) -> list:
"""The method includes a functionality to retrieve all resources, optionally filtered by name

Args:
Expand All @@ -47,8 +49,8 @@ def _get_all(self, name: str = None) -> list:
path = f"{path}?name={name}"
result = self.api.call_the_api(path)
if not isinstance(result, list):
logging.error(f"Failed to retrieve resources from {self._base_path()}.")
raise Exception(result)
logger.error(f"Failed to retrieve resources from {self._base_path()}.")
raise TypeError(result)
return result

def _get_one(self, name: str) -> dict:
Expand All @@ -68,8 +70,8 @@ def _get_one(self, name: str) -> dict:
raise ValueError("name must not be empty")
result = self.api.call_the_api(f"{self._base_path()}/{name}")
if not isinstance(result, dict):
logging.error(f"Failed to retrieve resource: {name}")
raise Exception(result)
logger.error(f"Failed to retrieve resource: {name}")
raise TypeError(result)
return result

def _create(self, body) -> dict:
Expand All @@ -90,8 +92,8 @@ def _create(self, body) -> dict:
json_complete=body.model_dump_json(by_alias=True, exclude_none=True),
)
if not isinstance(result, dict):
logging.error(f"Failed to create resource at {self._base_path()}.")
raise Exception(result)
logger.error(f"Failed to create resource at {self._base_path()}.")
raise TypeError(result)
return result

def _update(self, name: str, body) -> dict:
Expand All @@ -116,8 +118,8 @@ def _update(self, name: str, body) -> dict:
json_complete=body.model_dump_json(by_alias=True, exclude_none=True),
)
if not isinstance(result, dict):
logging.error(f"Failed to update resource: {name}")
raise Exception(result)
logger.error(f"Failed to update resource: {name}")
raise TypeError(result)
return result

def _delete(self, name: str) -> None:
Expand Down
14 changes: 8 additions & 6 deletions perses_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import base64
import json
import logging
from typing import Any, Union
from typing import Any

import httpx

from .model import APIModel, RequestsMethods

logger = logging.getLogger(__name__)


class Api:
"""The class includes all necessary methods to access the Perses API
Expand All @@ -28,7 +30,7 @@ def call_the_api(
self,
api_call: str,
method: RequestsMethods = RequestsMethods.GET,
json_complete: str = None,
json_complete: str | None = None,
response_status_code: bool = False,
) -> Any:
"""The method includes a functionality to execute a defined API call against the Perses endpoints
Expand Down Expand Up @@ -77,8 +79,8 @@ async def _run():
return self._check_the_api_call_response(response, response_status_code)

def create_the_http_api_client(
self, headers: dict = None
) -> Union[httpx.Client, httpx.AsyncClient]:
self, headers: dict | None = None
) -> httpx.Client | httpx.AsyncClient:
"""The method includes a functionality to create the HTTP client based on the API model configuration

Args:
Expand Down Expand Up @@ -119,7 +121,7 @@ def create_the_http_api_client(

def _send_request(
self,
http: Union[httpx.Client, httpx.AsyncClient],
http: httpx.Client | httpx.AsyncClient,
method: RequestsMethods,
api_url: str,
json_complete: str,
Expand All @@ -141,7 +143,7 @@ def _send_request(
if method in (RequestsMethods.GET, RequestsMethods.DELETE):
return http.request(method.value, api_url)
if json_complete is None:
logging.error("Please define the json_complete.")
logger.error("Please define the json_complete.")
raise ValueError(f"json_complete is required for {method.value}")
return http.request(method.value, api_url, content=json_complete)

Expand Down
22 changes: 12 additions & 10 deletions perses_api/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import logging

from .api import Api
from .model import APIModel, APIEndpoints, RequestsMethods

logger = logging.getLogger(__name__)
from .model import APIEndpoints, APIModel, RequestsMethods
from .model import Dashboard as DashboardModel


Expand All @@ -20,7 +22,7 @@ class Dashboard:
def __init__(self, perses_api_model: APIModel):
self.api = Api(perses_api_model)

def get_dashboards(self, project_name: str, name: str = None) -> list:
def get_dashboards(self, project_name: str, name: str | None = None) -> list:
"""The method includes a functionality to retrieve all dashboards within a project

Args:
Expand All @@ -41,8 +43,8 @@ def get_dashboards(self, project_name: str, name: str = None) -> list:
path = f"{path}?name={name}"
result = self.api.call_the_api(path)
if not isinstance(result, list):
logging.error("Failed to retrieve dashboards.")
raise Exception(result)
logger.error("Failed to retrieve dashboards.")
raise TypeError(result)
return result

def get_dashboard(self, project_name: str, name: str) -> dict:
Expand All @@ -67,8 +69,8 @@ def get_dashboard(self, project_name: str, name: str) -> dict:
APIEndpoints.DASHBOARD.value.format(project=project_name, name=name)
)
if not isinstance(result, dict):
logging.error(f"Failed to retrieve dashboard: {name}")
raise Exception(result)
logger.error(f"Failed to retrieve dashboard: {name}")
raise TypeError(result)
return result

def create_dashboard(self, project_name: str, dashboard: DashboardModel) -> dict:
Expand All @@ -93,8 +95,8 @@ def create_dashboard(self, project_name: str, dashboard: DashboardModel) -> dict
json_complete=dashboard.model_dump_json(by_alias=True, exclude_none=True),
)
if not isinstance(result, dict):
logging.error("Failed to create dashboard.")
raise Exception(result)
logger.error("Failed to create dashboard.")
raise TypeError(result)
return result

def update_dashboard(
Expand Down Expand Up @@ -124,8 +126,8 @@ def update_dashboard(
json_complete=dashboard.model_dump_json(by_alias=True, exclude_none=True),
)
if not isinstance(result, dict):
logging.error(f"Failed to update dashboard: {name}")
raise Exception(result)
logger.error(f"Failed to update dashboard: {name}")
raise TypeError(result)
return result

def delete_dashboard(self, project_name: str, name: str) -> None:
Expand Down
4 changes: 2 additions & 2 deletions perses_api/datasource.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from ._base import ResourceBase
from .model import APIModel, APIEndpoints
from .model import APIEndpoints, APIModel


class DatasourceBase(ResourceBase):
Expand All @@ -14,7 +14,7 @@ class DatasourceBase(ResourceBase):
api (Api): This is where we store the api
"""

def get_datasources(self, name: str = None) -> list:
def get_datasources(self, name: str | None = None) -> list:
"""The method includes a functionality to retrieve all datasources

Args:
Expand Down
24 changes: 14 additions & 10 deletions perses_api/ephemeral_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import logging

from .api import Api
from .model import APIModel, APIEndpoints, RequestsMethods

logger = logging.getLogger(__name__)
from .model import APIEndpoints, APIModel, RequestsMethods
from .model import EphemeralDashboard as EphemeralDashboardModel


Expand All @@ -20,7 +22,9 @@ class EphemeralDashboard:
def __init__(self, perses_api_model: APIModel):
self.api = Api(perses_api_model)

def get_ephemeral_dashboards(self, project_name: str, name: str = None) -> list:
def get_ephemeral_dashboards(
self, project_name: str, name: str | None = None
) -> list:
"""The method includes a functionality to retrieve all ephemeral dashboards within a project

Args:
Expand All @@ -41,8 +45,8 @@ def get_ephemeral_dashboards(self, project_name: str, name: str = None) -> list:
path = f"{path}?name={name}"
result = self.api.call_the_api(path)
if not isinstance(result, list):
logging.error("Failed to retrieve ephemeral dashboards.")
raise Exception(result)
logger.error("Failed to retrieve ephemeral dashboards.")
raise TypeError(result)
return result

def get_ephemeral_dashboard(self, project_name: str, name: str) -> dict:
Expand All @@ -69,8 +73,8 @@ def get_ephemeral_dashboard(self, project_name: str, name: str) -> dict:
)
)
if not isinstance(result, dict):
logging.error(f"Failed to retrieve ephemeral dashboard: {name}")
raise Exception(result)
logger.error(f"Failed to retrieve ephemeral dashboard: {name}")
raise TypeError(result)
return result

def create_ephemeral_dashboard(
Expand Down Expand Up @@ -99,8 +103,8 @@ def create_ephemeral_dashboard(
),
)
if not isinstance(result, dict):
logging.error("Failed to create ephemeral dashboard.")
raise Exception(result)
logger.error("Failed to create ephemeral dashboard.")
raise TypeError(result)
return result

def update_ephemeral_dashboard(
Expand Down Expand Up @@ -134,8 +138,8 @@ def update_ephemeral_dashboard(
),
)
if not isinstance(result, dict):
logging.error(f"Failed to update ephemeral dashboard: {name}")
raise Exception(result)
logger.error(f"Failed to update ephemeral dashboard: {name}")
raise TypeError(result)
return result

def delete_ephemeral_dashboard(self, project_name: str, name: str) -> None:
Expand Down
16 changes: 10 additions & 6 deletions perses_api/migrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import logging

from .api import Api
from .model import APIModel, APIEndpoints, RequestsMethods

logger = logging.getLogger(__name__)
from .model import APIEndpoints, APIModel, RequestsMethods


class Migrate:
Expand All @@ -20,7 +22,9 @@ class Migrate:
def __init__(self, perses_api_model: APIModel):
self.api = Api(perses_api_model)

def migrate(self, grafana_dashboard: dict, migration_input: dict = None) -> dict:
def migrate(
self, grafana_dashboard: dict, migration_input: dict | None = None
) -> dict:
"""The method includes a functionality to migrate a Grafana dashboard to the Perses format

Args:
Expand All @@ -45,10 +49,10 @@ def migrate(self, grafana_dashboard: dict, migration_input: dict = None) -> dict
json_complete=json.dumps(body),
)
if not isinstance(result, dict):
logging.error("Migration failed.")
raise Exception(result)
logger.error("Migration failed.")
raise TypeError(result)
if "kind" not in result:
error_msg = result.get("message", "Unknown error")
logging.error(f"Migration failed: {error_msg}")
raise Exception(result)
logger.error(f"Migration failed: {error_msg}")
raise TypeError(result)
return result
Loading