Skip to content

Commit e20ac43

Browse files
Enforce concrete tool param key types
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent c6c4557 commit e20ac43

2 files changed

Lines changed: 7 additions & 143 deletions

File tree

hyperbrowser/tools/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def _to_param_dict(params: Mapping[str, Any]) -> Dict[str, Any]:
141141
original_error=exc,
142142
) from exc
143143
for key in param_keys:
144-
if isinstance(key, str):
144+
if type(key) is str:
145145
try:
146146
normalized_key = key.strip()
147147
if not isinstance(normalized_key, str):

tests/test_tools_mapping_inputs.py

Lines changed: 6 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -223,20 +223,11 @@ def __getitem__(self, key: str) -> object:
223223

224224

225225
@pytest.mark.parametrize("runner", [_run_scrape_tool_sync, _run_scrape_tool_async])
226-
def test_tool_wrappers_fall_back_for_unreadable_param_value_read_keys(runner):
226+
def test_tool_wrappers_reject_string_subclass_param_keys(runner):
227227
class _BrokenKey(str):
228-
def __new__(cls, value: str):
229-
instance = super().__new__(cls, value)
230-
instance._iteration_count = 0
231-
return instance
228+
pass
232229

233-
def __iter__(self):
234-
self._iteration_count += 1
235-
if self._iteration_count > 1:
236-
raise RuntimeError("cannot iterate param key")
237-
return super().__iter__()
238-
239-
class _BrokenValueMapping(Mapping[str, object]):
230+
class _BrokenKeyMapping(Mapping[str, object]):
240231
def __iter__(self) -> Iterator[str]:
241232
yield _BrokenKey("url")
242233

@@ -245,134 +236,7 @@ def __len__(self) -> int:
245236

246237
def __getitem__(self, key: str) -> object:
247238
_ = key
248-
raise RuntimeError("cannot read value")
249-
250-
with pytest.raises(
251-
HyperbrowserError, match="Failed to read tool param '<unreadable key>'"
252-
) as exc_info:
253-
runner(_BrokenValueMapping())
254-
255-
assert isinstance(exc_info.value.original_error, RuntimeError)
256-
257-
258-
@pytest.mark.parametrize("runner", [_run_scrape_tool_sync, _run_scrape_tool_async])
259-
def test_tool_wrappers_wrap_param_key_strip_failures(runner):
260-
class _BrokenStripKey(str):
261-
def strip(self, chars=None): # type: ignore[override]
262-
_ = chars
263-
raise RuntimeError("tool param key strip exploded")
264-
265-
with pytest.raises(
266-
HyperbrowserError, match="Failed to normalize tool param key"
267-
) as exc_info:
268-
runner({_BrokenStripKey("url"): "https://example.com"})
269-
270-
assert isinstance(exc_info.value.original_error, RuntimeError)
271-
239+
return "https://example.com"
272240

273-
@pytest.mark.parametrize("runner", [_run_scrape_tool_sync, _run_scrape_tool_async])
274-
def test_tool_wrappers_preserve_hyperbrowser_param_key_strip_failures(runner):
275-
class _BrokenStripKey(str):
276-
def strip(self, chars=None): # type: ignore[override]
277-
_ = chars
278-
raise HyperbrowserError("custom tool param key strip failure")
279-
280-
with pytest.raises(
281-
HyperbrowserError, match="custom tool param key strip failure"
282-
) as exc_info:
283-
runner({_BrokenStripKey("url"): "https://example.com"})
284-
285-
assert exc_info.value.original_error is None
286-
287-
288-
@pytest.mark.parametrize("runner", [_run_scrape_tool_sync, _run_scrape_tool_async])
289-
def test_tool_wrappers_wrap_non_string_param_key_strip_results(runner):
290-
class _BrokenStripKey(str):
291-
def strip(self, chars=None): # type: ignore[override]
292-
_ = chars
293-
return object()
294-
295-
with pytest.raises(
296-
HyperbrowserError, match="Failed to normalize tool param key"
297-
) as exc_info:
298-
runner({_BrokenStripKey("url"): "https://example.com"})
299-
300-
assert isinstance(exc_info.value.original_error, TypeError)
301-
302-
303-
@pytest.mark.parametrize("runner", [_run_scrape_tool_sync, _run_scrape_tool_async])
304-
def test_tool_wrappers_wrap_param_key_empty_check_length_failures(runner):
305-
class _BrokenStripKey(str):
306-
class _NormalizedKey(str):
307-
def __len__(self):
308-
raise RuntimeError("tool param key length exploded")
309-
310-
def strip(self, chars=None): # type: ignore[override]
311-
_ = chars
312-
return self._NormalizedKey("url")
313-
314-
with pytest.raises(
315-
HyperbrowserError, match="Failed to normalize tool param key"
316-
) as exc_info:
317-
runner({_BrokenStripKey("url"): "https://example.com"})
318-
319-
assert isinstance(exc_info.value.original_error, RuntimeError)
320-
321-
322-
@pytest.mark.parametrize("runner", [_run_scrape_tool_sync, _run_scrape_tool_async])
323-
def test_tool_wrappers_preserve_hyperbrowser_param_key_empty_check_length_failures(
324-
runner,
325-
):
326-
class _BrokenStripKey(str):
327-
class _NormalizedKey(str):
328-
def __len__(self):
329-
raise HyperbrowserError("custom tool param key length failure")
330-
331-
def strip(self, chars=None): # type: ignore[override]
332-
_ = chars
333-
return self._NormalizedKey("url")
334-
335-
with pytest.raises(
336-
HyperbrowserError, match="custom tool param key length failure"
337-
) as exc_info:
338-
runner({_BrokenStripKey("url"): "https://example.com"})
339-
340-
assert exc_info.value.original_error is None
341-
342-
343-
@pytest.mark.parametrize("runner", [_run_scrape_tool_sync, _run_scrape_tool_async])
344-
def test_tool_wrappers_wrap_param_key_character_validation_failures(runner):
345-
class _BrokenIterKey(str):
346-
def strip(self, chars=None): # type: ignore[override]
347-
_ = chars
348-
return self
349-
350-
def __iter__(self):
351-
raise RuntimeError("tool param key iteration exploded")
352-
353-
with pytest.raises(
354-
HyperbrowserError, match="Failed to validate tool param key characters"
355-
) as exc_info:
356-
runner({_BrokenIterKey("url"): "https://example.com"})
357-
358-
assert isinstance(exc_info.value.original_error, RuntimeError)
359-
360-
361-
@pytest.mark.parametrize("runner", [_run_scrape_tool_sync, _run_scrape_tool_async])
362-
def test_tool_wrappers_preserve_hyperbrowser_param_key_character_validation_failures(
363-
runner,
364-
):
365-
class _BrokenIterKey(str):
366-
def strip(self, chars=None): # type: ignore[override]
367-
_ = chars
368-
return self
369-
370-
def __iter__(self):
371-
raise HyperbrowserError("custom tool param key iteration failure")
372-
373-
with pytest.raises(
374-
HyperbrowserError, match="custom tool param key iteration failure"
375-
) as exc_info:
376-
runner({_BrokenIterKey("url"): "https://example.com"})
377-
378-
assert exc_info.value.original_error is None
241+
with pytest.raises(HyperbrowserError, match="tool params keys must be strings"):
242+
runner(_BrokenKeyMapping())

0 commit comments

Comments
 (0)