Wraps a string in a read-only file-like object, but also calls a user callback with the number of bytes read whenever read() is called on the stream. Used for tracking upload progress, for example for a progress bar in a UI application.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import cStringIO as StringIO
class ReadCallbackStream(object):
    """Wraps a string in a read-only file-like object, but also calls
    callback(num_bytes_read) whenever read() is called on the stream. Used for
    tracking upload progress. Idea taken from this StackOverflow answer:
    http://stackoverflow.com/a/5928451/68707
    """
    def __init__(self, data, callback):
        self._len = len(data)
        self._io = StringIO.StringIO(data)
        self._callback = callback
    def __len__(self):
        return self._len
    def read(self, *args):
        chunk = self._io.read(*args)
        if len(chunk) > 0:
            self._callback(len(chunk))
        return chunk
 | 
An example using urllib2:
import json
import urllib2
def callback(num_bytes_read):
    print 'callback:', num_bytes_read, 'bytes read'
data = 'x' * 20000
stream = ReadCallbackStream(data, callback)
request = urllib2.Request('http://httpbin.org/post', stream)
f = urllib2.urlopen(request)
response = json.loads(f.read())
print 'httpbin.org said we POSTed', len(response['data']), 'bytes'
And the output:
callback: 8192 bytes read
callback: 8192 bytes read
callback: 3616 bytes read
httpbin.org said we POSTed 20000 bytes

 Download
Download Copy to clipboard
Copy to clipboard