Skip to content

Conversation

@albertsola
Copy link
Contributor

@albertsola albertsola commented Nov 26, 2025

Summary by CodeRabbit

  • New Features

    • Improved pricing policy attachments: unified create/upload and download flows with clearer upload field names.
  • Tests

    • Added comprehensive end-to-end async and sync tests covering attachment lifecycle (create, update, get, download, list/filter, delete).
    • Added and refined fixtures for pricing policies and attachments, with safer teardown behavior and many fixtures simplified (removed unused logger params).
    • Unit tests adjusted to remove activation-related checks.
  • Refactor

    • Consolidated file-operation handling for attachments for more consistent behavior.

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

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Walkthrough

Refactors pricing policy attachments to use CreateFile/DownloadFile mixins with explicit upload keys; adds sync and async end-to-end attachment tests and fixtures; removes activate/deactivate expectations from unit tests; centralizes pricing policy creation in fixtures; and removes logger parameters from many test fixtures.

Changes

Cohort / File(s) Summary
Service refactor
mpt_api_client/resources/catalog/pricing_policy_attachments.py
Replaced FilesOperationsMixin/ActivatableMixin with CreateFileMixin/DownloadFileMixin and async equivalents; added PricingPolicyAttachmentsServiceConfig with _upload_file_key = "file" and _upload_data_key = "attachment"; updated class inheritance and imports.
Attachments E2E tests & fixtures
tests/e2e/catalog/pricing_policies/attachments/conftest.py, tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py, tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py
Added fixtures (attachment_id, attachment_data, attachment_service, created_attachment / async variants) and new sync/async test modules covering create, update, get, download, iterate, filter, not-found, and delete flows.
Pricing policies fixtures & tests
tests/e2e/catalog/pricing_policies/conftest.py, tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py, tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py
Introduced pricing_policies_service and created_pricing_policy fixtures; pricing_policy_id now derives from created policy; updated async test to use primitive pricing_policy_id; removed older fixtures from sync tests.
Unit tests update
tests/unit/resources/catalog/test_pricing_policy_attachments.py
Removed activate/deactivate from expected methods; parameterized expected methods now: ["get","create","delete","update","download"] for both sync and async checks.
Fixture signature cleanup
many tests/e2e/**/test_* (examples)
tests/e2e/catalog/items/test_async_item.py, tests/e2e/catalog/items/test_sync_item.py, tests/e2e/catalog/product/**/test_*
Removed logger parameter from numerous fixtures (sync and async); a few fixtures gained teardown deletion with MPTAPIError handling; bodies otherwise unchanged.

Sequence Diagram(s)

sequenceDiagram
    participant Test
    participant AttachmentService
    participant CreateFileMixin
    participant DownloadFileMixin

    Note over Test,AttachmentService: Attachment lifecycle after mixin refactor

    rect rgb(230,245,240)
    Test->>AttachmentService: create(data, file)
    AttachmentService->>CreateFileMixin: upload(file, data, file_key="file", data_key="attachment")
    CreateFileMixin-->>AttachmentService: created Attachment
    AttachmentService-->>Test: Attachment resource
    end

    rect rgb(245,245,250)
    Test->>AttachmentService: get(attachment_id)
    AttachmentService-->>Test: Attachment
    end

    rect rgb(245,235,255)
    Test->>AttachmentService: download(attachment_id)
    AttachmentService->>DownloadFileMixin: download(file_id)
    DownloadFileMixin-->>AttachmentService: file content + filename
    AttachmentService-->>Test: file bytes, filename
    end

    rect rgb(255,245,230)
    Test->>AttachmentService: delete(attachment_id)
    AttachmentService-->>Test: deletion result
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Focus review on mpt_api_client/resources/catalog/pricing_policy_attachments.py for correct mixin imports, generic typing, and upload key constants.
  • Verify async/sync parity in service inheritance and method availability (create/download).
  • Inspect new E2E fixtures/tests for correct setup/teardown and MPTAPIError handling.
  • Search tests for any remaining references to removed activate/deactivate methods and removed logger parameters.

Poem

🐰 I hopped through code with careful cheer,
Swapped mixins, set upload keys clear.
Tests now dance in sync and async light,
Files upload, download — everything's right.
A rabbit applauds this tidy night.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 summarizes the main change: adding end-to-end tests for catalog pricing-policy attachments, directly matching the changeset content.
✨ 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 e2e/catalog/MPT-14900-pricing-policy-attachments

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

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

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

Generated by 🚫 dangerJS against 90761ff

@albertsola albertsola force-pushed the e2e/catalog/MPT-14900-pricing-policy-attachments branch from 0e1014e to 4d263d8 Compare November 26, 2025 12:48
@albertsola albertsola marked this pull request as ready for review November 26, 2025 12:52
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: 1

🧹 Nitpick comments (5)
tests/e2e/catalog/pricing_policies/attachments/conftest.py (1)

4-6: Consider using direct dictionary access for fail-fast behavior.

Using .get() silently returns None if the config key is missing, which could lead to confusing test failures. Direct access with [] would raise a clear KeyError immediately if the configuration is incomplete.

 @pytest.fixture
 def attachment_id(e2e_config):
-    return e2e_config.get("catalog.pricing_policy.attachment.id")
+    return e2e_config["catalog.pricing_policy.attachment.id"]
tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (3)

14-22: Remove unused logger parameter or use it for teardown logging.

The logger parameter is declared but never used. The teardown uses print() instead. Either remove the parameter or use it consistently.

Option 1 - Remove unused parameter:

 @pytest.fixture
-def created_attachment(logger, attachment_service, attachment_data, pdf_fd):
+def created_attachment(attachment_service, attachment_data, pdf_fd):
     attachment = attachment_service.create(attachment_data, file=pdf_fd)
     yield attachment
     try:
         attachment_service.delete(attachment.id)
     except MPTAPIError as error:
         print(f"TEARDOWN - Unable to delete attachment {attachment.id}: {error.title}")

Option 2 - Use logger consistently:

     except MPTAPIError as error:
-        print(f"TEARDOWN - Unable to delete attachment {attachment.id}: {error.title}")
+        logger.warning(f"TEARDOWN - Unable to delete attachment {attachment.id}: {error.title}")

57-59: Consider using a valid ID prefix pattern for the not-found test.

The ID "ATT-000-000-000" doesn't follow the PPA-* pattern used for pricing policy attachments elsewhere in the config. Using "PPA-0000-0000-0000-0000" would be more consistent and realistic.

 def test_not_found(attachment_service):
     with pytest.raises(MPTAPIError):
-        attachment_service.get("ATT-000-000-000")
+        attachment_service.get("PPA-0000-0000-0000-0000")

62-65: Potential double-delete: created_attachment fixture will attempt cleanup after test already deletes.

The test_delete_attachment test explicitly deletes the attachment, then the created_attachment fixture teardown attempts to delete it again. While the teardown handles the error gracefully, this logs a spurious error message. Consider marking the fixture to skip cleanup when intentionally deleted:

@pytest.fixture
def created_attachment(attachment_service, attachment_data, pdf_fd):
    attachment = attachment_service.create(attachment_data, file=pdf_fd)
    attachment._deleted = False  # Track deletion state
    yield attachment
    if not getattr(attachment, '_deleted', False):
        try:
            attachment_service.delete(attachment.id)
        except MPTAPIError as error:
            print(f"TEARDOWN - Unable to delete attachment {attachment.id}: {error.title}")

Alternatively, this is acceptable as-is since the error is caught.

tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1)

14-22: Use the injected logger instead of print and clear Ruff warning

