I have recently been trying to learning about WSGI and moreover, how the web works in regards to Python. So I've been reading through Werkzeug and PEP333 to learn.
However I've run up against a small question, that I think I understand but probably don't, so I would appreciate your steering in the right direction.
PEP333 states:
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. Application objects must be able to be invoked more than once, as virtually all servers/gateways (other than CGI) will make such repeated requests.
The implementation:
class AppClass:
"""Produce the same output, but using a class
(Note: 'AppClass' is the "application" here, so calling it
returns an instance of 'AppClass', which is then the iterable
return value of the "application callable" as required by
the spec.
If we wanted to use *instances* of 'AppClass' as application
objects instead, we would have to implement a '__call__'
method, which would be invoked to execute the application,
and we would need to create an instance for use by the
server or gateway.
"""
def __init__(self, environ, start_response):
self.environ = environ
self.start = start_response
def __iter__(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Hello world!\n"
My question here is just to clarify if I have understood it correctly.
It states that AppClass is the application, and when we call it, it returns an instance of AppClass. But then further down states that 'if we wanted to use instances of AppClass ass application objects instead', is this saying that when the server side of WSGI calls the AppClass object, there is only one instance running?
For example. The server can issue multiple requests (200 OK's) to the Application for more responses, hence why iter is placed into the class. But each request runs through the same singular AppClass instance, each request to the server basically doesn't instantiate more than one instance of the AppClass?
Sorry if this is long winded, and apologies again if I haven't made much sense. I'm trying to improve atm.
Appreciate your inputs as always.
Thanks.
The server technology will call your app
(in this case the class AppClass
, causing an object construction) for each request. This is because each request will have a potentially unique environ
.
The neat thing about this is it doesn't mean your app
has to be a class, I often find it useful to define my wsgi app (or middleware) as a function returning a function:
# I'd strongly suggest using a web framework instead to define your application
def my_application(environ, start_response):
start_response(str('200 OK'), [(str('Content-Type'), str('text/plain'))])
return [b'hello world!\n']
def my_middleware(app):
def middleware_func(environ, start_response):
# do something or call the inner app
return app(environ, start_response)
return middleware_func
# expose `app` for whatever server tech you're using (such as uwsgi)
app = my_application
app = my_middleware(app)
Another common pattern involves defining an object to store some application state which is constructed once:
class MyApplication(object):
def __init__(self):
# potentially some expensive initialization
self.routes = ...
def __call__(self, environ, start_response):
# Called once per request, must call `start_response` and then
# return something iterable -- could even be `return self` if
# this class were to define `__iter__`
...
return [...]
app = MyApplication(...)
As for PEP333, I'd suggest reading PEP3333 instead -- it contains largely the same information, but clarifies the datatypes used throughout.