Gary Godfrey wrote:
> Fun stuff.  BTW, if it didn't come across in my last message, I really
> got a feeling of "drinking the cool-aid" during pycon.  Finally "got"
> paste (and many aspects of TG) that I didn't before.  Some of the
> zelotry will likely wear off soon :-).

Yes, once you "get" it, its amazing where the thoughts start roaming.
:)

> The main issue that I have with library functions is that it's not
> (currently) portable across frameworks.  I can't do:
> from <current running parent framework> import Identity

Sure you can. Library functions are absolutely portable if they're well
encapsulated. The Python Email library works great regardless of
framework, the WebHelpers package spits out HTML in templates
regardless of template/framework choice, etc. Libraries can absolutely
be portable across frameworks.... if they're designed not to rely on
framework specific environment variables that is. ;)

> So I'm thinking of using environ as a proxy.  You can still do calls
> within this scope (just for example):
> environ['Identity'].user_can(permission='edit_people')

Again, is there some reason that won't work as a function? Heck, its
just a function you put in the environ, isn't it? That already means
you can use it as a library. Why does sticking the function in a dict
thats passed around make it any more framework-portable than a library?

When I heard about Identity being created, I asked at the time why not
make it as a combination. That is, middleware, and functions you use in
the framework. The middleware part of it is what you initialize before
your webapp starts, it also sets up a thread-safe global for use by
Identity functions throughout your application. This makes it easier to
use identity functions since you don't need to keep passing environ all
over the place in your application. Functions can just use a
thread-safe (request-local) global to pull config/objects out.

> I sort of like the idea that environ as the primary thread-safe area to
> use.  We need to be _very_ careful about namespace and clutter, but the
> same is true for any namespace.

Sure, though environ is thread-safe mainly because its a dict.
Cluttering environ is no better than cluttering the namespace, but
thread-safe module globals are a good way for some things to function.
Consider with the Identity middleware, if it sets a thread-safe global
as its called, before it calls your app, you would be able to do this
anywhere inside your webapp:

from identity import app_identity
print app_identity.user_can(permission='edit_people')

This could work, because the middleware during its call, initializes
the thread-local global for itself. Then any function that uses
Identity could import the config and get to the functions and active
setup that it needs to. No cluttering of environ, no cluttering of the
namespace, and its framework neutral. Middleware ensures that the
request-local module global is present, library functions can then be
used easily anywhere.

> Cool - I can see a big thing here is documentation.  It's going to be
> very easy to get this thing confused!  I'm also envisioning that the
> docstrings for these routines should have dot embedded in them.  Now,
> how to automagically create a pretty graph which automatically searches
> the source and looks for callbacks and exceptions up the wsgi stack...

Yup, definitely a big thing. Also, having a very handy way to setup the
middleware stack for a webapp is a good idea. In Pylons, the middleware
stack is setup for you, and put in the new projects config data, it
looks like this:
http://pylonshq.com/project/pylonshq/browser/Pylons/trunk/pylons/templates/paster_template/%2Bpackage%2B/config/middleware.py_tmpl

Making TurboGears run with full Paste-compatibility will lead to a
config file along these lines somewhere anyways, it'd be great to have
a format thats fairly generic and is in the same place between
frameworks even. Despite what pieces of middleware is being loaded, we
can then start standardizing on project layouts when possible.

> That's sort of what we have with WSGI, isn't it?  The only difference
> is that the method name and additional parameters are pulled from
> environ['PATH_INFO'] rather than passed in parameters.  I am thinking
> of making a function or two which will make managing this while doing
> RESTful stuff a bit easier.

Yes, that does work to an extent. I should note here, URL generation is
absolutely important at this point. Every single URL, whether referring
to a static or dynamic section, needs to use URL generation to ensure
the app works (as it needs to add SCRIPT_NAME when needed).

Since no one is going to want to hold environ and be passing it all
over the place during the template rendering, etc. its useful to
provide a module request-local access to it.

> Again, still easy to do WSGIish (top of head, no error checking)i:
> def __call__(self, environ, start_response):
>     tgEnviron(environ)    # Make sure environment has things in place
>     # lc path_info has PATH_INFO split on '/' and cleaned up.
>     if not environ['path_info'][0] in ['Login','Logout']:
>         identity.require(environ, identity.in_group('admin'))
>     return self.defaultCall(environ, start_response)     # standard
> Controller __call__

There's a lot to be said for nice request objects. While environ is
pretty easy to work with, having a nice request object to deal with is
even better. Other than that, I think your example looks slick. Does
every controller call tgEnviron then?

> Nope - only the wsgi Server/Gateway side needs to worry about that.
> environ is thread safe - if we hang everything there, then we're safe.

Hopefully my spiel about request-local module globals convinced you? :)

> You're right - each controller is really WSGI middleware.

Mmm, its not really middleware either, as middleware will assume its
between things, it still seems wrong to me to have middleware that
won't work by itself in the middle of some other stack. Consider the
following example:

You have a Blog app, the blog app has a few dozen controllers, one of
them is admin.comments for administrating the comments section as an
admin. How would you be able to use admin.comments in a Finance webapp
stack?

I really don't see how, because your admin.comments controller is
exceptionally dependent on the fact that its part of your Blog app and
is surrounded by other controllers you wrote it with. If it was truly
WSGI middleware, then it'd be pluggable into any stack you'd want to
use it in.

This is what I meant by abusing terminology. However, if you say that
your controllers use a WSGI interface when called, then you *could* put
in a fully independent wsgi middleware/app, or one of your apps
controllers, and it'd work the same either way. This is mainly a
terminology issue, as we seem to be in agreement that using the WSGI
interface is a "good idea". :)

> Again, I think it's completely valid (and necessary) for Applications
> to make assumpions about upstream middleware.  I'm assuming that a TG
> application which is running under a different Server/Gateway would
> have a small piece of middleware which marshalls the enviorn
> appropriately to resemble the normal TG Server environment.

Yup, makes sense. I think it sounds like a great idea, and is very
pluggable indeed. I'd consider using request-local module globals for
things like Identity and some middleware. Paste does this as well, and
its a pretty useful thing so that functions in various locations can
get to request-local data that was setup by middleware.

I think it'd be great to standardize on a few things so that besides
for being able to re-use components of frameworks like middleware, we
can re-use other chunks. To an extent some of the work done during the
sprint went this direction. Given the WSGI stuff you spoke of, I think
there's a few clear things that standardizing on would be great for:

request object - Paste's goes a good distance already, RT's does as
well, CP provides the cpg.request, etc. This could even be a small bit
of middleware that your application puts up front and then the rest of
your app can get to it like how you can get to cpg.request from
anywhere. Also, out of all the frameworks I've used, the request object
seems to differ the least.

middleware config - Having a nice place to setup the middleware stack
for your application is a good idea. I'd propose a config/ directory in
the project, with middleware.py. It's worked out quite well for Pylons
but am open to better ideas as well. I should note that we tried a
single config.py file as well, but setting up routes, middleware
stacks, etc. all in a single file became a real chore.

Hmm, now that I think about it, TG decorators could be quite portable
as well if they could assume there was a standard request object
available, and it was known that the method content was being returned
via the WSGI interface....

Some thoughts anyways. :)

- Ben


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"TurboGears" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/turbogears
-~----------~----~----~----~------~----~------~--~---

Reply via email to