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

feat: add gateway service #50

Merged
merged 1 commit into from
Apr 2, 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
3 changes: 3 additions & 0 deletions src/waylay/sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Optional

from waylay.sdk.services.gateway import GatewayService

from .plugin.client import WithServicesAndTools
from .config.client import WaylayConfig, WithConfig, HttpClientOptions
from .api import ApiClient
Expand All @@ -23,6 +25,7 @@
class WaylayClient(WithConfig, WithServicesAndTools):
"""REST client for the Waylay Platform."""

gateway: GatewayService
alarms: "AlarmsService"
data: "DataService"
registry: "RegistryService"
Expand Down
4 changes: 2 additions & 2 deletions src/waylay/sdk/plugin/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
from typing import Type, List

from .base import WaylayPlugin
from waylay.sdk.services.gateway import GatewayService

# no default services or tools for now.
PLUGINS: List[Type[WaylayPlugin]] = []
PLUGINS: List[Type[WaylayPlugin]] = [GatewayService]
160 changes: 160 additions & 0 deletions src/waylay/sdk/services/gateway.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
"""Gateway Service."""

from __future__ import annotations

from typing import Any, Dict, Literal, TypeVar, overload
from pydantic import ConfigDict

from waylay.sdk.api.client import ApiClient
from waylay.sdk.api.http import HeaderTypes, QueryParamTypes, Response
from waylay.sdk.plugin.base import WaylayService, WithApiClient
from waylay.sdk.api._models import BaseModel as WaylayBaseModel, Model

T = TypeVar("T")


class GatewayService(WaylayService):
"""Gateway Service Class."""

name = "gateway"
title = "Gateway Service"

about: AboutApi

def __init__(self, api_client: ApiClient):
"""Create the gateway service."""
super().__init__(api_client)
self.about = AboutApi(api_client)


class AboutApi(WithApiClient):
"""About service methods."""

@overload
async def get(
self,
*,
query: QueryParamTypes | None = None,
raw_response: Literal[False] = False,
select_path: Literal[""] = "",
response_type: Literal[None] = None,
headers: HeaderTypes | None = None,
**kwargs,
) -> GatewayResponse: ...

@overload
async def get(
self,
*,
query: QueryParamTypes | None = None,
raw_response: Literal[False] = False,
select_path: Literal[""] = "",
response_type: T,
headers: HeaderTypes | None = None,
**kwargs,
) -> T: ...

@overload
async def get(
self,
*,
query: QueryParamTypes | None = None,
raw_response: Literal[True],
select_path: Literal["_not_used_"] = "_not_used_",
response_type: Literal[None] = None, # not used
headers: HeaderTypes | None = None,
**kwargs,
) -> Response: ...

@overload
async def get(
self,
*,
query: QueryParamTypes | None = None,
raw_response: Literal[False] = False,
select_path: str,
response_type: Literal[None] = None,
headers: HeaderTypes | None = None,
**kwargs,
) -> Model: ...

@overload
async def get(
self,
*,
query: QueryParamTypes | None = None,
raw_response: Literal[False] = False,
select_path: str,
response_type: T,
headers: HeaderTypes | None = None,
**kwargs,
) -> T: ...

async def get(
self,
*,
query: QueryParamTypes | None = None,
raw_response: bool = False,
select_path: str = "",
response_type: T | None = None,
headers: HeaderTypes | None = None,
**kwargs,
) -> GatewayResponse | T | Response | Model:
"""Get the status of the gateway.

:param query: URL Query parameters.
:type query: QueryParamTypes, optional
:param raw_response: If true, return the http Response object instead of returning an api model object, or throwing an ApiError.
:param select_path: Denotes the json path applied to the response object before returning it.
Set it to the empty string `""` to receive the full response object.
:param response_type: If specified, the response is parsed into an instance of the specified type.
:param headers: Header parameters for this request
:type headers: dict, optional
:param `**kwargs`: Additional parameters passed on to the http client.
See below.
:Keyword Arguments:
* timeout: a single numeric timeout in seconds,
or a tuple of _connect_, _read_, _write_ and _pool_ timeouts.
* stream: if true, the response will be in streaming mode
* cookies
* extensions
* auth
* follow_redirects: bool

:return: Returns the result object if the http request succeeded with status code '2XX'.
:raises APIError: If the http request has a status code different from `2XX`. This
object wraps both the http Response and any parsed data.
"""
response_type_map: Dict[str, Any] = (
{"2XX": response_type}
if response_type is not None
else {
"200": GatewayResponse if not select_path else Model,
}
)
return await self.api_client.request(
method="GET",
resource_path="/",
path_params={},
params=query,
headers=headers,
response_type=response_type_map,
select_path=select_path,
raw_response=raw_response,
**kwargs,
)


class GatewayResponse(WaylayBaseModel):
"""Gateway status response."""

name: str
version: str
health: str

model_config = ConfigDict(
populate_by_name=True,
validate_assignment=True,
protected_namespaces=(),
extra="allow",
)
26 changes: 26 additions & 0 deletions test/unit/services/gateway_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import pytest
from pytest_httpx import HTTPXMock
from typeguard import check_type

from waylay.sdk.client import WaylayClient
from waylay.sdk.services.gateway import GatewayResponse, GatewayService


def test_gateway_service_loaded(client: WaylayClient):
"""Test plugin classes are loaded."""
assert isinstance(client.gateway, GatewayService)


@pytest.mark.asyncio
async def test_gateway_about(client: WaylayClient, httpx_mock: HTTPXMock):
"""Test gateway about status check"""
httpx_mock.add_response(
method="GET",
url=client.config.gateway_url + "/",
json={"name": "gateway", "version": "1.2.3", "health": "OK"},
status_code=200,
)
client.api_client.set_options({"auth": None})
async with client:
resp = await client.gateway.about.get()
check_type(resp, GatewayResponse)