Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cb47f65
WIP - add user agent interceptor/plugin
alextwoods Feb 25, 2025
91e8208
Working implementation with basic user agent
alextwoods Feb 25, 2025
d3b1d15
Fix pyright errors
alextwoods Feb 25, 2025
2031933
Use short form license
alextwoods Feb 25, 2025
d5473b5
Run pyupgrade
alextwoods Feb 26, 2025
83a0a8f
Cleanups from PR (still todo: seperate into generic user agent and aw…
alextwoods Feb 26, 2025
b7e15d1
Add Config/HttpConfig Protocols + generate __version__
alextwoods Feb 26, 2025
8afb134
Add __version__ to smithy and aws core
alextwoods Feb 26, 2025
a7475d7
WIP - generic useragent refactoring.
alextwoods Feb 27, 2025
296811b
Remove explicit Config protocol
alextwoods Feb 27, 2025
f449114
Major refactor - generic and aws specific user agent. Codegen userage…
alextwoods Feb 27, 2025
7b7573d
Merge branch 'develop' into user_agent
alextwoods Feb 28, 2025
6a49728
Use aws-sdk-python as sdk name + correctly use sdkId for serviceId
alextwoods Feb 28, 2025
b727753
Merge branch 'develop' into user_agent
alextwoods Feb 28, 2025
b88dfc2
Use aws core version as the "main" sdk version. client library versio…
alextwoods Feb 28, 2025
6c6458b
User agent tests
alextwoods Mar 3, 2025
7aac81c
Add user_agent interceptor test
alextwoods Mar 3, 2025
86e461c
Update packages/smithy-http/src/smithy_http/interceptors/user_agent.py
alextwoods Mar 3, 2025
0013139
Update packages/smithy-http/tests/unit/interceptors/test_user_agent.py
alextwoods Mar 3, 2025
00ce11f
PR cleanups
alextwoods Mar 3, 2025
8ea3bf2
PR updates
alextwoods Mar 3, 2025
a35f607
Merge branch 'develop' into user_agent
alextwoods Mar 4, 2025
5f128d4
Merge branch 'smithy-lang:develop' into user_agent
alextwoods Mar 5, 2025
20b97ed
PR Cleanups
alextwoods Mar 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions packages/smithy-http/src/smithy_http/interceptors/user_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class UserAgentInterceptor(Interceptor[Any, None, HTTPRequest, None]):
def read_before_execution(
self, context: InterceptorContext[Any, None, None, None]
) -> None:
context.properties["user_agent"] = _UserAgentBuilder.from_environment().build()
context.properties["user_agent"] = UserAgentBuilder.from_environment().build()

def modify_before_signing(
self, context: InterceptorContext[Any, None, HTTPRequest, None]
Expand All @@ -42,24 +42,23 @@ def modify_before_signing(
_USERAGENT_SDK_NAME = "python"


class _UserAgentBuilder:
class UserAgentBuilder:
def __init__(
self,
*,
platform_name: str | None,
platform_version: str | None,
platform_machine: str | None,
python_version: str | None,
python_implementation: str | None,
platform_name: str | None = None,
platform_version: str | None = None,
platform_machine: str | None = None,
python_version: str | None = None,
python_implementation: str | None = None,
sdk_version: str | None = None,
) -> None:
self._platform_name = platform_name
self._platform_version = platform_version
self._platform_machine = platform_machine
self._python_version = python_version
self._python_implementation = python_implementation
# TODO: Allow configuration through context
self._sdk_version = smithy_core.__version__
self._sdk_version = sdk_version

@classmethod
def from_environment(cls) -> Self:
Expand All @@ -69,20 +68,26 @@ def from_environment(cls) -> Self:
platform_machine=platform.machine(),
python_version=platform.python_version(),
python_implementation=platform.python_implementation(),
sdk_version=smithy_core.__version__,
)

def build(self) -> UserAgent:
user_agent = UserAgent()
user_agent.sdk_metadata.append(
UserAgentComponent(prefix=_USERAGENT_SDK_NAME, name=self._sdk_version)
)
user_agent.sdk_metadata.extend(self._build_sdk_metadata())
user_agent.ua_metadata.append(UserAgentComponent(prefix="ua", name="2.1"))
user_agent.os_metadata.extend(self._build_os_metadata())
user_agent.os_metadata.extend(self._build_architecture_metadata())
user_agent.language_metadata.extend(self._build_language_metadata())

return user_agent

def _build_sdk_metadata(self) -> list[UserAgentComponent]:
if self._sdk_version:
return [
UserAgentComponent(prefix=_USERAGENT_SDK_NAME, name=self._sdk_version)
]
return []

def _build_os_metadata(self) -> list[UserAgentComponent]:
"""Build the OS/platform components of the User-Agent header string.

Expand All @@ -97,7 +102,7 @@ def _build_os_metadata(self) -> list[UserAgentComponent]:
* ``os/other``
* ``os/other md/foobar#1.2.3``
"""
if self._platform_name is None:
if self._platform_name is None or self._platform_name == "":
return [UserAgentComponent("os", "other")]

plt_name_lower = self._platform_name.lower()
Expand Down
71 changes: 71 additions & 0 deletions packages/smithy-http/tests/unit/interceptors/test_user_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import platform

import smithy_core
from smithy_http.interceptors.user_agent import UserAgentBuilder


def test_from_environment(monkeypatch): # type: ignore
monkeypatch.setattr(platform, "system", lambda: "Linux") # type: ignore
monkeypatch.setattr(platform, "release", lambda: "5.4.228-131.415.AMZN2.X86_64") # type: ignore
monkeypatch.setattr(platform, "python_version", lambda: "4.3.2") # type: ignore
monkeypatch.setattr(platform, "python_implementation", lambda: "Cpython") # type: ignore
monkeypatch.setattr(smithy_core, "__version__", "1.2.3") # type: ignore

user_agent = str(UserAgentBuilder.from_environment().build())
assert "python/1.2.3" in user_agent
assert "os/linux#5.4.228-131.415.AMZN2.X86_64" in user_agent
assert "md/arch#arm64" in user_agent
assert "lang/python#4.3.2" in user_agent
assert "md/pyimpl#Cpython" in user_agent


def test_build_adds_sdk_metadata():
user_agent = UserAgentBuilder(sdk_version="1.2.3").build()
assert "python/1.2.3" in str(user_agent)


def test_build_adds_ua_metadata():
user_agent = UserAgentBuilder().build()
assert "ua/2.1" in str(user_agent)


def test_build_os_defaults_to_other():
user_agent = UserAgentBuilder().build()
assert "os/other" in str(user_agent)


def test_build_os_lowercases_platform():
user_agent = UserAgentBuilder(platform_name="LINUX").build()
assert "os/linux" in str(user_agent)


def test_build_os_maps_platform_names():
user_agent = UserAgentBuilder(platform_name="darwin").build()
assert "os/macos" in str(user_agent)


def test_build_os_includes_version():
user_agent = UserAgentBuilder(platform_name="linux", platform_version="5.4").build()
assert "os/linux#5.4" in str(user_agent)


def test_build_os_other_platform():
user_agent = UserAgentBuilder(
platform_name="myos", platform_version="0.0.1"
).build()
assert "os/other md/myos#0.0.1" in str(user_agent)


def test_build_arch_adds_md():
user_agent = UserAgentBuilder(platform_machine="x86_64").build()
assert "md/arch#x86_64" in str(user_agent)


def test_build_language_version():
user_agent = UserAgentBuilder(python_version="3.12").build()
assert "lang/python#3.12" in str(user_agent)


def test_build_language_implementation():
user_agent = UserAgentBuilder(python_implementation="CPython").build()
assert "md/pyimpl#CPython" in str(user_agent)
Loading