Skip to content

Add Stats API#62

Open
piobeny wants to merge 1 commit intomainfrom
stats-api
Open

Add Stats API#62
piobeny wants to merge 1 commit intomainfrom
stats-api

Conversation

@piobeny
Copy link

@piobeny piobeny commented Mar 6, 2026

Motivation

  • Add support for the Email Sending Stats API (/api/accounts/{account_id}/stats) to the Python SDK, enabling users to retrieve aggregated email sending statistics.

Changes

  • Add SendingStats and SendingStatGroup pydantic dataclasses with delivery, bounce, open, click, and spam counts/rates
  • Add StatsFilterParams dataclass extending RequestParams for filter handling
  • Add StatsApi class with 5 methods: get, by_domains, by_categories, by_email_service_providers, by_date
  • Add api_query_params to RequestParams for automatic [] serialization of list query params
  • Add usage example in examples/general/stats.py
  • Update README with Stats API reference
  • Update CHANGELOG with entry for v2.5.0

How to test

  • stats_api.get(account_id, params) with different parameters (start_date, end_date, sending_domain_ids, sending_streams, categories, email_service_providers)
  • Test grouped endpoints (by_domain, by_category, by_email_service_provider, by_date) with filters

Examples

import mailtrap as mt                                                                                                                                                                              
from mailtrap.models.stats import StatsFilterParams                                                                                                                                                
                                                                                                                                                                                                   
client = mt.MailtrapClient(token="api_key")                                                                                                                                                        
stats_api = client.general_api.stats                                                                                                                                                               
                                                                                                                                                                                                   
# Get aggregated stats with optional filters                                                                                                                                                       
params = StatsFilterParams(                                                                                                                                                                        
    start_date="2026-01-01",                                                                                                                                                                       
    end_date="2026-01-31",                                                                                                                                                                         
    categories=["Welcome email"],                                                                                                                                                                  
)                                                                                                                                                                                                  
result = stats_api.get(account_id=account_id, params=params)

Summary by CodeRabbit

  • New Features

    • Added a Statistics API for retrieving sending metrics with grouped views (by domain, category, provider, date) and flexible filtering.
    • Added an example demonstrating common statistics retrieval patterns.
  • Behavior Changes

    • List-valued query parameters are now serialized automatically for API requests.
  • Documentation

    • Updated API documentation URL.
  • Tests

    • Added unit tests covering stats endpoints and filtering.

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

Warning

Rate limit exceeded

@piobeny has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71432eee-bfef-4867-b5ba-208c2a31b05b

📥 Commits

Reviewing files that changed from the base of the PR and between 908dbe5 and 72004fc.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • examples/general/stats.py
  • mailtrap/__init__.py
  • mailtrap/api/general.py
  • mailtrap/api/resources/stats.py
  • mailtrap/models/common.py
  • mailtrap/models/stats.py
  • pyproject.toml
  • tests/unit/api/general/test_stats.py
📝 Walkthrough

Walkthrough

Adds a new StatsApi with methods to fetch sending statistics (aggregated and grouped by domains, categories, email service providers, date), new models and filter params, package export for StatsFilterParams, query-parameter serialization for list values, example usage, changelog tweaks, and unit tests.

Changes

Cohort / File(s) Summary
Stats API Core
mailtrap/api/resources/stats.py, mailtrap/models/stats.py
Adds StatsApi with get, by_domain, by_category, by_email_service_provider, by_date; introduces SendingStats, SendingStatGroup, and StatsFilterParams dataclasses.
API Integration & Exports
mailtrap/api/general.py, mailtrap/__init__.py, mailtrap/models/common.py
Integrates StatsApi into GeneralApi via .stats property; exports StatsFilterParams at package level; adds RequestParams.api_query_params to serialize list query params as key[] (mutates data).
Examples & Changelog
examples/general/stats.py, CHANGELOG.md, pyproject.toml
Adds an example demonstrating StatsApi usage; updates CHANGELOG (Unreleased / historical sign flips) and documentation URL in pyproject.
Tests
tests/unit/api/general/test_stats.py
Adds comprehensive unit tests for StatsApi covering error cases, aggregated stats, grouped endpoints, and list-parameter serialization.

Sequence Diagram

sequenceDiagram
    participant Client as Client Code
    participant GeneralApi as GeneralApi
    participant StatsApi as StatsApi
    participant HttpClient as HttpClient
    participant Server as Server
    participant Parser as ResponseParser

    Client->>GeneralApi: access .stats
    GeneralApi->>StatsApi: StatsApi(client=HttpClient)
    Client->>StatsApi: call get/by_domain/... (account_id, StatsFilterParams)
    StatsApi->>StatsApi: build path & params (uses api_query_params)
    StatsApi->>HttpClient: GET /api/accounts/{id}/stats[/{group}]?...
    HttpClient->>Server: HTTP GET
    Server-->>HttpClient: JSON response
    HttpClient-->>StatsApi: response dict
    StatsApi->>Parser: map dict -> SendingStats / SendingStatGroup
    Parser-->>StatsApi: typed models
    StatsApi-->>Client: return typed result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • IgorDobryn
  • i7an
  • andrii-porokhnavets
  • VladimirTaytor

Poem

🐰 Hop, hop, the stats arrive in line,

Domains and dates and categories fine.
Filters stacked, queries dancing free,
A rabbit cheers — new endpoints, whee! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add Stats API' clearly and concisely describes the main change in the pull request—adding support for a new Stats API endpoint to the Python SDK.
Description check ✅ Passed The pull request description follows the repository template with all major sections completed: Motivation clearly states the goal, Changes lists all modifications, How to test provides testing guidance, and Examples includes a practical code snippet demonstrating the new API.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch stats-api

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

