Skip to content

Commit b464ee2

Browse files
Add optional model serialization helper for manager create flows
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 7483ac1 commit b464ee2

File tree

9 files changed

+96
-28
lines changed

9 files changed

+96
-28
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ This runs lint, format checks, compile checks, tests, and package build.
9191
- `tests/test_manager_model_dump_usage.py` (manager serialization centralization),
9292
- `tests/test_mapping_keys_access_usage.py` (centralized key-iteration boundaries),
9393
- `tests/test_mapping_reader_usage.py` (shared mapping-read parser usage),
94+
- `tests/test_optional_serialization_helper_usage.py` (optional model serialization helper usage enforcement),
9495
- `tests/test_plain_type_guard_usage.py` (`str`/`int` guardrail enforcement via plain-type checks),
9596
- `tests/test_plain_type_identity_usage.py` (direct `type(... ) is str|int` guardrail enforcement via shared helpers),
9697
- `tests/test_polling_loop_usage.py` (`while True` polling-loop centralization in `hyperbrowser/client/polling.py`),

hyperbrowser/client/managers/async_manager/profile.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
ProfileResponse,
99
)
1010
from hyperbrowser.models.session import BasicResponse
11-
from ..serialization_utils import serialize_model_dump_to_dict
11+
from ..serialization_utils import (
12+
serialize_model_dump_to_dict,
13+
serialize_optional_model_dump_to_dict,
14+
)
1215
from ..response_utils import parse_response_model
1316

1417

