Skip to content

Conversation

Ihor-Bilous
Copy link
Collaborator

@Ihor-Bilous Ihor-Bilous commented Sep 5, 2025

Motivation

In this PR I added InboxesApi, related models, tests, examples, improved ProjectsApi with parameters classes, added docstrings to all resources methods.

Changes

  • Added InboxesApi, models, test, examples
  • Added ProjectParams model and used in create/update project resource method
  • Added docstring to all resource methods in all APIs
  • Improved test files structure

How to test

  • see examples/testing/inboxes.py

Summary by CodeRabbit

  • New Features

    • Testing Inboxes support: list, retrieve, create, update, clean, mark read, reset credentials/username, enable email address, delete.
    • Testing API exposes inboxes and an example demonstrating usage.
  • Improvements

    • Introduced parameter objects for inbox and project operations; inbox model includes api_domain and update validation.
    • Project creation/update now use structured params; IDs standardized as integers.
    • Expanded public exports for new parameter types.
  • Documentation

    • Added/expanded docstrings across contacts, contact lists/fields/imports, templates, and sending.
  • Tests

    • Added/updated unit tests for inboxes API and parameter models.

…ectsApi with parameters classes, add docstring to all resources methods.
Copy link

coderabbitai bot commented Sep 5, 2025

Walkthrough

Adds account-scoped InboxesApi and exposes it via TestingApi.inboxes; introduces CreateInboxParams, UpdateInboxParams, and ProjectParams models (with validation), re-exports them, updates ProjectsApi signatures to accept ProjectParams, adds example usage and tests, and adds docstrings to several resource modules.

Changes

Cohort / File(s) Summary
Inboxes API & Testing integration
mailtrap/api/resources/inboxes.py, mailtrap/api/testing.py
New InboxesApi class providing list/get/create/update/delete and inbox-specific actions (clean, all_read, reset_credentials, toggle_email_username, reset_email_username); TestingApi.inboxes property returns an InboxesApi.
Model params for Inboxes & Projects
mailtrap/models/inboxes.py, mailtrap/models/projects.py
Adds Inbox.api_domain; introduces CreateInboxParams and UpdateInboxParams (validation: at least one update field required) and ProjectParams; all inherit RequestParams.
Public exports
mailtrap/__init__.py
Re-exports CreateInboxParams, UpdateInboxParams, and ProjectParams.
Projects API & examples/tests updated
mailtrap/api/resources/projects.py, examples/testing/projects.py, tests/unit/api/testing/test_projects.py
ProjectsApi.create/update now accept ProjectParams and use .api_data; examples and tests updated to pass ProjectParams and use int IDs.
Examples: inboxes
examples/testing/inboxes.py
New example module demonstrating inbox operations using MailtrapClient, placeholder API_TOKEN and ACCOUNT_ID, with wrapper functions and a main listing.
Docstring-only changes
mailtrap/api/resources/contact_fields.py, mailtrap/api/resources/contact_imports.py, mailtrap/api/resources/contact_lists.py, mailtrap/api/resources/contacts.py, mailtrap/api/resources/templates.py, mailtrap/api/sending.py
Added/expanded docstrings for public methods; no signature or behavioral changes.
Unit tests: Inboxes API
tests/unit/api/testing/test_inboxes.py
New comprehensive tests covering list/get/create/update/delete and action endpoints, including success and error cases; uses CreateInboxParams / UpdateInboxParams.
Unit tests: Models
tests/unit/models/test_inboxes.py, tests/unit/models/test_projects.py, tests/unit/models/test_templates.py
Tests added/updated to validate CreateInboxParams, UpdateInboxParams behavior and ProjectParams.api_data; template test now expects ValueError.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant MC as MailtrapClient
  participant T as TestingApi
  participant I as InboxesApi
  participant HTTP as Mailtrap HTTP API

  Dev->>MC: instantiate(api_token)
  Dev->>T: MC.testing(account_id)
  T-->>Dev: TestingApi
  Dev->>I: T.inboxes (property)
  I-->>Dev: InboxesApi

  rect rgba(220,235,255,0.35)
    note right of I: List inboxes
    Dev->>I: get_list()
    I->>HTTP: GET /api/accounts/{account_id}/inboxes
    HTTP-->>I: 200 OK (list)
    I-->>Dev: list[Inbox]
  end

  rect rgba(220,255,220,0.35)
    note right of I: Create inbox
    Dev->>I: create(project_id, CreateInboxParams)
    I->>HTTP: POST /api/accounts/{account_id}/projects/{project_id}/inboxes {"inbox": {...}}
    HTTP-->>I: 201 Created (Inbox)
    I-->>Dev: Inbox
  end

  rect rgba(255,245,210,0.35)
    note right of I: Update & Actions
    Dev->>I: update(inbox_id, UpdateInboxParams)
    I->>HTTP: PATCH /api/accounts/{account_id}/inboxes/{inbox_id}
    HTTP-->>I: 200 OK (Inbox)
    I-->>Dev: Inbox
    Dev->>I: clean / all_read / reset_credentials / toggle_email_username / reset_email_username
    I->>HTTP: PATCH .../{action}
    HTTP-->>I: 200 OK (Inbox)
    I-->>Dev: Inbox
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • VladimirTaytor
  • IgorDobryn
  • andrii-porokhnavets

