From 93bf42f70da4d5e29ba0e6e21ebdacee2def45c7 Mon Sep 17 00:00:00 2001 From: Albert Sola Date: Wed, 3 Dec 2025 10:05:44 +0000 Subject: [PATCH 1/2] MPT-15844 Add catalog product items service --- mpt_api_client/resources/catalog/products.py | 16 +++++++ .../resources/catalog/products_items.py | 34 ++++++++++++++ tests/unit/resources/catalog/test_products.py | 6 +++ .../resources/catalog/test_products_items.py | 44 +++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 mpt_api_client/resources/catalog/products_items.py create mode 100644 tests/unit/resources/catalog/test_products_items.py diff --git a/mpt_api_client/resources/catalog/products.py b/mpt_api_client/resources/catalog/products.py index 268561f3..73f868b8 100644 --- a/mpt_api_client/resources/catalog/products.py +++ b/mpt_api_client/resources/catalog/products.py @@ -28,6 +28,10 @@ AsyncItemGroupsService, ItemGroupsService, ) +from mpt_api_client.resources.catalog.products_items import ( + AsyncProductItemService, + ProductItemService, +) from mpt_api_client.resources.catalog.products_media import ( AsyncMediaService, MediaService, @@ -72,6 +76,12 @@ class ProductsService( ): """Products service.""" + def items(self, product_id: str) -> ProductItemService: # noqa: WPS110 + """Return product items service.""" + return ProductItemService( + http_client=self.http_client, endpoint_params={"product_id": product_id} + ) + def item_groups(self, product_id: str) -> ItemGroupsService: """Return item_groups service.""" return ItemGroupsService( @@ -129,6 +139,12 @@ class AsyncProductsService( ): """Products service.""" + def items(self, product_id: str) -> AsyncProductItemService: # noqa: WPS110 + """Return product items service.""" + return AsyncProductItemService( + http_client=self.http_client, endpoint_params={"product_id": product_id} + ) + def item_groups(self, product_id: str) -> AsyncItemGroupsService: """Return item_groups service.""" return AsyncItemGroupsService( diff --git a/mpt_api_client/resources/catalog/products_items.py b/mpt_api_client/resources/catalog/products_items.py new file mode 100644 index 00000000..7b8dba03 --- /dev/null +++ b/mpt_api_client/resources/catalog/products_items.py @@ -0,0 +1,34 @@ +from mpt_api_client.http import AsyncService, Service +from mpt_api_client.http.mixins import ( + AsyncCollectionMixin, + AsyncGetMixin, + CollectionMixin, + GetMixin, +) +from mpt_api_client.resources.catalog.items import Item + + +class ProductItemServiceConfig: + """Product Item service configuration.""" + + _endpoint = "/public/v1/catalog/products/{product_id}/items" + _model_class = Item + _collection_key = "data" + + +class ProductItemService( + GetMixin[Item], + CollectionMixin[Item], + Service[Item], + ProductItemServiceConfig, +): + """Product Item service.""" + + +class AsyncProductItemService( + AsyncGetMixin[Item], + AsyncCollectionMixin[Item], + AsyncService[Item], + ProductItemServiceConfig, +): + """Product Item service.""" diff --git a/tests/unit/resources/catalog/test_products.py b/tests/unit/resources/catalog/test_products.py index b3ef2d17..e1192549 100644 --- a/tests/unit/resources/catalog/test_products.py +++ b/tests/unit/resources/catalog/test_products.py @@ -15,6 +15,10 @@ AsyncItemGroupsService, ItemGroupsService, ) +from mpt_api_client.resources.catalog.products_items import ( + AsyncProductItemService, + ProductItemService, +) from mpt_api_client.resources.catalog.products_media import ( AsyncMediaService, MediaService, @@ -66,6 +70,7 @@ def test_async_mixins_present(async_products_service, method): @pytest.mark.parametrize( ("service_method", "expected_service_class"), [ + ("items", ProductItemService), ("item_groups", ItemGroupsService), ("parameter_groups", ParameterGroupsService), ("media", MediaService), @@ -85,6 +90,7 @@ def test_property_services(products_service, service_method, expected_service_cl @pytest.mark.parametrize( ("service_method", "expected_service_class"), [ + ("items", AsyncProductItemService), ("item_groups", AsyncItemGroupsService), ("parameter_groups", AsyncParameterGroupsService), ("media", AsyncMediaService), diff --git a/tests/unit/resources/catalog/test_products_items.py b/tests/unit/resources/catalog/test_products_items.py new file mode 100644 index 00000000..26ed58f3 --- /dev/null +++ b/tests/unit/resources/catalog/test_products_items.py @@ -0,0 +1,44 @@ +import pytest + +from mpt_api_client.resources.catalog.products_items import ( + AsyncProductItemService, + ProductItemService, +) + + +@pytest.fixture +def product_items_service(http_client): + return ProductItemService(http_client=http_client, endpoint_params={"product_id": "PRD-001"}) + + +@pytest.fixture +def async_product_items_service(async_http_client): + return AsyncProductItemService( + http_client=async_http_client, endpoint_params={"product_id": "PRD-001"} + ) + + +def test_endpoint(product_items_service): + result = product_items_service.path == "/public/v1/catalog/products/PRD-001/items" + + assert result is True + + +def test_async_endpoint(async_product_items_service): + result = async_product_items_service.path == "/public/v1/catalog/products/PRD-001/items" + + assert result is True + + +@pytest.mark.parametrize("method", ["get", "iterate"]) +def test_methods_present(product_items_service, method): + result = hasattr(product_items_service, method) + + assert result is True + + +@pytest.mark.parametrize("method", ["get", "iterate"]) +def test_async_methods_present(async_product_items_service, method): + result = hasattr(async_product_items_service, method) + + assert result is True From 9379b070f6ee4bf68833dc9475a1a6abffb9828d Mon Sep 17 00:00:00 2001 From: Albert Sola Date: Wed, 3 Dec 2025 10:34:51 +0000 Subject: [PATCH 2/2] Increase timeouts as e2e fail by timeout --- mpt_api_client/http/async_client.py | 2 +- mpt_api_client/http/client.py | 2 +- tests/unit/http/test_async_client.py | 4 ++-- tests/unit/http/test_client.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mpt_api_client/http/async_client.py b/mpt_api_client/http/async_client.py index 281c55e5..7881af83 100644 --- a/mpt_api_client/http/async_client.py +++ b/mpt_api_client/http/async_client.py @@ -27,7 +27,7 @@ def __init__( *, base_url: str | None = None, api_token: str | None = None, - timeout: float = 5.0, + timeout: float = 10.0, retries: int = 5, ): api_token = api_token or os.getenv("MPT_TOKEN") diff --git a/mpt_api_client/http/client.py b/mpt_api_client/http/client.py index 96a49fe5..f244b689 100644 --- a/mpt_api_client/http/client.py +++ b/mpt_api_client/http/client.py @@ -40,7 +40,7 @@ def __init__( *, base_url: str | None = None, api_token: str | None = None, - timeout: float = 5.0, + timeout: float = 10.0, retries: int = 5, ): api_token = api_token or os.getenv("MPT_TOKEN") diff --git a/tests/unit/http/test_async_client.py b/tests/unit/http/test_async_client.py index 9ecb143b..7e823a88 100644 --- a/tests/unit/http/test_async_client.py +++ b/tests/unit/http/test_async_client.py @@ -33,7 +33,7 @@ def test_async_http_initialization(mocker): "Authorization": "Bearer test-token", "Accept": "application/json", }, - timeout=5.0, + timeout=10.0, transport=mocker.ANY, ) @@ -53,7 +53,7 @@ def test_async_env_initialization(monkeypatch, mocker): "Authorization": f"Bearer {API_TOKEN}", "Accept": "application/json", }, - timeout=5.0, + timeout=10.0, transport=mocker.ANY, ) diff --git a/tests/unit/http/test_client.py b/tests/unit/http/test_client.py index 041ab6d0..23b0c1ac 100644 --- a/tests/unit/http/test_client.py +++ b/tests/unit/http/test_client.py @@ -22,7 +22,7 @@ def test_http_initialization(mocker): "User-Agent": "swo-marketplace-client/1.0", "Authorization": "Bearer test-token", }, - timeout=5.0, + timeout=10.0, transport=mocker.ANY, ) @@ -41,7 +41,7 @@ def test_env_initialization(monkeypatch, mocker): "User-Agent": "swo-marketplace-client/1.0", "Authorization": f"Bearer {API_TOKEN}", }, - timeout=5.0, + timeout=10.0, transport=mocker.ANY, )