Commit f3dafef
fix(cli): report upload progress in bytes transferred (#1171)
* fix(cli): report upload progress in bytes transferred
`fal files upload` sized its progress task in parts, so a 100 MB file - ten
10 MB parts uploaded by ten concurrent workers - had nothing to advance until
those parts all landed at the end. The bar sat near 0% for the whole transfer
and then jumped to done. A full-file MD5 pass ran before the first byte went
out, adding a second phase with no advancement at all.
Progress is now sized in bytes and advanced as each part body is handed to the
transport, and the digest is folded into the reader thread the upload already
runs, so verifying the etag costs no extra read and no silent wait. The small
(non-multipart) branch advances the same way while its request body is written.
`BaseMultipartUpload.upload_file` gains an `on_bytes_uploaded` callback and a
`content_md5` property; `on_part_complete` and existing callers are unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): make upload integrity and retry safety explicit
Three follow-ups to the byte-progress change.
Retry safety no longer rests on the HTTP client rewinding a consumed body.
`_request` takes an optional `files_factory` and rebuilds the payload on every
attempt, so a part that fails and retries resends its bytes by construction
rather than because httpx happens to seek the stream back to zero. The raw
`bytes` body used when no progress callback is supplied is unchanged.
The part count is fixed from the size sampled before the read, so a file that
shrank underneath the reader would upload a prefix and report success. The
reader now counts the bytes it consumed and the upload fails if that does not
match the sampled size. This restores the end-to-end guarantee that was lost
when the digest stopped being computed from an independent pass over the file.
Computing the digest is now opt-in via `compute_md5`. Only the `/data` path
verifies the etag; app file sync was paying for a hash over every uploaded
file and discarding it.
Each of the three is covered by a test that fails when the change is reverted.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): settle the multipart bar on the uploaded size
Part callbacks compute their running total under the tracker lock but are
invoked outside it, so the last callback to arrive is not necessarily the
highest. The multipart branch took whatever the final callback reported, unlike
the small-file branch which already writes the full size at the end, so a
successful upload could leave the bar short of 100%.
Found by an end-to-end sweep against live storage: a backwards delivery is rare
(one in ~255,000 updates) but nothing made the final value correct, and no test
covered it -- the monotonicity tests run at concurrency 1 and the concurrent one
asserts only the maximum, never the last value.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): show a bracketed filename verbatim in the progress bar
A Rich task description is parsed as markup, so any bracketed span that looks
like a tag is dropped from the label: `x[bold]y.bin` rendered as `xy.bin`, and
`x[not a tag]y.bin` as `xy.bin`. Both filenames are legal. Escaping the
basename keeps the label matching what is on disk.
Pre-existing on both progress paths, not introduced by the byte-progress
change. A closing tag is not reachable here -- it needs `/`, which is the path
separator, so os.path.basename removes everything before it -- which means this
mangles the display and cannot raise.
Also corrects the digest comment: the byte-count check catches an edit that
changes the file's length, but an edit that preserves it is not detected, since
the digest is taken from the same bytes that were sent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): satisfy mypy on the per-attempt body factory
`on_progress` is Optional, and narrowing it with `if on_progress is None`
does not carry into the nested `build_files`, since a closure could run after
the name was rebound. Bind the narrowed callback to a non-Optional local that
the closure captures instead.
Caught by the pre-commit mypy hook (v1.3.0, --check-untyped-defs), which I had
not run on the earlier commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>1 parent 504e5a7 commit f3dafef
5 files changed
Lines changed: 694 additions & 62 deletions
File tree
- projects/fal
- src/fal
- tests/unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | 1 | | |
3 | 2 | | |
4 | 3 | | |
| |||
12 | 11 | | |
13 | 12 | | |
14 | 13 | | |
| 14 | + | |
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | 21 | | |
30 | 22 | | |
31 | 23 | | |
| |||
153 | 145 | | |
154 | 146 | | |
155 | 147 | | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
| 148 | + | |
160 | 149 | | |
161 | | - | |
162 | | - | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
163 | 157 | | |
164 | 158 | | |
165 | 159 | | |
| |||
168 | 162 | | |
169 | 163 | | |
170 | 164 | | |
171 | | - | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
172 | 168 | | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
173 | 179 | | |
174 | 180 | | |
175 | 181 | | |
176 | 182 | | |
177 | 183 | | |
178 | 184 | | |
179 | | - | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
180 | 193 | | |
181 | 194 | | |
182 | 195 | | |
| |||
189 | 202 | | |
190 | 203 | | |
191 | 204 | | |
| 205 | + | |
192 | 206 | | |
193 | 207 | | |
194 | 208 | | |
195 | 209 | | |
196 | | - | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
197 | 213 | | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
198 | 218 | | |
199 | 219 | | |
200 | 220 | | |
201 | | - | |
| 221 | + | |
202 | 222 | | |
203 | | - | |
| 223 | + | |
204 | 224 | | |
205 | 225 | | |
206 | 226 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
| 3 | + | |
2 | 4 | | |
3 | 5 | | |
4 | 6 | | |
5 | 7 | | |
6 | 8 | | |
7 | 9 | | |
8 | | - | |
| 10 | + | |
9 | 11 | | |
10 | 12 | | |
11 | 13 | | |
| |||
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
21 | 72 | | |
22 | 73 | | |
23 | 74 | | |
| |||
31 | 82 | | |
32 | 83 | | |
33 | 84 | | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
34 | 95 | | |
35 | 96 | | |
36 | 97 | | |
| |||
65 | 126 | | |
66 | 127 | | |
67 | 128 | | |
| 129 | + | |
68 | 130 | | |
69 | 131 | | |
70 | 132 | | |
71 | 133 | | |
72 | 134 | | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
73 | 139 | | |
74 | 140 | | |
75 | 141 | | |
| |||
139 | 205 | | |
140 | 206 | | |
141 | 207 | | |
142 | | - | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
143 | 213 | | |
144 | 214 | | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
150 | 235 | | |
151 | 236 | | |
152 | 237 | | |
| |||
177 | 262 | | |
178 | 263 | | |
179 | 264 | | |
| 265 | + | |
| 266 | + | |
180 | 267 | | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
181 | 276 | | |
182 | 277 | | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
183 | 284 | | |
184 | 285 | | |
185 | 286 | | |
| |||
191 | 292 | | |
192 | 293 | | |
193 | 294 | | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
194 | 299 | | |
195 | 300 | | |
196 | 301 | | |
| |||
209 | 314 | | |
210 | 315 | | |
211 | 316 | | |
| 317 | + | |
| 318 | + | |
212 | 319 | | |
213 | 320 | | |
214 | 321 | | |
| |||
217 | 324 | | |
218 | 325 | | |
219 | 326 | | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
220 | 332 | | |
221 | 333 | | |
222 | 334 | | |
| |||
243 | 355 | | |
244 | 356 | | |
245 | 357 | | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
246 | 361 | | |
247 | 362 | | |
248 | 363 | | |
| |||
257 | 372 | | |
258 | 373 | | |
259 | 374 | | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
260 | 386 | | |
261 | 387 | | |
262 | 388 | | |
| |||
This file was deleted.
0 commit comments