Skip to content

Conversation

@albertsola
Copy link
Contributor

@albertsola albertsola commented Dec 19, 2025

Summary by CodeRabbit

  • API Changes

    • Attachment handling split: separate metadata endpoint for batch attachments and a dedicated download endpoint; batch retrieval can optionally include attachments.
    • Async HTTP client no longer sends a default Accept header (may affect content negotiation).
  • Tests

    • Expanded unit and end-to-end coverage for attachment metadata and downloads (sync & async); added test config entry and fixtures for attachment IDs.

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 19, 2025

📝 Walkthrough

Walkthrough

Adds a BatchAttachment model and splits attachment handling into metadata retrieval (get_attachment) and binary download (download_attachment) for sync and async batches services; updates unit and e2e tests and fixtures; removes default Accept header from AsyncHTTPClient; adds e2e config key for a batch attachment id.

Changes

Cohort / File(s) Summary
Configuration
e2e_config.test.json
Added notifications.batch.attachment.id with an attachment id used by e2e tests.
Notifications — service implementation
mpt_api_client/resources/notifications/batches.py
Added public BatchAttachment model. Split single-step attachment API into get_attachment(batch_id, attachment_id) -> BatchAttachment and download_attachment(batch_id, attachment_id) -> FileModel for both BatchesService and AsyncBatchesService; renamed/adjusted previous method names accordingly.
HTTP client
mpt_api_client/http/async_client.py
Removed default "Accept": "application/json" header from AsyncHTTPClient base headers.
E2E test fixtures
tests/e2e/notifications/batch/conftest.py
Added batch_attachment_id(e2e_config) pytest fixture returning the new config value.
E2E tests
tests/e2e/notifications/batch/test_async_batches.py, tests/e2e/notifications/batch/test_batches.py
Updated batch retrieval to request select=["attachments"]; added/activated tests for get_attachment (metadata) and download_attachment (binary) asserting attachment id and filename.
Unit tests — notifications
tests/unit/resources/notifications/test_batches.py
Added fixtures and tests for attachment responses; extended parameterizations to include get_attachment and download_attachment (sync + async); exported BatchAttachment.
Unit tests — http
tests/unit/http/test_async_client.py
Adjusted test expectations to remove Accept header from AsyncHTTPClient initialization checks.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test/E2E
    participant Client as BatchesService (sync/async)
    participant API as Remote Notifications API
    participant Storage as File storage / Download endpoint

    rect rgb(235,245,255)
    Note over Test,Client: Metadata flow (new)
    Test->>Client: get(batch_id, select=["attachments"])
    Client->>API: GET /notifications/batches/{batch_id}?select=attachments
    API-->>Client: 200 JSON (batch + attachments metadata)
    Client-->>Test: Batch with attachments (including attachment ids)
    end

    rect rgb(245,255,235)
    Note over Test,Client: Attachment metadata vs binary download
    Test->>Client: get_attachment(batch_id, attachment_id)
    Client->>API: GET /notifications/batches/{batch_id}/attachments/{attachment_id}/metadata
    API-->>Client: 200 JSON (attachment metadata -> BatchAttachment)
    Client-->>Test: BatchAttachment
    Test->>Client: download_attachment(batch_id, attachment_id)
    Client->>Storage: GET /notifications/batches/{batch_id}/attachments/{attachment_id}/file
    Storage-->>Client: 200 Binary (file bytes + headers)
    Client-->>Test: FileModel (filename, content)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through code, split metadata from the bite,

One nibble for info, one for the sight,
Tests woke from slumber, fixtures held tight,
Async shed a header, everything's light,
A little rabbit clap — attachments take flight! 🥕

Pre-merge checks and finishing touches

✅ 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: implementing end-to-end tests for notification batch attachment functionality.
✨ 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/MPT-16512/notifications-batches-attachments-endpoints

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 29da3a4 and 1a287eb.

📒 Files selected for processing (8)
  • e2e_config.test.json
  • mpt_api_client/http/async_client.py
  • mpt_api_client/resources/notifications/batches.py
  • tests/e2e/notifications/batch/conftest.py
  • tests/e2e/notifications/batch/test_async_batches.py
  • tests/e2e/notifications/batch/test_batches.py
  • tests/unit/http/test_async_client.py
  • tests/unit/resources/notifications/test_batches.py