The logger fixture is injected but never used, and teardown logs go through print, which is inconsistent with structured logging and triggers Ruff’s ARG001 warning.

You can both fix the warning and improve logging by switching to logger.warning (or similar) in the teardown:

 @pytest.fixture
 async def created_attachment_async(logger, async_attachment_service, attachment_data, pdf_fd):
     attachment = await async_attachment_service.create(attachment_data, file=pdf_fd)
     yield attachment
     try:
         await async_attachment_service.delete(attachment.id)
     except MPTAPIError as error:
-        print(f"TEARDOWN - Unable to delete attachment {attachment.id}: {error.title}")
+        logger.warning(
+            "TEARDOWN - Unable to delete attachment %s: %s",
+            attachment.id,
+            error.title,
+        )

Note: this also makes the “unable to delete” message clearly come from test teardown, which is helpful given that test_delete_attachment_async will intentionally delete the resource before fixture teardown runs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8994da6 and 4d263d8.

📒 Files selected for processing (6)
  • e2e_config.test.json (1 hunks)
  • mpt_api_client/resources/catalog/pricing_policy_attachments.py (3 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/conftest.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (1 hunks)
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/e2e/catalog/pricing_policies/attachments/conftest.py (1)
tests/e2e/conftest.py (1)
  • e2e_config (89-92)
mpt_api_client/resources/catalog/pricing_policy_attachments.py (3)
mpt_api_client/http/mixins.py (2)
  • AsyncDownloadFileMixin (231-253)
  • DownloadFileMixin (59-81)
mpt_api_client/models/model.py (1)
  • Model (65-125)
mpt_api_client/resources/catalog/mixins.py (2)
  • AsyncCreateFileMixin (84-110)
  • CreateFileMixin (121-147)
🪛 Ruff (0.14.5)
tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py

15-15: Unused function argument: logger

(ARG001)

tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py

15-15: Unused function argument: logger

(ARG001)

⏰ 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 (8)
e2e_config.test.json (1)

22-24: LGTM!

The new configuration entries follow the existing naming conventions and ID patterns. The pricing policy attachment ID (PPA-1123-5132-3456-0001) appropriately includes the parent pricing policy ID prefix.

tests/e2e/catalog/pricing_policies/attachments/conftest.py (1)

9-14: LGTM!

The fixture provides reusable test data with clear, descriptive values.

tests/unit/resources/catalog/test_pricing_policy_attachments.py (1)

39-46: LGTM!

The updated method list correctly reflects the refactored service interface—download from DownloadFileMixin and create from CreateFileMixin, with activate/deactivate appropriately removed.

tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (1)

24-54: LGTM!

The test coverage is comprehensive, covering CRUD operations, iteration, filtering, and error handling. The assertions are appropriate and verify the expected behavior.

mpt_api_client/resources/catalog/pricing_policy_attachments.py (3)

1-14: LGTM!

The import restructuring cleanly separates concerns—DownloadFileMixin from generic HTTP mixins and CreateFileMixin from catalog-specific mixins. This aligns with the different behaviors needed for file operations.


21-28: LGTM!

The configuration class properly defines _upload_file_key and _upload_data_key which are consumed by CreateFileMixin for multipart form construction.


31-50: LGTM!

The service classes correctly inherit from the new mixins with proper MRO ordering. The removal of ActivatableMixin and replacement with explicit CreateFileMixin/DownloadFileMixin provides clearer, more precise file operation capabilities.

tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1)

29-66: Async lifecycle tests for attachments look comprehensive

The async tests for update, get, download, iteration, filtering, not‑found, and delete exercise the key behaviors of the attachments service (including iterator + RQL query usage and error handling) and read clearly. No issues from my side here.

Comment on lines 24 to 29
def test_create_attachment_async(created_attachment_async, attachment_data):
assert created_attachment_async.name == attachment_data["name"]
assert created_attachment_async.description == attachment_data["description"]

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

test_create_attachment_async should likely be async def to match the async fixture

All other tests using created_attachment_async are async def, but this one is a plain def. With an async fixture, this can result in the test receiving a coroutine instead of the resolved attachment object (depending on your async plugin configuration), and created_attachment_async.name would then fail.

Recommend aligning it with the rest of the suite:

-def test_create_attachment_async(created_attachment_async, attachment_data):
+async def test_create_attachment_async(created_attachment_async, attachment_data):
     assert created_attachment_async.name == attachment_data["name"]
     assert created_attachment_async.description == attachment_data["description"]

This keeps usage consistent and avoids potential coroutine/attribute errors at runtime.

🤖 Prompt for AI Agents
In tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py
around lines 24 to 27, the test function is declared as a synchronous def but
uses the async fixture created_attachment_async; change the test to be async def
so pytest/async plugin will await the fixture and provide the resolved
attachment, then keep the same assertions (i.e., make the function async to
avoid receiving a coroutine and attribute access errors).

@albertsola albertsola force-pushed the e2e/catalog/MPT-14900-pricing-policy-attachments branch from 4d263d8 to 89ffd3a Compare November 27, 2025 09:45
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 (3)
tests/e2e/catalog/pricing_policies/attachments/conftest.py (1)

24-31: Use the injected logger instead of print in teardown

logger is currently unused and teardown errors are printed instead of logged. You can both fix the Ruff warning and improve logging by wiring the logger into the exception path:

-@pytest.fixture
-def created_attachment(logger, attachment_service, attachment_data, pdf_fd):
+@pytest.fixture
+def created_attachment(logger, attachment_service, attachment_data, pdf_fd):
     attachment = attachment_service.create(attachment_data, file=pdf_fd)
     yield attachment
     try:
         attachment_service.delete(attachment.id)
     except MPTAPIError as error:
-        print(f"TEARDOWN - Unable to delete attachment {attachment.id}: {error.title}")
+        logger.warning(
+            "TEARDOWN - Unable to delete attachment %s: %s",
+            attachment.id,
+            error.title,
+        )
tests/e2e/catalog/pricing_policies/conftest.py (1)

23-37: Align teardown logging with the shared logger fixture (optional)

The teardown currently uses print to report failures deleting the pricing policy. For consistency with other e2e fixtures (and to keep logs centralized), consider injecting the logger fixture here and logging a warning instead:

-@pytest.fixture
-def created_pricing_policy(pricing_policies_service, pricing_policy_data):
+@pytest.fixture
+def created_pricing_policy(logger, pricing_policies_service, pricing_policy_data):
     policy = pricing_policies_service.create(pricing_policy_data)

     yield policy

     try:
         pricing_policies_service.delete(policy.id)
     except MPTAPIError as error:
-        print(f"TEARDOWN - Unable to delete pricing policy {policy.id}: {error.title}")
+        logger.warning(
+            "TEARDOWN - Unable to delete pricing policy %s: %s",
+            policy.id,
+            error.title,
+        )
tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1)

14-21: Use the logger fixture instead of print in async teardown

Same as the sync attachments fixture: logger is injected but unused, and teardown failures are printed. Switching to the logger both fixes the Ruff warning and improves observability.

-@pytest.fixture
-async def created_attachment_async(logger, async_attachment_service, attachment_data, pdf_fd):
+@pytest.fixture
+async def created_attachment_async(logger, async_attachment_service, attachment_data, pdf_fd):
     attachment = await async_attachment_service.create(attachment_data, file=pdf_fd)
     yield attachment
     try:
         await async_attachment_service.delete(attachment.id)
     except MPTAPIError as error:
