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
71 changes: 11 additions & 60 deletions mpt_api_client/http/async_service.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
from urllib.parse import urljoin

from mpt_api_client.constants import APPLICATION_JSON
from mpt_api_client.http.async_client import AsyncHTTPClient
from mpt_api_client.http.base_service import ServiceBase
from mpt_api_client.http.types import QueryParam, Response
from mpt_api_client.http.resource_accessor import AsyncResourceAccessor
from mpt_api_client.http.url_utils import join_url_path
from mpt_api_client.models import Model as BaseModel
from mpt_api_client.models import ResourceData
from mpt_api_client.models.collection import ResourceList


class AsyncService[Model: BaseModel](ServiceBase[AsyncHTTPClient, Model]): # noqa: WPS214
Expand All @@ -21,60 +17,15 @@ class AsyncService[Model: BaseModel](ServiceBase[AsyncHTTPClient, Model]): # no

"""

async def _resource_do_request( # noqa: WPS211
self,
resource_id: str,
method: str = "GET",
action: str | None = None,
json: ResourceData | ResourceList | None = None,
query_params: QueryParam | None = None,
headers: dict[str, str] | None = None,
) -> Response:
"""Perform an action on a specific resource using.

Request with action: `HTTP_METHOD /endpoint/{resource_id}/{action}`.
Request without action: `HTTP_METHOD /endpoint/{resource_id}`.

Args:
resource_id: The resource ID to operate on.
method: The HTTP method to use.
action: The action name to use.
json: The updated resource data.
query_params: Additional query parameters.
headers: Additional headers.

Raises:
HTTPError: If the action fails.
"""
resource_url = urljoin(f"{self.path}/", resource_id)
url = urljoin(f"{resource_url}/", action) if action else resource_url
return await self.http_client.request(
method, url, json=json, query_params=query_params, headers=headers
)
def _resource(self, resource_id: str) -> AsyncResourceAccessor[Model]:
"""Return an :class:`AsyncResourceAccessor` bound to *resource_id*.

async def _resource_action(
self,
resource_id: str,
method: str = "GET",
action: str | None = None,
json: ResourceData | ResourceList | None = None,
query_params: QueryParam | None = None,
) -> Model:
"""Perform an action on a specific resource using `HTTP_METHOD /endpoint/{resource_id}`.
Usage::

Args:
resource_id: The resource ID to operate on.
method: The HTTP method to use.
action: The action name to use.
json: The updated resource data.
query_params: Additional query parameters.
await self._resource("RES-123").post("complete", json=data)
await self._resource("RES-123").get()
await self._resource("RES-123").put(json=data)
await self._resource("RES-123").delete()
"""
response = await self._resource_do_request(
resource_id,
method,
action,
json=json,
query_params=query_params,
headers={"Accept": APPLICATION_JSON},
)
return self._model_class.from_response(response)
resource_url = join_url_path(self.path, resource_id)
return AsyncResourceAccessor(self.http_client, resource_url, self._model_class)
8 changes: 2 additions & 6 deletions mpt_api_client/http/mixins/delete_mixin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from urllib.parse import urljoin


class DeleteMixin:
"""Delete resource mixin."""

Expand All @@ -10,7 +7,7 @@ def delete(self, resource_id: str) -> None:
Args:
resource_id: Resource ID.
"""
self._resource_do_request(resource_id, "DELETE") # type: ignore[attr-defined]
self._resource(resource_id).delete() # type: ignore[attr-defined]


class AsyncDeleteMixin:
Expand All @@ -22,5 +19,4 @@ async def delete(self, resource_id: str) -> None:
Args:
resource_id: Resource ID.
"""
url = urljoin(f"{self.path}/", resource_id) # type: ignore[attr-defined]
await self.http_client.request("delete", url) # type: ignore[attr-defined]
await self._resource(resource_id).delete() # type: ignore[attr-defined]
8 changes: 2 additions & 6 deletions mpt_api_client/http/mixins/disable_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@ class AsyncDisableMixin[Model: BaseModel]:

