mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Give a resumed download's progress the whole file's size as its total.
The total was "length + have or size or 0", which is the part file's size when a resumed answer names no length: the bar ran past its end. It is now the expected size, else the server's length plus the part, else unknown. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -262,7 +262,12 @@ def download(url, dest, sha256=None, size=None, progress=None, cancel=None, head
|
||||
status = getattr(r, 'status', 200)
|
||||
if have and status != 206: # the server ignores Range: start over
|
||||
have = 0
|
||||
total = int(r.headers.get('Content-Length') or 0) + have or size or 0
|
||||
# The whole file's size for progress: the expected one, else what the server says is still to come
|
||||
# plus what the part file holds, else unknown (0: progress then gets the bytes so far as the total).
|
||||
# "length + have or size or 0" took the part file's size for the whole when a resumed answer named
|
||||
# no length, and the bar ran past its end.
|
||||
coming = int(r.headers.get('Content-Length') or 0)
|
||||
total = size or (coming + have if coming else 0)
|
||||
with open(part, 'ab' if have else 'wb') as f:
|
||||
done = have
|
||||
while True:
|
||||
|
||||
@@ -657,6 +657,42 @@ class NetTest(Tmp):
|
||||
with self.assertRaises(net.DownloadError):
|
||||
net.download(srv.url + 'missing.bin', self.tmp / 'out' / 'm.bin')
|
||||
|
||||
def test_the_download_total(self):
|
||||
"""progress gets the whole file's size as its total: the expected size, else the length the server names
|
||||
plus what the part file holds, else the bytes so far. A resumed answer without a length gave the part
|
||||
file's size as the total, so the bar passed 100 %."""
|
||||
data = os.urandom(2 * net.CHUNK + 500)
|
||||
have = 1000
|
||||
|
||||
class Answer(io.BytesIO): # what net.request returns: the rest of the file after a Range request
|
||||
status = 206
|
||||
length = None
|
||||
|
||||
def __init__(self, headers):
|
||||
super().__init__(data[have:])
|
||||
self.headers = headers
|
||||
|
||||
def fetch(headers, **kw):
|
||||
dest = self.tmp / 'total' / 'f.bin'
|
||||
shutil.rmtree(dest.parent, ignore_errors=True)
|
||||
dest.parent.mkdir()
|
||||
dest.with_name('f.bin.part').write_bytes(data[:have])
|
||||
seen = []
|
||||
with mock.patch.object(net, 'request', lambda url, h, timeout, version: Answer(headers)):
|
||||
net.download('https://example.invalid/f.bin', dest, progress=lambda d, t: seen.append((d, t)), **kw)
|
||||
self.assertEqual(dest.read_bytes(), data)
|
||||
self.assertEqual(seen[-1][0], len(data))
|
||||
return seen
|
||||
|
||||
for d, t in fetch({}): # no length, no expected size
|
||||
self.assertEqual(t, d) # (the part's 1000 bytes as the total before)
|
||||
for d, t in fetch({'Content-Length': str(len(data) - have)}): # the length of the rest
|
||||
self.assertEqual(t, len(data))
|
||||
for d, t in fetch({}, size=len(data)): # the expected size, whatever the server says
|
||||
self.assertEqual(t, len(data))
|
||||
for d, t in fetch({'Content-Length': '7'}, size=len(data)):
|
||||
self.assertEqual(t, len(data))
|
||||
|
||||
def test_plain_http_redirects_and_oversize(self):
|
||||
with self.assertRaises(net.DownloadError): # refused before any connection
|
||||
net.request('http://example.invalid/f.bin')
|
||||
|
||||
Reference in New Issue
Block a user