-        print(f"TEARDOWN - Unable to delete attachment {attachment.id}: {error.title}")
+        logger.warning(
+            "TEARDOWN - Unable to delete attachment %s: %s",
+            attachment.id,
+            error.title,
+        )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d263d8 and 89ffd3a.

📒 Files selected for processing (8)
  • mpt_api_client/resources/catalog/pricing_policy_attachments.py (3 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/conftest.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/conftest.py (2 hunks)
  • tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py (0 hunks)
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py (1 hunks)
💤 Files with no reviewable changes (1)
  • tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py
  • tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-27T00:05:54.691Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 131
File: tests/e2e/accounts/accounts_users/test_async_accounts_users.py:0-0
Timestamp: 2025-11-27T00:05:54.691Z
Learning: In pytest-asyncio, async fixtures are automatically resolved before being passed to test functions (both sync and async). Test functions receive the yielded value from async fixtures, not coroutines, so fixture parameters should never be awaited. A sync test function can use async fixtures without any special handling.

Applied to files:

  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py
🧬 Code graph analysis (4)
tests/e2e/catalog/pricing_policies/attachments/conftest.py (4)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
mpt_api_client/models/model.py (1)
  • id (119-121)
tests/e2e/conftest.py (3)
  • mpt_ops (31-32)
  • logger (63-64)
  • pdf_fd (73-75)
tests/e2e/catalog/pricing_policies/conftest.py (1)
  • pricing_policy_id (41-42)
mpt_api_client/resources/catalog/pricing_policy_attachments.py (2)
mpt_api_client/http/mixins.py (2)
  • AsyncDownloadFileMixin (231-253)
  • DownloadFileMixin (59-81)
mpt_api_client/resources/catalog/mixins.py (2)
  • AsyncCreateFileMixin (84-110)
  • CreateFileMixin (121-147)
tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (5)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
mpt_api_client/rql/query_builder.py (2)
  • RQLQuery (115-524)
  • any (260-270)
tests/e2e/conftest.py (2)
  • async_mpt_ops (36-39)
  • pdf_fd (73-75)
tests/e2e/catalog/pricing_policies/conftest.py (1)
  • pricing_policy_id (41-42)
tests/e2e/catalog/pricing_policies/attachments/conftest.py (2)
  • attachment_data (12-16)
  • attachment_id (7-8)
tests/e2e/catalog/pricing_policies/conftest.py (4)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
tests/unit/resources/catalog/test_pricing_policies.py (1)
  • pricing_policies_service (16-17)
tests/e2e/conftest.py (1)
  • mpt_ops (31-32)
mpt_api_client/models/model.py (1)
  • id (119-121)
🪛 Ruff (0.14.6)
tests/e2e/catalog/pricing_policies/attachments/conftest.py

25-25: Unused function argument: logger

(ARG001)

tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py

15-15: Unused function argument: logger

(ARG001)

⏰ 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/e2e/catalog/pricing_policies/test_async_pricing_policies.py (1)

35-37: Async get-by-id test wiring looks correct

Using pricing_policy_id here is a nice way to verify the async service can retrieve a policy created via the sync fixture; the assertions are minimal and sufficient.

mpt_api_client/resources/catalog/pricing_policy_attachments.py (1)

11-48: Create/download mixin wiring and upload config look consistent

The switch to CreateFileMixin/AsyncCreateFileMixin and DownloadFileMixin/AsyncDownloadFileMixin with _upload_file_key = "file" and _upload_data_key = "attachment" in PricingPolicyAttachmentsServiceConfig is consistent with the shared mixin implementations and keeps both sync and async services aligned.

tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1)

24-27: Sync test using async fixture is fine with your pytest-asyncio setup

test_create_attachment_async is a regular def but consumes the async created_attachment_async fixture. With pytest-asyncio automatically resolving async fixtures before injection, this pattern is valid, and the assertions read cleanly without extra await noise. Based on learnings, this does not need to be converted to async def.

@albertsola albertsola force-pushed the e2e/catalog/MPT-14900-pricing-policy-attachments branch from 89ffd3a to 5a5e2b4 Compare November 27, 2025 10:00
@albertsola albertsola changed the title MPT-14900 E2E tests for catalog pricing-policies MPT-14900 E2E tests for catalog pricing-policies attachments Nov 27, 2025
@svazquezco
Copy link
Contributor

Please, do me the favor of following the AAA pattern we already have here -> https://github.com/softwareone-platform/mpt-api-python-client/pull/134/files

And save me the work to fixing it once you merge the PR

@albertsola albertsola force-pushed the e2e/catalog/MPT-14900-pricing-policy-attachments branch from 5a5e2b4 to 994f471 Compare November 27, 2025 11:33
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/e2e/catalog/product/media/test_sync_media.py (1)

34-42: test_create_media_from_url is not using the URL-based fixture

The test named test_create_media_from_url currently depends on created_media_from_file, so it never exercises creation via URL and the created_media_from_url fixture is unused.

Consider wiring the test to the correct fixture so the URL path is actually covered:

-def test_create_media_from_url(created_media_from_file, media_data):  # noqa: AAA01
-    assert created_media_from_file.name == media_data["name"]
-    assert created_media_from_file.description == media_data["description"]
+def test_create_media_from_url(created_media_from_url, media_data):  # noqa: AAA01
+    assert created_media_from_url.name == media_data["name"]
+    assert created_media_from_url.description == media_data["description"]
🧹 Nitpick comments (1)
tests/e2e/catalog/pricing_policies/conftest.py (1)

40-42: Consider async variant for async tests.

While this fixture correctly extracts the ID from created_pricing_policy, it creates a synchronous dependency chain for async tests (as seen in test_async_pricing_policies.py line 38 where the async test now uses this fixture).

For consistency with the async test execution model, consider whether async tests should use an async_pricing_policy_id fixture derived from async_created_pricing_policy instead.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5a5e2b4 and 994f471.

📒 Files selected for processing (22)
  • mpt_api_client/resources/catalog/pricing_policy_attachments.py (3 hunks)
  • tests/e2e/catalog/items/test_async_item.py (1 hunks)
  • tests/e2e/catalog/items/test_sync_item.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/conftest.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/conftest.py (2 hunks)
  • tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py (0 hunks)
  • tests/e2e/catalog/product/documents/test_async_document.py (2 hunks)
  • tests/e2e/catalog/product/documents/test_sync_document.py (2 hunks)
  • tests/e2e/catalog/product/item_groups/test_async_item_groups.py (1 hunks)
  • tests/e2e/catalog/product/item_groups/test_sync_item_groups.py (1 hunks)
  • tests/e2e/catalog/product/media/test_async_media.py (2 hunks)
  • tests/e2e/catalog/product/media/test_sync_media.py (2 hunks)
  • tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py (1 hunks)
  • tests/e2e/catalog/product/parameter_groups/test_sync_parameter_groups.py (1 hunks)
  • tests/e2e/catalog/product/terms/test_sync_terms.py (2 hunks)
  • tests/e2e/catalog/product/terms/variants/test_sync_variants.py (2 hunks)
  • tests/e2e/catalog/product/test_async_product.py (1 hunks)
  • tests/e2e/catalog/product/test_sync_product.py (1 hunks)
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py (1 hunks)
💤 Files with no reviewable changes (1)
  • tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • tests/e2e/catalog/product/parameter_groups/test_sync_parameter_groups.py
  • tests/e2e/catalog/product/terms/test_sync_terms.py
  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py
  • tests/e2e/catalog/product/terms/variants/test_sync_variants.py
  • tests/e2e/catalog/product/test_async_product.py
  • tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-27T00:05:54.691Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 131
