Skip to content

Commit e02a234

Browse files
committed
MPT-19660 Improve resource action implementation
1 parent e09b096 commit e02a234

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+745
-476
lines changed
Lines changed: 11 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
from urllib.parse import urljoin
2-
3-
from mpt_api_client.constants import APPLICATION_JSON
41
from mpt_api_client.http.async_client import AsyncHTTPClient
52
from mpt_api_client.http.base_service import ServiceBase
6-
from mpt_api_client.http.types import QueryParam, Response
3+
from mpt_api_client.http.resource_accessor import AsyncResourceAccessor
4+
from mpt_api_client.http.url_utils import join_url_path
75
from mpt_api_client.models import Model as BaseModel
8-
from mpt_api_client.models import ResourceData
9-
from mpt_api_client.models.collection import ResourceList
106

117

128
class AsyncService[Model: BaseModel](ServiceBase[AsyncHTTPClient, Model]): # noqa: WPS214
@@ -21,60 +17,15 @@ class AsyncService[Model: BaseModel](ServiceBase[AsyncHTTPClient, Model]): # no
2117
2218
"""
2319

24-
async def _resource_do_request( # noqa: WPS211
25-
self,
26-
resource_id: str,
27-
method: str = "GET",
28-
action: str | None = None,
29-
json: ResourceData | ResourceList | None = None,
30-
query_params: QueryParam | None = None,
31-
headers: dict[str, str] | None = None,
32-
) -> Response:
33-
"""Perform an action on a specific resource using.
34-
35-
Request with action: `HTTP_METHOD /endpoint/{resource_id}/{action}`.
36-
Request without action: `HTTP_METHOD /endpoint/{resource_id}`.
37-
38-
Args:
39-
resource_id: The resource ID to operate on.
40-
method: The HTTP method to use.
41-
action: The action name to use.
42-
json: The updated resource data.
43-
query_params: Additional query parameters.
44-
headers: Additional headers.
45-
46-
Raises:
47-
HTTPError: If the action fails.
48-
"""
49-
resource_url = urljoin(f"{self.path}/", resource_id)
50-
url = urljoin(f"{resource_url}/", action) if action else resource_url
51-
return await self.http_client.request(
52-
method, url, json=json, query_params=query_params, headers=headers
53-
)
20+
def _resource(self, resource_id: str) -> AsyncResourceAccessor[Model]:
21+
"""Return an :class:`AsyncResourceAccessor` bound to *resource_id*.
5422
55-
async def _resource_action(
56-
self,
57-
resource_id: str,
58-
method: str = "GET",
59-
action: str | None = None,
60-
json: ResourceData | ResourceList | None = None,
61-
query_params: QueryParam | None = None,
62-
) -> Model:
63-
"""Perform an action on a specific resource using `HTTP_METHOD /endpoint/{resource_id}`.
23+
Usage::
6424
65-
Args:
66-
resource_id: The resource ID to operate on.
67-
method: The HTTP method to use.
68-
action: The action name to use.
69-
json: The updated resource data.
70-
query_params: Additional query parameters.
25+
await self._resource("RES-123").post("complete", json=data)
26+
await self._resource("RES-123").get()
27+
await self._resource("RES-123").put(json=data)
28+
await self._resource("RES-123").delete()
7129
"""
72-
response = await self._resource_do_request(
73-
resource_id,
74-
method,
75-
action,
76-
json=json,
77-
query_params=query_params,
78-
headers={"Accept": APPLICATION_JSON},
79-
)
80-
return self._model_class.from_response(response)
30+
resource_url = join_url_path(self.path, resource_id)
31+
return AsyncResourceAccessor(self.http_client, resource_url, self._model_class)
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
from urllib.parse import urljoin
2-
3-
41
class DeleteMixin:
52
"""Delete resource mixin."""
63

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

1512

1613
class AsyncDeleteMixin:
@@ -22,5 +19,4 @@ async def delete(self, resource_id: str) -> None:
2219
Args:
2320
resource_id: Resource ID.
2421
"""
25-
url = urljoin(f"{self.path}/", resource_id) # type: ignore[attr-defined]
26-
await self.http_client.request("delete", url) # type: ignore[attr-defined]
22+
await self._resource(resource_id).delete() # type: ignore[attr-defined]

mpt_api_client/http/mixins/disable_mixin.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,12 @@ class AsyncDisableMixin[Model: BaseModel]:
77

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

1412

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

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

mpt_api_client/http/mixins/download_file_mixin.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,13 @@ def download(self, resource_id: str, accept: str | None = None) -> FileModel:
1717
Returns:
1818
File model containing the downloaded file.
1919
"""
20+
accessor = self._resource(resource_id) # type: ignore[attr-defined]
2021
if not accept:
21-
resource: Model = self._resource_action(resource_id, method="GET") # type: ignore[attr-defined]
22+
resource: Model = accessor.get()
2223
accept = resource.content_type # type: ignore[attr-defined]
2324
if not accept:
2425
raise MPTError("Unable to download file. Content type not found in resource")
25-
response: Response = self._resource_do_request( # type: ignore[attr-defined]
26-
resource_id, method="GET", headers={"Accept": accept}
27-
)
26+
response: Response = accessor.do_request("GET", headers={"Accept": accept})
2827
return FileModel(response)
2928

