Commit 19e5a97f authored by Gerhard Weis's avatar Gerhard Weis

Introduce IUnboundStreamIterator to support publishing iterators of unknown length

parent 9d17e061
from zope.interface import Interface from zope.interface import Interface
from zope.interface import implements from zope.interface import implements
class IUnboundStreamIterator(Interface):
"""
An iterator with unknown length that can be published.
"""
def next():
"""
Return a sequence of bytes out of the bytestream, or raise
StopIeration if we've reached the end of the bytestream.
"""
class IStreamIterator(Interface): class IStreamIterator(Interface):
""" """
An iterator that can be published. An iterator with known length that can be published.
IStreamIterators must not read from the object database. IStreamIterators must not read from the object database.
After the application finishes interpreting a request and After the application finishes interpreting a request and
...@@ -15,12 +27,6 @@ class IStreamIterator(Interface): ...@@ -15,12 +27,6 @@ class IStreamIterator(Interface):
but it has a chance of going insane if it happens to be loading but it has a chance of going insane if it happens to be loading
or storing something in the other thread at the same time. """ or storing something in the other thread at the same time. """
def next():
"""
Return a sequence of bytes out of the bytestream, or raise
StopIeration if we've reached the end of the bytestream.
"""
def __len__(): def __len__():
""" """
Return an integer representing the length of the object Return an integer representing the length of the object
......
...@@ -32,7 +32,7 @@ from ZPublisher.Publish import dont_publish_class ...@@ -32,7 +32,7 @@ from ZPublisher.Publish import dont_publish_class
from ZPublisher.Publish import get_module_info from ZPublisher.Publish import get_module_info
from ZPublisher.Publish import missing_name from ZPublisher.Publish import missing_name
from ZPublisher.pubevents import PubStart, PubBeforeCommit, PubAfterTraversal from ZPublisher.pubevents import PubStart, PubBeforeCommit, PubAfterTraversal
from ZPublisher.Iterators import IStreamIterator from ZPublisher.Iterators import IUnboundStreamIterator, IStreamIterator
_NOW = None # overwrite for testing _NOW = None # overwrite for testing
def _now(): def _now():
...@@ -137,10 +137,13 @@ class WSGIResponse(HTTPResponse): ...@@ -137,10 +137,13 @@ class WSGIResponse(HTTPResponse):
body.seek(0) body.seek(0)
self.setHeader('Content-Length', '%d' % length) self.setHeader('Content-Length', '%d' % length)
self.body = body self.body = body
elif IStreamIterator.providedBy(body): elif IUnboundStreamIterator.providedBy(body):
self.body = body self.body = body
self._streaming = 1 self._streaming = 1
HTTPResponse.setBody(self, '', title, is_error) HTTPResponse.setBody(self, '', title, is_error)
elif IStreamIterator.providedBy(body):
self.body = body
HTTPResponse.setBody(self, '', title, is_error)
else: else:
HTTPResponse.setBody(self, body, title, is_error) HTTPResponse.setBody(self, body, title, is_error)
......
...@@ -136,6 +136,28 @@ class WSGIResponseTests(unittest.TestCase): ...@@ -136,6 +136,28 @@ class WSGIResponseTests(unittest.TestCase):
time.gmtime(time.mktime(WHEN))) time.gmtime(time.mktime(WHEN)))
self.assertTrue(('Date', whenstr) in headers) self.assertTrue(('Date', whenstr) in headers)
def test_setBody_IUnboundStreamIterator(self):
from ZPublisher.Iterators import IUnboundStreamIterator
from zope.interface import implements
class test_streamiterator:
implements(IUnboundStreamIterator)
data = "hello"
done = 0
def next(self):
if not self.done:
self.done = 1
return self.data
raise StopIteration
response = self._makeOne()
response.setStatus(200)
body = test_streamiterator()
response.setBody(body)
response.finalize()
self.assertTrue(body is response.body)
def test_setBody_IStreamIterator(self): def test_setBody_IStreamIterator(self):
from ZPublisher.Iterators import IStreamIterator from ZPublisher.Iterators import IStreamIterator
from zope.interface import implements from zope.interface import implements
...@@ -151,6 +173,9 @@ class WSGIResponseTests(unittest.TestCase): ...@@ -151,6 +173,9 @@ class WSGIResponseTests(unittest.TestCase):
return self.data return self.data
raise StopIteration raise StopIteration
def __len__(self):
return len(self.data)
response = self._makeOne() response = self._makeOne()
response.setStatus(200) response.setStatus(200)
body = test_streamiterator() body = test_streamiterator()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment