Skip to content

Commit fe3cbbb

Browse files
committed
fix: report Python SDK identity and package version in User-Agent
Sync-Source-Commit: 5061fafcb56f54f7677583f5fea8f3e681d1243e Hand-Written-Reason: No Ark-APIs provenance marker; treated as a hand-written source commit. Release-Version: 0.5.0
1 parent 6410460 commit fe3cbbb

4 files changed

Lines changed: 101 additions & 2 deletions

File tree

‎src/arkruntime/_base_client.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def auth_headers(self) -> dict[str, str]:
184184

185185
@property
186186
def user_agent(self) -> str:
187-
return "volc-sdk-python/" + VERSION
187+
return "ark-runtime-python/" + VERSION
188188

189189
def default_headers(self) -> Dict[str, str]:
190190
return {

‎src/arkruntime/_constants.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
import httpx
66

7-
VERSION = "1.0.0"
7+
from ._version import VERSION as VERSION
8+
89
BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"
910

1011

‎src/arkruntime/_version.py‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright (c) 2026 ByteDance Ltd. and/or its affiliates.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import re
5+
from importlib.metadata import version
6+
from pathlib import Path
7+
8+
9+
def _get_version() -> str:
10+
# Source and editable imports must use this checkout, even if another
11+
# arkruntime distribution is installed. Releases use wheel metadata,
12+
# which setuptools derives from the same pyproject.toml project.version.
13+
source_root = Path(__file__).resolve().parent.parent
14+
pyproject = source_root.parent / "pyproject.toml"
15+
if source_root.name == "src" and pyproject.is_file():
16+
# The project declares a static, single-line version. Read only the
17+
# [project] table without requiring a TOML dependency on Python 3.8.
18+
project = re.search(r"(?ms)^\[project\][ \t]*\n(.*?)(?=^\[|\Z)", pyproject.read_text(encoding="utf-8"))
19+
if project is not None:
20+
declared = re.search(r"""(?m)^version\s*=\s*["']([^"'\r\n]+)["'][ \t]*(?:#.*)?$""", project[1])
21+
if declared is not None:
22+
return declared[1]
23+
raise RuntimeError("Expected a static project.version in " + str(pyproject))
24+
return version("arkruntime")
25+
26+
27+
VERSION = _get_version()

‎tests/test_user_agent.py‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright (c) 2026 ByteDance Ltd. and/or its affiliates.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from __future__ import annotations
5+
6+
import asyncio
7+
from importlib.metadata import version
8+
from pathlib import Path
9+
10+
import httpx
11+
import pytest
12+
13+
from arkruntime import Ark, AsyncArk, _version
14+
15+
16+
@pytest.mark.parametrize("custom", [None, "my-app/2.0"])
17+
@pytest.mark.parametrize("asynchronous", [False, True])
18+
def test_user_agent_on_requests(custom: str | None, asynchronous: bool) -> None:
19+
requests = []
20+
21+
def handle(request: httpx.Request) -> httpx.Response:
22+
requests.append(request)
23+
return httpx.Response(200, json={"id": "test-file", "object": "file"})
24+
25+
headers = {"User-Agent": custom} if custom else {}
26+
transport = httpx.MockTransport(handle)
27+
if asynchronous:
28+
29+
async def run() -> None:
30+
async with AsyncArk(api_key="placeholder", http_client=httpx.AsyncClient(transport=transport)) as client:
31+
await client.files.retrieve("test-file", extra_headers=headers)
32+
33+
asyncio.run(run())
34+
else:
35+
with Ark(api_key="placeholder", http_client=httpx.Client(transport=transport)) as client:
36+
client.files.retrieve("test-file", extra_headers=headers)
37+
38+
assert len(requests) == 1
39+
assert requests[0].headers.get_list("User-Agent") == [custom or "ark-runtime-python/" + version("arkruntime")]
40+
41+
42+
def test_checkout_version_takes_precedence_over_installed_metadata(
43+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
44+
) -> None:
45+
source = tmp_path / "src" / "arkruntime" / "_version.py"
46+
monkeypatch.setattr(_version, "__file__", str(source))
47+
monkeypatch.setattr(_version, "version", lambda name: "0.0.1")
48+
(tmp_path / "pyproject.toml").write_text(
49+
'[tool.example]\nversion = "9.9.9"\n[project]\nname = "arkruntime"\nversion = "2.3.4rc1"\n'
50+
'[tool.other]\nversion = "8.8.8"\n',
51+
encoding="utf-8",
52+
)
53+
assert _version._get_version() == "2.3.4rc1"
54+
55+
56+
def test_installed_version_uses_distribution_metadata(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
57+
monkeypatch.setattr(_version, "__file__", str(tmp_path / "site-packages" / "arkruntime" / "_version.py"))
58+
59+
def metadata_version(name: str) -> str:
60+
assert name == "arkruntime"
61+
return "3.4.5"
62+
63+
monkeypatch.setattr(_version, "version", metadata_version)
64+
assert _version._get_version() == "3.4.5"
65+
66+
67+
def test_missing_source_version_does_not_use_stale_metadata(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
68+
monkeypatch.setattr(_version, "__file__", str(tmp_path / "src" / "arkruntime" / "_version.py"))
69+
(tmp_path / "pyproject.toml").write_text('[project]\nname = "arkruntime"\n', encoding="utf-8")
70+
with pytest.raises(RuntimeError, match="Expected a static project.version"):
71+
_version._get_version()

0 commit comments

Comments
 (0)