Am Samstag, den 19.06.2010, 08:33 +0200 schrieb Enrico Zini: > ...in this case we still lose the .close() method in case > wsgi.file_wrapper is not present in the environment.
True. I simplified your wrapper a bit but hope it still catches all eventualities. See b294b57793b716346c18aaed9effaf465d1c22fd or the attached patch. -- Mit freundlichen Grüßen Marcel Hellkamp
>From b294b57793b716346c18aaed9effaf465d1c22fd Mon Sep 17 00:00:00 2001 From: Marcel Hellkamp <m...@gsites.de> Date: Sat, 19 Jun 2010 14:41:20 +0200 Subject: [PATCH] fix: A fallback for 'wsgi.file_wrapper' MUST have a close() method that invokes the original file-like object's close() method. Thanks to Enrico Zini. --- bottle.py | 21 ++++++++++++++++++--- 1 files changed, 18 insertions(+), 3 deletions(-) diff --git a/bottle.py b/bottle.py index e968bdd..197871f 100755 --- a/bottle.py +++ b/bottle.py @@ -506,10 +506,12 @@ class Bottle(object): out.apply(response) return self._cast(out.output, request, response) - # File-like objects. Wrap or transfer in chunks that fit into memory. + # File-like objects. if hasattr(out, 'read'): - return request.environ.get('wsgi.file_wrapper', - lambda x: iter(lambda: x.read(1024*64), tob('')))(out) + if 'wsgi.file_wrapper' in request.environ: + return request.environ['wsgi.file_wrapper'](out) + elif hasattr(out, 'close') or not hasattr(out, '__iter__'): + return WSGIFileWrapper(out) # Handle Iterables. We peek into them to detect their inner type. try: @@ -944,6 +946,19 @@ class AppStack(list): self.append(value) return value +class WSGIFileWrapper(object): + + def __init__(self, fp, buffer_size=1024*64): + self.fp, self.buffer_size = fp, buffer_size + for attr in ('fileno', 'close', 'read', 'readlines'): + if hasattr(fp, attr): setattr(self, attr, getattr(fp, attr)) + + def __iter__(self): + read, buff = self.fp.read, self.buffer_size + while True: + part = read(buff) + if not part: break + yield part -- 1.7.0.4