💤 Files with no reviewable changes (2)
  • tests/unit/http/test_async_client.py
  • mpt_api_client/http/async_client.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e_config.test.json
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-12T15:02:20.732Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 160
File: tests/e2e/commerce/agreement/attachment/test_async_agreement_attachment.py:55-58
Timestamp: 2025-12-12T15:02:20.732Z
Learning: In pytest with pytest-asyncio, if a test function uses async fixtures but contains no await, declare the test function as def (synchronous) instead of async def. Pytest-asyncio will resolve the async fixtures automatically; this avoids linter complaints about unnecessary async functions. This pattern applies to any test file under the tests/ directory that uses such fixtures.

Applied to files:

  • tests/e2e/notifications/batch/test_async_batches.py
  • tests/e2e/notifications/batch/test_batches.py
  • tests/unit/resources/notifications/test_batches.py
  • tests/e2e/notifications/batch/conftest.py
🧬 Code graph analysis (4)
tests/e2e/notifications/batch/test_async_batches.py (5)
tests/e2e/notifications/batch/conftest.py (3)
  • async_batch_service (10-11)
  • batch_id (15-16)
  • batch_attachment_id (30-31)
tests/e2e/notifications/batch/test_batches.py (2)
  • test_download_attachment (33-36)
  • test_get_attachment (39-42)
tests/unit/resources/notifications/test_batches.py (2)
  • test_download_attachment (99-111)
  • test_get_attachment (61-76)
mpt_api_client/resources/notifications/batches.py (4)
  • download_attachment (58-72)
  • download_attachment (101-114)
  • get_attachment (40-56)
  • get_attachment (84-99)
mpt_api_client/models/file_model.py (1)
  • filename (13-32)
tests/unit/resources/notifications/test_batches.py (4)
mpt_api_client/http/types.py (1)
  • Response (27-42)
mpt_api_client/models/file_model.py (1)
  • FileModel (6-55)
mpt_api_client/resources/notifications/batches.py (5)
  • BatchAttachment (17-18)
  • get_attachment (40-56)
  • get_attachment (84-99)
  • download_attachment (58-72)
  • download_attachment (101-114)
mpt_api_client/models/model.py (1)
  • id (119-121)
mpt_api_client/resources/notifications/batches.py (3)
mpt_api_client/models/model.py (2)
  • Model (65-125)
  • from_response (102-116)
mpt_api_client/http/base_service.py (1)
  • path (28-30)
mpt_api_client/models/file_model.py (1)
  • FileModel (6-55)
tests/e2e/notifications/batch/conftest.py (1)
tests/e2e/conftest.py (1)
  • e2e_config (89-92)
🪛 Ruff (0.14.10)
tests/unit/resources/notifications/test_batches.py

114-114: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

⏰ 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 (14)
tests/e2e/notifications/batch/conftest.py (1)

29-31: LGTM!

The fixture follows the established pattern for retrieving test configuration and is consistent with other fixtures in the file.

tests/e2e/notifications/batch/test_batches.py (2)

14-14: LGTM!

The addition of select=["attachments"] properly exercises the new attachment retrieval functionality.


33-42: LGTM!

The new e2e tests properly validate both attachment metadata retrieval and binary download functionality. The assertions verify the expected attachment ID and filename.

tests/e2e/notifications/batch/test_async_batches.py (2)

14-14: LGTM!

The addition of select=["attachments"] properly exercises the new attachment retrieval functionality in the async context.


33-42: LGTM!

The async attachment tests correctly use await and validate both metadata retrieval and download functionality. The tests mirror their synchronous counterparts appropriately.

mpt_api_client/resources/notifications/batches.py (3)

17-18: LGTM!

The new BatchAttachment model follows the established pattern for resource models in the codebase.


40-72: LGTM!

The implementation provides a clean separation of concerns:

  • get_attachment retrieves attachment metadata (JSON) by explicitly setting Accept: application/json
  • download_attachment retrieves the binary file content without an Accept header

Both methods are well-documented and follow established patterns.


