Jim Fulton wrote:
> There are a number of reasons we needed IResult:
> - We want to be able to adapt existing output, especially
>    string output and we needed an interface to adapt to.

I see. I presume this is for the reason you state below, namely to be able to 
the setting of the Content Type, etc. I guess that's valid use case, but it 
seems like a
separate issue from streaming or trickling data. Maybe we should make them 
interfaces: The IOutputHeaders adapter would be responsible for figuring out 
headers on a result object (incl. a string), the IBodyIterator adapter would be
responsible for streaming/trickling.

> - An adapter may need to affect outut headers, so IResult
>    needed to provide header data.

Well, the view, before falling into iteration, could set response headers 

> - We needed iterable data for WSGI.

I don't understand how my example of a generator view fails there. It *does* 
iterable data to the publishing framework. In fact, the generator itself is the 

> There are two interesting use cases that would drive
> applications to pay attention to IResult:
> A. Returning large amounts of data
> B. Dribbling data from the application, for example
>     to provide progress on a long-running application.
> For A, you want to compute that data and then leave
> application code.  You don't want to stay in the
> application, holding application resources, like database
> connections, while the data is being consumed.  In this case,
> you generally want to create a temporary file and return that
> as the IResult body.

Ah, yes, good point. So, while IResult seems to be needed for the decoupling of
application space and server space, I still think the interface itself is too
complicated. Instead of requiring this 'body' attribute which is iterable, 
IResult itself
should be iterable. I propose to change it to:

  class IResult(Interface):

      headers = Attribute('A sequence of tuples of result headers, such as'
                          '"Content-Type" and "Content-Length", etc.')
      def __iter__(self):
          """Provide the body data of the response"""

Or, if we adopt my suggestion of separating headers from body iterators, we'd 
have two

  class IOutputHeaders(IReadMapping):
      """Provide headers for the response output"""

  class IBodyIterator(Interface):
      """Provide the response body in an iterable manner"""

      def __iter__(self):
          """Provide the body data of the response"""

Implementations of IBodyIterator that would create temporary files like you 
suggest could
then easily implement __iter__ by returning iter(file_handle_of_the_tempfile).

> BTW, your implementation also doesn't work because it doesn't
> set the content length.

I don't think setting content length is mandatory. It's definitely nice, though,
especially for the usability of the app.

> Unfortunately, we still aren't addressing use base B above.
> Some more API enhancements will be needed to address that.
> There will need to be some way to signal that the publisher
> should not release applicatuon resources (not call
> publication.endRequest and request.close) until after the data
> has been streamed.  In any case, this needs more thought and
> a proposal before we attack this.

Indeed. Also, I still haven't given up my implementation for case B, but of 
course I'm not
attached to it. My goal is to have a *simple* way of writing views that A) 
stream large
data (I guess the indirection of a temporary file masked by 
IResult/IBodyIterator is
needed here) and B) trickle data to the client.

I would presume for B) we could still also use IResult/IBodyIterator by writing 
like this (assuming my suggestion of making IResult objects iterable from 

  class StreamingView(BrowserView):

      def __iter__(self):
          return self

     def next(self):
         data = self.context.getMoreDataToTrickle()
         if not data:
             raise StopIteration
         return data

This would be sufficiently simple I think, but a simple generator like my 
suggestion or the one below would still be more straight-forward.

> We'll need a way to inspect the output to determine which
> strategy is being used.  An interface seems to be a good
> way to do this.


> I think that either of these use cases is advanced and
> should be handled explcitly.

Sure. So what would be wrong with:

   class TrickleView(BrowserView):
       # tell the publisher that we'll be trickling data the client slowly
       # so that all resources stay available for that period of time

       def __call__(self):
           yield self.context.getDataToTrickle()
           yield self.context.getMoreDataToTrickle()
           yield self.context.getEvenMoreDataToTrickle()

> Yet another use case was to make pluggable the traditional
> implicit determination of output content type and text
> encoding.  The adaptation to IResult allows this to be
> customized.

Like I said, this seems like a separate issue from streaming/trickling data to 
the client.


This message was sent using IMP, the Internet Messaging Program.
Zope3-dev mailing list
Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com

Reply via email to