🧹 Nitpick comments (1)
examples/general/stats.py (1)

1-4: Consider consolidating imports.

The three imports from mailtrap.models.stats can be combined into a single line for brevity.

Proposed fix
 import mailtrap as mt
-from mailtrap.models.stats import SendingStatGroup
-from mailtrap.models.stats import SendingStats
-from mailtrap.models.stats import StatsFilterParams
+from mailtrap.models.stats import SendingStatGroup, SendingStats, StatsFilterParams
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/general/stats.py` around lines 1 - 4, Consolidate the three separate
imports from mailtrap.models.stats into a single statement: replace the three
lines importing SendingStatGroup, SendingStats, and StatsFilterParams with one
combined import that lists those symbols together (keep the existing import
mailtrap as mt intact); ensure the combined import includes SendingStatGroup,
SendingStats, and StatsFilterParams exactly as named.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/general/stats.py`:
- Around line 6-7: The example defines ACCOUNT_ID as a string while helper
functions expect account_id: int; update the example to provide an integer
ACCOUNT_ID (replace "YOUR_ACCOUNT_ID" with a numeric literal) or explicitly
cast/convert it before passing to functions so the value matches the account_id:
int signatures (look for the ACCOUNT_ID constant and any functions/methods that
declare account_id: int).

In `@mailtrap/api/resources/stats.py`:
- Around line 18-39: Reformat the oversized function signatures and long calls
in this file to satisfy Black/E501: wrap long parameter lists and chained calls
for the methods get, by_domains, by_categories, by_email_service_providers, and
by_date so no line exceeds the max width; specifically break the signature and
the return/_grouped_stats call lines that pass StatsFilterParams (e.g., the
by_email_service_providers(...) -> return self._grouped_stats(...)) across
multiple lines consistent with Black's style, then run Black on
mailtrap/api/resources/stats.py to ensure CI passes.

In `@mailtrap/models/stats.py`:
- Around line 31-33: The StatsFilterParams class uses empty-string defaults for
start_date/end_date causing RequestParams.api_data(..., exclude_none=True) to
still serialize them; change both fields in StatsFilterParams to use
Optional[str] with default None (and add the typing import if missing) so when
unset they are omitted from api_data serialization; update any related
validation or consumers that expect empty strings to handle None instead.

In `@tests/unit/api/general/test_stats.py`:
- Line 146: The test function signature for test_get_with_filter_params is too
long and must be wrapped to satisfy line-length rules; edit the def
test_get_with_filter_params(self, client: StatsApi, sample_stats_dict: dict) ->
None: signature to break parameters across multiple lines (e.g., place each
parameter on its own line or use a hanging indent inside the def parentheses) so
the line length is under the configured limit, then re-run/commit Black (or run
the project's formatter) to ensure the file passes CI formatting checks.

---

Nitpick comments:
In `@examples/general/stats.py`:
- Around line 1-4: Consolidate the three separate imports from
mailtrap.models.stats into a single statement: replace the three lines importing
SendingStatGroup, SendingStats, and StatsFilterParams with one combined import
that lists those symbols together (keep the existing import mailtrap as mt
intact); ensure the combined import includes SendingStatGroup, SendingStats, and
StatsFilterParams exactly as named.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c0ad3c1f-6b85-4473-a950-b27b381aec46

📥 Commits

Reviewing files that changed from the base of the PR and between 8821498 and d5c86be.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • examples/general/stats.py
  • mailtrap/__init__.py
  • mailtrap/api/general.py
  • mailtrap/api/resources/stats.py
  • mailtrap/models/common.py
  • mailtrap/models/stats.py
  • pyproject.toml
  • tests/unit/api/general/test_stats.py

@piobeny piobeny force-pushed the stats-api branch 3 times, most recently from 5bbca85 to a8a254b Compare March 6, 2026 11:59
@piobeny piobeny closed this Mar 9, 2026
@piobeny piobeny reopened this Mar 10, 2026
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 (1)
tests/unit/api/general/test_stats.py (1)

145-169: Cover scalar filters and the “unset params are omitted” case too.

This test locks in the list serialization, but it still misses the other half of the contract: start_date / end_date being sent under the expected keys, and StatsFilterParams() omitting unset fields entirely. Adding those assertions here would make regressions in RequestParams.api_data(..., exclude_none=True) much easier to catch.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/general/stats.py`:
- Around line 1-2: The import block in examples/general/stats.py was reordered
by the project's isort pre-commit hook and must be committed to pass CI; run
your local import formatter (isort) or the project's pre-commit hooks against
this file, accept the rewritten import ordering (affecting the top-level import
"mailtrap as mt" and the from-import of SendingStatGroup, SendingStats,
StatsFilterParams from mailtrap.models.stats), and commit the resulting changes
so the file matches the repo's canonical import ordering.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4782846c-b227-4e63-b0b8-0be945578cf9

📥 Commits

Reviewing files that changed from the base of the PR and between d5c86be and 908dbe5.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • examples/general/stats.py
  • mailtrap/__init__.py
  • mailtrap/api/general.py
  • mailtrap/api/resources/stats.py
  • mailtrap/models/common.py
  • mailtrap/models/stats.py
  • pyproject.toml
  • tests/unit/api/general/test_stats.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • mailtrap/init.py
  • mailtrap/models/common.py
  • CHANGELOG.md
  • mailtrap/api/resources/stats.py
  • pyproject.toml

@piobeny
Copy link
Author

piobeny commented Mar 10, 2026

@mklocek it's same but wanted to have another PR for version release

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.

2 participants