84-114: LGTM!

The async variants correctly mirror their synchronous counterparts with proper await usage and maintain the same clean separation between metadata retrieval and binary download.

tests/unit/resources/notifications/test_batches.py (6)

3-10: LGTM!

The new imports properly support the expanded test coverage for attachment functionality.


14-20: LGTM!

Adding type hints to the fixture signatures improves code clarity and maintainability.


23-38: LGTM!

The response fixtures appropriately simulate attachment metadata (JSON) and binary file responses for testing.


41-58: LGTM!

The parametrized tests now properly include the new attachment methods in the validation suite.


61-96: LGTM!

The unit tests for get_attachment properly validate:

  • Return type is BatchAttachment
  • Correct HTTP call with Accept: application/json header
  • Both sync and async variants are covered

99-129: Remove unused noqa directive.

The # noqa: WPS210 comment on line 114 is flagged by Ruff as unused. The directive should be removed.

🔎 Proposed fix
-async def test_async_download_attachment(  # noqa: WPS210
+async def test_async_download_attachment(
     mocker, async_batches_service, attachment_response
 ) -> None:

Otherwise, the tests properly validate that download_attachment returns a FileModel and makes the correct HTTP call without an Accept header for both sync and async variants.

⛔ Skipped due to learnings
Learnt from: jentyk
Repo: softwareone-platform/mpt-api-python-client PR: 136
File: tests/e2e/notifications/subscribers/conftest.py:14-25
Timestamp: 2025-12-01T10:48:52.586Z
Learning: The repository softwareone-platform/mpt-api-python-client uses wemake-python-styleguide linter, so noqa directives for WPS rules should not be flagged as unused.

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

@github-actions
Copy link

github-actions bot commented Dec 19, 2025

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

Generated by 🚫 dangerJS against 1a287eb

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)
tests/unit/resources/notifications/test_batches.py (1)

62-77: Consider removing the unused noqa directive.

The test correctly validates async attachment download behavior. However, Ruff flags the noqa: WPS210 directive as unused because it's specific to wemake-python-styleguide, which may not be active in your linting pipeline.

🔎 Suggested fix
-async def test_async_download_attachment(  # noqa: WPS210
+async def test_async_download_attachment(
     mocker, async_batches_service, attachment_response
 ):
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 359d60e and b300542.

📒 Files selected for processing (6)
  • e2e_config.test.json (1 hunks)
  • mpt_api_client/resources/notifications/batches.py (2 hunks)
  • tests/e2e/notifications/batch/conftest.py (1 hunks)
  • tests/e2e/notifications/batch/test_async_batches.py (2 hunks)
  • tests/e2e/notifications/batch/test_batches.py (2 hunks)
  • tests/unit/resources/notifications/test_batches.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-12T15:02:20.732Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 160
File: tests/e2e/commerce/agreement/attachment/test_async_agreement_attachment.py:55-58
Timestamp: 2025-12-12T15:02:20.732Z
Learning: In pytest with pytest-asyncio, if a test function uses async fixtures but contains no await, declare the test function as def (synchronous) instead of async def. Pytest-asyncio will resolve the async fixtures automatically; this avoids linter complaints about unnecessary async functions. This pattern applies to any test file under the tests/ directory that uses such fixtures.

Applied to files:

  • tests/unit/resources/notifications/test_batches.py
  • tests/e2e/notifications/batch/conftest.py
  • tests/e2e/notifications/batch/test_batches.py
  • tests/e2e/notifications/batch/test_async_batches.py
🧬 Code graph analysis (5)
tests/unit/resources/notifications/test_batches.py (5)
mpt_api_client/http/async_client.py (1)
  • AsyncHTTPClient (22-117)
mpt_api_client/http/client.py (1)
  • HTTPClient (35-129)
mpt_api_client/http/types.py (1)
  • Response (27-42)
mpt_api_client/models/file_model.py (1)
  • FileModel (6-55)
mpt_api_client/resources/notifications/batches.py (3)
  • BatchesService (27-50)
  • download_attachment (36-50)
  • download_attachment (62-75)
mpt_api_client/resources/notifications/batches.py (1)
mpt_api_client/models/file_model.py (1)
  • FileModel (6-55)
tests/e2e/notifications/batch/conftest.py (1)
tests/e2e/conftest.py (1)
  • e2e_config (89-92)
tests/e2e/notifications/batch/test_batches.py (3)
tests/unit/resources/notifications/test_batches.py (1)
  • test_download_attachment (47-59)
mpt_api_client/resources/notifications/batches.py (2)
  • download_attachment (36-50)
  • download_attachment (62-75)
mpt_api_client/models/file_model.py (1)
  • filename (13-32)
tests/e2e/notifications/batch/test_async_batches.py (5)
tests/e2e/notifications/batch/conftest.py (3)
  • async_batch_service (10-11)
  • batch_id (15-16)
  • batch_attachment_id (30-31)
tests/e2e/notifications/batch/test_batches.py (1)
  • test_download_attachment (33-36)
tests/unit/resources/notifications/test_batches.py (1)
  • test_download_attachment (47-59)
mpt_api_client/resources/notifications/batches.py (2)
  • download_attachment (36-50)
  • download_attachment (62-75)
mpt_api_client/models/file_model.py (1)
  • filename (13-32)
🪛 Ruff (0.14.8)
tests/unit/resources/notifications/test_batches.py

62-62: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

⏰ 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)
mpt_api_client/resources/notifications/batches.py (2)