File: tests/e2e/accounts/accounts_users/test_async_accounts_users.py:0-0
Timestamp: 2025-11-27T00:05:54.691Z
Learning: In pytest-asyncio, async fixtures are automatically resolved before being passed to test functions (both sync and async). Test functions receive the yielded value from async fixtures, not coroutines, so fixture parameters should never be awaited. A sync test function can use async fixtures without any special handling.

Applied to files:

  • tests/e2e/catalog/items/test_async_item.py
  • tests/e2e/catalog/product/documents/test_async_document.py
  • tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py
  • tests/e2e/catalog/product/media/test_async_media.py
🧬 Code graph analysis (12)
tests/e2e/catalog/items/test_async_item.py (2)
tests/e2e/conftest.py (1)
  • async_mpt_vendor (24-27)
tests/e2e/catalog/items/conftest.py (1)
  • item_data (5-20)
tests/e2e/catalog/product/documents/test_async_document.py (3)
tests/unit/resources/catalog/test_mixins.py (1)
  • async_document_service (354-355)
tests/e2e/catalog/product/documents/conftest.py (1)
  • document_data (10-16)
tests/e2e/conftest.py (2)
  • pdf_fd (73-75)
  • pdf_url (79-80)
tests/e2e/catalog/product/item_groups/test_sync_item_groups.py (2)
tests/e2e/conftest.py (2)
  • mpt_vendor (19-20)
  • product_id (96-97)
tests/e2e/catalog/product/item_groups/conftest.py (1)
  • item_group_data (5-15)
tests/e2e/catalog/items/test_sync_item.py (2)
tests/e2e/conftest.py (1)
  • mpt_vendor (19-20)
tests/e2e/catalog/items/conftest.py (1)
  • item_data (5-20)
tests/e2e/catalog/product/item_groups/test_async_item_groups.py (2)
tests/e2e/conftest.py (2)
  • async_mpt_vendor (24-27)
  • product_id (96-97)
tests/e2e/catalog/product/item_groups/conftest.py (1)
  • item_group_data (5-15)
tests/e2e/catalog/product/documents/test_sync_document.py (2)
tests/e2e/catalog/product/documents/conftest.py (2)
  • vendor_document_service (20-21)
  • document_data (10-16)
tests/e2e/conftest.py (2)
  • pdf_fd (73-75)
  • pdf_url (79-80)
tests/e2e/catalog/product/media/test_async_media.py (3)
tests/unit/http/test_mixins.py (1)
  • async_media_service (35-38)
tests/e2e/catalog/product/media/conftest.py (2)
  • media_data (5-14)
  • test_media_file (18-19)
tests/e2e/conftest.py (1)
  • jpg_url (84-85)
tests/e2e/catalog/pricing_policies/attachments/conftest.py (4)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
mpt_api_client/models/model.py (1)
  • id (119-121)
tests/e2e/conftest.py (2)
  • mpt_ops (31-32)
  • pdf_fd (73-75)
tests/e2e/catalog/pricing_policies/conftest.py (1)
  • pricing_policy_id (41-42)
tests/e2e/catalog/product/test_sync_product.py (2)
tests/e2e/conftest.py (2)
  • mpt_vendor (19-20)
  • logo_fd (106-108)
tests/e2e/catalog/product/conftest.py (1)
  • product_data (5-6)
tests/e2e/catalog/pricing_policies/conftest.py (4)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
tests/unit/resources/catalog/test_pricing_policies.py (1)
  • pricing_policies_service (16-17)
tests/e2e/conftest.py (1)
  • mpt_ops (31-32)
mpt_api_client/models/model.py (1)
  • id (119-121)
tests/e2e/catalog/product/media/test_sync_media.py (2)
tests/e2e/catalog/product/media/conftest.py (2)
  • media_data (5-14)
  • test_media_file (18-19)
tests/e2e/conftest.py (1)
  • jpg_url (84-85)
mpt_api_client/resources/catalog/pricing_policy_attachments.py (2)
mpt_api_client/http/mixins.py (2)
  • AsyncDownloadFileMixin (231-253)
  • DownloadFileMixin (59-81)
mpt_api_client/resources/catalog/mixins.py (2)
  • AsyncCreateFileMixin (84-110)
  • CreateFileMixin (121-147)
🔇 Additional comments (20)
tests/unit/resources/catalog/test_pricing_policy_attachments.py (1)

43-43: LGTM!

The parameterized methods list correctly reflects the service's new API surface after replacing ActivatableMixin with CreateFileMixin and DownloadFileMixin.

Also applies to: 50-50

tests/e2e/catalog/items/test_async_item.py (1)

9-17: LGTM!

Removing the unused logger parameter simplifies the fixture signature without affecting functionality.

tests/e2e/catalog/product/test_sync_product.py (1)

7-16: LGTM!

Consistent with the PR-wide cleanup of unused logger parameters from fixtures.

tests/e2e/catalog/product/documents/test_async_document.py (1)

14-33: LGTM!

Both fixtures (created_document_from_file_async and created_document_from_link_async) have their unused logger parameters removed, consistent with the PR-wide cleanup.

tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py (1)

6-14: LGTM!

Removing the unused logger parameter aligns with the PR-wide fixture signature cleanup.

mpt_api_client/resources/catalog/pricing_policy_attachments.py (2)

21-28: Configuration keys look correct for file upload semantics.

The _upload_file_key = "file" and _upload_data_key = "attachment" will be used by CreateFileMixin to structure multipart requests. Ensure these keys match the API's expected field names for pricing policy attachments.


31-50: Well-structured mixin composition.

The service classes correctly compose the file-operations mixins (CreateFileMixin, DownloadFileMixin) with the resource management mixins. The MRO places mixins before the base Service class, ensuring proper method resolution. This aligns with the updated unit test expectations.

tests/e2e/catalog/product/item_groups/test_async_item_groups.py (1)

9-17: Async item group fixture change looks correct

Removing the unused logger parameter keeps the fixture clean, and the async create/delete flow remains unchanged and consistent with the sync variant.

tests/e2e/catalog/items/test_sync_item.py (1)

9-17: Synchronous item fixture refactor is safe

Dropping the logger parameter from created_item is harmless here—the body never used it, and create/teardown behavior is preserved.

tests/e2e/catalog/product/item_groups/test_sync_item_groups.py (1)

9-17: Sync item group fixture cleanup looks good

The created_item_group fixture no longer accepts an unused logger, while creation and teardown semantics remain intact and aligned with other catalog fixtures.

tests/e2e/catalog/product/media/test_sync_media.py (1)

13-31: Media fixtures simplified correctly

Both created_media_from_file and created_media_from_url no longer take a logger, and their create/yield/delete flows are unchanged, so behavior and teardown guarantees remain the same.

tests/e2e/catalog/product/media/test_async_media.py (1)

18-36: Async media fixtures are structured correctly after logger removal

The async fixtures still await create/delete and yield the media objects, and tests use the fixtures directly without awaiting them, which matches pytest-asyncio fixture semantics. Removing the unused logger argument is safe here. Based on learnings, async fixtures are being used as intended.

tests/e2e/catalog/product/documents/test_sync_document.py (1)

9-28: Document fixtures logger removal is non-disruptive

created_document_from_file and created_document_from_url no longer accept a logger, but their create and teardown logic is unchanged, so existing tests keep the same behavior with a simpler fixture surface.

tests/e2e/catalog/pricing_policies/attachments/conftest.py (4)

6-8: LGTM!

This fixture follows the standard pattern of extracting a primitive ID from a created resource, which is useful for tests that only need the identifier.


