Skip to content

Commit 4426f30

Browse files
Share strict list normalization in manager parsing utilities
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent b464ee2 commit 4426f30

4 files changed

Lines changed: 62 additions & 29 deletions

File tree

hyperbrowser/client/managers/extension_utils.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from hyperbrowser.exceptions import HyperbrowserError
66
from hyperbrowser.models.extension import ExtensionResponse
77
from hyperbrowser.type_utils import is_plain_string
8-
from .list_parsing_utils import parse_mapping_list_items
8+
from .list_parsing_utils import parse_mapping_list_items, read_plain_list_items
99

1010
_MAX_DISPLAYED_MISSING_KEYS = 20
1111
_MAX_DISPLAYED_MISSING_KEY_LENGTH = 120
@@ -84,20 +84,14 @@ def parse_extension_list_response_data(response_data: Any) -> List[ExtensionResp
8484
"Failed to read 'extensions' value from response",
8585
original_error=exc,
8686
) from exc
87-
if type(extensions_value) is not list:
88-
raise HyperbrowserError(
87+
extension_items = read_plain_list_items(
88+
extensions_value,
89+
expected_list_error=(
8990
"Expected list in 'extensions' key but got "
9091
f"{_get_type_name(extensions_value)}"
91-
)
92-
try:
93-
extension_items = list(extensions_value)
94-
except HyperbrowserError:
95-
raise
96-
except Exception as exc:
97-
raise HyperbrowserError(
98-
"Failed to iterate 'extensions' list from response",
99-
original_error=exc,
100-
) from exc
92+
),
93+
read_list_error="Failed to iterate 'extensions' list from response",
94+
)
10195
return parse_mapping_list_items(
10296
extension_items,
10397
item_label="extension",

hyperbrowser/client/managers/list_parsing_utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@
66
T = TypeVar("T")
77

88

9+
def read_plain_list_items(
10+
items_value: Any,
11+
*,
12+
expected_list_error: str,
13+
read_list_error: str,
14+
) -> List[Any]:
15+
if type(items_value) is not list:
16+
raise HyperbrowserError(expected_list_error)
17+
try:
18+
return list(items_value)
19+
except HyperbrowserError:
20+
raise
21+
except Exception as exc:
22+
raise HyperbrowserError(read_list_error, original_error=exc) from exc
23+
24+
925
def parse_mapping_list_items(
1026
items: List[Any],
1127
*,

hyperbrowser/client/managers/session_utils.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
from typing import Any, List, Type, TypeVar
22

33
from hyperbrowser.display_utils import format_string_key_for_error
4-
from hyperbrowser.exceptions import HyperbrowserError
54
from hyperbrowser.models.session import SessionRecording
6-
from .list_parsing_utils import parse_mapping_list_items
5+
from .list_parsing_utils import parse_mapping_list_items, read_plain_list_items
76
from .response_utils import parse_response_model
87

98
T = TypeVar("T")
@@ -30,19 +29,11 @@ def parse_session_response_model(
3029
def parse_session_recordings_response_data(
3130
response_data: Any,
3231
) -> List[SessionRecording]:
33-
if type(response_data) is not list:
34-
raise HyperbrowserError(
35-
"Expected session recording response to be a list of objects"
36-
)
37-
try:
38-
recording_items = list(response_data)
39-
except HyperbrowserError:
40-
raise
41-
except Exception as exc:
42-
raise HyperbrowserError(
43-
"Failed to iterate session recording response list",
44-
original_error=exc,
45-
) from exc
32+
recording_items = read_plain_list_items(
33+
response_data,
34+
expected_list_error="Expected session recording response to be a list of objects",
35+
read_list_error="Failed to iterate session recording response list",
36+
)
4637
return parse_mapping_list_items(
4738
recording_items,
4839
item_label="session recording",

tests/test_list_parsing_utils.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
import pytest
55

6-
from hyperbrowser.client.managers.list_parsing_utils import parse_mapping_list_items
6+
from hyperbrowser.client.managers.list_parsing_utils import (
7+
parse_mapping_list_items,
8+
read_plain_list_items,
9+
)
710
from hyperbrowser.exceptions import HyperbrowserError
811

912

@@ -141,3 +144,32 @@ def test_parse_mapping_list_items_wraps_parse_failures():
141144
)
142145

143146
assert isinstance(exc_info.value.original_error, ZeroDivisionError)
147+
148+
149+
def test_read_plain_list_items_returns_list_values():
150+
assert read_plain_list_items(
151+
["a", "b"],
152+
expected_list_error="expected list",
153+
read_list_error="failed list iteration",
154+
) == ["a", "b"]
155+
156+
157+
def test_read_plain_list_items_rejects_non_list_values():
158+
with pytest.raises(HyperbrowserError, match="expected list"):
159+
read_plain_list_items(
160+
("a", "b"),
161+
expected_list_error="expected list",
162+
read_list_error="failed list iteration",
163+
)
164+
165+
166+
def test_read_plain_list_items_rejects_list_subclass_values():
167+
class _ListSubclass(list):
168+
pass
169+
170+
with pytest.raises(HyperbrowserError, match="expected list"):
171+
read_plain_list_items(
172+
_ListSubclass(["a"]), # type: ignore[arg-type]
173+
expected_list_error="expected list",
174+
read_list_error="failed list iteration",
175+
)

0 commit comments

Comments
 (0)