If I’ve got an iterable containing strings, is there a simple way to turn it into a stream? I want to do something like this:
JavaScript
x
8
1
def make_file():
2
yield "hellon"
3
yield "worldn"
4
5
output = tarfile.TarFile(…)
6
stream = iterable_to_stream(make_file())
7
output.addfile(…, stream)
8
Advertisement
Answer
Here’s my streaming iterator an experimental branch of urllib3 supporting streaming chunked request via iterables:
JavaScript
1
35
35
1
class IterStreamer(object):
2
"""
3
File-like streaming iterator.
4
"""
5
def __init__(self, generator):
6
self.generator = generator
7
self.iterator = iter(generator)
8
self.leftover = ''
9
10
def __len__(self):
11
return self.generator.__len__()
12
13
def __iter__(self):
14
return self.iterator
15
16
def next(self):
17
return self.iterator.next()
18
19
def read(self, size):
20
data = self.leftover
21
count = len(self.leftover)
22
23
if count < size:
24
try:
25
while count < size:
26
chunk = self.next()
27
data += chunk
28
count += len(chunk)
29
except StopIteration:
30
pass
31
32
self.leftover = data[size:]
33
34
return data[:size]
35
Source with context: https://github.com/shazow/urllib3/blob/filepost-stream/urllib3/filepost.py#L23
Related unit tests: https://github.com/shazow/urllib3/blob/filepost-stream/test/test_filepost.py#L9
Alas this code hasn’t made it into the stable branch yet as sizeless chunked requests are poorly supported, but it should be a good foundation for what you’re trying to do. See the source link for examples showing how it can be used.