Poem

I hop through inbox meadows, quick and spry,
I wrap params, tests, and routes beneath the sky.
Projects grow, inbox doors swing wide,
Toggles, cleans, and creds now side by side.
A rabbit signs the patch—then off I fly 🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ISSUE-27

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

Caution

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

⚠️ Outside diff range comments (1)
mailtrap/api/resources/contact_fields.py (1)

29-33: api_data used as attribute; should be called

This will otherwise send a method object in JSON.

-            json=field_params.api_data,
+            json=field_params.api_data(),
-            json=field_params.api_data,
+            json=field_params.api_data(),

Also applies to: 42-45

🧹 Nitpick comments (21)
mailtrap/api/resources/templates.py (2)

50-51: Truthiness check may skip template_id=0

Be explicit to avoid accidental falsy IDs.

-        if template_id:
+        if template_id is not None:
             return f"{path}/{template_id}"

16-16: Nit: tighten docstring phrasing

Prefer imperative, consistent style across resources.

-        """Get all email templates existing in your account."""
+        """List email templates in the account."""
mailtrap/api/resources/contact_fields.py (1)

16-16: Polish docstrings for grammar/consistency

Lowercase “contact field”, use singular where appropriate, and remove comma splices.

-        """Get all Contact Fields existing in your account."""
+        """List contact fields in the account."""
-        """Get a contact Field by ID."""
+        """Get a contact field by ID."""
-        """Create new Contact Fields. Please note, you can have up to 40 fields."""
+        """Create a contact field. You can have up to 40 custom fields per account."""
-        """
-        Update existing Contact Field. Please note,
-        you cannot change data_type of the field.
-        """
+        """Update a contact field. Note: data_type cannot be changed."""
-        """
-        Delete existing Contact Field Please, note, you cannot delete a Contact Field
-        which is used in Automations, Email Campaigns (started or scheduled), and in
-        conditions of Contact Segments (you'll see the corresponding error)
-        """
+        """Delete a contact field.
+
+        You cannot delete a field used in Automations, Email Campaigns (started or scheduled),
+        or in Contact Segment conditions; the API will return an error."""

Also applies to: 21-21, 28-28, 38-41, 49-53

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

15-15: Unify docstring style

Use imperative mood and singular nouns.

-        """Get all contact lists existing in your account."""
+        """List contact lists in the account."""
-        """Get a contact list by ID."""
+        """Get a contact list by ID."""
-        """Create new Contact Lists."""
+        """Create a contact list."""
-        """Update existing Contact List."""
+        """Update a contact list."""
-        """Delete existing Contact List."""
+        """Delete a contact list."""

Also applies to: 20-20, 25-25, 33-33, 41-41

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

18-18: Clarify that URL encoding is handled internally; standardize docstring style.
The current phrasing may imply users must pre-encode. Also consider adding Parameters/Returns/Raises for consistency.

Apply this doc tweak:

-        """Get contact using id or email (URL encoded)."""
+        """Get a contact by id or email (URL encoding handled automatically)."""
-        """Create a new contact."""
+        """Create a new contact."""
-        """Update contact using id or email (URL encoded)."""
+        """Update a contact by id or email (URL encoding handled automatically)."""
-        """Delete contact using id or email (URL encoded)."""
+        """Delete a contact by id or email (URL encoding handled automatically)."""

Also applies to: 23-23, 33-33, 41-41

tests/unit/models/test_projects.py (1)

7-7: Ruff S101 in tests — either ignore or configure per-file.
If the repo doesn’t already ignore S101 for tests, add a local noqa.

-        assert entity.api_data == {"name": "test"}
+        assert entity.api_data == {"name": "test"}  # noqa: S101