3029

@@ -42,12 +41,11 @@ async def download(self, resource_id: str, accept: str | None = None) -> FileMod
4241
Returns:
4342
File model containing the downloaded file.
4443
"""
44+
accessor = self._resource(resource_id) # type: ignore[attr-defined]
4545
if not accept:
46-
resource: Model = await self._resource_action(resource_id, method="GET") # type: ignore[attr-defined]
46+
resource: Model = await accessor.get()
4747
accept = resource.content_type # type: ignore[attr-defined]
4848
if not accept:
4949
raise MPTError("Unable to download file. Content type not found in resource")
50-
response = await self._resource_do_request( # type: ignore[attr-defined]
51-
resource_id, method="GET", headers={"Accept": accept}
52-
)
50+
response = await accessor.do_request("GET", headers={"Accept": accept})
5351
return FileModel(response)

mpt_api_client/http/mixins/enable_mixin.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,12 @@ class AsyncEnableMixin[Model: BaseModel]:
77

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

1412

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

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

mpt_api_client/http/mixins/get_mixin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def get(self, resource_id: str, select: list[str] | str | None = None) -> Model:
1414
if isinstance(select, list):
1515
select = ",".join(select) if select else None
1616

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

1919

2020
class AsyncGetMixin[Model]:
@@ -32,4 +32,4 @@ async def get(self, resource_id: str, select: list[str] | str | None = None) ->
3232
"""
3333
if isinstance(select, list):
3434
select = ",".join(select) if select else None
35-
return await self._resource_action(resource_id=resource_id, query_params={"select": select}) # type: ignore[attr-defined, no-any-return]
35+
return await self._resource(resource_id).get(query_params={"select": select}) # type: ignore[attr-defined, no-any-return]

mpt_api_client/http/mixins/update_file_mixin.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from urllib.parse import urljoin
2-
31
from mpt_api_client.http.types import FileTypes
2+
from mpt_api_client.http.url_utils import join_url_path
43
from mpt_api_client.models import ResourceData
54

65

@@ -27,7 +26,7 @@ def update(
2726
"""
2827
files = {}
2928

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

3231
if file:
3332
files[self._upload_file_key] = file # type: ignore[attr-defined]
@@ -67,7 +66,7 @@ async def update(
6766
"""
6867
files = {}
6968

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

7271
if file:
7372
files[self._upload_file_key] = file # type: ignore[attr-defined]

mpt_api_client/http/mixins/update_mixin.py

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,13 @@ class UpdateMixin[Model]:
55
"""Update resource mixin."""
66

77
def update(self, resource_id: str, resource_data: ResourceData) -> Model:
8-
"""Update a resource using `PUT /endpoint/{resource_id}`.
9-
10-
Args:
11-
resource_id: Resource ID.
12-
resource_data: Resource data.
13-
14-
Returns:
15-
Resource object.
16-
17-
"""
18-
return self._resource_action(resource_id, "PUT", json=resource_data) # type: ignore[attr-defined, no-any-return]
8+
"""Update a resource using `PUT /endpoint/{resource_id}`."""
9+
return self._resource(resource_id).put(json=resource_data) # type: ignore[attr-defined, no-any-return]
1910

2011

2112
class AsyncUpdateMixin[Model]:
2213
"""Update resource mixin."""
2314

2415
async def update(self, resource_id: str, resource_data: ResourceData) -> Model:
25-
"""Update a resource using `PUT /endpoint/{resource_id}`.
26-
27-
Args:
28-
resource_id: Resource ID.
29-
resource_data: Resource data.
30-
31-
Returns:
32-
Resource object.
33-
34-
"""
35-
return await self._resource_action(resource_id, "PUT", json=resource_data) # type: ignore[attr-defined, no-any-return]
16+
"""Update a resource using `PUT /endpoint/{resource_id}`."""
17+
return await self._resource(resource_id).put(json=resource_data) # type: ignore[attr-defined, no-any-return]

0 commit comments

Comments
 (0)