11-16: LGTM!

The attachment data structure is appropriate, and the "please delete" naming convention helps identify orphaned test resources.


19-21: LGTM!

The fixture correctly scopes the attachment service to a specific pricing policy using the pricing_policy_id parameter, which aligns with the service architecture.


24-31: The original review comment is incorrect. Async attachment tests already have corresponding async fixtures that are properly implemented.

The created_attachment_async fixture is defined in test_async_attachment.py (lines 16-22) with proper async/await semantics for setup and teardown. Per pytest-asyncio behavior (confirmed by learnings), async fixtures are automatically resolved before being passed to test functions—both sync and async. The sync test function test_create_attachment_async correctly receives the resolved fixture value without requiring any manual awaiting. The fixture organization and implementation is correct and requires no changes.

tests/e2e/catalog/pricing_policies/conftest.py (3)

3-3: LGTM!

The MPTAPIError import is correctly added to support exception handling during teardown.


24-25: LGTM!

The fixture follows the standard pattern for accessing the pricing policies service from the MPT client.


28-37: I'll verify the concerns raised in the review comment. Let me start by investigating the actual state of the fixtures and the AAA pattern mentioned.
<function_calls>


#!/bin/bash

Find async fixture in pricing policies tests

find . -name "pricing" -type f | head -20


</function_calls>
<function_calls>


#!/bin/bash

Search for async_created_pricing_policy fixture

rg "async_created_pricing_policy" -n -A 5 -B 2


</function_calls>
<function_calls>


#!/bin/bash

Search for all pricing policy fixtures

rg "@pytest.fixture" -A 3 tests/e2e/catalog/pricing_policies/


</function_calls>

Now let me check the GitHub PR #134 to understand the AAA pattern context:
<function_calls>

GitHub softwareone-platform/mpt-api-python-client PR 134 AAA pattern

</function_calls>

Comment on lines +38 to +41
async def test_get_pricing_policy_by_id(async_pricing_policies_service, pricing_policy_id):
result = await async_pricing_policies_service.get(pricing_policy_id)

assert result.id == async_created_pricing_policy.id
assert result.id == pricing_policy_id
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent fixture usage in async test.

This async test now uses pricing_policy_id, which depends on the synchronous created_pricing_policy fixture (from conftest.py). However, the file defines its own async_created_pricing_policy fixture (lines 15-23), and other async tests in this file still use it (e.g., lines 32-35, 44-51).

This creates an inconsistency where async tests have mixed dependencies on both sync and async fixtures. For consistency and clarity, async tests should use async fixtures.

Based on the reviewer's comment about following the AAA pattern from PR #134, consider reverting this change to use async_created_pricing_policy instead, maintaining consistency across async tests.

-async def test_get_pricing_policy_by_id(async_pricing_policies_service, pricing_policy_id):
-    result = await async_pricing_policies_service.get(pricing_policy_id)
+async def test_get_pricing_policy_by_id(async_pricing_policies_service, async_created_pricing_policy):
+    result = await async_pricing_policies_service.get(async_created_pricing_policy.id)
 
-    assert result.id == pricing_policy_id
+    assert result.id == async_created_pricing_policy.id

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py around
lines 38 to 41, the async test currently depends on the synchronous fixture
pricing_policy_id creating an inconsistent mix of sync and async fixtures;
change the test to depend on the async_created_pricing_policy fixture instead
(accept async_created_pricing_policy as the parameter) and use its id (e.g.,
async_created_pricing_policy.id) when calling async_pricing_policies_service.get
so the test consistently uses async fixtures like the other tests in this file.

@albertsola albertsola force-pushed the e2e/catalog/MPT-14900-pricing-policy-attachments branch from 994f471 to 518047f Compare November 27, 2025 11:40
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/e2e/catalog/product/media/test_sync_media.py (1)

84-86: Fix async/sync mismatch in sync test file.

This test is defined as async def and uses await, but vendor_media_service is a synchronous service. This will cause a runtime error.

Apply this diff to fix the issue:

-async def test_get_not_found_media(vendor_media_service):
+def test_get_not_found_media(vendor_media_service):
     with pytest.raises(MPTAPIError, match=r"404 Not Found"):
-        await vendor_media_service.get("INVALID-ID")
+        vendor_media_service.get("INVALID-ID")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 994f471 and 518047f.

📒 Files selected for processing (22)
  • mpt_api_client/resources/catalog/pricing_policy_attachments.py (3 hunks)
  • tests/e2e/catalog/items/test_async_item.py (1 hunks)
  • tests/e2e/catalog/items/test_sync_item.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/conftest.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/conftest.py (2 hunks)
  • tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py (0 hunks)
  • tests/e2e/catalog/product/documents/test_async_document.py (2 hunks)
  • tests/e2e/catalog/product/documents/test_sync_document.py (2 hunks)
  • tests/e2e/catalog/product/item_groups/test_async_item_groups.py (1 hunks)
  • tests/e2e/catalog/product/item_groups/test_sync_item_groups.py (1 hunks)
  • tests/e2e/catalog/product/media/test_async_media.py (2 hunks)
  • tests/e2e/catalog/product/media/test_sync_media.py (2 hunks)
  • tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py (1 hunks)
  • tests/e2e/catalog/product/parameter_groups/test_sync_parameter_groups.py (1 hunks)
  • tests/e2e/catalog/product/terms/test_sync_terms.py (2 hunks)
  • tests/e2e/catalog/product/terms/variants/test_sync_variants.py (2 hunks)
  • tests/e2e/catalog/product/test_async_product.py (1 hunks)
  • tests/e2e/catalog/product/test_sync_product.py (1 hunks)
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py (1 hunks)
💤 Files with no reviewable changes (1)
  • tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py
🚧 Files skipped from review as they are similar to previous changes (10)
  • tests/e2e/catalog/product/item_groups/test_sync_item_groups.py
  • tests/e2e/catalog/items/test_sync_item.py
  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py
  • tests/e2e/catalog/product/item_groups/test_async_item_groups.py
  • tests/e2e/catalog/pricing_policies/conftest.py
  • tests/e2e/catalog/product/documents/test_sync_document.py
  • tests/e2e/catalog/product/documents/test_async_document.py
  • tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py
  • tests/e2e/catalog/product/terms/variants/test_sync_variants.py
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-27T00:05:54.691Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 131
File: tests/e2e/accounts/accounts_users/test_async_accounts_users.py:0-0
Timestamp: 2025-11-27T00:05:54.691Z
Learning: In pytest-asyncio, async fixtures are automatically resolved before being passed to test functions (both sync and async). Test functions receive the yielded value from async fixtures, not coroutines, so fixture parameters should never be awaited. A sync test function can use async fixtures without any special handling.

Applied to files:

  • tests/e2e/catalog/product/media/test_async_media.py
  • tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py
  • tests/e2e/catalog/items/test_async_item.py
  • tests/e2e/catalog/product/test_async_product.py
🧬 Code graph analysis (8)
tests/e2e/catalog/pricing_policies/attachments/conftest.py (3)
mpt_api_client/exceptions.py (1)
  • MPTAPIError (20-42)
mpt_api_client/models/model.py (1)
  • id (119-121)
tests/e2e/conftest.py (2)
  • mpt_ops (31-32)
  • pdf_fd (73-75)
tests/e2e/catalog/product/parameter_groups/test_sync_parameter_groups.py (2)
tests/e2e/conftest.py (2)
  • mpt_vendor (19-20)
  • product_id (96-97)
tests/e2e/catalog/product/parameter_groups/conftest.py (1)
  • parameter_group_data (5-10)
tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py (2)
tests/e2e/conftest.py (2)
  • async_mpt_vendor (24-27)
  • product_id (96-97)
tests/e2e/catalog/product/parameter_groups/conftest.py (1)
  • parameter_group_data (5-10)
tests/e2e/catalog/items/test_async_item.py (2)
tests/e2e/conftest.py (1)
  • async_mpt_vendor (24-27)
tests/e2e/catalog/items/conftest.py (1)
  • item_data (5-20)
tests/e2e/catalog/product/terms/test_sync_terms.py (2)
tests/e2e/catalog/product/terms/conftest.py (1)
  • term_data (5-6)
tests/e2e/conftest.py (1)
  • pdf_url (79-80)
tests/e2e/catalog/product/media/test_sync_media.py (2)
tests/e2e/catalog/product/media/conftest.py (2)
  • media_data (5-14)
  • test_media_file (18-19)
tests/e2e/conftest.py (1)
  • jpg_url (84-85)
tests/e2e/catalog/product/test_sync_product.py (2)
tests/e2e/conftest.py (2)
  • mpt_vendor (19-20)
  • logo_fd (106-108)
tests/e2e/catalog/product/conftest.py (1)
  • product_data (5-6)
tests/e2e/catalog/product/test_async_product.py (2)
tests/e2e/conftest.py (2)
  • async_mpt_vendor (24-27)
  • logo_fd (106-108)
tests/e2e/catalog/product/conftest.py (1)
  • product_data (5-6)
⏰ 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 (24)
mpt_api_client/resources/catalog/pricing_policy_attachments.py (4)

1-14: Clean import organization with clear separation of concerns.

The imports are well-organized, separating generic HTTP mixins from domain-specific catalog mixins. The choice to import CreateFileMixin from the catalog module suggests domain-specific upload logic, while DownloadFileMixin remains generic.


21-28: Configuration properly centralizes upload keys for the new file mixins.

The addition of _upload_file_key and _upload_data_key aligns with the new CreateFileMixin requirements. The configuration class pattern ensures consistency between sync and async service variants.


31-39: LGTM!

The inheritance order follows the correct MRO pattern: specific mixins first (file operations), then CRUD mixins, base service, and configuration last. This ensures proper method resolution and attribute availability.


42-50: LGTM!

The async service maintains perfect parity with its sync counterpart, reusing the shared configuration class. The inheritance structure and type parameters are consistent.

tests/e2e/catalog/product/test_async_product.py (1)

8-8: LGTM: Fixture signature simplified.

The removal of the unused logger parameter streamlines the fixture signature without affecting functionality.

tests/e2e/catalog/items/test_async_item.py (1)

10-10: LGTM: Fixture signature simplified.

The removal of the unused logger parameter is consistent with the cleanup pattern across the test suite.

tests/e2e/catalog/product/media/test_async_media.py (1)

19-19: LGTM: Fixture signatures simplified.

Both fixture signatures have been appropriately simplified by removing the unused logger parameter.

Also applies to: 29-29

tests/e2e/catalog/product/test_sync_product.py (1)

8-8: LGTM: Fixture signature simplified.

The removal of the unused logger parameter is appropriate and consistent with the sync test pattern.

tests/e2e/catalog/product/terms/test_sync_terms.py (1)

15-15: LGTM: Fixture signatures simplified.

Both fixtures have been appropriately updated by removing the unused logger parameter.

Also applies to: 26-26

tests/e2e/catalog/product/parameter_groups/test_sync_parameter_groups.py (1)

7-7: LGTM: Fixture signature simplified.

The logger parameter removal is appropriate and maintains consistency across the test suite.

tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py (1)

7-7: LGTM: Fixture signature simplified.

The removal of the unused logger parameter aligns with the async test fixture pattern.

tests/e2e/catalog/product/media/test_sync_media.py (1)

14-14: LGTM: Fixture signatures simplified.

Both fixtures have been appropriately updated by removing the unused logger parameter.

Also applies to: 24-24

tests/e2e/catalog/pricing_policies/attachments/conftest.py (4)

6-8: LGTM!

Standard fixture pattern for extracting the ID from the created attachment resource.


11-16: LGTM!

Test data fixture is well-structured with clear test indicators in the values.


19-21: LGTM!

Standard service accessor fixture following the established pattern.


24-31: LGTM!

Standard lifecycle fixture with appropriate teardown error handling for E2E tests. The error message in the teardown provides helpful debugging context.

tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (8)

16-21: LGTM!

This test follows the AAA pattern correctly with an explicit Act step and clear assertions.


24-27: LGTM!

Clean test with explicit Act step and appropriate assertion.


30-34: LGTM!

Test follows AAA pattern with explicit download operation and verifies both content and filename.


37-40: LGTM!

Test follows AAA pattern with explicit iteration and appropriate membership assertion.


43-47: LGTM!

Test follows AAA pattern with explicit filter operation and verifies both result count and content.


50-52: LGTM!

Appropriate use of pytest.raises for exception testing. The combined Act+Assert pattern is standard for negative test cases.


55-59: LGTM!

Test follows AAA pattern with explicit delete operation and appropriate verification that the resource is no longer accessible.


6-6: LGTM!

Appropriate use of pytest.mark.flaky for E2E tests that may experience intermittent failures.

Comment on lines +9 to +13
def test_create_attachment(created_attachment, attachment_data):
result = created_attachment

assert result.name == attachment_data["name"]
assert result.description == attachment_data["description"]
Copy link

@coderabbitai coderabbitai bot Nov 27, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Refactor to follow AAA (Arrange-Act-Assert) pattern.

This test doesn't follow the AAA pattern requested by the reviewer. The "Act" step (creating the attachment) is hidden in the created_attachment fixture, making it unclear what operation is being tested. The test should explicitly call attachment_service.create() to make the action visible.

Based on the reviewer's feedback, consider this structure:

-def test_create_attachment(created_attachment, attachment_data):
-    result = created_attachment
+def test_create_attachment(attachment_service, attachment_data, pdf_fd):
+    # Act
+    result = attachment_service.create(attachment_data, file=pdf_fd)
 
+    # Assert
     assert result.name == attachment_data["name"]
     assert result.description == attachment_data["description"]
+    
+    # Cleanup
+    try:
+        attachment_service.delete(result.id)
+    except MPTAPIError:
+        pass

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py around
lines 9 to 13, the test hides the "Act" step by using the created_attachment
fixture; update the test to follow Arrange-Act-Assert by arranging any needed
dependencies (e.g., attachment_service and attachment_data fixtures), explicitly
calling the action under test (call attachment_service.create(...) with
attachment_data) as the Act, and then assert on the returned result's name and
description; remove reliance on the created_attachment fixture or rename it to a
helper, and keep asserts the same.

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch PR #134 to see the AAA pattern being referenced
gh pr view 134 --repo softwareone-platform/mpt-api-python-client --json files --jq '.files[].path' | head -20

Length of output: 910


🏁 Script executed:

#!/bin/bash
# Get the actual test file content from PR #134 to see the AAA pattern
gh pr diff 134 --repo softwareone-platform/mpt-api-python-client | head -300

Length of output: 10072


@jentyk You're absolutely right! I apologize for the confusion. After reviewing PR #134, I can see that the AAA pattern they use does rely on fixtures for setup and teardown.

Looking at examples from PR #134:

def test_create_account(created_account):
    result = created_account

    assert result is not None

The current test in this PR already follows that same pattern:

def test_create_attachment(created_attachment, attachment_data):
    result = created_attachment

    assert result.name == attachment_data["name"]
    assert result.description == attachment_data["description"]

