On Nov 8, 2007, at 1:04 PM, Mike Orr wrote:
I'm all for fail-safe solutions with implementations that users can
understand and verify they're correct.  The @generator looks like the
best compromise.  The _buffet is also straightforward though ugly.

What would the overhead be of creating a context object for all
requests?  That would avoid the ugly decorator.  There's no reason we
can't require users to call 'self.render' instead of 'render' if it
streamlines the implementation and fixes a design bug.

The first two solutions are the least desirable because if even the
Pylons developers can't be sure they'll work in all cases, they're too
fragile.

I've made some changes in the current pylons-dev trunk to address issues one is likely to encounter when running in an async environment, which also addresses the generator issue. They both need to be able to get references to the objects currently in pylons SOP's, but without using something as global as a thread-local (or in the generators case, globals that were already cleaned up).

The code I added puts references to the c, request, and response global objects, in the environ. The request is slightly delicate, because request holds a copy of environ... which then holds a reference to request. Python has no problem collecting circular references, but they're cleaned up quite a bit slower than when they're non-circular, so at the end of the WSGI PylonsApp, it deletes the environ reference to the request object.

The code add's _py_c, _py_request, and _py_response to the controller instance, which are references to the same objects the SOP's proxy to. This way someone running in twisted or some other async based server can still use Pylons and just avoid any of the pylons SOP's. It's a little more work, but no more work any any other system that works under async.

Since the controller is holding references to these objects, its also pretty easy to add a special render method to the controller, that includes references to the same objects the SOP's reference, when it makes the render call. This way you could just use self.render('/some/ template.html') inside a generator, with no worries.

Or as Phil pointed out:

@generator # assumes the method is a generator, and creates a context object for it to use
     def yieldstuff(self, pylons, id):
pylons.session['stuff'] = get_stuff(id, pylons.request.POST.get ('value'))
         yield pylons.render('/a.mako')

         pylons.c.name = None
         yield pylons.render('/b.mako')
         yield 'more stuff'

Would all just work. I'm uncertain if I'd want it all to be attached to another pylons object, I'd prefer having to ask for the ones you need, like so:

@generator # assumes the method is a generator, and creates a context object for it to use
     def yieldstuff(self, c, session, request, render, id):
        session['stuff'] = get_stuff(id, request.POST.get('value'))
         yield render('/a.mako')

         c.name = None
         yield render('/b.mako')
         yield 'more stuff'

If that method doesn't need one of the SOP's locally for a generator, you just don't ask for it.

Any preferences on which one we should use?

Cons of each approach:
- pylons object with the other main vars attached:
We have to instantiate yet another object per request. It can also confuse a user because there's the global pylons package name, and the method local pylons object which is totally different.

- attach each one to self:
We get in the way of anyone wanting to use 'request', 'response', 'session', or 'c' as an action name.

- users asks for them in function args
We get in the way of anyone wanting to use request, response, session, or c as a routes dict variable

I'm leaning towards the first one so far, despite the possible user confusion about scoping of the pylons namespace, just because it doesn't possibly conflict with action or route names.

Cheers,
Ben

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to