Skip to content

Commit d038975

Browse files
Validate session upload file input shape
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 7d8a31f commit d038975

3 files changed

Lines changed: 50 additions & 4 deletions

File tree

hyperbrowser/client/managers/async_manager/session.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,20 +112,21 @@ async def get_downloads_url(self, id: str) -> GetSessionDownloadsUrlResponse:
112112
async def upload_file(
113113
self, id: str, file_input: Union[str, PathLike[str], IO]
114114
) -> UploadFileResponse:
115-
response = None
116115
if isinstance(file_input, (str, PathLike)):
117116
with open(os.fspath(file_input), "rb") as file_obj:
118117
files = {"file": file_obj}
119118
response = await self._client.transport.post(
120119
self._client._build_url(f"/session/{id}/uploads"),
121120
files=files,
122121
)
123-
else:
122+
elif hasattr(file_input, "read"):
124123
files = {"file": file_input}
125124
response = await self._client.transport.post(
126125
self._client._build_url(f"/session/{id}/uploads"),
127126
files=files,
128127
)
128+
else:
129+
raise TypeError("file_input must be a file path or file-like object")
129130

130131
return UploadFileResponse(**response.data)
131132

hyperbrowser/client/managers/sync_manager/session.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,20 +104,21 @@ def get_downloads_url(self, id: str) -> GetSessionDownloadsUrlResponse:
104104
def upload_file(
105105
self, id: str, file_input: Union[str, PathLike[str], IO]
106106
) -> UploadFileResponse:
107-
response = None
108107
if isinstance(file_input, (str, PathLike)):
109108
with open(os.fspath(file_input), "rb") as file_obj:
110109
files = {"file": file_obj}
111110
response = self._client.transport.post(
112111
self._client._build_url(f"/session/{id}/uploads"),
113112
files=files,
114113
)
115-
else:
114+
elif hasattr(file_input, "read"):
116115
files = {"file": file_input}
117116
response = self._client.transport.post(
118117
self._client._build_url(f"/session/{id}/uploads"),
119118
files=files,
120119
)
120+
else:
121+
raise TypeError("file_input must be a file path or file-like object")
121122

122123
return UploadFileResponse(**response.data)
123124

tests/test_session_upload_file.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import asyncio
2+
import io
23
from pathlib import Path
4+
import pytest
35

46
from hyperbrowser.client.managers.async_manager.session import (
57
SessionManager as AsyncSessionManager,
@@ -93,3 +95,45 @@ async def run():
9395
assert (
9496
transport.received_file is not None and transport.received_file.closed is True
9597
)
98+
99+
100+
def test_sync_session_upload_file_accepts_file_like_object():
101+
transport = _SyncTransport()
102+
manager = SyncSessionManager(_FakeClient(transport))
103+
file_obj = io.BytesIO(b"content")
104+
105+
response = manager.upload_file("session_123", file_obj)
106+
107+
assert response.file_name == "file.txt"
108+
assert transport.received_file is file_obj
109+
110+
111+
def test_async_session_upload_file_accepts_file_like_object():
112+
transport = _AsyncTransport()
113+
manager = AsyncSessionManager(_FakeClient(transport))
114+
file_obj = io.BytesIO(b"content")
115+
116+
async def run():
117+
return await manager.upload_file("session_123", file_obj)
118+
119+
response = asyncio.run(run())
120+
121+
assert response.file_name == "file.txt"
122+
assert transport.received_file is file_obj
123+
124+
125+
def test_sync_session_upload_file_rejects_invalid_input_type():
126+
manager = SyncSessionManager(_FakeClient(_SyncTransport()))
127+
128+
with pytest.raises(TypeError, match="file_input must be a file path"):
129+
manager.upload_file("session_123", 123) # type: ignore[arg-type]
130+
131+
132+
def test_async_session_upload_file_rejects_invalid_input_type():
133+
manager = AsyncSessionManager(_FakeClient(_AsyncTransport()))
134+
135+
async def run():
136+
with pytest.raises(TypeError, match="file_input must be a file path"):
137+
await manager.upload_file("session_123", 123) # type: ignore[arg-type]
138+
139+
asyncio.run(run())

0 commit comments

Comments
 (0)