Pylons makes it super easy to return data to a client. You just return a string from your controller method!
class HelloController(BaseController):
def index(self):
return 'Hello World!'
Very nice. However, what if you want to serve up a potentially quite large file to the client? Sure, you could read the file into memory, and then return the entire buffer, but that is not very efficient. If you have a multi-megabyte file, you end up wasting lots of memory.
What you want to do, actually, is read a chunk of the file at a time, and then send that. So instead of reading the entire file into memory and returning it in a single go, you do lots of little chunks.
Simple conceptually. How do you do this in Pylons? Thankfully you can do this with a Python generator. Instead of returning a buffer, you return a generator:
class ImageController(BaseController):
def index(self, id):
''' Stream local image contents to client '''
try:
imgf = open("%s/%s" %(config['image_data_dir'],
os.path.basename(id)), 'r')
except IOError:
abort(404)
def stream_img():
chunk = imgf.read(1024)
while chunk:
yield chunk
chunk = imgf.read(1024)
imgf.close()
return stream_img()
This works quite nicely. Hope that helps!
Niall O'Higgins is an author and software developer. He wrote the O'Reilly book MongoDB and Python. He is the co-founder of BeyondFog, Inc which makes Strider Brilliant Continuous Deployment. Strider is a hosted Continuous Integration & Deployment service for Node.JS and Python.
