Fixed middleware example not handling 'close' correctly. Fixed an
erroneous statement re: calling 'write()' with empty strings. Moved "Multiple Invocations" note into overview, and moved "callable" definition to overview's preface.
This commit is contained in:
parent
3f6ca60005
commit
3fd244d830
92
pep-0333.txt
92
pep-0333.txt
|
@ -132,6 +132,15 @@ application to their containing server, and as a server to a
|
|||
contained application, and can be used to provide extended APIs,
|
||||
content transformation, navigation, and other useful functions.
|
||||
|
||||
Throughout this specification, we will use the term "a callable" to
|
||||
mean "a function, method, class, or an instance with a ``__call__``
|
||||
method". It is up to the server, gateway, or application implementing
|
||||
the callable to choose the appropriate implementation technique for
|
||||
their needs. Conversely, a server, gateway, or application that is
|
||||
invoking a callable **must not** have any dependency on what kind of
|
||||
callable was provided to it. Callables are only to be called, not
|
||||
introspected upon.
|
||||
|
||||
|
||||
The Application/Framework Side
|
||||
------------------------------
|
||||
|
@ -140,7 +149,9 @@ The application object is simply a callable object that accepts
|
|||
two arguments. The term "object" should not be misconstrued as
|
||||
requiring an actual object instance: a function, method, class,
|
||||
or instance with a ``__call__`` method are all acceptable for
|
||||
use as an application object.
|
||||
use as an application object. Application objects must be able
|
||||
to be invoked more than once, as virtually all servers/gateways
|
||||
(other than CGI) will make such repeated requests.
|
||||
|
||||
(Note: although we refer to it as an "application" object, this
|
||||
should not be construed to mean that application developers will use
|
||||
|
@ -186,15 +197,6 @@ other is a class::
|
|||
self.start(status, headers)
|
||||
yield "Hello world!\n"
|
||||
|
||||
Throughout this specification, we will use the term "a callable" to
|
||||
mean "a function, method, class, or an instance with a ``__call__``
|
||||
method". It is up to the server, gateway, or application implementing
|
||||
the callable to choose the appropriate implementation technique for
|
||||
their needs. Conversely, a server, gateway, or application that is
|
||||
invoking a callable must *not* have any dependency on what kind of
|
||||
callable was provided to it. Callables are only to be called, not
|
||||
introspected upon.
|
||||
|
||||
|
||||
The Server/Gateway Side
|
||||
-----------------------
|
||||
|
@ -311,30 +313,54 @@ Here is a (tongue-in-cheek) example of a middleware component that
|
|||
converts ``text/plain`` responses to pig latin, using Joe Strout's
|
||||
``piglatin.py``. (Note: a "real" middleware component would
|
||||
probably use a more robust way of checking the content type, and
|
||||
should also check for a content encoding.)
|
||||
should also check for a content encoding. Also, this simple
|
||||
example ignores the possibility that a word might be split across
|
||||
a block boundary.)
|
||||
|
||||
::
|
||||
|
||||
from piglatin import piglatin
|
||||
|
||||
class LatinIter:
|
||||
|
||||
"""Transform iterated output to piglatin, if it's okay to do so
|
||||
|
||||
Note that the "okayness" can change until the application yields
|
||||
its first non-empty string, so 'transform_ok' has to be a mutable
|
||||
truth value."""
|
||||
|
||||
def __init__(self,result,transform_ok):
|
||||
if hasattr(result,'close'):
|
||||
self.close = result.close
|
||||
self._next = iter(result).next
|
||||
self.transform_ok = transform_ok
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
if self.transform_ok:
|
||||
return piglatin(self._next())
|
||||
else:
|
||||
return self._next()
|
||||
|
||||
class Latinator:
|
||||
|
||||
# by default, don't transform output
|
||||
transform = str
|
||||
transform = False
|
||||
|
||||
def __init__(self, application):
|
||||
self.application = application
|
||||
|
||||
def __call__(environ, start_response):
|
||||
|
||||
def write_latin(data):
|
||||
self.write(self.transform(data))
|
||||
|
||||
|
||||
transform_ok = []
|
||||
|
||||
def start_latin(status,headers,exc_info=None):
|
||||
|
||||
for name,value in headers:
|
||||
if name.lower()=='content-type' and value=='text/plain':
|
||||
self.transform = piglatin
|
||||
transform_ok.append(True)
|
||||
# Strip content-length if present, else it'll be wrong
|
||||
headers = [(name,value)
|
||||
for name,value in headers
|
||||
|
@ -342,11 +368,17 @@ should also check for a content encoding.)
|
|||
]
|
||||
break
|
||||
|
||||
self.write = start_response(status,headers,exc_info)
|
||||
return write_latin
|
||||
write = start_response(status,headers,exc_info)
|
||||
|
||||
if transform_ok:
|
||||
def write_latin(data):
|
||||
write(piglatin(data))
|
||||
return write_latin
|
||||
else:
|
||||
return write
|
||||
|
||||
return LatinIter(self.application(environ,start_latin),transform_ok)
|
||||
|
||||
for data in self.application(environ,start_latin):
|
||||
yield self.transform(data)
|
||||
|
||||
# Run foo_app under a Latinator's control, using the example CGI gateway
|
||||
from foo_app import foo_app
|
||||
|
@ -672,12 +704,11 @@ using them, and raise an error if they are supplied to
|
|||
headers, please see the `Other HTTP Features`_ section below.)
|
||||
|
||||
The ``start_response`` callable **must not** actually transmit the
|
||||
HTTP headers. It must store them until the first ``write`` call that
|
||||
is passed a non-empty string, or until after the first iteration of
|
||||
the application return value that yields a non-empty string. This is
|
||||
to ensure that buffered and asynchronous applications can replace
|
||||
their originally intended output with error output, up until the last
|
||||
possible moment.
|
||||
HTTP headers. It must store them until the first ``write`` call, or
|
||||
until after the first iteration of the application return value that
|
||||
yields a non-empty string. This is to ensure that buffered and
|
||||
asynchronous applications can replace their originally intended output
|
||||
with error output, up until the last possible moment.
|
||||
|
||||
The ``exc_info`` argument, if supplied, must be a Python
|
||||
``sys.exc_info()`` tuple. This argument should be supplied by the
|
||||
|
@ -919,13 +950,6 @@ only the lower 8 bits may be used, for any value referred to in
|
|||
this specification as a "string".
|
||||
|
||||
|
||||
Multiple Invocations
|
||||
--------------------
|
||||
|
||||
Application objects must be able to be invoked more than once, since
|
||||
virtually all servers/gateways will make such requests.
|
||||
|
||||
|
||||
Error Handling
|
||||
--------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue