Controllers and WSGI apps

10 views
Skip to first unread message

Ben Bangert

unread,
Nov 14, 2005, 1:31:51 AM11/14/05
to pylons-...@googlegroups.com
Controllers can now be set to a WSGI app, like so:

#controllers/wsgi.py
from base import *

def myWSGIAppFromSomewhereElse(environ, start_response):
start_response('200 OK', [['Content-type','text/plain']])
yield str(environ['pylons.r'].environ)
yield 'Yup, I work'

WsgiController = myWSGIAppFromSomewhereElse


The following environ variables are added by Pylons:
pylons.r - request object
pylons.m - myghty object
pylons.s - session object
pylons.params - dict of params that method would've recieved
pylons.action - action string
pylons.controller - controller string

Pylons controllers remain unchanged. This should make it easier to
migrate WSGI apps into Pylons, or just wrap them. Everyone good with
this?

Cheers,
Ben

Ian Bicking

unread,
Nov 15, 2005, 4:19:55 PM11/15/05
to pylons-...@googlegroups.com
Ben Bangert wrote:
>
> Controllers can now be set to a WSGI app, like so:
>
> #controllers/wsgi.py
> from base import *
>
> def myWSGIAppFromSomewhereElse(environ, start_response):
> start_response('200 OK', [['Content-type','text/plain']])
> yield str(environ['pylons.r'].environ)
> yield 'Yup, I work'
>
> WsgiController = myWSGIAppFromSomewhereElse
>
>
> The following environ variables are added by Pylons:
> pylons.r - request object
> pylons.m - myghty object
> pylons.s - session object

If these are environmental variables, they are already a little clunky
to get at. Why not use longer names, then?



--
Ian Bicking / ia...@colorstudy.com / http://blog.ianbicking.org

Ben Bangert

unread,
Nov 15, 2005, 5:01:12 PM11/15/05
to pylons-...@googlegroups.com
On Nov 15, 2005, at 1:19 PM, Ian Bicking wrote:

>> The following environ variables are added by Pylons:
>> pylons.r - request object
>> pylons.m - myghty object
>> pylons.s - session object
>
> If these are environmental variables, they are already a little
> clunky to get at. Why not use longer names, then?

Like what? Those are the names used inside Pylons so it seemed like
the ones to put into environ. I prefixed them with pylons to avoid
name conflicts, is that the standard for that?

- Ben

Ian Bicking

unread,
Nov 15, 2005, 5:01:17 PM11/15/05
to pylons-...@googlegroups.com
Yes, the prefix is standard. I'd think "pylons.request",
"pylons.myghty" (or "pylons.template"?) and "pylons.session" would make
sense.

Ben Bangert

unread,
Nov 15, 2005, 6:09:26 PM11/15/05
to pylons-...@googlegroups.com
On Nov 15, 2005, at 2:01 PM, Ian Bicking wrote:

Yes, the prefix is standard.  I'd think "pylons.request", "pylons.myghty" (or "pylons.template"?) and "pylons.session" would make sense.

Yes, thats true. Myghty (inheriting this from Mason) makes a few one-letter names available, which is the scheme I was copying for the environ. If the environ and testing make use of the full-names it makes some sense for consistency to use them everywhere else. At this point it all goes back to the somewhat bizarre Mason convention for these single letter names.

I'm tempted to just attach them to the controller instance (when its Pylons) as the full name as well, and make them available in the Pylons templates with them as well for consistency. Of course, for Myghty to be more 'Pythonic' (that term annoys me the more I see it for some reason), it'd actually make some sense to divvy up the functionality attached to the m object. To further complicate matters, Myghty refers to 'm' as:

"m is known as the "request", which represents the runtime context of the template being executed. Its not the same as the HTTP-specific request object r and is mostly agnostic of HTTP. m includes methods for handling output and writing content, calling other components, as well as other services that a template will usually need."

So I'm not sure calling it 'pylons.myghty' makes sense. Actually, after looking over all this, odd's are if you want to use the 'm' object, you'll either know Myghty, or be looking it up in the Myghty docs, at which point calling it 'm' instead of using some other name will likely help out.

The alternative, is a light layer of functions that utilize these in a more integrated fashion with Routes, ie, to render a different controller its:
m.comp('MODULE:controllername, action='something', id=4)

When it'd be more Route consistent to have something like:
render_comp(controller='name', action='something', id=4)

Then make the library of common render functions available as pylons.myghty or something and for those that need more under the hood access to Myghty, there'd still be pylons.m as well. I rather like the idea of using session everywhere, as scanning code with 's' all over is less than obvious.

- Ben

Ian Bicking

unread,
Nov 15, 2005, 6:15:31 PM11/15/05
to pylons-...@googlegroups.com
Ben Bangert wrote:
> On Nov 15, 2005, at 2:01 PM, Ian Bicking wrote:
>
>> Yes, the prefix is standard. I'd think "pylons.request",
>> "pylons.myghty" (or "pylons.template"?) and "pylons.session" would
>> make sense.
>
>
> Yes, thats true. Myghty (inheriting this from Mason) makes a few
> one-letter names available, which is the scheme I was copying for the
> environ. If the environ and testing make use of the full-names it makes
> some sense for consistency to use them everywhere else. At this point it
> all goes back to the somewhat bizarre Mason convention for these single
> letter names.

Yeah... it is a bit weird. I think req is good enough for request, if
you want it to be unambiguous but also compact. sessions shouldn't be
used so often you need a shortcut. And...

> I'm tempted to just attach them to the controller instance (when its
> Pylons) as the full name as well, and make them available in the Pylons
> templates with them as well for consistency. Of course, for Myghty to be
> more 'Pythonic' (that term annoys me the more I see it for some reason),
> it'd actually make some sense to divvy up the functionality attached to
> the m object. To further complicate matters, Myghty refers to 'm' as:
>
> "/m/ is known as the "request", which represents the runtime context of
> the template being executed. Its not the same as the HTTP-specific
> request object /r/ and is mostly agnostic of HTTP. /m/ includes methods
> for handling output and writing content, calling other components, as
> well as other services that a template will usually need."

... that's just confusing. m is the request, not r? I don't know what
to make of that all. m almost feels like the response. Or... something.

Anyway, as for splitting them up, I don't think it matters that much.
In Wareweb I put the controller, request, and response all together in
the same object. I think it's usually pretty clear, and except for a
few things there's not too much of a problem. The presence of both
incoming and outgoing cookies and headers is a little confusing, I guess.

Ben Bangert

unread,
Nov 15, 2005, 9:11:33 PM11/15/05
to pylons-...@googlegroups.com
On Nov 15, 2005, at 3:15 PM, Ian Bicking wrote:

> Yeah... it is a bit weird. I think req is good enough for request,
> if you want it to be unambiguous but also compact. sessions
> shouldn't be used so often you need a shortcut. And...

Agreed, I'm going to use session for that right now.

> ... that's just confusing. m is the request, not r? I don't know
> what to make of that all. m almost feels like the response. Or...
> something.

It's the 'Myghty Request', in Mason its 'HTML::Mason::Request', and
yes. its confusing as heck. I usually just call it the Myghty object
when I talk to people, calling it the 'request' will no doubt drive
them nutty. 'r' is the WSGI/mod_python request object. 'm' is some
other object which has component calling, sub-request creation, and
some other functionality tacked onto it (redirects, etc).

No clue why its designed that way actually, and the more I examine
it, the less sense it makes. heh

I'm not even sure without trying it, whether 'm' will work the same
should you use it in a WSGI app, though I don't see why it wouldn't.
In the meantime, I'll load up the WSGI vars like this:

pylons.request - obj - Request object
pylons.m - obj - Myghty 'request' object
pylons.session - dict - Session object
pylons.params - dict - Params that would've been passed into the
controller method (these come from Routes mainly)
pylons.action - str - Action from Routes
pylons.controller - str - Controller from Routes

That should give you anything you'd need for migration (or just
having them work side-by-side).

The other issue is having a uniform way to deal with the SCRIPT_NAME/
PATH_INFO when its spawned. I could test for a 'url' param, and load
that into PATH_INFO automatically before calling the script, such that:
m.connect(':controller/*url', action='index')

Would then call your wsgi app controller, and this would work rather
similar in fashion to the URLParser middleware. Or should this step
be taken care of by the WSGI app?

- Ben

James Gardner

unread,
Nov 16, 2005, 9:05:28 AM11/16/05
to pylons-...@googlegroups.com
Ben Bangert wrote:

> Controllers can now be set to a WSGI app, like so:
>
> #controllers/wsgi.py
> from base import *
>
> def myWSGIAppFromSomewhereElse(environ, start_response):
> start_response('200 OK', [['Content-type','text/plain']])
> yield str(environ['pylons.r'].environ)
> yield 'Yup, I work'
>
> WsgiController = myWSGIAppFromSomewhereElse

Perfect!

> In the meantime, I'll load up the WSGI vars like this:
>
> pylons.request - obj - Request object
> pylons.m - obj - Myghty 'request' object
> pylons.session - dict - Session object
> pylons.params - dict - Params that would've been passed into
> the controller method (these come from Routes mainly)
> pylons.action - str - Action from Routes
> pylons.controller - str - Controller from Routes

