Skip to content

Conversation

@robcsegal
Copy link
Contributor

@robcsegal robcsegal commented Dec 2, 2025

Added commerce assets endpoints
https://softwareone.atlassian.net/browse/MPT-16142

Summary by CodeRabbit

  • New Features

    • Commerce asset management: create, read, update, terminate, and render endpoints — available synchronously and asynchronously.
    • Commerce resource now exposes an assets accessor for both sync and async clients.
  • Tests

    • Unit and async tests added covering render, terminate, and standard CRUD behaviors for the assets service, plus integration with commerce accessors.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 2, 2025

Walkthrough

Adds Asset and AssetTemplate models and synchronous/asynchronous Assets services (create/update/get/collection) with terminate and render endpoints, integrates assets accessors into Commerce/AsyncCommerce, and adds unit + async tests for the new services and integration.

Changes

Cohort / File(s) Change Summary
New Asset models & services
mpt_api_client/resources/commerce/assets.py
Adds Asset and AssetTemplate model classes; AssetsServiceConfig with _endpoint="/public/v1/commerce/assets", _model_class=Asset, _collection_key="data"; AssetsService (sync) and AsyncAssetsService (async) composed from CRUD mixins and implementing terminate(...) and render(...), using _resource_do_request / async variant and from_response.
Commerce integration
mpt_api_client/resources/commerce/commerce.py
Imports AssetsService and AsyncAssetsService; adds assets properties to Commerce and AsyncCommerce returning respective service instances.
Tests
tests/unit/resources/commerce/test_assets.py, tests/unit/resources/commerce/test_commerce.py
Adds unit and async tests covering render and terminate endpoints, presence of CRUD methods for both sync/async services, and Commerce integration; uses HTTP client mocks and fixtures.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AssetsService
    participant HTTP_API as "Commerce API"
    participant Model as "Asset / AssetTemplate"

    Client->>AssetsService: render(asset_id) / terminate(asset_id, resource_data?)
    AssetsService->>HTTP_API: HTTP request to /public/v1/commerce/assets/... (sync/async)
    HTTP_API-->>AssetsService: JSON response
    AssetsService->>Model: from_response(json) -> Asset / AssetTemplate
    AssetsService-->>Client: return model instance
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review request paths, HTTP methods and payloads used by terminate and render (sync + async) in mpt_api_client/resources/commerce/assets.py.
  • Verify AssetsServiceConfig attributes and generic mixin composition.
  • Check async test fixtures and respx/httpx mock usage in tests/unit/resources/commerce/test_assets.py.
  • Confirm assets property wiring in mpt_api_client/resources/commerce/commerce.py and extended commerce tests.

Suggested reviewers

  • d3rky
  • jentyk
  • alephsur
  • ruben-sebrango

Poem

🐰 I hopped into code with eager paws,
Assets, templates, endpoints in a row,
Render and terminate — both fast and spry,
Tests give a nod as mocks flutter by,
Puff of carrots, then off I go!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding commerce assets endpoints to the API client.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch MPT-16142-add-missing-assets-endpoints-to-commerce

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 2, 2025

Warnings
⚠️

Some newly added source files do not have corresponding tests in the tests/ folder with matching structure and the test_ prefix.

✅ Found Jira issue key in the title: MPT-16142

Tests mirroring check (created files only)

Added source file Expected test (added in this PR)
mpt_api_client/resources/commerce/assets.py tests/resources/commerce/test_assets.py

Generated by 🚫 dangerJS against b6593ae

@robcsegal robcsegal force-pushed the MPT-16142-add-missing-assets-endpoints-to-commerce branch from 74aeec2 to 3032b6d Compare December 2, 2025 18:09
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
mpt_api_client/resources/commerce/assets.py (2)

42-50: Guard terminate against sending json=None when no payload is required

Both sync and async terminate pass json=resource_data directly into _resource_do_request, which means that when resource_data is None, the underlying client may serialize a literal null body instead of omitting the request body entirely. If the terminate endpoint expects an empty body, this could be undesirable.

Consider only including the json argument when resource_data is not None, e.g.:

