Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/storage/src/storage3/_async/file_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,10 @@ async def upload_to_signed_url(
return UploadResponse(path=path, Key=data["Key"])

def _make_signed_url(
self, signed_url: str, download_query: dict[str, str]
self, signed_url: Optional[str], download_query: dict[str, str]
) -> SignedUrlResponse:
if signed_url is None:
return {"signedURL": None, "signedUrl": None}
url = URL(signed_url[1:]) # ignore starting slash
signedURL = self._base_url.join(url).extend_query(download_query)
return {"signedURL": str(signedURL), "signedUrl": str(signedURL)}
Expand Down
4 changes: 3 additions & 1 deletion src/storage/src/storage3/_sync/file_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,10 @@ def upload_to_signed_url(
return UploadResponse(path=path, Key=data["Key"])

def _make_signed_url(
self, signed_url: str, download_query: dict[str, str]
self, signed_url: Optional[str], download_query: dict[str, str]
) -> SignedUrlResponse:
if signed_url is None:
return {"signedURL": None, "signedUrl": None}
url = URL(signed_url[1:]) # ignore starting slash
signedURL = self._base_url.join(url).extend_query(download_query)
return {"signedURL": str(signedURL), "signedUrl": str(signedURL)}
Expand Down
10 changes: 5 additions & 5 deletions src/storage/src/storage3/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,15 @@ def __init__(self, path: str, Key: str) -> None:


class SignedUrlResponse(TypedDict):
signedURL: str
signedUrl: str
signedURL: Optional[str]
signedUrl: Optional[str]


class CreateSignedUrlResponse(TypedDict):
error: Optional[str]
path: str
signedURL: str
signedUrl: str
signedURL: Optional[str]
signedUrl: Optional[str]


class SignedUrlJsonResponse(BaseModel, extra="ignore"):
Expand All @@ -170,7 +170,7 @@ class SignedUrlJsonResponse(BaseModel, extra="ignore"):
class SignedUrlsJsonItem(BaseModel, extra="ignore"):
error: Optional[str]
path: str
signedURL: str
signedURL: Optional[str]


SignedUrlsJsonResponse = TypeAdapter(list[SignedUrlsJsonItem])
Expand Down
5 changes: 5 additions & 0 deletions src/storage/tests/_async/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ async def test_client_create_signed_url(

# Test basic signed URL
signed_url = await storage_file_client.create_signed_url(file.bucket_path, 60)
assert signed_url["signedURL"]
async with HttpxClient(timeout=None) as client:
response = await client.get(signed_url["signedURL"])
response.raise_for_status()
Expand All @@ -421,6 +422,7 @@ async def test_client_create_signed_url(
download_signed_url = await storage_file_client.create_signed_url(
file.bucket_path, 60, options={"download": "custom_download.svg"}
)
assert download_signed_url["signedURL"]
async with HttpxClient(timeout=None) as client:
response = await client.get(download_signed_url["signedURL"])

Expand All @@ -441,6 +443,7 @@ async def test_client_create_signed_url(
# assert "height=200" in transform_signed_url["signedURL"]
# assert "resize=cover" in transform_signed_url["signedURL"]
# assert "format=png" in transform_signed_url["signedURL"]
assert transform_signed_url["signedURL"]
async with HttpxClient(timeout=None) as client:
response = await client.get(transform_signed_url["signedURL"])
response.raise_for_status()
Expand All @@ -461,6 +464,7 @@ async def test_client_create_signed_urls(

async with HttpxClient() as client:
for url in signed_urls:
assert url["signedURL"]
response = await client.get(url["signedURL"])
response.raise_for_status()
assert response.content == multi_file[0].file_content
Expand Down Expand Up @@ -734,6 +738,7 @@ async def test_client_create_signed_urls_with_download(

async with HttpxClient() as client:
for i, url in enumerate(signed_urls):
assert url["signedURL"]
response = await client.get(url["signedURL"])
response.raise_for_status()
assert response.content == multi_file[i].file_content
Expand Down
36 changes: 36 additions & 0 deletions src/storage/tests/_sync/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ def test_client_create_signed_url(

# Test basic signed URL
signed_url = storage_file_client.create_signed_url(file.bucket_path, 60)
assert signed_url["signedURL"]
with HttpxClient(timeout=None) as client:
response = client.get(signed_url["signedURL"])
response.raise_for_status()
Expand All @@ -419,6 +420,7 @@ def test_client_create_signed_url(
download_signed_url = storage_file_client.create_signed_url(
file.bucket_path, 60, options={"download": "custom_download.svg"}
)
assert download_signed_url["signedURL"]
with HttpxClient(timeout=None) as client:
response = client.get(download_signed_url["signedURL"])

Expand All @@ -439,6 +441,7 @@ def test_client_create_signed_url(
# assert "height=200" in transform_signed_url["signedURL"]
# assert "resize=cover" in transform_signed_url["signedURL"]
# assert "format=png" in transform_signed_url["signedURL"]
assert transform_signed_url["signedURL"]
with HttpxClient(timeout=None) as client:
response = client.get(transform_signed_url["signedURL"])
response.raise_for_status()
Expand All @@ -459,6 +462,7 @@ def test_client_create_signed_urls(

with HttpxClient() as client:
for url in signed_urls:
assert url["signedURL"]
response = client.get(url["signedURL"])
response.raise_for_status()
assert response.content == multi_file[0].file_content
Expand Down Expand Up @@ -732,6 +736,7 @@ def test_client_create_signed_urls_with_download(

with HttpxClient() as client:
for i, url in enumerate(signed_urls):
assert url["signedURL"]
response = client.get(url["signedURL"])
response.raise_for_status()
assert response.content == multi_file[i].file_content
Expand Down Expand Up @@ -770,3 +775,34 @@ def test_client_list_v2_folder(
assert len(result.folders) == 1
folder = result.folders[0]
assert folder.key == file.bucket_folder


def test_client_list_v2_paginated(
storage_file_client: SyncBucketProxy, file: FileForTesting
) -> None:
"""Ensure we can upload files to a bucket"""
suffixes = ["zz", "bb", "xx", "ww", "cc", "aa", "yy", "oo"]
for suffix in suffixes:
storage_file_client.upload(
file.bucket_path + suffix, file.local_path, {"content-type": file.mime_type}
)

has_next = True
cursor = ""
pages = 0
while has_next:
result = storage_file_client.list_v2(
{
"with_delimiter": True,
"prefix": f"{file.bucket_folder}/",
"limit": 2,
"cursor": cursor,
}
)
has_next = result.hasNext
cursor = result.nextCursor or ""

assert len(result.objects) == 2
assert all(f.name.startswith(file.bucket_path) for f in result.objects)
pages += 1
assert pages == 4
Loading