I am uploading a large file using the Python requests package, and I can’t find any way to give data back about the progress of the upload. I have seen a number of progress meters for downloading a file, but these will not work for a file upload.
The ideal solution would be some sort of callback method such as:
JavaScript
x
4
1
def progress(percent):
2
print percent
3
r = requests.post(URL, files={'f':hugeFileHandle}, callback=progress)
4
Thanks in advance for your help :)
Advertisement
Answer
requests
doesn’t support upload streaming e.g.:
JavaScript
1
30
30
1
import os
2
import sys
3
import requests # pip install requests
4
5
class upload_in_chunks(object):
6
def __init__(self, filename, chunksize=1 << 13):
7
self.filename = filename
8
self.chunksize = chunksize
9
self.totalsize = os.path.getsize(filename)
10
self.readsofar = 0
11
12
def __iter__(self):
13
with open(self.filename, 'rb') as file:
14
while True:
15
data = file.read(self.chunksize)
16
if not data:
17
sys.stderr.write("n")
18
break
19
self.readsofar += len(data)
20
percent = self.readsofar * 1e2 / self.totalsize
21
sys.stderr.write("r{percent:3.0f}%".format(percent=percent))
22
yield data
23
24
def __len__(self):
25
return self.totalsize
26
27
# XXX fails
28
r = requests.post("http://httpbin.org/post",
29
data=upload_in_chunks(__file__, chunksize=10))
30
btw, if you don’t need to report progress; you could use memory-mapped file to upload large file.
To workaround it, you could create a file adaptor similar to the one from urllib2 POST progress monitoring:
JavaScript
1
11
11
1
class IterableToFileAdapter(object):
2
def __init__(self, iterable):
3
self.iterator = iter(iterable)
4
self.length = len(iterable)
5
6
def read(self, size=-1): # TBD: add buffer for `len(data) > size` case
7
return next(self.iterator, b'')
8
9
def __len__(self):
10
return self.length
11
Example
JavaScript
1
7
1
it = upload_in_chunks(__file__, 10)
2
r = requests.post("http://httpbin.org/post", data=IterableToFileAdapter(it))
3
4
# pretty print
5
import json
6
json.dump(r.json, sys.stdout, indent=4, ensure_ascii=False)
7