Skip to content

Commit 8c77824

Browse files
Allow direct custom headers in client constructors
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 7838485 commit 8c77824

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

hyperbrowser/client/async_client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional
1+
from typing import Dict, Optional
22

33
from ..config import ClientConfig
44
from ..transport.async_transport import AsyncTransport
@@ -23,9 +23,10 @@ def __init__(
2323
config: Optional[ClientConfig] = None,
2424
api_key: Optional[str] = None,
2525
base_url: Optional[str] = None,
26+
headers: Optional[Dict[str, str]] = None,
2627
timeout: Optional[int] = 30,
2728
):
28-
super().__init__(AsyncTransport, config, api_key, base_url)
29+
super().__init__(AsyncTransport, config, api_key, base_url, headers)
2930
self.transport.client.timeout = timeout
3031
self.sessions = SessionManager(self)
3132
self.web = WebManager(self)

hyperbrowser/client/base.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
from typing import Optional, Type, Union
1+
import os
2+
from typing import Dict, Optional, Type, Union
23

34
from hyperbrowser.exceptions import HyperbrowserError
45
from ..config import ClientConfig
56
from ..transport.base import AsyncTransportStrategy, SyncTransportStrategy
6-
import os
77

88

99
class HyperbrowserBase:
@@ -15,7 +15,15 @@ def __init__(
1515
config: Optional[ClientConfig] = None,
1616
api_key: Optional[str] = None,
1717
base_url: Optional[str] = None,
18+
headers: Optional[Dict[str, str]] = None,
1819
):
20+
if config is not None and any(
21+
value is not None for value in (api_key, base_url, headers)
22+
):
23+
raise TypeError(
24+
"Pass either `config` or `api_key`/`base_url`/`headers`, not both."
25+
)
26+
1927
if config is None:
2028
config = ClientConfig(
2129
api_key=(
@@ -30,6 +38,7 @@ def __init__(
3038
"HYPERBROWSER_BASE_URL", "https://api.hyperbrowser.ai"
3139
)
3240
),
41+
headers=headers,
3342
)
3443

3544
if not config.api_key:

hyperbrowser/client/sync.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional
1+
from typing import Dict, Optional
22

33
from ..config import ClientConfig
44
from ..transport.sync import SyncTransport
@@ -23,9 +23,10 @@ def __init__(
2323
config: Optional[ClientConfig] = None,
2424
api_key: Optional[str] = None,
2525
base_url: Optional[str] = None,
26+
headers: Optional[Dict[str, str]] = None,
2627
timeout: Optional[int] = 30,
2728
):
28-
super().__init__(SyncTransport, config, api_key, base_url)
29+
super().__init__(SyncTransport, config, api_key, base_url, headers)
2930
self.transport.client.timeout = timeout
3031
self.sessions = SessionManager(self)
3132
self.web = WebManager(self)

tests/test_custom_headers.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import asyncio
22

3+
import pytest
4+
35
from hyperbrowser import AsyncHyperbrowser, Hyperbrowser
46
from hyperbrowser.config import ClientConfig
57
from hyperbrowser.transport.async_transport import AsyncTransport
@@ -45,6 +47,14 @@ def test_sync_client_config_headers_are_applied_to_transport():
4547
client.close()
4648

4749

50+
def test_sync_client_constructor_headers_are_applied_to_transport():
51+
client = Hyperbrowser(api_key="test-key", headers={"X-Team-Trace": "team-2"})
52+
try:
53+
assert client.transport.client.headers["X-Team-Trace"] == "team-2"
54+
finally:
55+
client.close()
56+
57+
4858
def test_async_client_config_headers_are_applied_to_transport():
4959
async def run() -> None:
5060
client = AsyncHyperbrowser(
@@ -56,3 +66,22 @@ async def run() -> None:
5666
await client.close()
5767

5868
asyncio.run(run())
69+
70+
71+
def test_async_client_constructor_headers_are_applied_to_transport():
72+
async def run() -> None:
73+
client = AsyncHyperbrowser(api_key="test-key", headers={"X-Team-Trace": "team-2"})
74+
try:
75+
assert client.transport.client.headers["X-Team-Trace"] == "team-2"
76+
finally:
77+
await client.close()
78+
79+
asyncio.run(run())
80+
81+
82+
def test_client_constructor_rejects_mixed_config_and_direct_args():
83+
with pytest.raises(TypeError, match="Pass either `config`"):
84+
Hyperbrowser(
85+
config=ClientConfig(api_key="test-key"),
86+
headers={"X-Team-Trace": "team-1"},
87+
)

0 commit comments

Comments
 (0)