diff --git a/pyiceberg/catalog/rest/__init__.py b/pyiceberg/catalog/rest/__init__.py index 785940ea54..bcf883c4ad 100644 --- a/pyiceberg/catalog/rest/__init__.py +++ b/pyiceberg/catalog/rest/__init__.py @@ -18,6 +18,7 @@ import logging import os +import platform import sys import time import uuid @@ -1231,7 +1232,9 @@ def _config_headers(self, session: Session) -> None: header_properties = get_header_properties(self.properties) session.headers.update(header_properties) session.headers["Content-type"] = "application/json" - session.headers["User-Agent"] = f"PyIceberg/{__version__}" + session.headers["User-Agent"] = ( + f"pyiceberg/{__version__} ({platform.python_implementation().lower()} {platform.python_version()})" + ) session.headers["X-Client-Version"] = f"PyIceberg {__version__}" session.headers.setdefault("X-Iceberg-Access-Delegation", ACCESS_DELEGATION_DEFAULT) diff --git a/tests/catalog/test_rest.py b/tests/catalog/test_rest.py index a11adc55ee..01f2ae8c05 100644 --- a/tests/catalog/test_rest.py +++ b/tests/catalog/test_rest.py @@ -19,6 +19,7 @@ import base64 import os +import platform import uuid from collections.abc import Callable, Iterator from contextlib import contextmanager @@ -95,7 +96,7 @@ TEST_HEADERS = { "Content-type": "application/json", - "User-Agent": f"PyIceberg/{pyiceberg.__version__}", + "User-Agent": f"pyiceberg/{pyiceberg.__version__} ({platform.python_implementation().lower()} {platform.python_version()})", "Authorization": f"Bearer {TEST_TOKEN}", "X-Iceberg-Access-Delegation": "vended-credentials", } @@ -3217,6 +3218,20 @@ def test_auth_header(rest_mock: Mocker) -> None: ) +@pytest.mark.parametrize( + ("implementation", "python_version", "expected"), + [("CPython", "3.11.4", "pyiceberg/0.11.0 (cpython 3.11.4)"), ("PyPy", "3.10.16", "pyiceberg/0.11.0 (pypy 3.10.16)")], +) +def test_user_agent_header( + rest_mock: Mocker, monkeypatch: pytest.MonkeyPatch, implementation: str, python_version: str, expected: str +) -> None: + monkeypatch.setattr("pyiceberg.catalog.rest.__version__", "0.11.0") + monkeypatch.setattr(platform, "python_implementation", lambda: implementation) + monkeypatch.setattr(platform, "python_version", lambda: python_version) + catalog = RestCatalog("rest", uri=TEST_URI, warehouse="s3://some-bucket") + assert catalog._session.headers["User-Agent"] == expected + + def test_client_version_header(rest_mock: Mocker) -> None: catalog = RestCatalog("rest", uri=TEST_URI, warehouse="s3://some-bucket") assert catalog._session.headers.get("X-Client-Version") == f"PyIceberg {pyiceberg.__version__}"