Skip to content

Commit 39a4534

Browse files
committed
Use shared response for all computer actions
1 parent 870d717 commit 39a4534

7 files changed

Lines changed: 22 additions & 62 deletions

File tree

‎README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,9 @@ finally:
466466

467467
Existing positional arguments remain unchanged; `keys` is appended and optional.
468468
`scroll()` still requires coordinates; `scroll_at_cursor()` scrolls at the current
469-
pointer. `cursor_position()` returns a dedicated `CursorPositionActionResponse`,
470-
so its coordinates are accessible after checking that `data` exists. The general
471-
action enum and request/response unions include cursor position.
469+
pointer. All actions, including `cursor_position()`, return `ComputerActionResponse`.
470+
Check that `data` is `ComputerActionResponseDataCursorPosition` before accessing
471+
coordinates. The general action enum and request/response unions include cursor position.
472472

473473
## License
474474

‎hyperbrowser/client/managers/async_manager/computer_action.py‎

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from collections.abc import Mapping
2-
from typing import Any, Dict, Union, List, Optional, Type, TypeVar
2+
from typing import Union, List, Optional
33

44
from hyperbrowser.client._request import coerce_request, dump_request
55
from hyperbrowser.models import (
@@ -13,7 +13,6 @@
1313
MoveMouseActionParams,
1414
ScreenshotActionParams,
1515
CursorPositionActionParams,
16-
CursorPositionActionResponse,
1716
ScrollAtCursorActionParams,
1817
ScrollActionParams,
1918
TypeTextActionParams,
@@ -49,10 +48,6 @@
4948
ComputerAction.LIST_WINDOWS.value: ListWindowsActionParams,
5049
}
5150

52-
_ResponseModel = TypeVar(
53-
"_ResponseModel", ComputerActionResponse, CursorPositionActionResponse
54-
)
55-
5651

5752
def _action_param_model(params):
5853
if isinstance(params, ScrollAtCursorActionParams):
@@ -85,14 +80,6 @@ async def _execute_request(
8580
params: Union[ComputerActionParamsDict, ComputerActionParams],
8681
) -> ComputerActionResponse:
8782
payload = dump_request(params, _action_param_model(params), name="params")
88-
return await self._post_request(session, payload, ComputerActionResponse)
89-
90-
async def _post_request(
91-
self,
92-
session: Union[SessionDetail, str],
93-
payload: Dict[str, Any],
94-
response_model: Type[_ResponseModel],
95-
) -> _ResponseModel:
9683
if isinstance(session, str):
9784
session = await self._client.sessions.get(session)
9885

@@ -103,7 +90,7 @@ async def _post_request(
10390
session.computer_action_endpoint,
10491
data=payload,
10592
)
106-
return response_model(**response.data)
93+
return ComputerActionResponse(**response.data)
10794

10895
async def click(
10996
self,
@@ -145,10 +132,9 @@ async def cursor_position(
145132
self,
146133
session: Union[SessionDetail, str],
147134
return_screenshot: bool = False,
148-
) -> CursorPositionActionResponse:
135+
) -> ComputerActionResponse:
149136
params = CursorPositionActionParams(return_screenshot=return_screenshot)
150-
payload = dump_request(params, CursorPositionActionParams, name="params")
151-
return await self._post_request(session, payload, CursorPositionActionResponse)
137+
return await self._execute_request(session, params)
152138