36-50: LGTM! Semantic improvement with the method rename.

The rename from get_batch_attachment to download_attachment better conveys the action being performed. The implementation is correct and the docstring has been appropriately updated.


62-75: LGTM! Async variant correctly implements the renamed method.

The async version mirrors the synchronous implementation correctly with proper await usage and consistent return type.

e2e_config.test.json (1)

49-49: LGTM! Configuration entry added for E2E attachment testing.

The new attachment ID follows the existing pattern and integrates well with the E2E test fixtures.

tests/e2e/notifications/batch/conftest.py (1)

29-31: LGTM! Fixture properly exposes attachment ID for E2E tests.

The new fixture follows the established pattern and provides the attachment ID from the E2E configuration for testing attachment download functionality.

tests/e2e/notifications/batch/test_batches.py (2)

14-14: LGTM! Testing selective field inclusion.

The test now exercises the select parameter to ensure attachments are included in the batch response when requested.


33-36: LGTM! E2E test validates attachment download functionality.

The test correctly exercises the download_attachment method and verifies the returned filename matches the expected attachment.

tests/e2e/notifications/batch/test_async_batches.py (2)

14-14: LGTM! Async test exercises selective field inclusion.

The async test correctly includes the select parameter to fetch attachments with the batch.


33-36: LGTM! Async E2E test properly validates attachment download.

The test correctly uses await and validates the same behavior as the synchronous version.

tests/unit/resources/notifications/test_batches.py (5)

3-5: LGTM! Improved type safety with explicit imports.

Adding type annotations and the FileModel import enhances code clarity and type checking.


13-19: LGTM! Type annotations improve fixture clarity.

The explicit type hints for both fixtures enhance code readability and enable better IDE support.


22-28: LGTM! Well-constructed fixture for attachment testing.

The mock response includes appropriate headers and content for testing attachment download behavior.


31-44: LGTM! Parametrized tests cover the renamed method.

Both sync and async tests now verify the presence of the download_attachment method on their respective service classes.


47-59: LGTM! Unit test validates synchronous attachment download.

The test correctly mocks the HTTP client, verifies the FileModel return type, and ensures the correct endpoint is called.

@albertsola albertsola marked this pull request as draft December 19, 2025 15:14
@albertsola albertsola force-pushed the e2e/MPT-16512/notifications-batches-attachments-endpoints branch 2 times, most recently from 51b8a57 to 4ce3954 Compare December 19, 2025 15:24
@albertsola albertsola marked this pull request as ready for review December 19, 2025 15:25
@albertsola albertsola force-pushed the e2e/MPT-16512/notifications-batches-attachments-endpoints branch 2 times, most recently from 5f5b678 to 29da3a4 Compare December 19, 2025 15:27
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)
tests/unit/resources/notifications/test_batches.py (1)

114-116: Remove unused noqa directive.

Static analysis indicates WPS210 is not triggered here. Remove the unnecessary suppression comment.

🔎 Proposed fix
-async def test_async_download_attachment(  # noqa: WPS210
+async def test_async_download_attachment(
     mocker, async_batches_service, attachment_response
 ) -> None:
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b300542 and 29da3a4.

📒 Files selected for processing (8)
  • e2e_config.test.json (1 hunks)
  • mpt_api_client/http/async_client.py (0 hunks)
  • mpt_api_client/resources/notifications/batches.py (3 hunks)
  • tests/e2e/notifications/batch/conftest.py (1 hunks)
  • tests/e2e/notifications/batch/test_async_batches.py (2 hunks)
  • tests/e2e/notifications/batch/test_batches.py (2 hunks)
  • tests/unit/http/test_async_client.py (0 hunks)
  • tests/unit/resources/notifications/test_batches.py (1 hunks)
💤 Files with no reviewable changes (2)
  • tests/unit/http/test_async_client.py
  • mpt_api_client/http/async_client.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/e2e/notifications/batch/conftest.py
  • e2e_config.test.json
  • tests/e2e/notifications/batch/test_async_batches.py
  • tests/e2e/notifications/batch/test_batches.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-12T15:02:20.732Z
Learnt from: robcsegal
Repo: softwareone-platform/mpt-api-python-client PR: 160
File: tests/e2e/commerce/agreement/attachment/test_async_agreement_attachment.py:55-58
Timestamp: 2025-12-12T15:02:20.732Z
Learning: In pytest with pytest-asyncio, if a test function uses async fixtures but contains no await, declare the test function as def (synchronous) instead of async def. Pytest-asyncio will resolve the async fixtures automatically; this avoids linter complaints about unnecessary async functions. This pattern applies to any test file under the tests/ directory that uses such fixtures.

Applied to files:

  • tests/unit/resources/notifications/test_batches.py
🧬 Code graph analysis (1)
mpt_api_client/resources/notifications/batches.py (3)
mpt_api_client/models/model.py (2)
  • Model (65-125)
  • from_response (102-116)
mpt_api_client/http/base_service.py (1)
  • path (28-30)
mpt_api_client/models/file_model.py (1)
  • FileModel (6-55)
🪛 Ruff (0.14.8)
tests/unit/resources/notifications/test_batches.py

114-114: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

⏰ 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 (11)
mpt_api_client/resources/notifications/batches.py (5)

17-18: LGTM!

The new BatchAttachment model follows the established pattern and correctly extends Model to inherit the from_response class method and other base functionality.


40-56: LGTM!

Clean implementation with explicit Accept: application/json header to differentiate metadata retrieval from binary download.


58-72: LGTM!

The download method correctly omits the Accept header to receive binary content and wraps the response in FileModel for file handling.


84-99: LGTM!

Async implementation correctly mirrors the synchronous version with proper await usage.


101-114: LGTM!

Async implementation is consistent with the synchronous version.

tests/unit/resources/notifications/test_batches.py (6)

1-39: LGTM!

Well-structured fixtures with appropriate mock responses for both JSON metadata (batch_attachment_response) and binary download (attachment_response) scenarios.


41-58: LGTM!

Parameterized tests correctly extended to verify the new attachment methods exist on both sync and async services.


61-76: LGTM!

Comprehensive test that verifies both the return type and the HTTP call details including the Accept: application/json header.


79-96: LGTM!

Async test correctly uses await and mirrors the sync test coverage.


99-111: LGTM!

Test correctly verifies the download method returns FileModel and makes the HTTP call without the Accept header.


117-129: LGTM!

Test correctly verifies the async download method behavior.

@albertsola albertsola force-pushed the e2e/MPT-16512/notifications-batches-attachments-endpoints branch from 29da3a4 to 1a287eb Compare December 29, 2025 09:10
@sonarqubecloud
Copy link

@d3rky d3rky merged commit 5b5d899 into main Dec 29, 2025
6 checks passed
@d3rky d3rky deleted the e2e/MPT-16512/notifications-batches-attachments-endpoints branch December 29, 2025 10:13
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.

3 participants