I strongly prefer what was suggested to start with. Looking at this I
have to think to myself, "is pylons.request the r object?" and then I
think, "because pylons.request is r perhaps pylons.params isn't params?"
so it just becomes more confusing. I can see why you want to give things
sensible names but in this case the names have already been decided for
us and calling them something else seems to me to just confuse the matter.

How about this instead:

myghty.r - obj - Request object
myghty.m - obj - Myghty 'request' object
myghty.s - obj - Session object
pylons.action - str - Action from Routes
pylons.controller - str - Controller from Routes
pylons.params - the params

I prefer this since it is instantly obvious what is what. If we want to
we can then set things like pylons.session which can be the same object
as myghty.s so that users need only worry about things named pylons.*
but can access myghty.m and myghty.r if they like.

In fact at the moment what we seem to be doing is finding a happy medium
between exposing the Myghty API and creating a new Pylons one. How about
we agree to stop trying to integrate Myghty variables and state that
users will always do something through a pylons API which exposes the
Myghty one?

If we agree this we can change Pylons actions to this:

def action(self, pylons, ...):
...

instead of r, m etc. Users just learn to always add a pylons variable
after self. Conceptually going from class method to Pylons controller
method it isn't too different from learning to add a self variable going
from function to method.

This pylons object would provide all the Myghty functions through
pylons.myghty. We can then create methods like the
render_comp(controller='name', action='something', id=4) as
pylons.render.comp() so that the only object the user needs to worry
about anywhere in their application is the pylons object.

Another advantage of encapsulating all the functionality in one object
is that it would be much easier to use Cheetah or some other templating
language. You'd just pass the Pylons object in and a large part of the
functionality would still be available.

The more I think about this the more I like it. A lot of the Pylons
functions would map straight onto their Myghty counterparts so there
wouldn't be a lot of programming, just a lot of thinking about how best
to design the overall API.

James



Ben Bangert

unread,
Nov 16, 2005, 7:32:46 PM11/16/05
to pylons-...@googlegroups.com
On Nov 16, 2005, at 6:05 AM, James Gardner wrote:

>> #controllers/wsgi.py
>> from base import *
>> def myWSGIAppFromSomewhereElse(environ, start_response):
>> start_response('200 OK', [['Content-type','text/plain']])
>> yield str(environ['pylons.r'].environ)
>> yield 'Yup, I work'
>> WsgiController = myWSGIAppFromSomewhereElse
>
> Perfect!

Excellent, glad that will work for you. Format for that suggested by
Ian. :)

> I strongly prefer what was suggested to start with. Looking at this
> I have to think to myself, "is pylons.request the r object?" and
> then I think, "because pylons.request is r perhaps pylons.params
> isn't params?" so it just becomes more confusing. I can see why you
> want to give things sensible names but in this case the names have
> already been decided for us and calling them something else seems
> to me to just confuse the matter.

Very true. Which means we can either remap those names into the new
Pylons object API, ie, pylons.session, etc. Or stick with the Myghty
stuff. It's a toss-up, docs make more sense in Myghty if we stick
with that, but the one-letter names are rather odd in Python when a
slightly longer name expresses more.

> How about this instead:
>
> myghty.r - obj - Request object
> myghty.m - obj - Myghty 'request' object
> myghty.s - obj - Session object
> pylons.action - str - Action from Routes
> pylons.controller - str - Controller from Routes
> pylons.params - the params
>
> I prefer this since it is instantly obvious what is what. If we
> want to we can then set things like pylons.session which can be the
> same object as myghty.s so that users need only worry about things
> named pylons.* but can access myghty.m and myghty.r if they like.

Right, that works.
Agreed. Do we have a better name for it than the 'Pylons object'?
This is part of the reason 'm' is called the "Mason/Myghty Request
object", ie, its a new object for the framework thats created each
request... and they couldn't come up with any other name for the
object they attached all the functions to.

If we have our own, should we attach any of the attributes of it to
the controller instance? Ie, should it have a self.session?

Cheers,
Ben

James Gardner

unread,
Nov 17, 2005, 8:04:05 AM11/17/05
to pylons-...@googlegroups.com
[was Controllers and WSGI apps]

How about replacing the whole lot of keys in the WSGI environ dictionary
with just a single 'pylons' key to the pylons object which exposes the
whole API?

> Agreed. Do we have a better name for it than the 'Pylons object'?
> This is part of the reason 'm' is called the "Mason/Myghty Request
> object", ie, its a new object for the framework thats created each
> request... and they couldn't come up with any other name for the
> object they attached all the functions to.

Well, I'd call it the "Web API object" as that is what it is. I
certainly wouldn't mention requests. [In fact if we could think of an
acronym LON or LONS then Pylons would make a lot more sense!] If we
design the web API object really well, other frameworks could implement
it and we would have produced another nice layer of abstraction and
interoperability.

> If we have our own, should we attach any of the attributes of it to
> the controller instance? Ie, should it have a self.session?

I've been thinking about this. If a user wanted to use decorators around
the function methods they would no doubt need access to the pylons
object so the whole Pylons object really needs to be attached to the
controller, session and all, probably as self.pylons, self.p or maybe
self.web? I'll need access to the object for auth stuff for example.
This needn't be a huge overhead though actually because almost all of
the objects are already created anyway, we are just exposing them in a
nice way.

So, the API so far looks like this:

pylons.myghty - the myghty objects r,s,c,ARGS accessed as attributes of
pylons.myghty
pylons.translate - a translate method for internationalisation
pylons.write - same as m.write
pylons.security - auth related functions
pylons.config - configuration from server.conf

If you look in pylons.util are you happy with the way I'm currently
implementing this structure using attributes and the _Attr class? My
view is that it is alright to assign things as attributes if the
developer is assigning them but any user-specifiable strings should go
in dictionaries as the user might overwrite an important part of the
object. So for example, the myghty objects can be accessed as attributes
of pylons.myghty but the user config from server.conf is accessed by
pylons.config.app[...].

We should probably also have pylons.session (which for would, at the
moment, be the same as pylons.myghty.s)

Cheers,

James

Ian Bicking

unread,
Nov 18, 2005, 7:26:11 PM11/18/05
to pylons-...@googlegroups.com
James Gardner wrote:
>
> [was Controllers and WSGI apps]
>
> How about replacing the whole lot of keys in the WSGI environ dictionary
> with just a single 'pylons' key to the pylons object which exposes the
> whole API?

The WSGI spec indicates everything should go in a two-level key, like
pylons.something. pylons.object, perhaps.

I think there's value in separating out the keys if you have a
documented interface that non-Pylons components might use. If it's just
an internal object with no particular interface, putting it all in one
object is probably just as well.

--
Ian Bicking | ia...@colorstudy.com | http://blog.ianbicking.org

Ben Bangert

unread,
Nov 22, 2005, 11:59:51 AM11/22/05
to pylons-...@googlegroups.com
On Nov 17, 2005, at 5:04 AM, James Gardner wrote:

> How about replacing the whole lot of keys in the WSGI environ
> dictionary with just a single 'pylons' key to the pylons object
> which exposes the whole API?

As Ian mentioned, it should probably go in pylons.object or
something. Other than that I don't see a problem with that.

> Well, I'd call it the "Web API object" as that is what it is. I
> certainly wouldn't mention requests. [In fact if we could think of
> an acronym LON or LONS then Pylons would make a lot more sense!] If
> we design the web API object really well, other frameworks could
> implement it and we would have produced another nice layer of
> abstraction and interoperability.

I agree. It would also be a good point to attach the Routes
integrated Controller render function to.

> I've been thinking about this. If a user wanted to use decorators
> around the function methods they would no doubt need access to the
> pylons object so the whole Pylons object really needs to be
> attached to the controller, session and all, probably as
> self.pylons, self.p or maybe self.web? I'll need access to the
> object for auth stuff for example. This needn't be a huge overhead
> though actually because almost all of the objects are already
> created anyway, we are just exposing them in a nice way.

Whichever way would be easiest for the user to get at them. I'm
inclined to go with the shortest, so either self.p or self.web.
Calling it self.pylons inside a Pylons app just seems weird...

We could then expose it in the environ to WSGI apps as pylons.web so
I think that should work.

> So, the API so far looks like this:
> pylons.myghty - the myghty objects r,s,c,ARGS accessed as
> attributes of pylons.myghty

The c variable isn't part of Myghty, its attached to self for
controller variables to be passed around and into templates so it
prolly shouldn't go under pylons.myghty.

> pylons.translate - a translate method for internationalisation
> pylons.write - same as m.write
> pylons.security - auth related functions
> pylons.config - configuration from server.conf
>
> If you look in pylons.util are you happy with the way I'm currently
> implementing this structure using attributes and the _Attr class?
> My view is that it is alright to assign things as attributes if the
> developer is assigning them but any user-specifiable strings should
> go in dictionaries as the user might overwrite an important part of
> the object. So for example, the myghty objects can be accessed as
> attributes of pylons.myghty but the user config from server.conf is
> accessed by pylons.config.app[...].
> We should probably also have pylons.session (which for would, at
> the moment, be the same as pylons.myghty.s)

Yup, that all looks good to me. Should we be passing in the pylons
object as I see you doing now in Internationalization or attaching it
to the controller instance?

Cheers,
Ben
Reply all
Reply to author
Forward
0 new messages