another question from me, today. Can someone maybe explain the "big
picture" of what happens, when the client/browser makes a request to
the pylons application...?
I mean... first the request goes to the paster-server, right (maybe
through Apache/Lighttpd, first) ? Then paster somehow forwards the
request as WSGI-thingy to pylons, where Routes decodes the request URL?
Then, based on the routes match, a controller is started. Somewhere
along the way, the request parameters are put into request.params? Then
there is request.environ as well. Ideally, the controller returns a
Response-object which goes back up the WSGI-chain, until it arrives at
the browser. In between, there is the c-object, which is somehow
special, but in what way? (apart from the obvious use as "bridge" to
the template/view)
Hmm... sorry, this sounds pretty strange and very much newbie-like, but
I am confused by this. I can grasp some of those internal aspects, but
not how it all plays together.
Cheers, Martin
I gave a presentation at Google as a TechTalk on WSGI, Paste, and
Pylons where I also put up a slide showing a full "stack" and walked
over how the request goes through the process. That might help you
here. I posted a blog entry linking to both the video and the slides
(as the video is highly compressed):
http://groovie.org/articles/2006/09/18/wsgi-paste-pylons-and-all-that
A brief explanation that might also help here, first, its important to
know how your WSGI application is loaded:
1) Your project defines an entry point for setuptools (a package
installation tool). The entry point is a bit of data that can be found
by other packages when they look around for specific points that other
packages have indicated that they support. It is in the setup.py file
in your new project and looks something like this:
[paste.app_factory]
main=${package}:make_app
Where ${package} is your packages name. So in this way, paster serve
knows how to find your projects application.
2) If you take a look in your packages proj/__init__.py file, you'll
see that it imports make_app from your config/middleware.py. make_app
is a function that will return a WSGI application, if you look at
middleware.py, you can see that there's a lot of WSGI middleware that
wraps around your base Pylons application, which is defined near the
top of the function like so:
# Load our default Pylons WSGI app and make g available
app = pylons.wsgiapp.PylonsApp(config)
This base Pylons application is what uses Routes to do a URL lookup,
sets up the special globals (c, session, request), creates the request
object, finds the controller to call, then calls it. That is how the
controllers in your project get called and run. The PylonsApp object is
pretty brief, and I think its pretty easy to understand, so if you're
up for it, here's a direct link to its code:
http://pylonshq.com/project/pylonshq/browser/Pylons/trunk/pylons/
wsgiapp.py#L27
Notice that I split out the bit that handles URL resolving and
dispatching, so if someone is feeling creative and wants to resolve
URL's and call controllers differently, they can just sub-class the
PylonsApp object, and override the dispatch/resolve methods.
3) So, your make_app function creates the WSGI application, and returns
it, which paster serve then uses. Using paste loadapp, or other methods
to load your WSGI application do the same thing, and return a WSGI
application object ready to run.
Now, onto how the request is handled, though I think I inadvertently
answered some of that in describing how the app is loaded...
1) paster handles the HTTP request, or maybe its through flup SCGI, or
flup FCGI, or you load your WSGI app directly in some other server.
Regardless, the front bit of code will translate from *something* to
WSGI. They're typically referred to as WSGI gateways. They then hand
off a WSGI spec request to your WSGI application
2) As your base PylonsApp was wrapped in other functions (WSGI
middleware), they all get called going down the chain. One of them
add's a session/cache object, one of them is there purely for
exceptions (to give you the interactive debugger), or it can catch them
and email them if in production mode. One of them (ErrorDocuments)
turns 404's and such into prettier error messages that you can skin.
etc.
3) PylonsApp is finally called, it looks up the URL using Routes, finds
the controller in your project, and imports it.
4) Your controller speaks a WSGI interface, so PylonsApp (after setting
up those special objects), calls your controller just like a WSGI
application.
5) Your controller is called, it uses the Routes information by default
to decide what method it should call. This is totally in your hands
again, and feel free to look at how the controller you inherit from
works:
http://pylonshq.com/project/pylonshq/browser/Pylons/trunk/pylons/
controllers.py#L115
6) Your controllers method (action) is run, it renders a template or
does what it needs to and returns a response.
7) The response goes back up the WSGI stack, if an exception was
thrown, middleware may catch it, etc. But it typically goes straight
back out.
8) The WSGI gateway takes the response and translates it appropriately
for whatever it was a "gateway" to; HTTP, FCGI, SCGI, etc.
Hopefully this answers your question without causing a migraine. :)
Cheers,
Ben
Hopefully this answers your question without causing a migraine. :)
Thank you very much for that answer!... and I don't think I got
migraine from reading it yet :-) I am also curious about your
presentation, but that will have to wait until tomorrow.
Cheers, Martin