async def disable(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
"""Disable a specific resource."""
return await self._resource_action( # type: ignore[attr-defined, no-any-return]
resource_id=resource_id, method="POST", action="disable", json=resource_data
)
return await self._resource(resource_id).post("disable", json=resource_data) # type: ignore[attr-defined, no-any-return]


class DisableMixin[Model: BaseModel]:
"""Disable resource mixin."""

def disable(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
"""Disable a specific resource."""
return self._resource_action( # type: ignore[attr-defined, no-any-return]
resource_id=resource_id, method="POST", action="disable", json=resource_data
)
return self._resource(resource_id).post("disable", json=resource_data) # type: ignore[attr-defined, no-any-return]
14 changes: 6 additions & 8 deletions mpt_api_client/http/mixins/download_file_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ def download(self, resource_id: str, accept: str | None = None) -> FileModel:
Returns:
File model containing the downloaded file.
"""
accessor = self._resource(resource_id) # type: ignore[attr-defined]
if not accept:
resource: Model = self._resource_action(resource_id, method="GET") # type: ignore[attr-defined]
resource: Model = accessor.get()
accept = resource.content_type # type: ignore[attr-defined]
if not accept:
raise MPTError("Unable to download file. Content type not found in resource")
response: Response = self._resource_do_request( # type: ignore[attr-defined]
resource_id, method="GET", headers={"Accept": accept}
)
response: Response = accessor.do_request("GET", headers={"Accept": accept})
return FileModel(response)


Expand All @@ -42,12 +41,11 @@ async def download(self, resource_id: str, accept: str | None = None) -> FileMod
Returns:
File model containing the downloaded file.
"""
accessor = self._resource(resource_id) # type: ignore[attr-defined]
if not accept:
resource: Model = await self._resource_action(resource_id, method="GET") # type: ignore[attr-defined]
resource: Model = await accessor.get()
accept = resource.content_type # type: ignore[attr-defined]
if not accept:
raise MPTError("Unable to download file. Content type not found in resource")
response = await self._resource_do_request( # type: ignore[attr-defined]
resource_id, method="GET", headers={"Accept": accept}
)
response = await accessor.do_request("GET", headers={"Accept": accept})
return FileModel(response)
8 changes: 2 additions & 6 deletions mpt_api_client/http/mixins/enable_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@ class AsyncEnableMixin[Model: BaseModel]:

async def enable(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
"""Enable a specific resource."""
return await self._resource_action( # type: ignore[attr-defined, no-any-return]
resource_id=resource_id, method="POST", action="enable", json=resource_data
)
return await self._resource(resource_id).post("enable", json=resource_data) # type: ignore[attr-defined, no-any-return]


class EnableMixin[Model: BaseModel]:
"""Enable resource mixin."""

def enable(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
"""Enable a specific resource."""
return self._resource_action( # type: ignore[attr-defined, no-any-return]
resource_id=resource_id, method="POST", action="enable", json=resource_data
)
return self._resource(resource_id).post("enable", json=resource_data) # type: ignore[attr-defined, no-any-return]
4 changes: 2 additions & 2 deletions mpt_api_client/http/mixins/get_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def get(self, resource_id: str, select: list[str] | str | None = None) -> Model:
if isinstance(select, list):
select = ",".join(select) if select else None

return self._resource_action(resource_id=resource_id, query_params={"select": select}) # type: ignore[attr-defined, no-any-return]
return self._resource(resource_id).get(query_params={"select": select}) # type: ignore[attr-defined, no-any-return]


class AsyncGetMixin[Model]:
Expand All @@ -32,4 +32,4 @@ async def get(self, resource_id: str, select: list[str] | str | None = None) ->
"""
if isinstance(select, list):
select = ",".join(select) if select else None
return await self._resource_action(resource_id=resource_id, query_params={"select": select}) # type: ignore[attr-defined, no-any-return]
return await self._resource(resource_id).get(query_params={"select": select}) # type: ignore[attr-defined, no-any-return]
7 changes: 3 additions & 4 deletions mpt_api_client/http/mixins/update_file_mixin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from urllib.parse import urljoin

from mpt_api_client.http.types import FileTypes
from mpt_api_client.http.url_utils import join_url_path
from mpt_api_client.models import ResourceData


Expand All @@ -27,7 +26,7 @@ def update(
"""
files = {}

url = urljoin(f"{self.path}/", resource_id) # type: ignore[attr-defined]
url = join_url_path(self.path, resource_id) # type: ignore[attr-defined]

if file:
files[self._upload_file_key] = file # type: ignore[attr-defined]
Expand Down Expand Up @@ -67,7 +66,7 @@ async def update(
"""
files = {}

url = urljoin(f"{self.path}/", resource_id) # type: ignore[attr-defined]
url = join_url_path(self.path, resource_id) # type: ignore[attr-defined]

if file:
files[self._upload_file_key] = file # type: ignore[attr-defined]
Expand Down
26 changes: 4 additions & 22 deletions mpt_api_client/http/mixins/update_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,13 @@ class UpdateMixin[Model]:
"""Update resource mixin."""

def update(self, resource_id: str, resource_data: ResourceData) -> Model:
"""Update a resource using `PUT /endpoint/{resource_id}`.

Args:
resource_id: Resource ID.
resource_data: Resource data.

Returns:
Resource object.

"""
return self._resource_action(resource_id, "PUT", json=resource_data) # type: ignore[attr-defined, no-any-return]
"""Update a resource using `PUT /endpoint/{resource_id}`."""
return self._resource(resource_id).put(json=resource_data) # type: ignore[attr-defined, no-any-return]


class AsyncUpdateMixin[Model]:
"""Update resource mixin."""

async def update(self, resource_id: str, resource_data: ResourceData) -> Model:
"""Update a resource using `PUT /endpoint/{resource_id}`.

Args:
resource_id: Resource ID.
resource_data: Resource data.

Returns:
Resource object.

"""
return await self._resource_action(resource_id, "PUT", json=resource_data) # type: ignore[attr-defined, no-any-return]
"""Update a resource using `PUT /endpoint/{resource_id}`."""
return await self._resource(resource_id).put(json=resource_data) # type: ignore[attr-defined, no-any-return]
Loading
Loading