Skip to content

Make it possible to set a custom user agent#61

Merged
leonid-shevtsov merged 1 commit intomainfrom
set-user-agent
Mar 18, 2026
Merged

Make it possible to set a custom user agent#61
leonid-shevtsov merged 1 commit intomainfrom
set-user-agent

Conversation

@leonid-shevtsov
Copy link
Contributor

@leonid-shevtsov leonid-shevtsov commented Feb 19, 2026

Motivation

Make it possible to set a custom user agent to identify specific clients

Changes

  • Add user agent to options

Summary by CodeRabbit

  • New Features

    • You can now customize the User-Agent header sent with requests; if not specified, it defaults to an auto-generated identifier derived from the package version.
  • Tests

    • Test suite updated to validate the new default User-Agent behavior and to cover providing a custom User-Agent.

@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

The MailtrapClient now allows runtime customization of the User-Agent header. A new DEFAULT_USER_AGENT class attribute (derived from package version via importlib.metadata.version('mailtrap')) and an optional user_agent constructor parameter set a private _user_agent used in request headers.

Changes

Cohort / File(s) Summary
User-Agent Customization
mailtrap/client.py
Added DEFAULT_USER_AGENT built from importlib.metadata.version('mailtrap'); added user_agent: Optional[str] = None parameter to MailtrapClient.__init__; stored value in _user_agent; headers now uses _user_agent.
User-Agent Tests
tests/unit/test_client.py
Updated tests to assert against MailtrapClient.DEFAULT_USER_AGENT and added a test verifying a provided custom user_agent appears in headers.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I tweaked my header with a hop and a cheer,

DEFAULT version found, and custom ones near.
No more hard strings that made me feel blue,
Now clients can say what they send — who knew? 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description covers motivation and changes but omits required sections like 'How to test' and 'Images and GIFs', making it incomplete against the template. Add 'How to test' section with test steps and update 'Changes' with more specific implementation details like the new parameter and DEFAULT_USER_AGENT constant.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: enabling custom user agent configuration in the MailtrapClient.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch set-user-agent
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

You can customize the high-level summary generated by CodeRabbit.

Configure the reviews.high_level_summary_instructions setting to provide custom instructions for generating the high-level summary.

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

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

Inline comments:
In `@mailtrap/client.py`:
- Line 63: The assignment to self._user_agent on the line using the ternary
expression (user_agent if user_agent is not None else self.DEFAULT_USER_AGENT)
exceeds the 90-char limit; fix it by splitting the expression across multiple
lines or by assigning the chosen value to a short temporary variable before
setting self._user_agent so that the final assignment line is under 90
characters — update the code around the self._user_agent assignment (where
user_agent and DEFAULT_USER_AGENT are referenced) to use a wrapped conditional
or intermediate variable to satisfy the line-length rule.
- Around line 1-5: Reorder and format the imports in mailtrap/client.py to
satisfy isort/Black: ensure stdlib imports are grouped together and alphabetized
(place import importlib.metadata and import warnings together in alpha order)
and include from typing import Optional in the correct stdlib group, then run
isort and black (e.g., isort mailtrap/client.py && black mailtrap/client.py) to
apply the final formatting; focus on the imports referencing importlib.metadata,
warnings, and Optional so CI pre-commit hooks pass.
- Around line 40-43: The module-level DEFAULT_USER_AGENT currently calls
importlib.metadata.version('mailtrap') at import time which raises
PackageNotFoundError in a raw checkout; change this to handle that exception
(catch PackageNotFoundError from importlib.metadata.version) and fall back to a
safe default version string (e.g., "0+unknown" or "local") or compute the
version lazily when needed; update the DEFAULT_USER_AGENT construction in
mailtrap.client to use the try/except fallback (or a helper like a
get_user_agent() function) so importing mailtrap.client no longer fails when the
package metadata is missing.

Comment on lines +40 to +43
DEFAULT_USER_AGENT = (
f"mailtrap-python/{importlib.metadata.version('mailtrap')} "
"(https://github.com/railsware/mailtrap-python)"
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

PackageNotFoundError at module import time if package is not installed.

importlib.metadata.version('mailtrap') is evaluated when the class body is executed (i.e., when mailtrap.client is first imported). In a raw git checkout without pip install -e ., this raises PackageNotFoundError, making the entire module unimportable. Consider a fallback:

🛡️ Proposed fallback
+try:
+    _mailtrap_version = importlib.metadata.version("mailtrap")
+except importlib.metadata.PackageNotFoundError:
+    _mailtrap_version = "unknown"
+
 class MailtrapClient:
     ...
     DEFAULT_USER_AGENT = (
-        f"mailtrap-python/{importlib.metadata.version('mailtrap')} "
+        f"mailtrap-python/{_mailtrap_version} "
         "(https://github.com/railsware/mailtrap-python)"
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mailtrap/client.py` around lines 40 - 43, The module-level DEFAULT_USER_AGENT
currently calls importlib.metadata.version('mailtrap') at import time which
raises PackageNotFoundError in a raw checkout; change this to handle that
exception (catch PackageNotFoundError from importlib.metadata.version) and fall
back to a safe default version string (e.g., "0+unknown" or "local") or compute
the version lazily when needed; update the DEFAULT_USER_AGENT construction in
mailtrap.client to use the try/except fallback (or a helper like a
get_user_agent() function) so importing mailtrap.client no longer fails when the
package metadata is missing.

BULK_HOST = BULK_HOST
SANDBOX_HOST = SANDBOX_HOST
DEFAULT_USER_AGENT = (
f"mailtrap-python/{importlib.metadata.version('mailtrap')} "
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need a version though? I didn't see it advertised in our other SDKs. We'll need to update analytics to parse the version out for groupping

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.

♻️ Duplicate comments (1)
mailtrap/client.py (1)

38-41: ⚠️ Potential issue | 🟡 Minor

PackageNotFoundError at module import time if package is not installed.

This issue was flagged in a previous review but appears unaddressed. When importing this module from a raw git checkout (without pip install -e .), importlib.metadata.version('mailtrap') will raise PackageNotFoundError, making the module unimportable. Consider adding a fallback:

🛡️ Proposed fallback
+try:
+    _mailtrap_version = importlib.metadata.version("mailtrap")
+except importlib.metadata.PackageNotFoundError:
+    _mailtrap_version = "unknown"
+
 class MailtrapClient:
     ...
     DEFAULT_USER_AGENT = (
-        f"mailtrap-python/{importlib.metadata.version('mailtrap')} "
+        f"mailtrap-python/{_mailtrap_version} "
         "(https://github.com/railsware/mailtrap-python)"
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mailtrap/client.py` around lines 38 - 41, The DEFAULT_USER_AGENT construction
currently calls importlib.metadata.version('mailtrap') at import time which
raises importlib.metadata.PackageNotFoundError for raw checkouts; wrap the
version lookup in a try/except that catches
importlib.metadata.PackageNotFoundError (or Exception) and falls back to a safe
default string (e.g., a generic version token or empty version) when
importlib.metadata.version('mailtrap') fails so DEFAULT_USER_AGENT is always
defined; update the DEFAULT_USER_AGENT expression to use that protected lookup
instead of calling importlib.metadata.version(...) directly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@mailtrap/client.py`:
- Around line 38-41: The DEFAULT_USER_AGENT construction currently calls
importlib.metadata.version('mailtrap') at import time which raises
importlib.metadata.PackageNotFoundError for raw checkouts; wrap the version
lookup in a try/except that catches importlib.metadata.PackageNotFoundError (or
Exception) and falls back to a safe default string (e.g., a generic version
token or empty version) when importlib.metadata.version('mailtrap') fails so
DEFAULT_USER_AGENT is always defined; update the DEFAULT_USER_AGENT expression
to use that protected lookup instead of calling importlib.metadata.version(...)
directly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eaa41914-b33c-47da-a673-1fb977af5f51

📥 Commits

Reviewing files that changed from the base of the PR and between 8fe4303 and 8da73a7.

📒 Files selected for processing (2)
  • mailtrap/client.py
  • tests/unit/test_client.py

@leonid-shevtsov leonid-shevtsov merged commit 750af1d into main Mar 18, 2026
16 checks passed
@leonid-shevtsov leonid-shevtsov deleted the set-user-agent branch March 18, 2026 13:16
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