So I've started taking a look at what it would take to port a large
suite of Pylons 0.9.6 apps to Pyramid. Most of what needs to happen
looks pretty straightforward; we'd need to convert all of the routes
wiring to the new handler / action mechanisms, and make some superficial
changes to the code within the action methods. Maybe a bit painstaking
and repetitive, but not particularly mind-bending.
There's one pattern in use that presents a bigger problem, however.
These apps have a shared set of controller base classes, from which the
actual controller implementations within the apps themselves inherit.
Some of what happens in these controller base classes is just additional
API stuff, fairly easily converted to a parallel set of handler base
classes.
The tricky parts, though, are the cases where these controllers have
overridden the __call__ method to effectively wrap the entire WSGI
invocation to do such handy things as logging, caching, and error
handling. This isn't easy to replicate, because with Pyramid there's no
way to get control of the outer layers of the request processing cycle
like there is with Pylons (see
http://docs.pylonshq.com/pyramid/dev/narr/router.html).
In trying to think this through I've come up w/ a couple of ideas:
- I could write my own set of action decorators that implement the
desired functionality in addition to marking the wrapped functions as
exposed actions. This would essentially be the same thing as stacking
multiple decorators around each of the functions, except that it avoids
having to stack multiple decorators around each of the functions. ;)
- I could override the router itself, to allow me to keep the wrapped
functionality closer to the WSGI level. Pyramid doesn't really provide
any hooks for this, however. It'd be easy enough to change Pyramid to
fetch the router by interface rather than by class, making it possible
to supply an alternate router implementation, but there's a lot of code
in that __call__ method; I'm not terribly fond of copy/pasting large
blocks of code only to add a handful of additional lines to the middle
somewhere.
Does anyone have any other suggestions? Opinions on the suggestions
I've made? Has anybody out there thought about how to handle this
pattern in a Pyramid upgrade?
Thanks!
-r
This is probably not a 100% solution, but have you seen
http://docs.pylonshq.com/pyramid/dev/narr/hooks.html#using-finished-callbacks ?
>
> Thanks!
>
> -r
>
Yeah, I saw both the response and the finished callbacks, and am already
using them for other purposes. But, as you said, they don't handle all
of the cases, especially not those where try: excepts are put around the
entire WSGIController.__call__ invocation.
Right now I'm leaning towards using a custom @action decorator. This
decorator would call a method on the handler that would wrap the view
callable before adding the view callable to the registry. I'll let you
know how it turns out.
-r
I'd probably do it the other way around:
@view_config(...)
@mydecorator(...)
def aview(request):
...
or
class AHandler(object):
def __init__(self, request):
self.request = request
@action(....)
@mydecorator(...)
def aview(self):
Both cases would add the *decorated* function / method to the registry,
which is probably what you want (the @action and @view_config
dectorators just attach attributes to the function / method, they don't
actually wrap the callable when it is called).
- C
>
> -r
>
Yeah, that's essentially what I meant, sorry for being unclear. I'm
thinking a bit more syntactic sugar, though, something along the lines of:
class AHandler(object):
def __init__(self, request):
self.request = request
@classmethod
def _action_wrapper(klass, wrapped):
def action_method_wrapper(self, *args, **kw):
<do stuff>
ret = wrapped(self, *args, **kw)
<do more stuff>
return ret
return action_method_wrapper
@myaction(...)
def aview(self):
<regular view code>
Then the myaction decorator would call AHandler._action_wrapper(aview)
to generate a wrapped view callable, which would then finally be
registered. This is only half-baked; I'm not even sure I can _get_ to
the AHandler class from within the myaction decorator yet, but if I can
then this would let me mirror the existing controller class hierarchy
with a set of handler classes, moving the code from the older __call__
methods to the newer _action_wrapper class methods w/o too much of a
conceptual leap.
does this seem like it would work?
-r