-    def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
+    def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
@@
-        response = self._resource_do_request(asset_id, "POST", "terminate", json=resource_data)
+        kwargs = {"json": resource_data} if resource_data is not None else {}
+        response = self._resource_do_request(asset_id, "POST", "terminate", **kwargs)
@@
-    async def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
+    async def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
@@
-        response = await self._resource_do_request(
-            asset_id, "POST", "terminate", json=resource_data
-        )
+        kwargs = {"json": resource_data} if resource_data is not None else {}
+        response = await self._resource_do_request(
+            asset_id, "POST", "terminate", **kwargs
+        )

Also applies to: 76-85


52-63: Align render docstrings with the actual return type

Both sync and async render methods return an AssetTemplate model instance, but the docstring says “Render asset template json.” Updating the return description to explicitly mention AssetTemplate will better reflect the API and help IDEs/docs:

  • E.g., “Returns: AssetTemplate model representing the rendered asset template.”

Also applies to: 89-100

tests/unit/resources/commerce/test_commerce.py (1)

55-65: Use async_http_client in async properties test to tighten type coverage

test_async_commerce_properties constructs AsyncCommerce(http_client=http_client), so all async services (including the new assets accessor) are built with the sync http_client fixture. This passes the current isinstance checks but won’t catch interface drift between AsyncHTTPClient and HTTPClient.

Consider switching the fixture to async_http_client (as in test_async_commerce_init) so async services are instantiated with the correct client type.

