Skip to content

Commit 8b2aa99

Browse files
author
Robert Segal
committed
Added create and update with icon mixin and updated product
1 parent 5a75c11 commit 8b2aa99

File tree

8 files changed

+549
-36
lines changed

8 files changed

+549
-36
lines changed

mpt_api_client/http/mixins.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,77 @@ def download(self, resource_id: str) -> FileModel:
105105
return FileModel(response)
106106

107107

108+
class CreateWithIconMixin[Model]:
109+
"""Create resource with icon mixin."""
110+
111+
def create(
112+
self,
113+
resource_data: ResourceData,
114+
data_key: str,
115+
icon: FileTypes,
116+
icon_key: str,
117+
) -> Model:
118+
"""Create resource with icon.
119+
120+
Args:
121+
resource_data: Resource data.
122+
data_key: Key for the resource data.
123+
icon: Icon image in jpg, png, GIF, etc.
124+
icon_key: Key for the icon.
125+
126+
Returns:
127+
Created resource.
128+
"""
129+
files: dict[str, FileTypes] = {}
130+
files[data_key] = (
131+
None,
132+
json.dumps(resource_data),
133+
"application/json",
134+
)
135+
files[icon_key] = icon
136+
response = self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]
137+
138+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
139+
140+
141+
class UpdateWithIconMixin[Model]:
142+
"""Update resource with icon mixin."""
143+
144+
def update(
145+
self,
146+
resource_id: str,
147+
resource_data: ResourceData,
148+
data_key: str,
149+
icon: FileTypes,
150+
icon_key: str,
151+
) -> Model:
152+
"""Update resource with icon.
153+
154+
Args:
155+
resource_id: Resource ID.
156+
resource_data: Resource data.
157+
data_key: Key for the resource data.
158+
icon: Icon image in jpg, png, GIF, etc.
159+
icon_key: Key for the icon.
160+
161+
Returns:
162+
Updated resource.
163+
"""
164+
files: dict[str, FileTypes] = {}
165+
files[data_key] = (
166+
None,
167+
json.dumps(resource_data),
168+
"application/json",
169+
)
170+
files[icon_key] = icon
171+
172+
url = urljoin(f"{self.path}/", resource_id) # type: ignore[attr-defined]
173+
174+
response = self.http_client.request("put", url, files=files) # type: ignore[attr-defined]
175+
176+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
177+
178+
108179
class AsyncCreateMixin[Model]:
109180
"""Create resource mixin."""
110181

@@ -196,6 +267,77 @@ async def download(self, resource_id: str) -> FileModel:
196267
return FileModel(response)
197268

198269

270+
class AsyncCreateWithIconMixin[Model]:
271+
"""Create resource with icon mixin."""
272+
273+
async def create(
274+
self,
275+
resource_data: ResourceData,
276+
data_key: str,
277+
icon: FileTypes,
278+
icon_key: str,
279+
) -> Model:
280+
"""Create resource with icon.
281+
282+
Args:
283+
resource_data: Resource data.
284+
data_key: Key for the resource data.
285+
icon: Icon image in jpg, png, GIF, etc.
286+
icon_key: Key for the icon.
287+
288+
Returns:
289+
Created resource.
290+
"""
291+
files: dict[str, FileTypes] = {}
292+
files[data_key] = (
293+
None,
294+
json.dumps(resource_data),
295+
"application/json",
296+
)
297+
files[icon_key] = icon
298+
response = await self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]
299+
300+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
301+
302+
303+
class AsyncUpdateWithIconMixin[Model]:
304+
"""Update resource with icon mixin."""
305+
306+
async def update(
307+
self,
308+
resource_id: str,
309+
resource_data: ResourceData,
310+
data_key: str,
311+
icon: FileTypes,
312+
icon_key: str,
313+
) -> Model:
314+
"""Update resource with icon.
315+
316+
Args:
317+
resource_id: Resource ID.
318+
resource_data: Resource data.
319+
data_key: Key for the resource data.
320+
icon: Icon image in jpg, png, GIF, etc.
321+
icon_key: Key for the icon.
322+
323+
Returns:
324+
Updated resource.
325+
"""
326+
files: dict[str, FileTypes] = {}
327+
files[data_key] = (
328+
None,
329+
json.dumps(resource_data),
330+
"application/json",
331+
)
332+
files[icon_key] = icon
333+
334+
url = urljoin(f"{self.path}/", resource_id) # type: ignore[attr-defined]
335+
336+
response = await self.http_client.request("put", url, files=files) # type: ignore[attr-defined]
337+
338+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
339+
340+
199341
class GetMixin[Model]:
200342
"""Get resource mixin."""
201343

mpt_api_client/resources/catalog/products.py

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import json
1+
from typing import override
22

33
from mpt_api_client.http import AsyncService, Service
44
from mpt_api_client.http.mixins import (
55
AsyncCollectionMixin,
6-
AsyncModifiableResourceMixin,
6+
AsyncCreateWithIconMixin,
7+
AsyncDeleteMixin,
8+
AsyncGetMixin,
9+
AsyncUpdateWithIconMixin,
710
CollectionMixin,
8-
ModifiableResourceMixin,
11+
CreateWithIconMixin,
12+
DeleteMixin,
13+
GetMixin,
14+
UpdateWithIconMixin,
915
)
1016
from mpt_api_client.http.types import FileTypes
1117
from mpt_api_client.models import Model, ResourceData
@@ -56,38 +62,71 @@ class ProductsServiceConfig:
5662

5763

5864
class ProductsService(
65+
CreateWithIconMixin[Product],
66+
UpdateWithIconMixin[Product],
5967
PublishableMixin[Product],
60-
ModifiableResourceMixin[Product],
68+
GetMixin[Product],
69+
DeleteMixin,
6170
CollectionMixin[Product],
6271
Service[Product],
6372
ProductsServiceConfig,
6473
):
6574
"""Products service."""
6675

76+
@override
6777
def create(
6878
self,
6979
resource_data: ResourceData,
80+
data_key: str,
7081
icon: FileTypes,
82+
icon_key: str,
7183
) -> Product:
7284
"""Create product with icon.
7385
7486
Args:
7587
resource_data: Product data.
88+
data_key: Key for the product data.
7689
icon: Icon image in jpg, png, GIF, etc.
90+
icon_key: Key for the icon.
7791
7892
Returns:
7993
Created resource.
8094
"""
81-
files: dict[str, FileTypes] = {}
82-
files["product"] = (
83-
None,
84-
json.dumps(resource_data),
85-
"application/json",
95+
return super().create(
96+
resource_data=resource_data,
97+
data_key=data_key,
98+
icon=icon,
99+
icon_key=icon_key,
86100
)
87-
files["icon"] = icon
88-
response = self.http_client.request("post", self.path, files=files)
89101

90-
return self._model_class.from_response(response)
102+
@override
103+
def update(
104+
self,
105+
resource_id: str,
106+
resource_data: ResourceData,
107+
data_key: str,
108+
icon: FileTypes,
109+
icon_key: str,
110+
) -> Product:
111+
"""Update product with icon.
112+
113+
Args:
114+
resource_id: Product ID.
115+
resource_data: Product data.
116+
data_key: Key for the product data.
117+
icon: Icon image in jpg, png, GIF, etc.
118+
icon_key: Key for the icon.
119+
120+
Returns:
121+
Updated resource.
122+
"""
123+
return super().update(
124+
resource_id=resource_id,
125+
resource_data=resource_data,
126+
data_key=data_key,
127+
icon=icon,
128+
icon_key=icon_key,
129+
)
91130

92131
def item_groups(self, product_id: str) -> ItemGroupsService:
93132
"""Return item_groups service."""
@@ -135,37 +174,71 @@ def update_settings(self, product_id: str, settings: ResourceData) -> Product:
135174

136175

137176
class AsyncProductsService(
177+
AsyncCreateWithIconMixin[Product],
178+
AsyncUpdateWithIconMixin[Product],
138179
AsyncPublishableMixin[Product],
139-
AsyncModifiableResourceMixin[Product],
180+
AsyncGetMixin[Product],
181+
AsyncDeleteMixin,
140182
AsyncCollectionMixin[Product],
141183
AsyncService[Product],
142184
ProductsServiceConfig,
143185
):
144186
"""Products service."""
145187

188+
@override
146189
async def create(
147190
self,
148191
resource_data: ResourceData,
192+
data_key: str,
149193
icon: FileTypes,
194+
icon_key: str,
150195
) -> Product:
151196
"""Create product with icon.
152197
153198
Args:
154199
resource_data: Product data.
200+
data_key: Key for the product data.
155201
icon: Icon image in jpg, png, GIF, etc.
202+
icon_key: Key for the icon.
156203
157204
Returns:
158205
Created resource.
159206
"""
160-
files: dict[str, FileTypes] = {}
161-
files["product"] = (
162-
None,
163-
json.dumps(resource_data),
164-
"application/json",
165-
)
166-
files["icon"] = icon
167-
response = await self.http_client.request("post", self.path, files=files)
168-
return self._model_class.from_response(response)
207+
return await super().create(
208+
resource_data=resource_data,
209+
data_key=data_key,
210+
icon=icon,
211+
icon_key=icon_key,
212+
)
213+
214+
@override
215+
async def update(
216+
self,
217+
resource_id: str,
218+
resource_data: ResourceData,
219+
data_key: str,
220+
icon: FileTypes,
221+
icon_key: str,
222+
) -> Product:
223+
"""Update product with icon.
224+
225+
Args:
226+
resource_id: Product ID.
227+
resource_data: Product data.
228+
data_key: Key for the product data.
229+
icon: Icon image in jpg, png, GIF, etc.
230+
icon_key: Key for the icon.
231+
232+
Returns:
233+
Updated resource.
234+
"""
235+
return await super().update(
236+
resource_id=resource_id,
237+
resource_data=resource_data,
238+
data_key=data_key,
239+
icon=icon,
240+
icon_key=icon_key,
241+
)
169242

170243
def item_groups(self, product_id: str) -> AsyncItemGroupsService:
171244
"""Return item_groups service."""

seed/catalog/product.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ async def init_product(
4848
logger.debug("Creating product ...")
4949
with pathlib.Path.open(icon, "rb") as icon_file:
5050
product = await mpt_vendor.catalog.products.create(
51-
{"name": "E2E Seeded", "website": "https://www.example.com"}, icon=icon_file
51+
{"name": "E2E Seeded", "website": "https://www.example.com"},
52+
data_key="product",
53+
icon=icon_file,
54+
icon_key="icon",
5255
)
5356
context.set_resource(namespace, product)
5457
context[f"{namespace}.id"] = product.id

setup.cfg

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,16 @@ extend-ignore =
3333

3434
per-file-ignores =
3535
mpt_api_client/mpt_client.py: WPS214 WPS235
36-
mpt_api_client/http/mixins.py: WPS202
36+
mpt_api_client/http/mixins.py: WPS202 WPS204 WPS235
3737
mpt_api_client/resources/*: WPS215
3838
mpt_api_client/resources/accounts/*.py: WPS202 WPS215 WPS214
3939
mpt_api_client/resources/billing/*.py: WPS202 WPS204 WPS214 WPS215
40-
mpt_api_client/resources/catalog/*.py: WPS110 WPS214 WPS215
41-
mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215
40+
mpt_api_client/resources/catalog/*.py: WPS110 WPS214 WPS215 WPS235
41+
mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215 WPS235
4242
mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214
4343
tests/unit/http/test_async_service.py: WPS204 WPS202
4444
tests/unit/http/test_service.py: WPS204 WPS202
45-
tests/unit/http/test_mixins.py: WPS204 WPS202
45+
tests/unit/http/test_mixins.py: WPS204 WPS202 WPS210
4646
tests/unit/resources/catalog/test_products.py: WPS202 WPS210
4747
tests/unit/resources/*/test_mixins.py: WPS118 WPS202 WPS204 WPS235
4848
tests/unit/resources/accounts/test_users.py: WPS204 WPS202 WPS210

0 commit comments

Comments
 (0)