153139
async def press_keys(
154140
self,

‎hyperbrowser/client/managers/sync_manager/computer_action.py‎

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from collections.abc import Mapping
2-
from typing import Any, Dict, Union, List, Optional, Type, TypeVar
2+
from typing import Union, List, Optional
33

44
from hyperbrowser.client._request import coerce_request, dump_request
55
from hyperbrowser.models import (
@@ -13,7 +13,6 @@
1313
MoveMouseActionParams,
1414
ScreenshotActionParams,
1515
CursorPositionActionParams,
16-
CursorPositionActionResponse,
1716
ScrollAtCursorActionParams,
1817
ScrollActionParams,
1918
TypeTextActionParams,
@@ -49,10 +48,6 @@
4948
ComputerAction.LIST_WINDOWS.value: ListWindowsActionParams,
5049
}
5150

52-
_ResponseModel = TypeVar(
53-
"_ResponseModel", ComputerActionResponse, CursorPositionActionResponse
54-
)
55-
5651

5752
def _action_param_model(params):
5853
if isinstance(params, ScrollAtCursorActionParams):
@@ -85,14 +80,6 @@ def _execute_request(
8580
params: Union[ComputerActionParamsDict, ComputerActionParams],
8681
) -> ComputerActionResponse:
8782
payload = dump_request(params, _action_param_model(params), name="params")
88-
return self._post_request(session, payload, ComputerActionResponse)
89-
90-
def _post_request(
91-
self,
92-
session: Union[SessionDetail, str],
93-
payload: Dict[str, Any],
94-
response_model: Type[_ResponseModel],
95-
) -> _ResponseModel:
9683
if isinstance(session, str):
9784
session = self._client.sessions.get(session)
9885

@@ -103,7 +90,7 @@ def _post_request(
10390
session.computer_action_endpoint,
10491
data=payload,
10592
)
106-
return response_model(**response.data)
93+
return ComputerActionResponse(**response.data)
10794

10895
def click(
10996
self,
@@ -145,10 +132,9 @@ def cursor_position(
145132
self,
146133
session: Union[SessionDetail, str],
147134
return_screenshot: bool = False,
148-
) -> CursorPositionActionResponse:
135+
) -> ComputerActionResponse:
149136
params = CursorPositionActionParams(return_screenshot=return_screenshot)
150-
payload = dump_request(params, CursorPositionActionParams, name="params")
151-
return self._post_request(session, payload, CursorPositionActionResponse)
137+
return self._execute_request(session, params)
152138

153139
def press_keys(
154140
self,

‎hyperbrowser/models/__init__.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@
275275
PressKeysActionParams,
276276
ScreenshotActionParams,
277277
CursorPositionActionParams,
278-
CursorPositionActionResponse,
279278
ScrollAtCursorActionParams,
280279
ScrollActionParams,
281280
TypeTextActionParams,
@@ -784,7 +783,6 @@
784783
"PressKeysActionParams",
785784
"ScreenshotActionParams",
786785
"CursorPositionActionParams",
787-
"CursorPositionActionResponse",
788786
"ScrollAtCursorActionParams",
789787
"ScrollActionParams",
790788
"TypeTextActionParams",

‎hyperbrowser/models/computer_action.py‎

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -294,15 +294,3 @@ class ComputerActionResponse(BaseModel):
294294
data: Optional[ComputerActionResponseData] = None
295295
error: Optional[str] = None
296296
message: Optional[str] = None
297-
298-
299-
class CursorPositionActionResponse(BaseModel):
300-
"""Response from reading the desktop cursor position."""
301-
302-
model_config = ConfigDict(populate_by_alias=True)
303-
304-
success: bool
305-
screenshot: Optional[str] = None
306-
data: Optional[ComputerActionResponseDataCursorPosition] = None
307-
error: Optional[str] = None
308-
message: Optional[str] = None

‎tests/test_computer_action_primitives.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
ComputerActionResponseDataCursorPosition,
2525
ComputerActionResponseDataListWindows,
2626
CursorPositionActionParams,
27-
CursorPositionActionResponse,
2827
DragActionParams,
2928
ScrollActionParams,
3029
ScrollAtCursorActionParams,
@@ -70,7 +69,11 @@ def test_cursor_position_helper(manager, by_id):
7069
driver, session, calls = manager
7170
result = run(driver.cursor_position("session-id" if by_id else session, True))
7271
assert result.success
73-
assert isinstance(result, CursorPositionActionResponse)
72+
assert isinstance(result, ComputerActionResponse)
73+
assert (
74+
inspect.signature(driver.cursor_position).return_annotation
75+
is ComputerActionResponse
76+
)
7477
assert isinstance(result.data, ComputerActionResponseDataCursorPosition)
7578
assert (result.data.x, result.data.y) == (123, 456)
7679
assert calls[-1] == (
@@ -211,7 +214,6 @@ def test_new_request_and_response_types_are_public():
211214

212215
assert "CursorPositionActionParams" in models.__all__
213216
assert "CursorPositionActionParams" in types.__all__
214-
assert "CursorPositionActionResponse" in models.__all__
215217
assert "ScrollAtCursorActionParams" in models.__all__
216218
assert "ScrollAtCursorActionParams" in types.__all__
217219
assert ScrollAtCursorActionParams in get_args(ComputerActionParams)
@@ -267,7 +269,7 @@ def test_old_scroll_helper_still_requires_coordinates(manager_class):
267269

268270

269271
def test_cursor_response_preserves_failure_without_coordinates():
270-
response = CursorPositionActionResponse(success=False, error="action failed")
272+
response = ComputerActionResponse(success=False, error="action failed")
271273
assert response.data is None
272274
assert response.error == "action failed"
273275

‎tests/typecheck/valid_requests.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
ComputerActionResponseData,
1616
ComputerActionResponseDataListWindows,
1717
ComputerActionResponseDataCursorPosition,
18-
CursorPositionActionResponse,
18+
ComputerActionResponse,
1919
)
2020
from hyperbrowser.types import ScrollActionParams
2121
from hyperbrowser.tools import WebsiteExtractTool
@@ -397,10 +397,10 @@ def valid_sync_computer_actions(client: Hyperbrowser) -> None:
397397
client.computer_action._execute_request(
398398
"session-id", LegacyScrollAtCursorActionParams(scroll_x=0, scroll_y=1)
399399
)
400-
cursor: CursorPositionActionResponse = client.computer_action.cursor_position(
400+
cursor: ComputerActionResponse = client.computer_action.cursor_position(
401401
"session-id"
402402
)
403-
if cursor.data is not None:
403+
if isinstance(cursor.data, ComputerActionResponseDataCursorPosition):
404404
x: int = cursor.data.x
405405
y: int = cursor.data.y
406406
print(x, y)
@@ -433,10 +433,10 @@ async def valid_async_computer_actions(client: AsyncHyperbrowser) -> None:
433433
await client.computer_action._execute_request(
434434
"session-id", LegacyScrollAtCursorActionParams(scroll_x=0, scroll_y=1)
435435
)
436-
cursor: CursorPositionActionResponse = await client.computer_action.cursor_position(
436+
cursor: ComputerActionResponse = await client.computer_action.cursor_position(
437437
"session-id"
438438
)
439-
if cursor.data is not None:
439+
if isinstance(cursor.data, ComputerActionResponseDataCursorPosition):
440440
x: int = cursor.data.x
441441
y: int = cursor.data.y
442442
print(x, y)

0 commit comments

Comments
 (0)