Skip to content

Conversation

Ihor-Bilous
Copy link
Collaborator

@Ihor-Bilous Ihor-Bilous commented Oct 6, 2025

Motivation

In this PR I added ContactExportsApi, related models, tests, examples

How to test

  • see examples/contacts/contact_exports.py

Summary by CodeRabbit

  • New Features

    • Added contact export support: create exports with filters and retrieve export details.
    • Export-related parameters and filters made available via the public API.
    • Included an example demonstrating how to initiate and fetch contact exports.
  • Tests

    • Added unit tests for export creation and retrieval covering success, validation errors, and error responses.
    • Added tests verifying correct serialization of export parameters and filters.

Copy link

coderabbitai bot commented Oct 6, 2025

Walkthrough

Adds contact exports: new models, a ContactExportsApi client with create/get_by_id, exposes it on ContactsBaseApi, re-exports model types, includes an example script, and adds unit tests for models and API behaviors.

Changes

Cohort / File(s) Summary
Contacts Exports API client
mailtrap/api/resources/contact_exports.py, mailtrap/api/contacts.py
Adds ContactExportsApi with create and get_by_id, and exposes it via ContactsBaseApi.contact_exports.
Models for contact exports
mailtrap/models/contacts.py
Adds ContactExportFilter, CreateContactExportParams, and ContactExportDetail dataclasses (includes datetime fields).
Package exports
mailtrap/__init__.py
Re-exports ContactExportFilter and CreateContactExportParams from mailtrap.models.contacts.
Example usage
examples/contacts/contact_exports.py
New example script demonstrating creating an export and fetching it by ID.
Unit tests: API
tests/unit/api/contacts/test_contact_exports.py
Adds tests for create and get-by-id flows, success and error (401/403/404/422) cases, and request URL assertions.
Unit tests: models
tests/unit/models/test_contacts.py
Adds tests validating api_data for ContactExportFilter and CreateContactExportParams (single/multiple/empty filters).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant Client as Mailtrap Client
  participant Contacts as ContactsBaseApi
  participant Exports as ContactExportsApi
  participant HTTP as HttpClient
  participant API as Mailtrap REST API

  rect rgb(240,248,255)
    note left of Dev: Create contact export
    Dev->>Client: instantiate(client, account_id)
    Dev->>Contacts: client.contacts
    Contacts->>Contacts: .contact_exports (property)
    Contacts-->>Dev: ContactExportsApi
    Dev->>Exports: create(CreateContactExportParams)
    Exports->>HTTP: POST /api/accounts/{id}/contacts/exports\nbody: params.api_data
    HTTP->>API: request
    API-->>HTTP: 201 {export_detail}
    HTTP-->>Exports: response
    Exports-->>Dev: ContactExportDetail
  end

  rect rgb(245,255,245)
    note left of Dev: Get export by ID
    Dev->>Exports: get_by_id(export_id)
    Exports->>HTTP: GET /api/accounts/{id}/contacts/exports/{export_id}
    HTTP->>API: request
    API-->>HTTP: 200 {export_detail}
    HTTP-->>Exports: response
    Exports-->>Dev: ContactExportDetail
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • IgorDobryn
  • i7an
  • VladimirTaytor
  • andrii-porokhnavets

Poem

I thump my paw—exports in flight,
filters packed and JSON bright.
POST then GET, URLs align,
dataclass carrots, timestamps fine.
A rabbit hops — your data's right. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The description includes Motivation and How to test sections but omits the required Changes section that outlines the specific modifications and does not address the Images and GIFs section from the repository template, leaving the template incomplete. Please add a Changes section that lists the new API, models, tests, and example script introduced by this PR and include the Images and GIFs section or clarify that it is not applicable for this change.
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 (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title concisely and accurately describes the main change by highlighting the addition of ContactExportsApi along with the related models, tests, and examples, directly matching the content of the pull request without unrelated or vague terms.
✨ 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 ISSUE-41

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d50e2d4 and a2c7117.

📒 Files selected for processing (7)
  • examples/contacts/contact_exports.py (1 hunks)
  • mailtrap/__init__.py (1 hunks)
  • mailtrap/api/contacts.py (2 hunks)
  • mailtrap/api/resources/contact_exports.py (1 hunks)
  • mailtrap/models/contacts.py (2 hunks)
  • tests/unit/api/contacts/test_contact_exports.py (1 hunks)
  • tests/unit/models/test_contacts.py (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-29T21:15:03.708Z
Learnt from: Ihor-Bilous
PR: railsware/mailtrap-python#38
File: mailtrap/api/resources/contact_imports.py:13-18
Timestamp: 2025-08-29T21:15:03.708Z
Learning: In mailtrap/models/contacts.py, ImportContactParams.api_data is defined as a property, not a method, so it can be accessed without parentheses like contact.api_data.

Applied to files:

  • mailtrap/api/contacts.py
📚 Learning: 2025-08-22T13:51:31.437Z
Learnt from: Ihor-Bilous
PR: railsware/mailtrap-python#35
File: examples/contacts/contact_fields.py:11-11
Timestamp: 2025-08-22T13:51:31.437Z
Learning: In mailtrap/api/contacts.py, ContactsBaseApi.contact_fields is defined as a property, not a method, so it can be accessed without parentheses like client.contacts_api.contact_fields.

Applied to files:

  • mailtrap/api/contacts.py
🧬 Code graph analysis (7)
mailtrap/api/contacts.py (2)
mailtrap/api/resources/contact_exports.py (1)
  • ContactExportsApi (8-32)
tests/unit/api/contacts/test_contact_exports.py (1)
  • client (23-24)
examples/contacts/contact_exports.py (3)
mailtrap/api/contacts.py (2)
  • contacts (31-32)
  • contact_exports (15-16)
mailtrap/models/contacts.py (3)
  • ContactImport (109-114)
  • CreateContactExportParams (135-136)
  • ContactExportFilter (128-131)
mailtrap/api/resources/contact_exports.py (2)
  • create (13-21)
  • get_by_id (23-26)
tests/unit/models/test_contacts.py (2)
mailtrap/models/contacts.py (2)
  • ContactExportFilter (128-131)
  • CreateContactExportParams (135-136)
mailtrap/models/common.py (1)
  • api_data (15-19)
mailtrap/models/contacts.py (1)
mailtrap/models/common.py (1)
  • RequestParams (13-19)
tests/unit/api/contacts/test_contact_exports.py (5)
mailtrap/api/contacts.py (2)
  • contact_exports (15-16)
  • contacts (31-32)
mailtrap/api/resources/contact_exports.py (3)
  • ContactExportsApi (8-32)
  • create (13-21)
  • get_by_id (23-26)
mailtrap/exceptions.py (1)
  • APIError (10-15)
mailtrap/http.py (2)
  • HttpClient (14-106)
  • post (32-34)
mailtrap/models/contacts.py (3)
  • ContactExportDetail (140-145)
  • ContactExportFilter (128-131)
  • CreateContactExportParams (135-136)
mailtrap/api/resources/contact_exports.py (3)
mailtrap/http.py (2)
  • HttpClient (14-106)
  • post (32-34)
mailtrap/models/contacts.py (2)
  • ContactExportDetail (140-145)
  • CreateContactExportParams (135-136)
tests/unit/api/contacts/test_contact_exports.py (1)
  • client (23-24)
mailtrap/__init__.py (2)
mailtrap/api/contacts.py (1)
  • contacts (31-32)
mailtrap/models/contacts.py (3)
  • ContactExportFilter (128-131)
  • ContactListParams (37-38)
  • CreateContactExportParams (135-136)
🪛 Ruff (0.13.3)
examples/contacts/contact_exports.py

4-4: Possible hardcoded password assigned to: "API_TOKEN"

(S105)

⏰ 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: Test python3.9 on windows-latest
🔇 Additional comments (9)
mailtrap/__init__.py (1)

9-11: LGTM!

The new exports follow the established pattern and correctly expose the new contact export models for external use.

mailtrap/api/contacts.py (2)

1-1: LGTM!

Import correctly placed at the top with other resource imports.


14-16: LGTM!

The contact_exports property follows the same pattern as other properties in this class and correctly instantiates the ContactExportsApi with the required parameters.

tests/unit/models/test_contacts.py (2)

3-5: LGTM!

Imports are correctly placed with other model imports.


154-200: LGTM!

The test coverage is comprehensive and follows the established patterns:

  • Tests api_data generation for ContactExportFilter
  • Tests single, multiple, and empty filter scenarios for CreateContactExportParams
  • All assertions are clear and verify the expected behavior
mailtrap/models/contacts.py (2)

1-1: LGTM!

The datetime import is necessary for the ContactExportDetail model's timestamp fields.


127-145: LGTM!

The new dataclasses are well-structured:

  • ContactExportFilter and CreateContactExportParams correctly extend RequestParams for API request serialization via the api_data property
  • ContactExportDetail uses Pydantic's dataclass, which will automatically parse ISO datetime strings from API responses
  • Field types are appropriate for the domain
tests/unit/api/contacts/test_contact_exports.py (1)

1-244: LGTM!

Excellent test coverage for the ContactExportsApi:

  • Comprehensive error handling tests (401, 403, 404, 422 status codes)
  • Success path validation for both create and get_by_id operations
  • Verification of correct URL construction with different export IDs
  • Proper use of fixtures and parameterized tests
  • Clear assertions on response types, fields, and HTTP request details

The test suite follows established patterns and will catch regressions effectively.

mailtrap/api/resources/contact_exports.py (1)

8-32: LGTM!

The ContactExportsApi implementation is clean and follows the established patterns in the codebase:

  • Constructor correctly stores dependencies
  • create and get_by_id methods properly use the HTTP client and return strongly-typed results
  • _api_path helper correctly constructs the endpoint path with optional export_id
  • Consistent with other resource API classes (ContactFieldsApi, ContactListsApi, etc.)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
examples/contacts/contact_exports.py (2)

1-2: Consider using consistent import style for clarity.

The direct import of ContactExportDetail on line 2 is inconsistent with the module-prefixed style (mt.CreateContactExportParams, mt.ContactExportFilter) used throughout the rest of the example. In example files, consistently using the module prefix helps readers understand where types originate.

Apply this diff to use consistent module-prefixed imports:

 import mailtrap as mt
-from mailtrap.models.contacts import ContactExportDetail


 API_TOKEN = "YOUR_API_TOKEN"

Then update the return type annotations to use mt.ContactExportDetail:

 def create_export_contacts(
     contact_exports_params: mt.CreateContactExportParams,
-) -> ContactExportDetail:
+) -> mt.ContactExportDetail:
     return contact_exports_api.create(contact_exports_params=contact_exports_params)


-def get_contact_export(export_id: int) -> ContactExportDetail:
+def get_contact_export(export_id: int) -> mt.ContactExportDetail:
     return contact_exports_api.get_by_id(export_id)

11-18: Wrapper functions are acceptable but could be inlined.

The wrapper functions demonstrate a reasonable pattern but aren't strictly necessary in an example file. Direct API calls in the __main__ block would make the example more concise and immediately show the API surface. However, the current approach is also acceptable as it demonstrates how users might structure their own code.

If you prefer a more concise example, you could inline these calls:

if __name__ == "__main__":
    contact_export = contact_exports_api.create(
        contact_exports_params=mt.CreateContactExportParams(
            filters=[mt.ContactExportFilter(name="list_id", operator="equal", value=[10])]
        )
    )
    print(contact_export)

    contact_export = contact_exports_api.get_by_id(contact_export.id)
    print(contact_export)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2c7117 and 079c044.

📒 Files selected for processing (1)
  • examples/contacts/contact_exports.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
examples/contacts/contact_exports.py (3)
mailtrap/api/contacts.py (2)
  • contacts (31-32)
  • contact_exports (15-16)
mailtrap/models/contacts.py (3)
  • ContactExportDetail (140-145)
  • CreateContactExportParams (135-136)
  • ContactExportFilter (128-131)
mailtrap/api/resources/contact_exports.py (2)
  • create (13-21)
  • get_by_id (23-26)
🪛 Ruff (0.13.3)
examples/contacts/contact_exports.py

4-4: Possible hardcoded password assigned to: "API_TOKEN"

(S105)

⏰ 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). (5)
  • GitHub Check: Test python3.13 on windows-latest
  • GitHub Check: Test python3.9 on windows-latest
  • GitHub Check: Test python3.10 on windows-latest
  • GitHub Check: Test python3.12 on windows-latest
  • GitHub Check: Test python3.11 on windows-latest
🔇 Additional comments (2)
examples/contacts/contact_exports.py (2)

4-5: Static analysis false positive: hardcoded credentials are appropriate here.

The Ruff warning about a hardcoded password on line 4 is a false positive. These placeholder values ("YOUR_API_TOKEN" and "YOUR_ACCOUNT_ID") are clearly marked for user replacement and are appropriate for an example file.


21-30: LGTM! Clear demonstration of the API usage.

The main block effectively demonstrates creating a contact export with filters and then retrieving it by ID. The flow is clear and easy to follow.

@Ihor-Bilous Ihor-Bilous merged commit 1a8fb79 into main Oct 9, 2025
19 checks passed
@Ihor-Bilous Ihor-Bilous deleted the ISSUE-41 branch October 9, 2025 14:07
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