Skip to content

Commit 46f0249

Browse files
Robert Denhamclaude
andcommitted
Handle server API differences in file response fields
Some FileSender servers (observed on AARNet's instance) return numeric fields as strings and use 'puid' instead of 'uid' as the per-file upload key. Cast size to int before arithmetic and resolve the key field from whichever of uid/puid is present. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3ccff71 commit 46f0249

3 files changed

Lines changed: 15 additions & 7 deletions

File tree

filesender/api.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ def iter_files(paths: Iterable[Path], root: Optional[Path] = None) -> Iterable[T
9999
# If this is a nested file, use the relative path from the root directory as the name
100100
yield str(path.relative_to(root)), path
101101

102+
def _file_key(file_info: response.File) -> str:
103+
key = file_info.get("uid") or file_info.get("puid") # type: ignore[typeddict-item]
104+
if key is None:
105+
raise Exception(f"File response for {file_info['name']!r} has neither 'uid' nor 'puid' field")
106+
return key
107+
102108
class EndpointHandler:
103109
base: str
104110

@@ -292,7 +298,7 @@ async def update_file(
292298
self.http_client.build_request(
293299
"PUT",
294300
self.urls.file(file_info['id']),
295-
params={"key": file_info["uid"]},
301+
params={"key": _file_key(file_info)},
296302
json=body,
297303
)
298304
)
@@ -322,7 +328,7 @@ async def _task_generator(chunk_size: int) -> AsyncIterator[Tuple[response.File,
322328
task_limit=self.concurrent_chunks
323329
)
324330
).stream() as streamer:
325-
async for _ in tqdm(streamer, total=math.ceil(file_info["size"] / self.chunk_size), desc=file_info["name"]): # type: ignore
331+
async for _ in tqdm(streamer, total=math.ceil(int(file_info["size"]) / self.chunk_size), desc=file_info["name"]): # type: ignore
326332
pass
327333

328334
async def _upload_chunk(
@@ -338,7 +344,7 @@ async def _upload_chunk(
338344
self.http_client.build_request(
339345
"PUT",
340346
self.urls.chunk(file_info["id"], offset),
341-
params={"key": file_info["uid"]},
347+
params={"key": _file_key(file_info)},
342348
content=chunk,
343349
headers={
344350
"Content-Type": "application/octet-stream",
@@ -430,7 +436,7 @@ async def download_file(
430436
file_path.parent.mkdir(parents=True, exist_ok=True)
431437
chunk_size = 8192
432438
chunk_size_mb = chunk_size / 1024 / 1024
433-
with tqdm(desc=file_name, unit="MB", total=None if file_size is None else int(file_size / 1024 / 1024)) as progress:
439+
with tqdm(desc=file_name, unit="MB", total=None if file_size is None else int(int(file_size) / 1024 / 1024)) as progress:
434440
async with aiofiles.open(out_dir / file_name, "wb") as fp:
435441
# We can't add the total here, because we don't know it:
436442
# https://github.com/filesender/filesender/issues/1555

filesender/response_types.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from typing import List
2-
from typing_extensions import TypedDict
2+
from typing_extensions import TypedDict, NotRequired
33

44
class File(TypedDict):
55
id: int
66
transfer_id: int
7-
uid: str
7+
uid: NotRequired[str] # older FileSender servers
8+
puid: NotRequired[str] # newer FileSender servers
89
name: str
910
size: int
1011
sha1: str

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ dependencies = [
2525
"cryptography",
2626
"typing_extensions",
2727
"tenacity",
28-
"tqdm"
28+
"tqdm",
29+
"click>=8.1.8",
2930
]
3031

3132
[tool.setuptools.packages.find]

0 commit comments

Comments
 (0)