@@ -19,12 +22,10 @@ def __init__(self, client):
1922
async def create(
2023
self, params: Optional[CreateProfileParams] = None
2124
) -> CreateProfileResponse:
22-
payload = {}
23-
if params is not None:
24-
payload = serialize_model_dump_to_dict(
25-
params,
26-
error_message="Failed to serialize profile create params",
27-
)
25+
payload = serialize_optional_model_dump_to_dict(
26+
params,
27+
error_message="Failed to serialize profile create params",
28+
)
2829
response = await self._client.transport.post(
2930
self._client._build_url("/profile"),
3031
data=payload,

hyperbrowser/client/managers/async_manager/session.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
from typing import IO, List, Optional, Union, overload
33
import warnings
44
from hyperbrowser.exceptions import HyperbrowserError
5-
from ..serialization_utils import serialize_model_dump_to_dict
5+
from ..serialization_utils import (
6+
serialize_model_dump_to_dict,
7+
serialize_optional_model_dump_to_dict,
8+
)
69
from ..session_upload_utils import normalize_upload_file_input
710
from ..session_utils import (
811
parse_session_recordings_response_data,
@@ -61,12 +64,10 @@ def __init__(self, client):
6164
async def create(
6265
self, params: Optional[CreateSessionParams] = None
6366
) -> SessionDetail:
64-
payload = {}
65-
if params is not None:
66-
payload = serialize_model_dump_to_dict(
67-
params,
68-
error_message="Failed to serialize session create params",
69-
)
67+
payload = serialize_optional_model_dump_to_dict(
68+
params,
69+
error_message="Failed to serialize session create params",
70+
)
7071
response = await self._client.transport.post(
7172
self._client._build_url("/session"),
7273
data=payload,

hyperbrowser/client/managers/serialization_utils.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,20 @@ def serialize_model_dump_to_dict(
2222
if type(payload) is not dict:
2323
raise HyperbrowserError(error_message)
2424
return payload
25+
26+
27+
def serialize_optional_model_dump_to_dict(
28+
model: Any,
29+
*,
30+
error_message: str,
31+
exclude_none: bool = True,
32+
by_alias: bool = True,
33+
) -> Dict[str, Any]:
34+
if model is None:
35+
return {}
36+
return serialize_model_dump_to_dict(
37+
model,
38+
error_message=error_message,
39+
exclude_none=exclude_none,
40+
by_alias=by_alias,
41+
)

hyperbrowser/client/managers/sync_manager/profile.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
ProfileResponse,
99
)
1010
from hyperbrowser.models.session import BasicResponse
11-
from ..serialization_utils import serialize_model_dump_to_dict
11+
from ..serialization_utils import (
12+
serialize_model_dump_to_dict,
13+
serialize_optional_model_dump_to_dict,
14+
)
1215
from ..response_utils import parse_response_model
1316

1417

@@ -19,12 +22,10 @@ def __init__(self, client):
1922
def create(
2023
self, params: Optional[CreateProfileParams] = None
2124
) -> CreateProfileResponse:
22-
payload = {}
23-
if params is not None:
24-
payload = serialize_model_dump_to_dict(
25-
params,
26-
error_message="Failed to serialize profile create params",
27-
)
25+
payload = serialize_optional_model_dump_to_dict(
26+
params,
27+
error_message="Failed to serialize profile create params",
28+
)
2829
response = self._client.transport.post(
2930
self._client._build_url("/profile"),
3031
data=payload,

hyperbrowser/client/managers/sync_manager/session.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
from typing import IO, List, Optional, Union, overload
33
import warnings
44
from hyperbrowser.exceptions import HyperbrowserError
5-
from ..serialization_utils import serialize_model_dump_to_dict
5+
from ..serialization_utils import (
6+
serialize_model_dump_to_dict,
7+
serialize_optional_model_dump_to_dict,
8+
)
69
from ..session_upload_utils import normalize_upload_file_input
710
from ..session_utils import (
811
parse_session_recordings_response_data,
@@ -59,12 +62,10 @@ def __init__(self, client):
5962
self.event_logs = SessionEventLogsManager(client)
6063

6164
def create(self, params: Optional[CreateSessionParams] = None) -> SessionDetail:
62-
payload = {}
63-
if params is not None:
64-
payload = serialize_model_dump_to_dict(
65-
params,
66-
error_message="Failed to serialize session create params",
67-
)
65+
payload = serialize_optional_model_dump_to_dict(
66+
params,
67+
error_message="Failed to serialize session create params",
68+
)
6869
response = self._client.transport.post(
6970
self._client._build_url("/session"),
7071
data=payload,

tests/test_architecture_marker_usage.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"tests/test_architecture_marker_usage.py",
1919
"tests/test_plain_type_guard_usage.py",
2020
"tests/test_plain_type_identity_usage.py",
21+
"tests/test_optional_serialization_helper_usage.py",
2122
"tests/test_type_utils_usage.py",
2223
"tests/test_polling_loop_usage.py",
2324
"tests/test_core_type_helper_usage.py",

tests/test_manager_serialization_utils.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from hyperbrowser.client.managers.serialization_utils import (
66
serialize_model_dump_to_dict,
7+
serialize_optional_model_dump_to_dict,
78
)
89
from hyperbrowser.exceptions import HyperbrowserError
910

@@ -74,3 +75,27 @@ def test_serialize_model_dump_to_dict_rejects_non_dict_payloads():
7475
)
7576

7677
assert exc_info.value.original_error is None
78+
79+
80+
def test_serialize_optional_model_dump_to_dict_returns_empty_dict_for_none():
81+
assert (
82+
serialize_optional_model_dump_to_dict(
83+
None,
84+
error_message="serialize failure",
85+
)
86+
== {}
87+
)
88+
89+
90+
def test_serialize_optional_model_dump_to_dict_serializes_non_none_values():
91+
model = _ModelWithPayload({"value": 1})
92+
93+
payload = serialize_optional_model_dump_to_dict(
94+
model,
95+
error_message="serialize failure",
96+
exclude_none=False,
97+
by_alias=False,
98+
)
99+
100+
assert payload == {"value": 1}
101+
assert model.calls == [(False, False)]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from pathlib import Path
2+
3+
import pytest
4+
5+
pytestmark = pytest.mark.architecture
6+
7+
8+
MANAGER_MODULES = (
9+
"hyperbrowser/client/managers/sync_manager/profile.py",
10+
"hyperbrowser/client/managers/async_manager/profile.py",
11+
"hyperbrowser/client/managers/sync_manager/session.py",
12+
"hyperbrowser/client/managers/async_manager/session.py",
13+
)
14+
15+
16+
def test_profile_and_session_managers_use_optional_serialization_helper():
17+
for module_path in MANAGER_MODULES:
18+
module_text = Path(module_path).read_text(encoding="utf-8")
19+
assert "serialize_optional_model_dump_to_dict(" in module_text
20+
assert "payload = {}" not in module_text

0 commit comments

Comments
 (0)