Alternatively, configure Ruff: [tool.ruff.per-file-ignores] "tests/**" = ["S101"].

mailtrap/models/projects.py (1)

25-27: Add a brief docstring for discoverability.
Optional but keeps parity with other request param models.

 @dataclass
 class ProjectParams(RequestParams):
-    name: str
+    """Payload for project create/update."""
+    name: str
mailtrap/api/testing.py (1)

20-22: Optional: add a short docstring to the inboxes property.
Improves IDE/tooling hints and matches docstring push in this PR.

     @property
     def inboxes(self) -> InboxesApi:
-        return InboxesApi(account_id=self._account_id, client=self._client)
+        """Access the Inboxes API for the current account."""
+        return InboxesApi(account_id=self._account_id, client=self._client)
tests/unit/models/test_inboxes.py (1)

1-31: Optional: silence Ruff S101 for tests

If Ruff is enforced in CI, either add per-file ignores for tests or annotate individual asserts with noqa to avoid noise.

Example pyproject setting:

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S101"]
tests/unit/api/testing/test_projects.py (2)

236-239: Typo in test input string

Minor nit: “Update Project Namet” → “Updated Project Name” for clarity. No behavior change.

-            _ = client.update(
-                PROJECT_ID, project_params=ProjectParams(name="Update Project Namet")
-            )
+            _ = client.update(
+                PROJECT_ID, project_params=ProjectParams(name="Updated Project Name")
+            )

190-197: Optionally assert request JSON payloads

To harden tests, assert the exact JSON body sent on create/update using responses matchers.

+from responses import matchers
@@
-        responses.post(
-            BASE_PROJECTS_URL,
-            json=sample_project_dict,
-            status=201,
-        )
+        responses.post(
+            BASE_PROJECTS_URL,
+            json=sample_project_dict,
+            status=201,
+            match=[matchers.json_params_matcher({"project": {"name": "New Project"}})],
+        )
@@
-        responses.patch(
-            url,
-            json=updated_project_dict,
-            status=200,
-        )
+        responses.patch(
+            url,
+            json=updated_project_dict,
+            status=200,
+            match=[matchers.json_params_matcher({"project": {"name": updated_name}})],
+        )

Also applies to: 252-260

mailtrap/models/inboxes.py (1)

45-57: Keep ValueError, but centralize the message and simplify the check

Behavior is fine; consider de-duplicating the error string (helps tests) and simplifying the condition. Also addresses TRY003 hint.

-from typing import Optional
+from typing import Optional, ClassVar
@@
 @dataclass
 class UpdateInboxParams(RequestParams):
     name: Optional[str] = None
     email_username: Optional[str] = None
+    ERROR_MSG: ClassVar[str] = "At least one field must be provided for update action"
 
     def __post_init__(self) -> None:
-        if all(
-            value is None
-            for value in [
-                self.name,
-                self.email_username,
-            ]
-        ):
-            raise ValueError("At least one field must be provided for update action")
+        if self.name is None and self.email_username is None:
+            raise ValueError(self.ERROR_MSG)
mailtrap/api/resources/projects.py (1)

51-55: Guard against falsy project_id values in _api_path

Use an explicit None check to avoid misrouting if 0 ever surfaces.

-        if project_id:
+        if project_id is not None:
             return f"{path}/{project_id}"
tests/unit/api/testing/test_inboxes.py (2)

200-211: Optionally assert JSON payloads for create/update

Like projects tests, add matchers to verify exact request bodies sent to the API.

+from responses import matchers
@@
-        responses.post(
+        responses.post(
             BASE_PROJECT_INBOXES_URL,
             status=status_code,
             json=response_json,
-        )
+        )
@@
-        responses.post(
+        responses.post(
             BASE_PROJECT_INBOXES_URL,
             json=sample_inbox_dict,
             status=201,
+            match=[matchers.json_params_matcher({"inbox": {"name": "New Inbox"}})],
         )
@@
-        responses.patch(
+        responses.patch(
             url,
             status=status_code,
             json=response_json,
-        )
+        )
@@
-        responses.patch(
+        responses.patch(
             url,
             json=updated_inbox_dict,
             status=200,
+            match=[matchers.json_params_matcher({"inbox": {"name": updated_name}})],
         )

Also applies to: 223-229, 258-269, 287-290


536-553: Naming nit: “enable_email_address” toggles state

Method name implies one-way “enable”, but endpoint is toggle_email_username. Consider adding a toggle_email_username alias in the API for clarity while keeping the current name for backward compatibility.

Would you like a follow-up PR to add a method alias and docstring clarifications?

Also applies to: 556-571

examples/testing/projects.py (1)

4-4: Silence the S105 false positive for example creds.

Keep placeholders for consistency across examples, but add a localized Ruff ignore to avoid noisy alerts.

-API_TOKEN = "YOU_API_TOKEN"
+API_TOKEN = "YOU_API_TOKEN"  # noqa: S105
examples/testing/inboxes.py (3)

49-51: Rename to reflect toggle behavior.

Endpoint toggles the state; consider naming the wrapper accordingly to avoid confusion.

-def enable_inbox_email_address(inbox_id: int) -> Inbox:
-    return inboxes_api.enable_email_address(inbox_id)
+def toggle_inbox_email_address(inbox_id: int) -> Inbox:
+    return inboxes_api.enable_email_address(inbox_id)

57-58: Add return type for consistency.

Resources return Inbox on delete; mirror that in the example.

-def delete_inbox(inbox_id: int):
+def delete_inbox(inbox_id: int) -> Inbox:
     return inboxes_api.delete(inbox_id)

6-6: Silence the S105 false positive for example creds.

Same rationale as other examples.

-API_TOKEN = "YOU_API_TOKEN"
+API_TOKEN = "YOU_API_TOKEN"  # noqa: S105
mailtrap/api/resources/inboxes.py (2)

70-74: Robust None-check for ID.

Use an explicit None check to avoid edge cases if 0 ever appears (defensive, low risk).

-    def _api_path(self, inbox_id: Optional[int] = None) -> str:
+    def _api_path(self, inbox_id: int | None = None) -> str:
         path = f"/api/accounts/{self._account_id}/inboxes"
-        if inbox_id:
+        if inbox_id is not None:
             return f"{path}/{inbox_id}"
         return path

Also remove the now-unused Optional import at Line 1:

-from typing import Optional
+from __future__ import annotations

60-64: Method name vs. behavior (toggle).

Endpoint toggles the email address; consider an alias with clearer naming to reduce ambiguity without breaking the current API.

     def enable_email_address(self, inbox_id: int) -> Inbox:
         """Turn the email address of the inbox on/off."""
         response = self._client.patch(f"{self._api_path(inbox_id)}/toggle_email_username")
         return Inbox(**response)
+
+    # Alias for clarity; preserves existing name.
+    def toggle_email_address(self, inbox_id: int) -> Inbox:
+        """Alias for enable_email_address; toggles the inbox email address."""
+        return self.enable_email_address(inbox_id)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ddfac64 and 29d6cdd.

📒 Files selected for processing (18)
  • examples/testing/inboxes.py (1 hunks)
  • examples/testing/projects.py (1 hunks)
  • mailtrap/__init__.py (1 hunks)
  • mailtrap/api/resources/contact_fields.py (2 hunks)
  • mailtrap/api/resources/contact_imports.py (1 hunks)
  • mailtrap/api/resources/contact_lists.py (1 hunks)
  • mailtrap/api/resources/contacts.py (2 hunks)
  • mailtrap/api/resources/inboxes.py (1 hunks)
  • mailtrap/api/resources/projects.py (2 hunks)
  • mailtrap/api/resources/templates.py (2 hunks)
  • mailtrap/api/sending.py (1 hunks)
  • mailtrap/api/testing.py (2 hunks)
  • mailtrap/models/inboxes.py (3 hunks)
  • mailtrap/models/projects.py (2 hunks)
  • tests/unit/api/testing/test_inboxes.py (1 hunks)
  • tests/unit/api/testing/test_projects.py (5 hunks)
  • tests/unit/models/test_inboxes.py (1 hunks)
  • tests/unit/models/test_projects.py (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 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 inherits from RequestParams, which defines api_data as a property that returns a filtered dictionary, so it should be accessed without parentheses like contact.api_data.

Applied to files:

  • mailtrap/models/inboxes.py
  • tests/unit/models/test_projects.py
  • mailtrap/__init__.py
  • mailtrap/models/projects.py
📚 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/__init__.py
📚 Learning: 2025-08-12T23:07:25.653Z
Learnt from: Ihor-Bilous
PR: railsware/mailtrap-python#31
File: mailtrap/config.py:1-1
Timestamp: 2025-08-12T23:07:25.653Z
Learning: In Mailtrap's API architecture, Testing API resources (Projects, Inboxes, etc.) use the main "mailtrap.io" host, while only email sending functionality uses "sandbox.api.mailtrap.io" as the host.

Applied to files:

  • mailtrap/api/testing.py
  • tests/unit/api/testing/test_projects.py
  • examples/testing/projects.py
  • mailtrap/api/resources/projects.py
  • examples/testing/inboxes.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/resources/contact_fields.py
📚 Learning: 2025-09-04T19:31:01.169Z
Learnt from: Ihor-Bilous
PR: railsware/mailtrap-python#39
File: examples/suppressions.py:1-10
Timestamp: 2025-09-04T19:31:01.169Z
Learning: In the mailtrap-python repository, all example files consistently use placeholder strings like `API_TOKEN = "YOU_API_TOKEN"` and `ACCOUNT_ID = "YOU_ACCOUNT_ID"` instead of environment variable lookups. This pattern should be maintained for consistency across examples.

Applied to files:

  • examples/testing/inboxes.py
🧬 Code graph analysis (17)
mailtrap/models/inboxes.py (1)
mailtrap/models/common.py (1)
  • RequestParams (13-19)
tests/unit/models/test_projects.py (2)
mailtrap/models/projects.py (1)
  • ProjectParams (26-27)
mailtrap/models/common.py (1)
  • api_data (15-19)
mailtrap/__init__.py (3)
mailtrap/api/testing.py (2)
  • inboxes (21-22)
  • projects (17-18)
mailtrap/models/inboxes.py (2)
  • CreateInboxParams (40-41)
  • UpdateInboxParams (45-57)
mailtrap/models/projects.py (1)
  • ProjectParams (26-27)
mailtrap/api/testing.py (4)
mailtrap/api/resources/inboxes.py (1)
  • InboxesApi (9-74)
tests/unit/api/testing/test_inboxes.py (1)
  • client (25-26)
tests/unit/api/testing/test_projects.py (1)
  • client (21-22)
tests/unit/api/email_templates/test_email_templates.py (1)
  • client (22-23)
mailtrap/api/resources/templates.py (3)
mailtrap/http.py (3)
  • get (25-29)
  • patch (39-41)
  • delete (43-45)
mailtrap/models/templates.py (2)
  • EmailTemplate (40-49)
  • CreateEmailTemplateParams (9-14)
mailtrap/models/common.py (2)
  • api_data (15-19)
  • DeletedObject (23-24)
mailtrap/api/resources/contact_imports.py (3)
mailtrap/http.py (1)
  • post (31-33)
mailtrap/models/common.py (1)
  • api_data (15-19)
mailtrap/models/contacts.py (1)
  • ContactImport (108-113)
mailtrap/api/resources/contact_fields.py (3)
mailtrap/http.py (2)
  • get (25-29)
  • patch (39-41)
mailtrap/models/contacts.py (2)
  • ContactField (28-32)
  • CreateContactFieldParams (11-14)
mailtrap/models/common.py (2)
  • api_data (15-19)
  • DeletedObject (23-24)
mailtrap/api/resources/contacts.py (3)
mailtrap/http.py (2)
  • get (25-29)
  • patch (39-41)
mailtrap/models/contacts.py (3)
  • ContactResponse (96-97)
  • CreateContactParams (52-57)
  • Contact (85-92)
mailtrap/models/common.py (1)
  • DeletedObject (23-24)
mailtrap/api/resources/contact_lists.py (4)
mailtrap/api/resources/contact_fields.py (1)
  • _api_path (57-61)
mailtrap/api/resources/contacts.py (1)
  • _api_path (45-49)
mailtrap/models/contacts.py (2)
  • ContactList (41-43)
  • ContactListParams (36-37)
mailtrap/models/common.py (2)
  • api_data (15-19)
  • DeletedObject (23-24)
tests/unit/api/testing/test_inboxes.py (5)
mailtrap/api/testing.py (1)
  • inboxes (21-22)
mailtrap/api/resources/inboxes.py (11)
  • InboxesApi (9-74)
  • get_list (14-17)
  • get_by_id (19-22)
  • create (24-30)
  • update (32-38)
  • delete (40-43)
  • clean (45-48)
  • mark_as_read (50-53)
  • reset_credentials (55-58)
  • enable_email_address (60-63)
  • reset_email_username (65-68)
mailtrap/exceptions.py (1)
  • APIError (10-15)
mailtrap/http.py (4)
  • HttpClient (13-96)
  • get (25-29)
  • post (31-33)
  • patch (39-41)
mailtrap/models/inboxes.py (3)
  • CreateInboxParams (40-41)
  • Inbox (10-36)
  • UpdateInboxParams (45-57)
tests/unit/models/test_inboxes.py (2)
mailtrap/models/inboxes.py (2)
  • CreateInboxParams (40-41)
  • UpdateInboxParams (45-57)
mailtrap/models/common.py (1)
  • api_data (15-19)
mailtrap/models/projects.py (1)
mailtrap/models/common.py (1)
  • RequestParams (13-19)
mailtrap/api/resources/inboxes.py (4)
mailtrap/http.py (4)
  • HttpClient (13-96)
  • get (25-29)
  • post (31-33)
  • patch (39-41)
mailtrap/api/testing.py (1)
  • inboxes (21-22)
mailtrap/models/inboxes.py (3)
  • CreateInboxParams (40-41)
  • Inbox (10-36)
  • UpdateInboxParams (45-57)
mailtrap/models/common.py (1)
  • api_data (15-19)
tests/unit/api/testing/test_projects.py (3)
mailtrap/api/testing.py (1)
  • projects (17-18)
mailtrap/models/projects.py (1)
  • ProjectParams (26-27)
mailtrap/api/resources/projects.py (2)
  • create (24-33)
  • update (35-44)
examples/testing/projects.py (3)
mailtrap/models/projects.py (2)
  • Project (17-22)
  • ProjectParams (26-27)
mailtrap/client.py (2)
  • MailtrapClient (24-142)
  • testing_api (51-57)
mailtrap/api/resources/projects.py (4)
  • get_list (14-17)
  • get_by_id (19-22)
  • create (24-33)
  • update (35-44)
mailtrap/api/resources/projects.py (3)
mailtrap/api/testing.py (1)
  • projects (17-18)
mailtrap/models/projects.py (2)
  • ProjectParams (26-27)
  • Project (17-22)
mailtrap/models/common.py (1)
  • api_data (15-19)
examples/testing/inboxes.py (4)
mailtrap/api/testing.py (1)
  • inboxes (21-22)
mailtrap/models/inboxes.py (3)
  • Inbox (10-36)
  • CreateInboxParams (40-41)
  • UpdateInboxParams (45-57)
mailtrap/client.py (2)
  • MailtrapClient (24-142)
  • testing_api (51-57)
mailtrap/api/resources/inboxes.py (10)
  • get_list (14-17)
  • create (24-30)
  • get_by_id (19-22)
  • update (32-38)
  • clean (45-48)
  • mark_as_read (50-53)
  • reset_credentials (55-58)
  • enable_email_address (60-63)
  • reset_email_username (65-68)
  • delete (40-43)
🪛 Ruff (0.12.2)
mailtrap/models/inboxes.py

57-57: Avoid specifying long messages outside the exception class

(TRY003)

tests/unit/models/test_projects.py

7-7: Use of assert detected

(S101)

tests/unit/api/testing/test_inboxes.py

98-98: Use of assert detected

(S101)


112-112: Use of assert detected

(S101)


113-113: Use of assert detected

(S101)


114-114: Use of assert detected

(S101)


154-154: Use of assert detected

(S101)


169-169: Use of assert detected

(S101)


170-170: Use of assert detected

(S101)


211-211: Use of assert detected

(S101)


227-227: Use of assert detected

(S101)


228-228: Use of assert detected

(S101)


270-270: Use of assert detected

(S101)


289-289: Use of assert detected

(S101)


290-290: Use of assert detected

(S101)


330-330: Use of assert detected

(S101)


345-345: Use of assert detected

(S101)


346-346: Use of assert detected

(S101)


386-386: Use of assert detected

(S101)


401-401: Use of assert detected

(S101)


402-402: Use of assert detected

(S101)


442-442: Use of assert detected

(S101)


457-457: Use of assert detected

(S101)


458-458: Use of assert detected

(S101)


498-498: Use of assert detected

(S101)


513-513: Use of assert detected

(S101)


514-514: Use of assert detected

(S101)


554-554: Use of assert detected

(S101)


569-569: Use of assert detected

(S101)


570-570: Use of assert detected

(S101)


610-610: Use of assert detected

(S101)


625-625: Use of assert detected

(S101)


626-626: Use of assert detected

(S101)

tests/unit/models/test_inboxes.py

11-11: Use of assert detected

(S101)


19-19: Use of assert detected

(S101)


23-23: Use of assert detected

(S101)


27-27: Use of assert detected

(S101)


30-30: Use of assert detected

(S101)

examples/testing/projects.py

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

(S105)

examples/testing/inboxes.py

6-6: 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.13 on macos-latest
🔇 Additional comments (20)
mailtrap/api/sending.py (1)

21-21: Docstring addition looks fine

Short, clear, and consistent with nearby resources.

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

26-31: Incorrect suggestion — api_data is a property, not a method
RequestParams declares api_data with @property, so .api_data already returns the payload dict. Adding () would attempt to call a dict and raise a TypeError. No changes needed.

Likely an incorrect or invalid review comment.

mailtrap/api/resources/contact_imports.py (2)

14-19: Docstring is solid

Clear limits and async behavior described.


20-23: api_data used as attribute in comprehension

Call the method to build a serializable payload.

-            json={"contacts": [contact.api_data for contact in contacts]},
+            json={"contacts": [contact.api_data() for contact in contacts]},
⛔ Skipped due to learnings
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.
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 inherits from RequestParams, which defines api_data as a property that returns a filtered dictionary, so it should be accessed without parentheses like contact.api_data.
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 inherits from RequestParams, which defines api_data as a property that returns a filtered dictionary, so it should be accessed without parentheses like contact.api_data.
mailtrap/api/resources/contact_lists.py (1)

26-29: api_data used as attribute; should be called

Fix payload construction in create/update.

-            json=list_params.api_data,
+            json=list_params.api_data(),
-            json=list_params.api_data,
+            json=list_params.api_data(),

Also applies to: 34-37

⛔ Skipped due to learnings
Learnt from: Ihor-Bilous
PR: railsware/mailtrap-python#34
File: mailtrap/api/resources/templates.py:33-36
Timestamp: 2025-08-21T10:37:54.227Z
Learning: In the mailtrap-python codebase, api_data is a property on ParametersObject (and classes that inherit from it), not a method. It should be accessed without parentheses: template_params.api_data, not template_params.api_data().
mailtrap/api/resources/contacts.py (1)

18-18: Docstrings added — nice coverage across CRUD.
Clearer public API docs; consistent with other resources.

Also applies to: 23-23, 33-33, 41-41

mailtrap/models/projects.py (1)

25-27: ProjectParams looks correct and aligns with RequestParams usage.
Matches how api_data is produced elsewhere; minimal, type-safe payload object.

mailtrap/__init__.py (1)

13-14: Re-exports LGTM.
Expands the public surface predictably (CreateInboxParams, UpdateInboxParams, ProjectParams).

Also applies to: 21-21

mailtrap/api/testing.py (1)

3-3: New inboxes property mirrors projects — LGTM.
Straightforward exposure of InboxesApi via TestingApi.

Also applies to: 20-22

tests/unit/models/test_inboxes.py (3)

10-11: LGTM: api_data for CreateInboxParams

Shape and property access look correct and consistent with RequestParams.api_data semantics.


21-24: LGTM: api_data for UpdateInboxParams with both fields

Output dict matches inputs and excludes None as intended.


25-31: LGTM: api_data for UpdateInboxParams with single-field inputs

Both cases are correct and validate exclude_none behavior.

tests/unit/api/testing/test_projects.py (1)

182-182: LGTM: switched to ProjectParams for create

Signature and payload usage align with ProjectsApi.create expecting params.api_data.

mailtrap/models/inboxes.py (2)

26-26: LGTM: Inbox.api_domain added

Field addition looks consistent with sample payloads and Inbox mapping.


39-42: LGTM: CreateInboxParams

Minimal, correct, and leverages RequestParams.api_data to serialize.

mailtrap/api/resources/projects.py (2)

24-33: LGTM: create now accepts ProjectParams

Signature and payload switch to params.api_data is clean and future-proof.


35-44: LGTM: update now accepts ProjectParams

Consistent with create; good docstring additions.

tests/unit/api/testing/test_inboxes.py (1)

29-61: LGTM: sample inbox fixture mirrors model schema well

Covers all required fields, including api_domain and permissions.

examples/testing/projects.py (1)

15-25: Good adoption of ProjectParams and ID-based ops.

API usage aligns with ProjectsApi surface (get_by_id/create/update) and new ProjectParams model. Looks consistent with the broader shift in this PR.

examples/testing/inboxes.py (1)

13-55: Example wrappers read well and mirror the InboxesApi.

Signatures and payloads (CreateInboxParams/UpdateInboxParams) match the API; type hints are clear.

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

♻️ Duplicate comments (1)
tests/unit/models/test_inboxes.py (1)

15-19: Fix exception assertion — use match and correct the message typo

Same issue as noted previously: rely on match and fix actioaction. Also drop the unused assignment.

-    def test_raise_error_when_all_fields_are_missing(self) -> None:
-        with pytest.raises(ValueError) as exc:
-            _ = UpdateInboxParams()
-
-        assert "At least one field must be provided for update actio" in str(exc)
+    def test_raise_error_when_all_fields_are_missing(self) -> None:
+        with pytest.raises(
+            ValueError,
+            match="At least one field must be provided for update action",
+        ):
+            UpdateInboxParams()
🧹 Nitpick comments (1)
tests/unit/models/test_inboxes.py (1)

10-10: Silence Ruff S101 for pytest assert in tests

Pytest idiomatically uses assert; to keep the current style and satisfy Ruff, add a per-file ignore.

Option A — file-level directive (quick fix):

+ # ruff: noqa: S101
 import pytest

Option B — repo-wide config (preferred, if consistent with the codebase):

# pyproject.toml
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S101"]

Also applies to: 18-18, 22-22, 26-26, 29-29

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 29d6cdd and 81b783f.

📒 Files selected for processing (2)
  • tests/unit/models/test_inboxes.py (1 hunks)
  • tests/unit/models/test_templates.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/unit/models/test_inboxes.py (2)
mailtrap/models/inboxes.py (2)
  • CreateInboxParams (40-41)
  • UpdateInboxParams (45-57)
mailtrap/models/common.py (1)
  • api_data (15-19)
🪛 Ruff (0.12.2)
tests/unit/models/test_inboxes.py

10-10: Use of assert detected

(S101)


18-18: Use of assert detected

(S101)


22-22: Use of assert detected

(S101)


26-26: Use of assert detected

(S101)


29-29: Use of assert detected

(S101)

⏰ 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.11 on windows-latest
  • GitHub Check: Test python3.12 on windows-latest
  • GitHub Check: Test python3.9 on windows-latest
  • GitHub Check: Test python3.10 on windows-latest

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 (4)
tests/unit/models/test_inboxes.py (4)

8-11: Rename “props” → “fields” in test names

Minor clarity/consistency with Python terminology.

-def test_api_data_should_return_dict_with_all_props(self) -> None:
+def test_api_data_returns_all_fields(self) -> None:
-    def test_api_data_should_return_dict_with_all_props(self) -> None:
+    def test_api_data_returns_all_fields(self) -> None:

Also applies to: 20-23


24-29: Clarify test name: it returns only provided fields, not “required props”

The params are optional; suggest reflecting that in the name.

-    def test_api_data_should_return_dict_with_required_props_only(self) -> None:
+    def test_api_data_returns_only_provided_fields(self) -> None:

18-18: Drop unused assignment

The temporary _ isn’t needed inside pytest.raises.

-            _ = UpdateInboxParams()
+            UpdateInboxParams()

10-10: Ruff S101 in tests — prefer config suppression over code changes

assert is idiomatic in pytest; suppress S101 for tests instead of rewriting assertions.

Add to pyproject.toml:

[tool.ruff.lint.per-file-ignores]
"tests/**/*" = ["S101"]

Also applies to: 22-22, 26-26, 29-29

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 81b783f and c4d85e5.

📒 Files selected for processing (2)
  • tests/unit/models/test_inboxes.py (1 hunks)
  • tests/unit/models/test_templates.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/models/test_templates.py
🧰 Additional context used
🧬 Code graph analysis (1)
tests/unit/models/test_inboxes.py (2)
mailtrap/models/inboxes.py (2)
  • CreateInboxParams (40-41)
  • UpdateInboxParams (45-57)
mailtrap/models/common.py (1)
  • api_data (15-19)
🪛 Ruff (0.12.2)
tests/unit/models/test_inboxes.py

10-10: Use of assert detected

(S101)


22-22: Use of assert detected

(S101)


26-26: Use of assert detected

(S101)


29-29: Use of assert detected

(S101)

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

14-19: Exception expectation fixed — LGTM

Now correctly asserts ValueError with match=.... This resolves the earlier failure mode.


20-23: api_data with both fields — LGTM

Covers the happy path and validates exclude_none=True behavior.

@Ihor-Bilous Ihor-Bilous merged commit 22b1e1d into main Sep 11, 2025
19 checks passed
@Ihor-Bilous Ihor-Bilous deleted the ISSUE-27 branch September 11, 2025 15:28
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants