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
1 change: 1 addition & 0 deletions mpt_api_client/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
APPLICATION_JSON = "application/json"
147 changes: 145 additions & 2 deletions mpt_api_client/http/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Self
from urllib.parse import urljoin

from mpt_api_client.constants import APPLICATION_JSON
from mpt_api_client.http.query_state import QueryState
from mpt_api_client.http.types import FileTypes, Response
from mpt_api_client.models import Collection, FileModel, ResourceData
Expand Down Expand Up @@ -84,7 +85,7 @@ def create(
files[data_key] = (
None,
_json_to_file_payload(resource_data),
"application/json",
APPLICATION_JSON,
)
response = self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]

Expand All @@ -105,6 +106,77 @@ def download(self, resource_id: str) -> FileModel:
return FileModel(response)


class CreateWithIconMixin[Model]:
"""Create resource with icon mixin."""

def create(
self,
resource_data: ResourceData,
icon: FileTypes,
data_key: str,
icon_key: str,
) -> Model:
"""Create resource with icon.

Args:
resource_data: Resource data.
data_key: Key for the resource data.
icon: Icon image in jpg, png, GIF, etc.
icon_key: Key for the icon.

Returns:
Created resource.
"""
files: dict[str, FileTypes] = {}
files[data_key] = (
None,
json.dumps(resource_data),
APPLICATION_JSON,
)
files[icon_key] = icon
response = self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]

return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]


class UpdateWithIconMixin[Model]:
"""Update resource with icon mixin."""

def update(
self,
resource_id: str,
resource_data: ResourceData,
icon: FileTypes,
data_key: str,
icon_key: str,
) -> Model:
"""Update resource with icon.

Args:
resource_id: Resource ID.
resource_data: Resource data.
data_key: Key for the resource data.
icon: Icon image in jpg, png, GIF, etc.
icon_key: Key for the icon.

Returns:
Updated resource.
"""
files: dict[str, FileTypes] = {}
files[data_key] = (
None,
json.dumps(resource_data),
APPLICATION_JSON,
)
files[icon_key] = icon

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

response = self.http_client.request("put", url, files=files) # type: ignore[attr-defined]

return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]


class AsyncCreateMixin[Model]:
"""Create resource mixin."""

Expand Down Expand Up @@ -174,7 +246,7 @@ async def create(
files[data_key] = (
None,
_json_to_file_payload(resource_data),
"application/json",
APPLICATION_JSON,
)

response = await self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]
Expand All @@ -196,6 +268,77 @@ async def download(self, resource_id: str) -> FileModel:
return FileModel(response)


class AsyncCreateWithIconMixin[Model]:
"""Create resource with icon mixin."""

async def create(
self,
resource_data: ResourceData,
icon: FileTypes,
data_key: str,
icon_key: str,
) -> Model:
"""Create resource with icon.

Args:
resource_data: Resource data.
data_key: Key for the resource data.
icon: Icon image in jpg, png, GIF, etc.
icon_key: Key for the icon.

Returns:
Created resource.
"""
files: dict[str, FileTypes] = {}
files[data_key] = (
None,
json.dumps(resource_data),
APPLICATION_JSON,
)
files[icon_key] = icon
response = await self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]

return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]


class AsyncUpdateWithIconMixin[Model]:
"""Update resource with icon mixin."""

async def update(
self,
resource_id: str,
resource_data: ResourceData,
icon: FileTypes,
data_key: str,
icon_key: str,
) -> Model:
"""Update resource with icon.

Args:
resource_id: Resource ID.
resource_data: Resource data.
data_key: Key for the resource data.
icon: Icon image in jpg, png, GIF, etc.
icon_key: Key for the icon.

Returns:
Updated resource.
"""
files: dict[str, FileTypes] = {}
files[data_key] = (
None,
json.dumps(resource_data),
APPLICATION_JSON,
)
files[icon_key] = icon

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

response = await self.http_client.request("put", url, files=files) # type: ignore[attr-defined]

return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]


class GetMixin[Model]:
"""Get resource mixin."""

Expand Down
117 changes: 95 additions & 22 deletions mpt_api_client/resources/catalog/products.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import json
from typing import override

from mpt_api_client.http import AsyncService, Service
from mpt_api_client.http.mixins import (
AsyncCollectionMixin,
AsyncModifiableResourceMixin,
AsyncCreateWithIconMixin,
AsyncDeleteMixin,
AsyncGetMixin,
AsyncUpdateWithIconMixin,
CollectionMixin,
ModifiableResourceMixin,
CreateWithIconMixin,
DeleteMixin,
GetMixin,
UpdateWithIconMixin,
)
from mpt_api_client.http.types import FileTypes
from mpt_api_client.models import Model, ResourceData
Expand Down Expand Up @@ -56,38 +62,71 @@ class ProductsServiceConfig:


class ProductsService(
CreateWithIconMixin[Product],
UpdateWithIconMixin[Product],
PublishableMixin[Product],
ModifiableResourceMixin[Product],
GetMixin[Product],
DeleteMixin,
CollectionMixin[Product],
Service[Product],
ProductsServiceConfig,
):
"""Products service."""

@override
def create(
self,
resource_data: ResourceData,
icon: FileTypes,
data_key: str = "product",
icon_key: str = "icon",
) -> Product:
"""Create product with icon.

Args:
resource_data: Product data.
icon: Icon image in jpg, png, GIF, etc.
data_key: Key for the product data.
icon_key: Key for the icon.

Returns:
Created resource.
"""
files: dict[str, FileTypes] = {}
files["product"] = (
None,
json.dumps(resource_data),
"application/json",
return super().create(
resource_data=resource_data,
icon=icon,
data_key=data_key,
icon_key=icon_key,
)
files["icon"] = icon
response = self.http_client.request("post", self.path, files=files)

return self._model_class.from_response(response)
@override
def update(
self,
resource_id: str,
resource_data: ResourceData,
icon: FileTypes,
data_key: str = "product",
icon_key: str = "icon",
) -> Product:
"""Update product with icon.

Args:
resource_id: Product ID.
resource_data: Product data.
icon: Icon image in jpg, png, GIF, etc.
data_key: Key for the product data.
icon_key: Key for the icon.

Returns:
Updated resource.
"""
return super().update(
resource_id=resource_id,
resource_data=resource_data,
icon=icon,
data_key=data_key,
icon_key=icon_key,
)

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


class AsyncProductsService(
AsyncCreateWithIconMixin[Product],
AsyncUpdateWithIconMixin[Product],
AsyncPublishableMixin[Product],
AsyncModifiableResourceMixin[Product],
AsyncGetMixin[Product],
AsyncDeleteMixin,
AsyncCollectionMixin[Product],
AsyncService[Product],
ProductsServiceConfig,
):
"""Products service."""

@override
async def create(
self,
resource_data: ResourceData,
icon: FileTypes,
data_key: str = "product",
icon_key: str = "icon",
) -> Product:
"""Create product with icon.

Args:
resource_data: Product data.
icon: Icon image in jpg, png, GIF, etc.
data_key: Key for the product data.
icon_key: Key for the icon.

Returns:
Created resource.
"""
files: dict[str, FileTypes] = {}
files["product"] = (
None,
json.dumps(resource_data),
"application/json",
)
files["icon"] = icon
response = await self.http_client.request("post", self.path, files=files)
return self._model_class.from_response(response)
return await super().create(
resource_data=resource_data,
data_key=data_key,
icon=icon,
icon_key=icon_key,
)

@override
async def update(
self,
resource_id: str,
resource_data: ResourceData,
icon: FileTypes,
data_key: str = "product",
icon_key: str = "icon",
) -> Product:
"""Update product with icon.

Args:
resource_id: Product ID.
resource_data: Product data.
icon: Icon image in jpg, png, GIF, etc.
data_key: Key for the product data.
icon_key: Key for the icon.

Returns:
Updated resource.
"""
return await super().update(
resource_id=resource_id,
resource_data=resource_data,
data_key=data_key,
icon=icon,
icon_key=icon_key,
)

def item_groups(self, product_id: str) -> AsyncItemGroupsService:
"""Return item_groups service."""
Expand Down
8 changes: 4 additions & 4 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ extend-ignore =

per-file-ignores =
mpt_api_client/mpt_client.py: WPS214 WPS235
mpt_api_client/http/mixins.py: WPS202
mpt_api_client/http/mixins.py: WPS202 WPS204 WPS235
mpt_api_client/resources/*: WPS215
mpt_api_client/models/model.py: WPS215 WPS110
mpt_api_client/resources/accounts/*.py: WPS202 WPS215 WPS214
mpt_api_client/resources/billing/*.py: WPS202 WPS204 WPS214 WPS215
mpt_api_client/resources/catalog/*.py: WPS110 WPS214 WPS215
mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215
mpt_api_client/resources/catalog/*.py: WPS110 WPS214 WPS215 WPS235
mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215 WPS235
mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214
tests/unit/http/test_async_service.py: WPS204 WPS202
tests/unit/http/test_service.py: WPS204 WPS202
tests/unit/http/test_mixins.py: WPS204 WPS202
tests/unit/http/test_mixins.py: WPS204 WPS202 WPS210
tests/unit/resources/catalog/test_products.py: WPS202 WPS210
tests/unit/resources/*/test_mixins.py: WPS118 WPS202 WPS204 WPS235
tests/unit/resources/accounts/test_users.py: WPS204 WPS202 WPS210
Expand Down
Loading