Skip to content

Commit 204d2b1

Browse files
Centralize session profile-update parameter resolution
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent ddf37ac commit 204d2b1

File tree

7 files changed

+171
-60
lines changed

7 files changed

+171
-60
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ This runs lint, format checks, compile checks, tests, and package build.
101101
- `tests/test_polling_loop_usage.py` (`while True` polling-loop centralization in `hyperbrowser/client/polling.py`),
102102
- `tests/test_pyproject_architecture_marker.py` (pytest marker registration enforcement),
103103
- `tests/test_readme_examples_listing.py` (README example-listing consistency enforcement),
104+
- `tests/test_session_profile_update_helper_usage.py` (session profile-update parameter helper usage enforcement),
104105
- `tests/test_session_upload_helper_usage.py` (session upload-input normalization helper usage enforcement),
105106
- `tests/test_tool_mapping_reader_usage.py` (tools mapping-helper usage),
106107
- `tests/test_type_utils_usage.py` (type `__mro__` boundary centralization in `hyperbrowser/type_utils.py`),

hyperbrowser/client/managers/async_manager/session.py

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
serialize_model_dump_to_dict,
88
serialize_optional_model_dump_to_dict,
99
)
10+
from ..session_profile_update_utils import resolve_update_profile_params
1011
from ..session_upload_utils import normalize_upload_file_input
1112
from ..session_utils import (
1213
parse_session_recordings_response_data,
@@ -225,36 +226,11 @@ async def update_profile_params(
225226
*,
226227
persist_changes: Optional[bool] = None,
227228
) -> BasicResponse:
228-
params_obj: UpdateSessionProfileParams
229-
230-
if type(params) is UpdateSessionProfileParams:
231-
if persist_changes is not None:
232-
raise HyperbrowserError(
233-
"Pass either UpdateSessionProfileParams as the second argument or persist_changes=bool, not both."
234-
)
235-
params_obj = params
236-
elif isinstance(params, UpdateSessionProfileParams):
237-
raise HyperbrowserError(
238-
"update_profile_params() requires a plain UpdateSessionProfileParams object."
239-
)
240-
elif isinstance(params, bool):
241-
if persist_changes is not None:
242-
raise HyperbrowserError(
243-
"Pass either a boolean as the second argument or persist_changes=bool, not both."
244-
)
245-
self._warn_update_profile_params_boolean_deprecated()
246-
params_obj = UpdateSessionProfileParams(persist_changes=params)
247-
elif params is None:
248-
if persist_changes is None:
249-
raise HyperbrowserError(
250-
"update_profile_params() requires either UpdateSessionProfileParams or persist_changes=bool."
251-
)
252-
self._warn_update_profile_params_boolean_deprecated()
253-
params_obj = UpdateSessionProfileParams(persist_changes=persist_changes)
254-
else:
255-
raise HyperbrowserError(
256-
"update_profile_params() requires either UpdateSessionProfileParams or a boolean persist_changes."
257-
)
229+
params_obj = resolve_update_profile_params(
230+
params,
231+
persist_changes=persist_changes,
232+
on_deprecated_bool_usage=self._warn_update_profile_params_boolean_deprecated,
233+
)
258234

259235
serialized_params = serialize_model_dump_to_dict(
260236
params_obj,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from typing import Callable, Optional, Union
2+
3+
from hyperbrowser.exceptions import HyperbrowserError
4+
from hyperbrowser.models.session import UpdateSessionProfileParams
5+
6+
7+
def resolve_update_profile_params(
8+
params: Union[UpdateSessionProfileParams, bool, None],
9+
*,
10+
persist_changes: Optional[bool],
11+
on_deprecated_bool_usage: Callable[[], None],
12+
) -> UpdateSessionProfileParams:
13+
if type(params) is UpdateSessionProfileParams:
14+
if persist_changes is not None:
15+
raise HyperbrowserError(
16+
"Pass either UpdateSessionProfileParams as the second argument or persist_changes=bool, not both."
17+
)
18+
return params
19+
if isinstance(params, UpdateSessionProfileParams):
20+
raise HyperbrowserError(
21+
"update_profile_params() requires a plain UpdateSessionProfileParams object."
22+
)
23+
if isinstance(params, bool):
24+
if persist_changes is not None:
25+
raise HyperbrowserError(
26+
"Pass either a boolean as the second argument or persist_changes=bool, not both."
27+
)
28+
on_deprecated_bool_usage()
29+
return UpdateSessionProfileParams(persist_changes=params)
30+
if params is None:
31+
if persist_changes is None:
32+
raise HyperbrowserError(
33+
"update_profile_params() requires either UpdateSessionProfileParams or persist_changes=bool."
34+
)
35+
on_deprecated_bool_usage()
36+
return UpdateSessionProfileParams(persist_changes=persist_changes)
37+
raise HyperbrowserError(
38+
"update_profile_params() requires either UpdateSessionProfileParams or a boolean persist_changes."
39+
)

hyperbrowser/client/managers/sync_manager/session.py

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
serialize_model_dump_to_dict,
88
serialize_optional_model_dump_to_dict,
99
)
10+
from ..session_profile_update_utils import resolve_update_profile_params
1011
from ..session_upload_utils import normalize_upload_file_input
1112
from ..session_utils import (
1213
parse_session_recordings_response_data,
@@ -217,36 +218,11 @@ def update_profile_params(
217218
*,
218219
persist_changes: Optional[bool] = None,
219220
) -> BasicResponse:
220-
params_obj: UpdateSessionProfileParams
221-
222-
if type(params) is UpdateSessionProfileParams:
223-
if persist_changes is not None:
224-
raise HyperbrowserError(
225-
"Pass either UpdateSessionProfileParams as the second argument or persist_changes=bool, not both."
226-
)
227-
params_obj = params
228-
elif isinstance(params, UpdateSessionProfileParams):
229-
raise HyperbrowserError(
230-
"update_profile_params() requires a plain UpdateSessionProfileParams object."
231-
)
232-
elif isinstance(params, bool):
233-
if persist_changes is not None:
234-
raise HyperbrowserError(
235-
"Pass either a boolean as the second argument or persist_changes=bool, not both."
236-
)
237-
self._warn_update_profile_params_boolean_deprecated()
238-
params_obj = UpdateSessionProfileParams(persist_changes=params)
239-
elif params is None:
240-
if persist_changes is None:
241-
raise HyperbrowserError(
242-
"update_profile_params() requires either UpdateSessionProfileParams or persist_changes=bool."
243-
)
244-
self._warn_update_profile_params_boolean_deprecated()
245-
params_obj = UpdateSessionProfileParams(persist_changes=persist_changes)
246-
else:
247-
raise HyperbrowserError(
248-
"update_profile_params() requires either UpdateSessionProfileParams or a boolean persist_changes."
249-
)
221+
params_obj = resolve_update_profile_params(
222+
params,
223+
persist_changes=persist_changes,
224+
on_deprecated_bool_usage=self._warn_update_profile_params_boolean_deprecated,
225+
)
250226

251227
serialized_params = serialize_model_dump_to_dict(
252228
params_obj,

tests/test_architecture_marker_usage.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"tests/test_example_sync_async_parity.py",
3434
"tests/test_example_run_instructions.py",
3535
"tests/test_computer_action_endpoint_helper_usage.py",
36+
"tests/test_session_profile_update_helper_usage.py",
3637
"tests/test_session_upload_helper_usage.py",
3738
"tests/test_web_payload_helper_usage.py",
3839
)
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+
SESSION_MANAGER_MODULES = (
9+
"hyperbrowser/client/managers/sync_manager/session.py",
10+
"hyperbrowser/client/managers/async_manager/session.py",
11+
)
12+
13+
14+
def test_session_managers_use_shared_profile_update_param_helper():
15+
for module_path in SESSION_MANAGER_MODULES:
16+
module_text = Path(module_path).read_text(encoding="utf-8")
17+
assert "resolve_update_profile_params(" in module_text
18+
assert "requires a plain UpdateSessionProfileParams object." not in module_text
19+
assert "Pass either UpdateSessionProfileParams as the second argument" not in module_text
20+
assert "Pass either a boolean as the second argument" not in module_text
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import pytest
2+
3+
from hyperbrowser.client.managers.session_profile_update_utils import (
4+
resolve_update_profile_params,
5+
)
6+
from hyperbrowser.exceptions import HyperbrowserError
7+
from hyperbrowser.models.session import UpdateSessionProfileParams
8+
9+
10+
def test_resolve_update_profile_params_returns_plain_params_without_warning():
11+
warnings_triggered = 0
12+
13+
def _on_deprecated_bool_usage() -> None:
14+
nonlocal warnings_triggered
15+
warnings_triggered += 1
16+
17+
params = UpdateSessionProfileParams(persist_changes=True)
18+
result = resolve_update_profile_params(
19+
params,
20+
persist_changes=None,
21+
on_deprecated_bool_usage=_on_deprecated_bool_usage,
22+
)
23+
24+
assert result is params
25+
assert warnings_triggered == 0
26+
27+
28+
def test_resolve_update_profile_params_rejects_plain_params_with_keyword_argument():
29+
with pytest.raises(HyperbrowserError, match="not both"):
30+
resolve_update_profile_params(
31+
UpdateSessionProfileParams(persist_changes=True),
32+
persist_changes=True,
33+
on_deprecated_bool_usage=lambda: None,
34+
)
35+
36+
37+
def test_resolve_update_profile_params_rejects_params_subclass():
38+
class _Params(UpdateSessionProfileParams):
39+
pass
40+
41+
with pytest.raises(HyperbrowserError, match="plain UpdateSessionProfileParams"):
42+
resolve_update_profile_params(
43+
_Params(persist_changes=True),
44+
persist_changes=None,
45+
on_deprecated_bool_usage=lambda: None,
46+
)
47+
48+
49+
def test_resolve_update_profile_params_builds_from_bool_and_warns():
50+
warnings_triggered = 0
51+
52+
def _on_deprecated_bool_usage() -> None:
53+
nonlocal warnings_triggered
54+
warnings_triggered += 1
55+
56+
result = resolve_update_profile_params(
57+
True,
58+
persist_changes=None,
59+
on_deprecated_bool_usage=_on_deprecated_bool_usage,
60+
)
61+
62+
assert result.persist_changes is True
63+
assert warnings_triggered == 1
64+
65+
66+
def test_resolve_update_profile_params_builds_from_keyword_bool_and_warns():
67+
warnings_triggered = 0
68+
69+
def _on_deprecated_bool_usage() -> None:
70+
nonlocal warnings_triggered
71+
warnings_triggered += 1
72+
73+
result = resolve_update_profile_params(
74+
None,
75+
persist_changes=False,
76+
on_deprecated_bool_usage=_on_deprecated_bool_usage,
77+
)
78+
79+
assert result.persist_changes is False
80+
assert warnings_triggered == 1
81+
82+
83+
def test_resolve_update_profile_params_requires_argument_or_keyword():
84+
with pytest.raises(HyperbrowserError, match="requires either"):
85+
resolve_update_profile_params(
86+
None,
87+
persist_changes=None,
88+
on_deprecated_bool_usage=lambda: None,
89+
)
90+
91+
92+
def test_resolve_update_profile_params_rejects_unexpected_param_value():
93+
with pytest.raises(HyperbrowserError, match="requires either"):
94+
resolve_update_profile_params( # type: ignore[arg-type]
95+
"true",
96+
persist_changes=None,
97+
on_deprecated_bool_usage=lambda: None,
98+
)

0 commit comments

Comments
 (0)