The test correctly:

  • ✅ Uses the fixture for arrangement (setup)
  • ✅ Assigns to result variable (act)
  • ✅ Has a blank line separating act from assert
  • ✅ Has clear assertions
  • ✅ Relies on fixture teardown for cleanup

My previous suggestion to add explicit cleanup and remove the fixture was incorrect. The test structure is actually fine as-is. Thank you for catching that!

@albertsola albertsola force-pushed the e2e/catalog/MPT-14900-pricing-policy-attachments branch from 518047f to 90761ff Compare November 27, 2025 13:35
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/e2e/catalog/product/media/test_sync_media.py (2)

39-42: test_create_media_from_url is not using the URL-based fixture

This test currently uses created_media_from_file, so it never verifies the URL-based creation path even though the name suggests it does.

Consider switching to the URL fixture:

-def test_create_media_from_url(created_media_from_file, media_data):  # noqa: AAA01
-    assert created_media_from_file.name == media_data["name"]
-    assert created_media_from_file.description == media_data["description"]
+def test_create_media_from_url(created_media_from_url, media_data):  # noqa: AAA01
+    assert created_media_from_url.name == media_data["name"]
+    assert created_media_from_url.description == media_data["description"]

[scratchpad_end] -->


84-86: Async test incorrectly awaits a synchronous service

vendor_media_service is a synchronous client, but test_get_not_found_media is async and awaits vendor_media_service.get(...), which is not awaitable. This is a runtime bug if the test runs.

You can make this a regular sync test:

-async def test_get_not_found_media(vendor_media_service):
-    with pytest.raises(MPTAPIError, match=r"404 Not Found"):
-        await vendor_media_service.get("INVALID-ID")
+def test_get_not_found_media(vendor_media_service):
+    with pytest.raises(MPTAPIError, match=r"404 Not Found"):
+        vendor_media_service.get("INVALID-ID")
♻️ Duplicate comments (1)
tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (1)

9-13: Refactor test_create_attachment to follow AAA explicitly

Here the "Act" step (creating the attachment) is hidden inside the created_attachment fixture. Given the reviewer’s request to follow the AAA pattern, this test should explicitly call attachment_service.create(...) so the operation under test is visible, and then perform its assertions and cleanup.

For example:

-def test_create_attachment(created_attachment, attachment_data):
-    result = created_attachment
-
-    assert result.name == attachment_data["name"]
-    assert result.description == attachment_data["description"]
+def test_create_attachment(attachment_service, attachment_data, pdf_fd):
+    # Act
+    result = attachment_service.create(attachment_data, file=pdf_fd)
+
+    # Assert
+    assert result.name == attachment_data["name"]
+    assert result.description == attachment_data["description"]
+
+    # Cleanup
+    try:
+        attachment_service.delete(result.id)
+    except MPTAPIError:
+        pass

This keeps the test self-contained and makes the action under test obvious while still ensuring cleanup.

🧹 Nitpick comments (2)
tests/e2e/catalog/product/terms/variants/test_sync_variants.py (1)

25-33: Consider avoiding in‑place mutation of variant_data inside the fixture

Here created_variant_from_url mutates the shared variant_data fixture (type, assetUrl). Because pytest shares a single fixture instance within a test, the variant_data argument in the test function will see these mutations, which is a bit subtle and could surprise future assertions on those fields. Behavior is correct today (tests only use name), but you might consider copying before mutation:

-@pytest.fixture
-def created_variant_from_url(vendor_variant_service, variant_data, pdf_url):
-    variant_data["type"] = "Online"
-    variant_data["assetUrl"] = pdf_url
-    variant = vendor_variant_service.create(variant_data)
+@pytest.fixture
+def created_variant_from_url(vendor_variant_service, variant_data, pdf_url):
+    data = {**variant_data}
+    data["type"] = "Online"
+    data["assetUrl"] = pdf_url
+    variant = vendor_variant_service.create(data)
     yield variant
     try:
         vendor_variant_service.delete(variant.id)
     except MPTAPIError as error:
         print(f"TEARDOWN - Unable to delete variant {variant.id}: {error.title}")

If you adopt this, consider applying the same pattern to the async created_variant_from_url fixture for consistency. Based on relevant snippets from tests/e2e/catalog/product/terms/variants/test_async_variants.py and tests/e2e/catalog/product/terms/variants/conftest.py.

tests/e2e/catalog/product/documents/test_async_document.py (1)

15-23: Async file‑based document fixture remains correct after logger removal

created_document_from_file_async still sets documenttype, creates the document, and cleans it up reliably; dropping the logger arg just simplifies the fixture surface without behavior change. As a small future improvement, consider ensuring pdf_fd is closed (e.g., via a context-managed fixture) to avoid lingering open file handles during long test runs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 518047f and 90761ff.

📒 Files selected for processing (22)
  • mpt_api_client/resources/catalog/pricing_policy_attachments.py (3 hunks)
  • tests/e2e/catalog/items/test_async_item.py (1 hunks)
  • tests/e2e/catalog/items/test_sync_item.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/conftest.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/attachments/test_sync_attachment.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/conftest.py (2 hunks)
  • tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py (1 hunks)
  • tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py (0 hunks)
  • tests/e2e/catalog/product/documents/test_async_document.py (2 hunks)
  • tests/e2e/catalog/product/documents/test_sync_document.py (2 hunks)
  • tests/e2e/catalog/product/item_groups/test_async_item_groups.py (1 hunks)
  • tests/e2e/catalog/product/item_groups/test_sync_item_groups.py (1 hunks)
  • tests/e2e/catalog/product/media/test_async_media.py (2 hunks)
  • tests/e2e/catalog/product/media/test_sync_media.py (2 hunks)
  • tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py (1 hunks)
  • tests/e2e/catalog/product/parameter_groups/test_sync_parameter_groups.py (1 hunks)
  • tests/e2e/catalog/product/terms/test_sync_terms.py (2 hunks)
  • tests/e2e/catalog/product/terms/variants/test_sync_variants.py (2 hunks)
  • tests/e2e/catalog/product/test_async_product.py (1 hunks)
  • tests/e2e/catalog/product/test_sync_product.py (1 hunks)
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py (1 hunks)
💤 Files with no reviewable changes (1)
  • tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py
  • tests/e2e/catalog/product/item_groups/test_async_item_groups.py
  • tests/e2e/catalog/product/media/test_async_media.py
  • tests/e2e/catalog/product/terms/test_sync_terms.py
  • tests/e2e/catalog/pricing_policies/attachments/test_async_attachment.py
  • tests/e2e/catalog/pricing_policies/conftest.py
  • tests/e2e/catalog/pricing_policies/attachments/conftest.py
  • tests/e2e/catalog/product/test_async_product.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-27T00:05:54.691Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 131
File: tests/e2e/accounts/accounts_users/test_async_accounts_users.py:0-0
Timestamp: 2025-11-27T00:05:54.691Z
Learning: In pytest-asyncio, async fixtures are automatically resolved before being passed to test functions (both sync and async). Test functions receive the yielded value from async fixtures, not coroutines, so fixture parameters should never be awaited. A sync test function can use async fixtures without any special handling.

Applied to files:

  • tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py
  • tests/e2e/catalog/product/documents/test_async_document.py
  • tests/e2e/catalog/items/test_async_item.py
📚 Learning: 2025-11-27T00:05:36.332Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 131
File: tests/e2e/conftest.py:0-0
Timestamp: 2025-11-27T00:05:36.332Z
Learning: When reviewing PRs that add fixtures to a parent conftest that may duplicate fixtures in child conftest files, do not suggest removing the duplicates from child conftest files that are outside the scope of the PR's changes.

Applied to files:

  • tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py
🧬 Code graph analysis (12)
tests/e2e/catalog/product/parameter_groups/test_sync_parameter_groups.py (2)
tests/e2e/conftest.py (2)
  • mpt_vendor (19-20)
  • product_id (96-97)
tests/e2e/catalog/product/parameter_groups/conftest.py (1)
  • parameter_group_data (5-10)
tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py (2)
tests/e2e/conftest.py (2)
  • async_mpt_vendor (24-27)
  • product_id (96-97)
tests/e2e/catalog/product/parameter_groups/conftest.py (1)
  • parameter_group_data (5-10)
tests/e2e/catalog/product/terms/variants/test_sync_variants.py (3)
tests/e2e/catalog/product/terms/variants/conftest.py (1)
  • variant_data (5-12)
tests/e2e/conftest.py (2)
  • pdf_fd (73-75)
  • pdf_url (79-80)
tests/e2e/catalog/product/terms/variants/test_async_variants.py (1)
  • created_variant_from_url (29-41)
tests/e2e/catalog/product/documents/test_async_document.py (3)
tests/unit/resources/catalog/test_mixins.py (1)
  • async_document_service (354-355)
tests/e2e/catalog/product/documents/conftest.py (1)
  • document_data (10-16)
tests/e2e/conftest.py (2)
  • pdf_fd (73-75)
  • pdf_url (79-80)
tests/e2e/catalog/items/test_sync_item.py (2)
tests/e2e/conftest.py (1)
  • mpt_vendor (19-20)
tests/e2e/catalog/items/conftest.py (1)
  • item_data (5-20)
tests/e2e/catalog/items/test_async_item.py (2)
tests/e2e/conftest.py (1)
  • async_mpt_vendor (24-27)
tests/e2e/catalog/items/conftest.py (1)
  • item_data (5-20)
mpt_api_client/resources/catalog/pricing_policy_attachments.py (2)
mpt_api_client/http/mixins.py (2)
  • AsyncDownloadFileMixin (231-253)
  • DownloadFileMixin (59-81)
mpt_api_client/resources/catalog/mixins.py (2)
  • AsyncCreateFileMixin (84-110)
  • CreateFileMixin (121-147)
tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py (3)
tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py (1)
  • test_get_pricing_policy_by_id (21-24)
tests/e2e/catalog/pricing_policies/conftest.py (1)
  • pricing_policy_id (41-42)
mpt_api_client/models/model.py (1)
  • id (119-121)
tests/e2e/catalog/product/media/test_sync_media.py (2)
tests/e2e/catalog/product/media/conftest.py (2)
  • media_data (5-14)
  • test_media_file (18-19)
tests/e2e/conftest.py (1)
  • jpg_url (84-85)
tests/e2e/catalog/product/documents/test_sync_document.py (2)
tests/e2e/catalog/product/documents/conftest.py (2)
  • vendor_document_service (20-21)
  • document_data (10-16)
tests/e2e/conftest.py (2)
  • pdf_fd (73-75)
  • pdf_url (79-80)
tests/e2e/catalog/product/item_groups/test_sync_item_groups.py (2)
tests/e2e/conftest.py (2)
  • mpt_vendor (19-20)
  • product_id (96-97)
tests/e2e/catalog/product/item_groups/conftest.py (1)
  • item_group_data (5-15)
tests/e2e/catalog/product/test_sync_product.py (2)
tests/e2e/conftest.py (2)
  • mpt_vendor (19-20)
  • logo_fd (106-108)
tests/e2e/catalog/product/conftest.py (1)
  • product_data (5-6)
⏰ 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 (13)
tests/e2e/catalog/product/terms/variants/test_sync_variants.py (1)

15-21: Synchronous created_variant fixture + teardown pattern look good

The create/yield/delete lifecycle and focused MPTAPIError handling are clear and match the async variant pattern; this keeps test setup/cleanup nicely encapsulated in the fixture.

tests/e2e/catalog/product/parameter_groups/test_async_parameter_groups.py (1)

7-14: Fixture signature simplification looks good

Dropping the unused logger parameter while keeping the async create/teardown logic unchanged is safe and consistent with how this fixture is used in the tests.

tests/e2e/catalog/product/item_groups/test_sync_item_groups.py (1)

4-17: Import usage and fixture signature change are consistent

RQLQuery is correctly used in test_filter_item_groups, and removing logger from created_item_group keeps creation/teardown behavior intact without affecting call sites.

tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py (1)

38-41: Using pricing_policy_id in async test is appropriate

Switching to the primitive pricing_policy_id fixture makes this test mirror the sync variant and keeps the action (get) explicit while still exercising the async service.

tests/e2e/catalog/product/test_sync_product.py (1)

7-16: Created product fixture refactor is safe

Removing logger from created_product without changing its create/teardown logic preserves behavior and matches the broader fixture simplification in this PR.

tests/e2e/catalog/product/parameter_groups/test_sync_parameter_groups.py (1)

7-14: Sync parameter group fixture change is straightforward

The fixture still creates and deletes parameter groups correctly; dropping the logger argument simply streamlines its signature without impacting the tests.

tests/e2e/catalog/product/media/test_sync_media.py (1)

14-31: Media fixtures signature updates are correct

Removing logger from created_media_from_file and created_media_from_url keeps creation and teardown behavior intact while simplifying fixture dependencies.

mpt_api_client/resources/catalog/pricing_policy_attachments.py (1)

2-48: New create/download mixins and upload config are wired correctly

Switching pricing policy attachments to CreateFileMixin/AsyncCreateFileMixin and DownloadFileMixin/AsyncDownloadFileMixin, with _upload_file_key = "file" and _upload_data_key = "attachment" in PricingPolicyAttachmentsServiceConfig, cleanly integrates with the shared mixin implementations and aligns with the new attachment tests.

tests/e2e/catalog/items/test_sync_item.py (1)

9-17: Fixture signature simplification looks good

created_item no longer depends on an unused logger and still encapsulates create/teardown correctly. Call sites in this file remain compatible.

tests/e2e/catalog/items/test_async_item.py (1)

9-17: Async fixture cleanup maintains correct behavior

Removing the logger arg from async_created_item is safe; the fixture still handles async create/teardown correctly. Using it in test_create_item as a plain value is appropriate for pytest-asyncio’s async fixtures. Based on learnings, this pattern is fine.

tests/e2e/catalog/product/documents/test_async_document.py (1)

25-33: Link‑based async document fixture cleanup is consistent

created_document_from_link_async keeps the same semantics (mutate document_data["url"], create, yield, delete with guarded teardown); removing the unused logger parameter simply aligns it with other fixtures.

tests/e2e/catalog/product/documents/test_sync_document.py (2)

9-17: Synchronous file‑based document fixture simplification is safe

created_document_from_file still encapsulates create/teardown correctly; dropping the logger argument reduces fixture coupling without changing behavior. Tests using this fixture remain valid.


20-28: URL‑based document fixture now matches the simplified fixture pattern

created_document_from_url likewise keeps its semantics (set url, create, delete on teardown) while removing an unused logger parameter, matching the pattern used elsewhere in the suite.

@sonarqubecloud
Copy link

@albertsola albertsola merged commit 9619a7a into main Nov 27, 2025
6 checks passed
@albertsola albertsola deleted the e2e/catalog/MPT-14900-pricing-policy-attachments branch November 27, 2025 16:25
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.

4 participants