Skip to content

Commit 6d97a66

Browse files
Validate tool wrapper params are mapping inputs
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent a1149cf commit 6d97a66

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

hyperbrowser/tools/__init__.py

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

2626

2727
def _prepare_extract_tool_params(params: Mapping[str, Any]) -> Dict[str, Any]:
28-
normalized_params: Dict[str, Any] = dict(params)
28+
normalized_params = _to_param_dict(params)
2929
schema_value = normalized_params.get("schema")
3030
if isinstance(schema_value, str):
3131
try:
@@ -39,6 +39,8 @@ def _prepare_extract_tool_params(params: Mapping[str, Any]) -> Dict[str, Any]:
3939

4040

4141
def _to_param_dict(params: Mapping[str, Any]) -> Dict[str, Any]:
42+
if not isinstance(params, Mapping):
43+
raise HyperbrowserError("tool params must be a mapping")
4244
return dict(params)
4345

4446

tests/test_tools_mapping_inputs.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
from types import MappingProxyType
22

3+
import pytest
4+
5+
from hyperbrowser.exceptions import HyperbrowserError
36
from hyperbrowser.models.scrape import StartScrapeJobParams
4-
from hyperbrowser.tools import WebsiteScrapeTool
7+
from hyperbrowser.tools import WebsiteExtractTool, WebsiteScrapeTool
58

69

710
class _Response:
@@ -31,3 +34,24 @@ def test_tool_wrappers_accept_mapping_inputs():
3134

3235
assert output == "ok"
3336
assert isinstance(client.scrape.last_params, StartScrapeJobParams)
37+
38+
39+
def test_tool_wrappers_reject_non_mapping_inputs():
40+
client = _Client()
41+
42+
with pytest.raises(HyperbrowserError, match="tool params must be a mapping"):
43+
WebsiteScrapeTool.runnable(client, ["https://example.com"]) # type: ignore[arg-type]
44+
45+
46+
def test_extract_tool_wrapper_rejects_non_mapping_inputs():
47+
class _ExtractManager:
48+
def start_and_wait(self, params):
49+
return type("_Response", (), {"data": {"ok": True}})()
50+
51+
class _ExtractClient:
52+
def __init__(self):
53+
self.extract = _ExtractManager()
54+
55+
client = _ExtractClient()
56+
with pytest.raises(HyperbrowserError, match="tool params must be a mapping"):
57+
WebsiteExtractTool.runnable(client, "bad") # type: ignore[arg-type]

0 commit comments

Comments
 (0)