-@pytest.mark.parametrize(
+@pytest.mark.parametrize(
@@
-def test_async_commerce_properties(http_client, attr_name, expected):
-    commerce = AsyncCommerce(http_client=http_client)
+def test_async_commerce_properties(async_http_client, attr_name, expected):
+    commerce = AsyncCommerce(http_client=async_http_client)
tests/unit/resources/commerce/test_assets.py (2)

19-34: Strengthen async tests with explicit markers and route assertions

Two small improvements to consider for the async tests:

  • test_async_render currently doesn’t capture the respx route or assert that it was called, unlike the terminate tests. You can mirror the other tests to verify the mock was hit:
-    with respx.mock:
-        respx.get("https://api.example.com/public/v1/commerce/assets/ASSET-123/render").mock(
+    with respx.mock:
+        mock_route = respx.get(
+            "https://api.example.com/public/v1/commerce/assets/ASSET-123/render"
+        ).mock(
@@
-        result = await async_assets_service.render("ASSET-123")
-
-        assert result is not None
+        result = await async_assets_service.render("ASSET-123")
+
+        assert mock_route.called
+        assert mock_route.call_count == 1
+        assert result is not None
  • Both test_async_render and test_async_terminate are plain async def tests without a visible marker. Depending on your pytest/pytest-asyncio configuration, you may need @pytest.mark.asyncio or @pytest.mark.anyio to ensure these tests are actually awaited and executed.

Also applies to: 75-92


95-102: Optionally assert that service attributes are callable, not just present

The parametrized method tests currently only check hasattr(assets_service, method). To guard against these attributes being accidentally replaced with non-callables, you could also assert callability:

-@pytest.mark.parametrize("method", ["create", "update", "get"])
-def test_assets_service_methods(assets_service, method):
-    assert hasattr(assets_service, method)  # act
+@pytest.mark.parametrize("method", ["create", "update", "get"])
+def test_assets_service_methods(assets_service, method):
+    assert hasattr(assets_service, method)
+    assert callable(getattr(assets_service, method))
@@
-@pytest.mark.parametrize("method", ["create", "update", "get"])
-def test_async_assets_service_methods(async_assets_service, method):
-    assert hasattr(async_assets_service, method)  # act
+@pytest.mark.parametrize("method", ["create", "update", "get"])
+def test_async_assets_service_methods(async_assets_service, method):
+    assert hasattr(async_assets_service, method)
+    assert callable(getattr(async_assets_service, method))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c24cde9 and 3032b6d.

📒 Files selected for processing (4)
  • mpt_api_client/resources/commerce/assets.py (1 hunks)
  • mpt_api_client/resources/commerce/commerce.py (3 hunks)
  • tests/unit/resources/commerce/test_assets.py (1 hunks)
  • tests/unit/resources/commerce/test_commerce.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
mpt_api_client/resources/commerce/commerce.py (1)
mpt_api_client/resources/commerce/assets.py (2)
  • AssetsService (32-63)
  • AsyncAssetsService (66-100)
tests/unit/resources/commerce/test_commerce.py (2)
mpt_api_client/resources/commerce/commerce.py (2)
  • assets (33-35)
  • assets (60-62)
mpt_api_client/resources/commerce/assets.py (2)
  • AssetsService (32-63)
  • AsyncAssetsService (66-100)
mpt_api_client/resources/commerce/assets.py (4)
mpt_api_client/http/async_service.py (1)
  • AsyncService (12-80)
mpt_api_client/http/service.py (1)
  • Service (12-80)
mpt_api_client/http/mixins.py (8)
  • AsyncCollectionMixin (538-605)
  • AsyncCreateMixin (259-270)
  • AsyncGetMixin (380-395)
  • AsyncUpdateMixin (286-300)
  • CollectionMixin (469-535)
  • CreateMixin (15-26)
  • GetMixin (361-377)
  • UpdateMixin (41-55)
mpt_api_client/models/model.py (1)
  • Model (65-125)
tests/unit/resources/commerce/test_assets.py (3)
mpt_api_client/resources/commerce/commerce.py (2)
  • assets (33-35)
  • assets (60-62)
mpt_api_client/resources/commerce/assets.py (4)
  • AssetsService (32-63)
  • AsyncAssetsService (66-100)
  • terminate (42-50)
  • terminate (76-87)
mpt_api_client/http/types.py (2)
  • Response (27-42)
  • json (40-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
mpt_api_client/resources/commerce/assets.py (1)

24-39: Assets service config and class composition look consistent

AssetsServiceConfig and the AssetsService / AsyncAssetsService inheritance order (mixins, then Service/AsyncService, then config) match the existing patterns from other commerce services, so endpoint, model binding, and collection handling should behave consistently.

tests/unit/resources/commerce/test_commerce.py (1)

38-45: Extending property coverage to assets keeps Commerce API surface consistent

Adding "assets" to the parametrized test_commerce_properties alongside agreements/orders/subscriptions ensures the new service accessor is exercised in the same way as existing ones.

mpt_api_client/resources/commerce/commerce.py (1)

3-3: New assets accessors align with existing Commerce service pattern

Importing AssetsService/AsyncAssetsService and exposing them via assets properties on Commerce and AsyncCommerce mirrors the existing agreements/orders/subscriptions accessors, keeping the public API shape consistent across all commerce sub-services.

Also applies to: 32-35, 59-62

@svazquezco svazquezco self-requested a review December 3, 2025 11:39
@robcsegal robcsegal force-pushed the MPT-16142-add-missing-assets-endpoints-to-commerce branch from 3032b6d to 5177ecf Compare December 3, 2025 13:00
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/unit/resources/commerce/test_assets.py (1)

95-102: Extend method-presence tests to cover iterate as well

The parametrized tests for method presence cover only create, update, and get. Given AssetsService / AsyncAssetsService also inherit CollectionMixin / AsyncCollectionMixin, consider adding "iterate" to the list to ensure collection iteration remains available on these services:

-@pytest.mark.parametrize("method", ["create", "update", "get"])
+@pytest.mark.parametrize("method", ["create", "update", "get", "iterate"])
 def test_assets_service_methods(assets_service, method):
     assert hasattr(assets_service, method)  # act


-@pytest.mark.parametrize("method", ["create", "update", "get"])
+@pytest.mark.parametrize("method", ["create", "update", "get", "iterate"])
 def test_async_assets_service_methods(async_assets_service, method):
     assert hasattr(async_assets_service, method)  # act

This aligns with previous feedback about checking iterate on the collection mixin-based services.

🧹 Nitpick comments (4)
tests/unit/resources/commerce/test_assets.py (2)

19-33: Align async render test with sync tests by asserting route usage

test_async_render only asserts that the result is not None, while the sync test_render additionally checks mock_route.called and call_count. For better verification that the correct URL/method are used, consider capturing the route and asserting it was called (and how many times), similar to the sync test:

 async def test_async_render(async_assets_service):
     render_response = {"id": "ASSET-123", "title": "Sample Asset"}
     with respx.mock:
-        respx.get("https://api.example.com/public/v1/commerce/assets/ASSET-123/render").mock(
+        mock_route = respx.get(
+            "https://api.example.com/public/v1/commerce/assets/ASSET-123/render"
+        ).mock(
             return_value=httpx.Response(
                 status_code=200,
                 headers={"content-type": APPLICATION_JSON},
                 json=render_response,
             )
         )

         result = await async_assets_service.render("ASSET-123")

-        assert result is not None
+        assert mock_route.called
+        assert mock_route.call_count == 1
+        assert result is not None

35-92: Optionally assert model fields, not just non-None results

The sync/async render and terminate tests currently assert only that the result is non-None (plus route usage for sync). To more tightly couple tests to expected behavior of Asset / AssetTemplate, you could also assert on key fields (e.g., result.id, result.status, result.title) to ensure the model parsing is correct:

assert result.id == "ASSET-123"
# for terminate:
assert result.status == "terminated"
# for render:
assert result.title == "Sample Asset"

This would catch mismatches between the API payload and model behavior earlier.

mpt_api_client/resources/commerce/assets.py (2)

42-50: Use _resource_action in terminate for consistency and headers

AssetsService.terminate currently calls _resource_do_request directly and then wraps the response with _model_class.from_response. Since Service already exposes _resource_action that handles Accept headers and wraps the response, you can simplify and align with other methods:

-    def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
+    def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
         """Terminate the given Asset id.
@@
-        response = self._resource_do_request(asset_id, "POST", "terminate", json=resource_data)
-        return self._model_class.from_response(response)
+        return self._resource_action(  # type: ignore[no-any-return]
+            asset_id,
+            "POST",
+            "terminate",
+            json=resource_data,
+        )

This reuses the shared logic and keeps behavior (including headers) consistent with other resource actions.


76-87: Mirror the same _resource_action usage in async terminate

For AsyncAssetsService.terminate, you can similarly delegate to AsyncService._resource_action to avoid duplicating response handling and ensure headers are applied consistently:

-    async def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
+    async def terminate(
+        self,
+        asset_id: str,
+        resource_data: ResourceData | None = None,
+    ) -> Asset:
@@
-        response = await self._resource_do_request(
-            asset_id, "POST", "terminate", json=resource_data
-        )
-
-        return self._model_class.from_response(response)
+        return await self._resource_action(  # type: ignore[no-any-return]
+            asset_id,
+            "POST",
+            "terminate",
+            json=resource_data,
+        )

This keeps sync and async implementations parallel and leverages the existing helper.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3032b6d and 5177ecf.

📒 Files selected for processing (4)
  • mpt_api_client/resources/commerce/assets.py (1 hunks)
  • mpt_api_client/resources/commerce/commerce.py (3 hunks)
  • tests/unit/resources/commerce/test_assets.py (1 hunks)
  • tests/unit/resources/commerce/test_commerce.py (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • mpt_api_client/resources/commerce/commerce.py
  • tests/unit/resources/commerce/test_commerce.py
🧰 Additional context used
🧬 Code graph analysis (2)
tests/unit/resources/commerce/test_assets.py (3)
mpt_api_client/resources/commerce/commerce.py (2)
  • assets (33-35)
  • assets (60-62)
mpt_api_client/resources/commerce/assets.py (6)
  • AssetsService (32-63)
  • AsyncAssetsService (66-100)
  • render (52-63)
  • render (89-100)
  • terminate (42-50)
  • terminate (76-87)
tests/unit/conftest.py (2)
  • http_client (17-18)
  • async_http_client (22-23)
mpt_api_client/resources/commerce/assets.py (4)
mpt_api_client/http/async_service.py (1)
  • AsyncService (12-80)
mpt_api_client/http/service.py (1)
  • Service (12-80)
mpt_api_client/http/mixins.py (7)
  • AsyncCreateMixin (259-270)
  • AsyncGetMixin (380-395)
  • AsyncUpdateMixin (286-300)
  • CollectionMixin (469-535)
  • CreateMixin (15-26)
  • GetMixin (361-377)
  • UpdateMixin (41-55)
mpt_api_client/models/model.py (1)
  • Model (65-125)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
mpt_api_client/resources/commerce/assets.py (2)

16-39: Models and service configuration look consistent with existing patterns

Asset, AssetTemplate, and AssetsServiceConfig are straightforward Model subclasses and config with _endpoint, _model_class, and _collection_key. This aligns with other services in the codebase and should integrate cleanly with the shared HTTP/mixins infrastructure.


52-63: Render methods are straightforward and align with HTTP helpers

Both sync and async render correctly use _resource_do_request with the "render" action and wrap the response with AssetTemplate.from_response, which fits the pattern for alternate model representations. The URL construction matches the shared Service/AsyncService helpers and the tests’ expectations.

Also applies to: 89-100

@robcsegal robcsegal force-pushed the MPT-16142-add-missing-assets-endpoints-to-commerce branch from 5177ecf to 4c01907 Compare December 3, 2025 13:06
@robcsegal robcsegal requested a review from albertsola December 3, 2025 13:07
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
mpt_api_client/resources/commerce/assets.py (1)

16-29: Assets models and services align with existing service/mixin patterns

Asset / AssetTemplate as Model subclasses, the AssetsServiceConfig endpoint/model/collection configuration, and the sync/async AssetsService/AsyncAssetsService classes all look consistent with the rest of the client:

  • terminate correctly goes through _resource_do_request with a POST and action "terminate" and returns Asset via self._model_class.from_response.
  • render correctly uses the same resource path with action "render" but wraps the response as an AssetTemplate, which is appropriate for a different response schema.
  • Async counterparts mirror the sync implementations using await _resource_do_request(...) with matching type hints.

The small duplication between sync and async implementations is acceptable and matches the existing style in this client; you could optionally factor shared logic later if more asset-specific operations are added.

Also applies to: 32-100

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5177ecf and 4c01907.

📒 Files selected for processing (4)
  • mpt_api_client/resources/commerce/assets.py (1 hunks)
  • mpt_api_client/resources/commerce/commerce.py (3 hunks)
  • tests/unit/resources/commerce/test_assets.py (1 hunks)
  • tests/unit/resources/commerce/test_commerce.py (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/unit/resources/commerce/test_assets.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • mpt_api_client/resources/commerce/commerce.py
🧰 Additional context used
🧬 Code graph analysis (2)
tests/unit/resources/commerce/test_commerce.py (2)
mpt_api_client/resources/commerce/commerce.py (2)
  • assets (33-35)
  • assets (60-62)
mpt_api_client/resources/commerce/assets.py (2)
  • AssetsService (32-63)
  • AsyncAssetsService (66-100)
mpt_api_client/resources/commerce/assets.py (3)
mpt_api_client/http/service.py (1)
  • Service (12-80)
mpt_api_client/http/mixins.py (8)
  • AsyncCollectionMixin (538-605)
  • AsyncCreateMixin (259-270)
  • AsyncGetMixin (380-395)
  • AsyncUpdateMixin (286-300)
  • CollectionMixin (469-535)
  • CreateMixin (15-26)
  • GetMixin (361-377)
  • UpdateMixin (41-55)
mpt_api_client/models/model.py (1)
  • Model (65-125)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
tests/unit/resources/commerce/test_commerce.py (1)

6-11: Assets services correctly integrated into Commerce/AsyncCommerce tests

The new imports and parametrized cases for "assets" cleanly extend the existing pattern for agreements/orders/subscriptions and correctly exercise the Commerce.assets / AsyncCommerce.assets accessors returning AssetsService and AsyncAssetsService. No issues from a wiring or type perspective.

Also applies to: 38-62

@robcsegal robcsegal force-pushed the MPT-16142-add-missing-assets-endpoints-to-commerce branch from 4c01907 to 75a7d82 Compare December 3, 2025 15:02
@robcsegal robcsegal force-pushed the MPT-16142-add-missing-assets-endpoints-to-commerce branch from 75a7d82 to b6593ae Compare December 3, 2025 16:47
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
tests/unit/resources/commerce/test_commerce.py (1)

64-69: Consider using async_http_client fixture for async commerce property tests

test_async_commerce_properties constructs AsyncCommerce(http_client=http_client), where http_client is the sync client fixture. That’s fine for the current getattr/isinstance checks, but if this test ever starts exercising service methods, passing the async HTTP client fixture would better mirror real usage and avoid accidental await on a sync client.

mpt_api_client/resources/commerce/assets.py (1)

42-50: Use _resource_action for terminate to reduce duplication and match other services

Both sync and async terminate call _resource_do_request and then manually invoke from_response. You can simplify and align with existing mixins by delegating to _resource_action, which already wraps _resource_do_request and sets the JSON Accept header:

@@ class AssetsService(
-    def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
-        """Terminate the given Asset id.
-
-        Args:
-            asset_id: Asset ID.
-            resource_data: Resource data will be updated
-        """
-        response = self._resource_do_request(asset_id, "POST", "terminate", json=resource_data)
-        return self._model_class.from_response(response)
+    def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
+        """Terminate the given Asset id.
+
+        Args:
+            asset_id: Asset ID.
+            resource_data: Resource data will be updated
+        """
+        return self._resource_action(asset_id, "POST", "terminate", json=resource_data)
@@ class AsyncAssetsService(
-    async def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
-        """Terminate the given Asset id.
-
-        Args:
-            asset_id: Asset ID.
-            resource_data: Resource data will be updated
-        """
-        response = await self._resource_do_request(
-            asset_id, "POST", "terminate", json=resource_data
-        )
-
-        return self._model_class.from_response(response)
+    async def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset:
+        """Terminate the given Asset id.
+
+        Args:
+            asset_id: Asset ID.
+            resource_data: Resource data will be updated
+        """
+        return await self._resource_action(asset_id, "POST", "terminate", json=resource_data)

Functionality stays the same, but this keeps the implementation closer to other actions and centralizes header handling.

Also applies to: 76-87

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75a7d82 and b6593ae.

📒 Files selected for processing (4)
  • mpt_api_client/resources/commerce/assets.py (1 hunks)
  • mpt_api_client/resources/commerce/commerce.py (3 hunks)
  • tests/unit/resources/commerce/test_assets.py (1 hunks)
  • tests/unit/resources/commerce/test_commerce.py (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/resources/commerce/test_assets.py
🧰 Additional context used
🧬 Code graph analysis (3)
tests/unit/resources/commerce/test_commerce.py (2)
mpt_api_client/resources/commerce/commerce.py (2)
  • assets (33-35)
  • assets (60-62)
mpt_api_client/resources/commerce/assets.py (2)
  • AssetsService (32-63)
  • AsyncAssetsService (66-100)
mpt_api_client/resources/commerce/assets.py (4)
mpt_api_client/http/async_service.py (1)
  • AsyncService (12-80)
mpt_api_client/http/service.py (1)
  • Service (12-80)
mpt_api_client/http/mixins.py (8)
  • AsyncCollectionMixin (538-605)
  • AsyncCreateMixin (259-270)
  • AsyncGetMixin (380-395)
  • AsyncUpdateMixin (286-300)
  • CollectionMixin (469-535)
  • CreateMixin (15-26)
  • GetMixin (361-377)
  • UpdateMixin (41-55)
mpt_api_client/models/model.py (1)
  • Model (65-125)
mpt_api_client/resources/commerce/commerce.py (3)
mpt_api_client/mpt_client.py (2)
  • commerce (49-51)
  • commerce (98-105)
mpt_api_client/resources/commerce/assets.py (2)
  • AssetsService (32-63)
  • AsyncAssetsService (66-100)
tests/unit/conftest.py (1)
  • http_client (17-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
tests/unit/resources/commerce/test_commerce.py (1)

6-7: Assets services correctly wired into Commerce/AsyncCommerce property tests

The new AssetsService / AsyncAssetsService imports and parametrization entries for "assets" are consistent with the existing agreements/orders/subscriptions patterns and will keep the generic property tests in sync with the new commerce surface.

Also applies to: 38-45, 55-62

mpt_api_client/resources/commerce/commerce.py (1)

3-3: New assets service accessors are consistent with existing commerce services

The sync and async assets properties mirror the existing agreements/orders/subscriptions patterns (typed accessors, simple service construction with http_client). Import and wiring look correct, and this cleanly exposes the new assets services through the Commerce/AsyncCommerce facades.

Also applies to: 32-35, 59-62

mpt_api_client/resources/commerce/assets.py (1)

16-39: Asset models and service configuration align with existing HTTP service patterns

Asset / AssetTemplate as thin Model subclasses plus AssetsServiceConfig with _endpoint, _model_class = Asset, and _collection_key = "data" are in line with other resources in the client. Combined into AssetsService / AsyncAssetsService with the standard CRUD mixins, this should integrate cleanly with existing collection and action helpers.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 3, 2025

@robcsegal robcsegal merged commit 1e68515 into main Dec 4, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants