Skip to content

Comments

Make it possible to set a custom user agent#61

Open
leonid-shevtsov wants to merge 1 commit intomainfrom
set-user-agent
Open

Make it possible to set a custom user agent#61
leonid-shevtsov wants to merge 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 automatically-generated identifier based on the package version.

@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

The MailtrapClient now supports runtime customization of the User-Agent header. A new DEFAULT_USER_AGENT class attribute (derived from package version) and optional user_agent parameter enable users to override the default User-Agent while maintaining backward compatibility.

Changes

Cohort / File(s) Summary
User-Agent Customization
mailtrap/client.py
Added DEFAULT_USER_AGENT class attribute from package version, user_agent parameter to constructor, and private _user_agent attribute. Updated headers to use configurable user agent via importlib.metadata.
User-Agent Tests
tests/unit/test_client.py
Updated existing user-agent header test to use MailtrapClient.DEFAULT_USER_AGENT constant and added new test verifying custom user-agent functionality.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A carrot of code, so small and so neat,
A user-agent now custom and sweet!
No more hardcoded strings in the way,
Let clients declare what they send and say. 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main feature added: making it possible to set a custom user agent, which is the primary change across all modified files.
Description check ✅ Passed The description includes motivation and a brief summary of changes, but is incomplete compared to the template. Missing 'How to test' section with test cases and the 'Images and GIFs' section.

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

✨ 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 set-user-agent

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: 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 1 to 5
import warnings

import importlib.metadata

from typing import Optional
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix import ordering and Black formatting to unblock CI.

The pre-commit hooks fail because import importlib.metadata and import warnings are stdlib imports that isort expects to be grouped together (no blank line between them) and sorted alphabetically (importlib < warnings). Black also flags a reformat of the file. Running isort mailtrap/client.py && black mailtrap/client.py locally should resolve both failures.

♻️ Proposed import fix (isort ordering)
-import warnings
-
-import importlib.metadata
-
-from typing import Optional
+import importlib.metadata
+import warnings
+from typing import Optional
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import warnings
import importlib.metadata
from typing import Optional
import importlib.metadata
import warnings
from typing import Optional
🧰 Tools
🪛 GitHub Actions: Tests and checks

[error] 1-1: isort: Import statements were reordered and the file was modified by the hook


[error] 1-1: Black: reformatted mailtrap/client.py


[error] 1-1: Pre-commit: The operation was canceled due to failures in hooks

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mailtrap/client.py` around lines 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.

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.

self.sandbox = sandbox
self.account_id = account_id
self.inbox_id = inbox_id
self._user_agent = user_agent if user_agent is not None else self.DEFAULT_USER_AGENT
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix E501: line 63 exceeds the 90-character limit (92 chars).

This is flagged by flake8 and is blocking CI.

🐛 Proposed fix
-        self._user_agent = user_agent if user_agent is not None else self.DEFAULT_USER_AGENT
+        self._user_agent = (
+            user_agent if user_agent is not None else self.DEFAULT_USER_AGENT
+        )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self._user_agent = user_agent if user_agent is not None else self.DEFAULT_USER_AGENT
self._user_agent = (
user_agent if user_agent is not None else self.DEFAULT_USER_AGENT
)
🧰 Tools
🪛 GitHub Actions: Tests and checks

[error] 63-63: flake8: E501 line too long (92 > 90 characters)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mailtrap/client.py` at 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.

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

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