How to get request object inside decorator?

181 views
Skip to first unread message

Max Avanov

unread,
Jun 19, 2012, 11:57:53 AM6/19/12
to pylons-...@googlegroups.com
I need to perform some manipulations with request object inside a decorator wrapper. How can I access it?

Jonathan Vanasco

unread,
Jun 19, 2012, 4:52:55 PM6/19/12
to pylons-discuss
If you are using class-based views, it's pretty easy...

def decorated( ok=True ):
log.debug("decorated -- decorated()")
def decorator( wrapped ):
log.debug("decorated -- decorated.decorator()")
def wrapper( self, *arg, **kw):
log.debug("decorated -- decorated.decorator.wrapper()")
try:
result = wrapped( self, *arg, **kw )
finally:
pass
return result
return wrapper
return decorator


class CoreHandler(object):
def __init__(self,request):
self.request = request

class MyView(CoreHandler):
@decorated(ok=True)
def login(self):
return render_to_response('/path/to/template')



Alexandre Conrad

unread,
Jun 19, 2012, 6:03:01 PM6/19/12
to pylons-...@googlegroups.com
I am assuming you want to decorate a view.

Here is a simple performance logger to know how long a it took for a view execute. As you can see, you have access to the request object. (not using traversal in this case)

def perflog_view(func):
    def wrapper(request):
        chrono = time.time()
        output = func(request)
        chrono = time.time() - chrono

        logger.debug("View 
%s.%s returned in %d ms", func.__module__, func.__name__, chrono*1000)

        return output
    return wrapper


@perflog_view
def my_view(request):
    # process the request and return some data ...
    return {}


Cheers,
Alex



2012/6/19 Max Avanov <maxim....@gmail.com>

>
> I need to perform some manipulations with request object inside a decorator wrapper. How can I access it?
>
> --
> You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/pylons-discuss/-/Kq-R-mZCuDYJ.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to pylons-discus...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/pylons-discuss?hl=en.




--
Alex | twitter.com/alexconrad

Michael Merickel

unread,
Jun 20, 2012, 1:21:47 AM6/20/12
to pylons-...@googlegroups.com
So the generic (supported) way to write a decorator in pyramid that
will work with any view is to use the decorator argument to add_view
or view_config. This allows your decorator to have a consistent
signature no matter whether the actual view is a method, or a function
that accepts either (context, request) or just (request).

def my_decorator(wrapped):
def _wrapper(context, request):
print("I'm totally decorated, man")
response = wrapped(context, request)
print("You *were* totally decorated, man")
return response
return _wrapper

This allows all of the below view signatures to work.

@view_config(..., decorator=my_decorator)
def my_view(request):
return {}

@view_config(..., decorator=my_decorator)
def my_view2(context, request):
return {}

class FooHandler(object):
def __init__(self, request):
self.request = request

@view_config(..., decorator=my_decorator)
def other_view(self):
return {}

On Tue, Jun 19, 2012 at 10:57 AM, Max Avanov <maxim....@gmail.com> wrote:
> I need to perform some manipulations with request object inside a decorator
> wrapper. How can I access it?
>

Alexandre Conrad

unread,
Jun 20, 2012, 1:28:34 AM6/20/12
to pylons-...@googlegroups.com

Oh, that's good to know! Thanks!

Jonathan Vanasco

unread,
Jun 20, 2012, 10:15:04 AM6/20/12
to pylons-discuss


On Jun 20, 1:28 am, Alexandre Conrad <alexandre.con...@gmail.com>
wrote:
> Oh, that's good to know! Thanks!

Pyramid needs a cheat-sheet that's just a listing of all these random
"generic (supported)" idioms.

Max Avanov

unread,
Jun 20, 2012, 11:01:53 AM6/20/12
to pylons-...@googlegroups.com
Does the decorator argument of view_config support a list of decorators?
> To post to this group, send email to pylons-discuss@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discuss+unsubscribe@googlegroups.com.

Chris McDonough

unread,
Jun 20, 2012, 11:22:16 AM6/20/12
to pylons-...@googlegroups.com
On 06/20/2012 11:01 AM, Max Avanov wrote:
> Does the decorator argument of view_config support a list of decorators?

No, but:

http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/views/chaining_decorators.html
> <https://groups.google.com/d/msg/pylons-discuss/-/Kq-R-mZCuDYJ>.
> > To post to this group, send email to
> pylons-...@googlegroups.com
> <mailto:pylons-...@googlegroups.com>.
> > To unsubscribe from this group, send email to
> > pylons-discus...@googlegroups.com
> <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
> > For more options, visit this group at
> > http://groups.google.com/group/pylons-discuss?hl=en
> <http://groups.google.com/group/pylons-discuss?hl=en>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/8XmyG7RQZpoJ.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.

Max Avanov

unread,
Jun 20, 2012, 11:46:51 AM6/20/12
to pylons-...@googlegroups.com
It seems that pyramid.threadlocal.get_current_request() is the lesser evil.
Is there a rationale why should I prefer this verbose and complicated (semantically unclear) code sample to "strictly prohibited" get_current_request?
>     pylons-discuss@googlegroups.com
>     <mailto:pylons-discuss@googlegroups.com>.
>      > To unsubscribe from this group, send email to
>      > pylons-discuss+unsubscribe@googlegroups.com
>     <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
>      > For more options, visit this group at
>      > http://groups.google.com/group/pylons-discuss?hl=en
>     <http://groups.google.com/group/pylons-discuss?hl=en>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/8XmyG7RQZpoJ.
> To post to this group, send email to pylons-discuss@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discuss+unsubscribe@googlegroups.com.

Chris McDonough

unread,
Jun 20, 2012, 11:49:45 AM6/20/12
to pylons-...@googlegroups.com
On 06/20/2012 11:46 AM, Max Avanov wrote:
> It seems that pyramid.threadlocal.get_current_request() is the lesser evil.
> Is there a rationale why should I prefer this verbose and complicated
> (semantically unclear) code sample to "strictly prohibited"
> get_current_request?

You can do as you like, it's your software.

- C

Max Avanov

unread,
Jun 20, 2012, 11:55:08 AM6/20/12
to pylons-...@googlegroups.com
I wonder why pyramid documentation prefers one solution to another. If some method is objectively better than another, I would like to know it before I make a decision.

Chris McDonough

unread,
Jun 20, 2012, 11:57:34 AM6/20/12
to pylons-...@googlegroups.com
On 06/20/2012 11:55 AM, Max Avanov wrote:
> I wonder why pyramid documentation prefers one solution to another. If
> some method is objectively better than another, I would like to know it
> before I make a decision.

It's discussed in the docs about get_current_registry and threadlocals.
You can read it and believe it, or not (it says something like "makes
testing harder and more fragile"). If you believe it, don't use
threadlocals. If you don't believe it or don't care, use them.

- C

Max Avanov

unread,
Jun 20, 2012, 12:14:33 PM6/20/12
to pylons-...@googlegroups.com
I don't used to blindly believe something just because it was written that way. The docs are not just a collection of essay about web development. It should be explanatory and clear. That is their main purpose.
I came to Pyramid after three years of Pylons-based web development. It wasn't hard to test pylons-based applications. So, why the get_current_request "makes it possible to write code that can be neither easily tested nor scripted"?

Chris McDonough

unread,
Jun 20, 2012, 12:24:30 PM6/20/12
to pylons-...@googlegroups.com
On 06/20/2012 12:14 PM, Max Avanov wrote:
> I don't used to blindly believe something just because it was written
> that way. The docs are not just a collection of essay about web
> development. It should be explanatory and clear. That is their main purpose.
> I came to Pyramid after three years of Pylons-based web development. It
> wasn't hard to test pylons-based applications. So, why the
> get_current_request "makes it possible to write code that can be neither
> easily tested nor scripted"?

Here's a presentation about API design I wrote recently, part of which
discusses why using thread locals are often a bad idea:

https://github.com/mcdonc/apidesign/blob/master/presentation.rst

But I probably test differently than you do, and have different
development practices than you. In particular, I probably treat my
applications more like libraries than you do, and write more unit tests
than functional tests. Thread locals tend to suck when you write actual
unit tests or you need to reuse code outside of the request/response
context.

- C

Max Avanov

unread,
Jun 20, 2012, 12:36:01 PM6/20/12
to pylons-...@googlegroups.com
But why view_config cannot accept a tuple of decorators?

Rob Miller

unread,
Jun 20, 2012, 2:14:14 PM6/20/12
to pylons-...@googlegroups.com, Max Avanov
See
http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/designdefense.html#stacked-object-proxies-are-too-clever-thread-locals-are-a-nuisance

When a request object is provided magically by the framework, then the
unit tests have to create a fake request object and then jump through
whatever hooks the framework requires to make the request available.
When a request object is expected as an argument, you don't have to do
this, you can just create the request object and pass it in to the
function that you're calling.

Even so, as Chris said, it's your software. `get_current_request` is
available. Do what you want. There's no need to get indignant just
because someone has an opinion that contradicts yours, even if your
opinion *is* based on 3 years of Pylons experience.

-r
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/ZmB9gWa-zkMJ.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.

Max Avanov

unread,
Jun 20, 2012, 4:18:11 PM6/20/12
to pylons-...@googlegroups.com, Max Avanov
There is nothing new to me. It is a matter of correct application design. If I have a single entry point, which is used both for production and test environments, it's no matter whether I setup a StackedObjectProxy or just create the request object and pass it in to the function that I'm calling.


> There's no need to get indignant just
because someone has an opinion that contradicts yours

You might wrongly interpret my writing, since English is not my native language. I really appreciate your (all of responded persons) effort to explain the topic. But. This is not the "give me some snippets to paste it in" topic. I'm, also, trying to figure out why the official documentation recommends me to use absolutely messy solution instead of just allowing me to pass a tuple of decorators to view_config or suggesting to use get_current_request.
Assigning multiple decorators to view callable is the common usage pattern. And I wonder why it wasn't implemented at the framework level. Do you really think that the provided example with explicit chained decorators is the best way to get things done?
> To post to this group, send email to pylons-discuss@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discuss+unsubscribe@googlegroups.com.

Chris McDonough

unread,
Jun 20, 2012, 4:42:46 PM6/20/12
to pylons-...@googlegroups.com
On 06/20/2012 04:18 PM, Max Avanov wrote:
> There is nothing new to me. It is a matter of correct application
> design. If I have a single entry point, which is used both for
> production and test environments, it's no matter whether I setup a
> StackedObjectProxy or just create the request object and pass it in to
> the function that I'm calling.
>
> > There's no need to get indignant just
> because someone has an opinion that contradicts yours
>
> You might wrongly interpret my writing, since English is not my native
> language. I really appreciate your (all of responded persons) effort to
> explain the topic. But. This is not the "give me some snippets to paste
> it in" topic. I'm, also, trying to figure out why the official
> documentation recommends me to use absolutely messy solution instead of
> just allowing me to pass a tuple of decorators to view_config or
> suggesting to use get_current_request.

As I revisit this thread from the beginning I'd suggest that these two
things are really not an "or" sort of thing. I don't really know why
you'd even think about using get_current_request at all.

If I understand your question, you're trying to decorate a view
function. Since every view function is already passed the request,
there's no good reason to ever use get_current_request(). This is
because, by definition, you will always have access to the request
argument in a function which decorates a view callable (either as a
"real" decorator or as an decorator= argument to view_config), so there
can't be any reason to use a threadlocal. You might choose to use the
threadlocal anyway within a decorator, because.. well.. I dont know why.
And that'd be OK with me, it's not my code.

In the meantime, I have no idea where multiple decorator functions came
into the picture. I think it's a separate issue. But assuming you need
that, you can get it today using the cookbook chaining recipe provided
at
http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/views/chaining_decorators.html.

If you believe that the view_config decorator= argument should accept a
sequence of decorators, that might be fine. It would just do what the
cookbook recipe does, by chaining them together using something like the
"combine" function described in the recipe. Ideally you would help us
by changing Pyramid to do this in such a way that the feature is
documented and tested.

> Assigning multiple decorators to view callable is the common usage
> pattern. And I wonder why it wasn't implemented at the framework level.
> Do you really think that the provided example with explicit chained
> decorators is the best way to get things done?

It really depends what "things" is. Your original question wasn't very
specific. The chained decorators thing feels a lot like a red herring.

- C



- C
> <https://groups.google.com/d/msg/pylons-discuss/-/ZmB9gWa-zkMJ>.
> > To post to this group, send email to
> pylons-...@googlegroups.com
> <mailto:pylons-...@googlegroups.com>.
> > To unsubscribe from this group, send email to
> > pylons-discus...@googlegroups.com
> <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
> > For more options, visit this group at
> > http://groups.google.com/group/pylons-discuss?hl=en
> <http://groups.google.com/group/pylons-discuss?hl=en>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/MJqKJtB36PcJ.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.

Max Avanov

unread,
Jun 20, 2012, 5:33:21 PM6/20/12
to pylons-...@googlegroups.com
Ok. Here's what I'm asking for:
- I need a way to get request object inside generic decorator of view callable
- View callable is, also, generic. It can be implemented either for traversal or route-based lookup. And it can be either a function or method.
- View callable should provide a clear way to assign multiple decorators, since it should be treated as "just callable object which is associated with the request".

Here's my reasoning:
1. As Michael Merickel has written (I uppercased the key points) - "the GENERIC (SUPPORTED) way to write a decorator in pyramid that
WILL WORK with ANY view is to use the DECORATOR ARGUMENT". Ok. I got it. This makes sense for me.
2. Then I asked whether view_callable supports a list of decorators. This is a reasonable question, since Michael said about "generics". A list of decorators - is a generic. A single decorator - is a specific, right?
3. It has turned out, that view_callable, in fact, doesn't support a generic case of view callable implementation, which may involve multiple decorators assigning.
4. **This point is hard to explain. I'll try to write it very polite, but it may sound arrogant (I don't intend to, though. Sorry if it is).**
Then, Chris gave me the link to a snippet with chained decorators. But! This is the point of our contradiction.
I think that if framework declares support of some generic approaches, it MUST implement it and NOT just provide code snippets in documentation. Otherwise, the documentation should carefully explain why this snippet wasn't included in API, and why it is still a bad idea to use get_current_request as a "generic approach that is worked right out of the box". The current implementation of view_config API could support multiple decorators, since someone had written down this code snippet in the docs. It means, that maintainers knew about this use case, but preferred not to implement generic API.
5. As a result, at this moment, there is no other way to get access to request object inside generic decorator of generic view callable than using get_current_request. Of course, I can use code snippet with chained decorators. But it is not the "generic way" by definition. This is my specific context inside my code base. And other pyramid users wouldn't have the generic way of getting request object inside their decorators.

That's all.
>     pylons-discuss@googlegroups.com
>     <mailto:pylons-discuss@googlegroups.com>.
>      > To unsubscribe from this group, send email to
>      > pylons-discuss+unsubscribe@googlegroups.com
>     <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
>      > For more options, visit this group at
>      > http://groups.google.com/group/pylons-discuss?hl=en
>     <http://groups.google.com/group/pylons-discuss?hl=en>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/MJqKJtB36PcJ.
> To post to this group, send email to pylons-discuss@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discuss+unsubscribe@googlegroups.com.

Chris McDonough

unread,
Jun 20, 2012, 5:56:09 PM6/20/12
to pylons-...@googlegroups.com
No, lack of framework-based multiple decorator support just hasn't been
a real pressing issue for anyone, especially given the linked recipe.
If we're lucky, someone for whom it seems to be a pressing issue can
help provide a patch that integrates the linked recipe into the config
with docs and tests.

> 5. As a result, at this moment, there is no other way to get access to
> request object inside generic decorator of generic view callable than
> using get_current_request. Of course, I can use code snippet with
> chained decorators. But it is not the "generic way" by definition. This
> is my specific context inside my code base. And other pyramid users
> wouldn't have the generic way of getting request object inside their
> decorators.

Any decorator used will be *passed* a request. It has to be passed a
request, because it will need to pass it along to the actual view
callable. That's the definition of a decorator. So I'm lost as to what
you mean by "no other way to get access to request object". You just
can't not have access to the request object in the decorator.

Anyway, I think daddy is just dizzy enough to go to sleep now.

- C

Max Avanov

unread,
Jun 20, 2012, 6:13:53 PM6/20/12
to pylons-...@googlegroups.com
>  So I'm lost as to what
you mean by "no other way to get access to request object"

Because I must
- either to follow the official approach provided by Michael (" a consistent signature no matter whether the actual view is a method, or a function
that accepts either (context, request) or just (request)...") with the consequent @view_config(decorator=...) and the chained code snipped.
- or use the "classic" way:
@decorator1
@decorator2
@decoratorN
@view_config
def func()

For classic way I use the decorator package - http://micheles.googlecode.com/hg/decorator/documentation.html - But the classic way allows me only one generic approach to get the request object - via get_current_request, right?

Chris McDonough

unread,
Jun 20, 2012, 6:39:57 PM6/20/12
to pylons-...@googlegroups.com
On 06/20/2012 06:13 PM, Max Avanov wrote:
> > So I'm lost as to what
> you mean by "no other way to get access to request object"
>
> Because I must
> - either to follow the official approach provided by Michael (" a
> consistent signature no matter whether the actual view is a method, or a
> function
> that accepts either (context, request) or just (request)...") with the
> consequent @view_config(decorator=...) and the chained code snipped.
> - or use the "classic" way:
> @decorator1
> @decorator2
> @decoratorN
> @view_config
> def func()
>
> For classic way I use the decorator package -
> http://micheles.googlecode.com/hg/decorator/documentation.html - But the
> classic way allows me only one generic approach to get the request
> object - via get_current_request, right?

No! View callable functions must accept at least a request argument.
There will never be something this that will work as a view callable:

def func():
...

It just wont work. A view callable must be:

def func(request):
...

An alternate view callable signature optionally accepts "(context,
request)" but if your code doesn't use that signature for any of your
view callables, you won't care. Pyramid view callables can also be
methods of classes, but if your code doesn't use view classes, you won't
care about that either.

If you *do* care about reusing a decorator across all of these view
callable conventions, however, you can use the decorator= argument to
view_config. The point of the decorator= argument to view_config is to
provide genericness by accepting a decorator that can use a single
common call signature for a decorator ("(context, request)"). So you
can use the following decorator:

def adecorator(viewcallable):
def inner(context, request):
print request.url
return viewcallable(context, request)
return inner

.. against this kind of view configuration ...

class AView(object):
def __init__(self, request):
self.request = request

@view_config(decorator=adecorator)
def aview(self):
return Response('OK')

.. or this kind ...

@view_config(decorator=adecorator)
def aview(request):
return Response('OK')

... or this kind ...

@view_config(decorator=adecorator)
def aview(context, request):
return Response('OK')

... or this kind ...

@view_config(decorator=adecorator)
class AView(object):
def __init__(self, request):
self.request = request

def __call__(self):
return Response('OK')

... or this kind ...

class AView(object):
def __init__(self, context, request):
self.context = context
self.request = request

@view_config(decorator=adecorator)
def aview(self):
return Response('OK')

You get the point. The *same decorator* will work against any view
callable you define, even though the place it gets used differs:
against a method of a class, against a class object, against a function
object, and the associated callable may have different arguments. It
will still work in all scenarios.

Since a decorator is just a callable that returns a callable, whether
you use the package you linked to or not to produce one is irrelevant.
Even the "@" syntax is just sugar. Instead of:

@decorator1
@decorator2
def func():
...

it could just be:

def func():
...

func = decorator2(decorator1(func))

If you're decorating functions or methods that you don't know the
argument list for, just make the decorator accept *arg, **kw and pass
those along to the wrapped function from your wrapper function defined
inside the decorator. That will work for any sort of wrapped function,
even those for a view callable.

If you mean you want to create some sort of omniscient decorator that
can be used for both a view callable *and any other kind of function*,
but which in both cases requires a request to.. do something.., then,
yes, you could use get_current_request inside the decorator logic. It'd
be insane to try to define such a decorator, when you could just create
one that expected the decorated function to supply the (context,
request) signature, but you could do it.

If this all boils down to "why dont you support a sequence rather than a
single function as a valid decorator= argument" because you need to mix
and match logic in your decorators, please either submit some code that
makes it so or use the recipe for chained decorators.

- C

Max Avanov

unread,
Jun 21, 2012, 7:29:48 AM6/21/12
to pylons-...@googlegroups.com
> No!  View callable functions must accept at least a request argument.
There will never be something this that will work as a view callable:

This is my typo. I was talking about a regular generic view callable.
I still don't get how to rewrite  these @authenticate_form and @https (as an example) - https://github.com/Pylons/pylons/blob/master/pylons/decorators/secure.py - to be able to do the common:

@view_config()
@https()
@autnenticate_form
def view(request) - or - def view(context, request) - or - def view(self)

without passing it to view_config

Chris McDonough

unread,
Jun 21, 2012, 8:21:24 AM6/21/12
to pylons-...@googlegroups.com
On 06/21/2012 07:29 AM, Max Avanov wrote:
> > No! View callable functions must accept at least a request argument.
> There will never be something this that will work as a view callable:
>
> This is my typo. I was talking about a regular generic view callable.
> I still don't get how to rewrite these @authenticate_form and @https (as
> an example) -
> https://github.com/Pylons/pylons/blob/master/pylons/decorators/secure.py
> - to be able to do the common:
>
> @view_config()
> @https()
> @autnenticate_form
> def view(request) - or - def view(context, request) - or - def view(self)
>
> without passing it to view_config

Why you don't want to pass the decorator to view_config via decorator= I
have no idea, given that dealing with the differences is the entire
purpose of that machinery and the code to support a chain of decorators
is entirely boilerplate.

But assuming you didn't, and assuming this isn't an entirely theoretical
exercise which we're beating to death, you could write a decorator that
assumed *one* signature which also set __module__, and __doc__ and on
the function returned from the decorator:

from functools import wraps

def adecorator(wrapped):
def inner(request):
print request.url
return wrapped(request)
return wraps(wrapped, ('__module__', '__doc__'))(decorator)

@view_config(....)
@adecorator
def view(request):
....

- C
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/fhyzewf5dfkJ.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.

Max Avanov

unread,
Jun 21, 2012, 9:59:03 AM6/21/12
to pylons-...@googlegroups.com
But I want to. I really do. And view_config doesn't allow me to do so.
You should understand me. I don't want to have extra imports in my project.
I want transparent support from the framework. This example makes sense for me:

from pyramid.view import view_config
@view_config(decorator=(decorator1, decorator2, ...))

But this is not:
from pyramid.view import view_config
# Why should I do this for each of my view modules?
from somewhere import chain_decorators

@view_config(decorator=chain_decorators(decorator1, decorator2, ...))
> To post to this group, send email to pylons-discuss@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discuss+unsubscribe@googlegroups.com.

Chris Rossi

unread,
Jun 21, 2012, 10:10:07 AM6/21/12
to pylons-...@googlegroups.com
Don't let the perfect be the enemy of the good.

Chris
>> > To post to this group, send email to pylons-...@googlegroups.com.
>> > To unsubscribe from this group, send email to
>> > pylons-discus...@googlegroups.com.
>> > For more options, visit this group at
>> > http://groups.google.com/group/pylons-discuss?hl=en.
>>
> --
> You received this message because you are subscribed to the Google Groups
> "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J.
>
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.

Chris McDonough

unread,
Jun 21, 2012, 10:14:10 AM6/21/12
to pylons-...@googlegroups.com
On 06/21/2012 09:59 AM, Max Avanov wrote:
> But I want to. I really do. And view_config doesn't allow me to do so.
> You should understand me. I don't want to have extra imports in my project.
> I want transparent support from the framework. This example makes sense
> for me:
>
> from pyramid.view import view_config
> @view_config(decorator=(decorator1, decorator2, ...))
>
> But this is not:
> from pyramid.view import view_config
> # Why should I do this for each of my view modules?
> from somewhere import chain_decorators
>
> @view_config(decorator=chain_decorators(decorator1, decorator2, ...))

I've already noted that if you want to not have to import the
chain_decorators thing from someplace, you should supply a patch to
Pyramid that allows it to handle a sequence of decorators passed to
decorator=. The patch should contain tests and docs. I've actually
noted that three times now, I'm just not sure what else to say about it.
Is it unclear?

In the meantime, you can already get what you want by just using the recipe.

- C


>
>
> <https://groups.google.com/d/msg/pylons-discuss/-/fhyzewf5dfkJ>.
> > To post to this group, send email to
> pylons-...@googlegroups.com
> <mailto:pylons-...@googlegroups.com>.
> > To unsubscribe from this group, send email to
> > pylons-discus...@googlegroups.com
> <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
> > For more options, visit this group at
> > http://groups.google.com/group/pylons-discuss?hl=en
> <http://groups.google.com/group/pylons-discuss?hl=en>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.

Max Avanov

unread,
Jun 21, 2012, 10:18:05 AM6/21/12
to pylons-...@googlegroups.com
What are you talking about? This is not just my stupid ideological behavior. My current project has 30+ different subpackages, each of thes has view-modules. For now, I have to make 30+ extra imports just because.... hmm... I still don't get why I have to.
>> > To post to this group, send email to pylons-discuss@googlegroups.com.
>> > To unsubscribe from this group, send email to
>> > pylons-discuss+unsubscribe@googlegroups.com.
>> > For more options, visit this group at
>> > http://groups.google.com/group/pylons-discuss?hl=en.
>>
> --
> You received this message because you are subscribed to the Google Groups
> "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J.
>
> To post to this group, send email to pylons-discuss@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discuss+unsubscribe@googlegroups.com.

Brian Sutherland

unread,
Jun 21, 2012, 10:19:03 AM6/21/12
to pylons-...@googlegroups.com
On Thu, Jun 21, 2012 at 06:59:03AM -0700, Max Avanov wrote:
> But I want to. I really do. And view_config doesn't allow me to do so.
> You should understand me. I don't want to have extra imports in my project.
> I want transparent support from the framework. This example makes sense for
> me:
>
> from pyramid.view import view_config
> @view_config(decorator=(decorator1, decorator2, ...))
>
> But this is not:
> from pyramid.view import view_config
> # Why should I do this for each of my view modules?
> from somewhere import chain_decorators
>
> @view_config(decorator=chain_decorators(decorator1, decorator2, ...))

Woo-hoo! Looks like this thread just went another time around the racetrack!

Go a few messages back and Chris says:

"lack of framework-based multiple decorator support just hasn't
been a real pressing issue for anyone, especially given the linked
recipe. If we're lucky, someone for whom it seems to be a pressing
issue can help provide a patch that integrates the linked recipe into
the config with docs and tests."

Which looks to me to be exactly what you want above. So, if this is a
pressing issue for you, please "help provide a patch that integrates the
linked recipe into the config with docs and tests."

>
>
> > > To post to this group, send email to pylons-...@googlegroups.com.
> > > To unsubscribe from this group, send email to
> > > pylons-discus...@googlegroups.com.
> > > For more options, visit this group at
> > > http://groups.google.com/group/pylons-discuss?hl=en.
> >
> >
>
> --
> You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to pylons-discus...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/pylons-discuss?hl=en.
>

--
Brian Sutherland

Michael Bayer

unread,
Jun 21, 2012, 10:20:19 AM6/21/12
to pylons-...@googlegroups.com
hey Max -

The Pyramid devs agree that it should accept a tuple argument.  I think it's a good idea too.   They're just looking for someone to provide a patch at this point.

- mike


To view this discussion on the web visit https://groups.google.com/d/msg/pylons-discuss/-/uf3n-nRpxvYJ.
To post to this group, send email to pylons-...@googlegroups.com.
To unsubscribe from this group, send email to pylons-discus...@googlegroups.com.

Max Avanov

unread,
Jun 21, 2012, 10:25:51 AM6/21/12
to pylons-...@googlegroups.com
I don't want to become a maintainer, for now. I'm a user. If I could provide a patch, I would have done it without any argument.
On the other hand, you're already a maintainer. But you decline to accept that the current API is incomplete and leave me alone with my problem.
I'd like to use the chained snippet if you ensure me that the API will be completed in the following releases.
>     pylons-discuss@googlegroups.com
>     <mailto:pylons-discuss@googlegroups.com>.
>      > To unsubscribe from this group, send email to
>      > pylons-discuss+unsubscribe@googlegroups.com
>     <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
>      > For more options, visit this group at
>      > http://groups.google.com/group/pylons-discuss?hl=en
>     <http://groups.google.com/group/pylons-discuss?hl=en>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J.
> To post to this group, send email to pylons-discuss@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discuss+unsubscribe@googlegroups.com.

Chris McDonough

unread,
Jun 21, 2012, 10:28:00 AM6/21/12
to pylons-...@googlegroups.com
On 06/21/2012 10:18 AM, Max Avanov wrote:
> What are you talking about? This is not just my stupid ideological
> behavior. My current project has 30+ different subpackages, each of thes
> has view-modules. For now, I have to make 30+ extra imports just
> because.... hmm... I still don't get why I have to.

Not that it matters, but no.. you don't have to do any extra imports, at
least no more imports than importing the decorator(s) from somewhere
anyway. In fact, you'd have to do fewer imports if you chained them
together in a place and imported the resulting chain, rather than
importing each of them separately and putting them into a list.

Without chaining, and with a patch to Pyramid to support a list argument
to decorator= :

# in decorators.py

def decorator1(context, request):
...

def decorator2(context, request):
...

def decorator3(context, request):
...

# in views.py

from decorators import decorator1, decorator2, decorator3

@view_config(decorator=[decorator1, decorator2, decorator3])
def aview(request):
...

With chaining that becomes:

# in decorators.py

def combine(*decorators):
def floo(view_callable):
for decorator in decorators:
view_callable = decorator(view_callable)
return view_callable
return floo

def decorator1(context, request):
...

def decorator2(context, request):
...

def decorator3(context, request):
...

combined = combine(decorator1, decorator2, decorator3)

# in views.py

from decorators import combined

@view_config(decorator=combined)
def aview(request):
...

So it's a seven-line difference in code, and arguably a bit cleaner in
the veiws module when the decorators are combined together using code
from the recipe.
> <https://groups.google.com/d/msg/pylons-discuss/-/fhyzewf5dfkJ>.
> >> > To post to this group, send email to
> pylons-...@googlegroups.com
> <mailto:pylons-...@googlegroups.com>.
> >> > To unsubscribe from this group, send email to
> >> > pylons-discus...@googlegroups.com
> <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
> >> > For more options, visit this group at
> >> > http://groups.google.com/group/pylons-discuss?hl=en
> <http://groups.google.com/group/pylons-discuss?hl=en>.
> >>
> > --
> > You received this message because you are subscribed to the
> Google Groups
> > "pylons-discuss" group.
> > To view this discussion on the web visit
> > https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J
> <https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J>.
> >
> > To post to this group, send email to
> pylons-...@googlegroups.com
> <mailto:pylons-...@googlegroups.com>.
> > To unsubscribe from this group, send email to
> > pylons-discus...@googlegroups.com
> <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
> > For more options, visit this group at
> > http://groups.google.com/group/pylons-discuss?hl=en
> <http://groups.google.com/group/pylons-discuss?hl=en>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/uf3n-nRpxvYJ.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.

Max Avanov

unread,
Jun 21, 2012, 10:28:32 AM6/21/12
to pylons-...@googlegroups.com
Thanks, Mike.

But as I said, I cannot become a maintainer. I would like to, but just cannot do it for now.

Max Avanov

unread,
Jun 21, 2012, 10:41:15 AM6/21/12
to pylons-...@googlegroups.com
Yes, it will work for some common combinations. Thank you for this note.

But I still have to import the combine function to some of my modules, which provide its own decorators. I use a custom auth library, which has a number of @authorize_* decorators.
>     pylons-discuss@googlegroups.com
>     <mailto:pylons-discuss@googlegroups.com>.
>      >> > To unsubscribe from this group, send email to
>      >> > pylons-discuss+unsubscribe@googlegroups.com
>     <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
>      >> > For more options, visit this group at
>      >> > http://groups.google.com/group/pylons-discuss?hl=en
>     <http://groups.google.com/group/pylons-discuss?hl=en>.
>      >>
>      > --
>      > You received this message because you are subscribed to the
>     Google Groups
>      > "pylons-discuss" group.
>      > To view this discussion on the web visit
>      > https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J
>     <https://groups.google.com/d/msg/pylons-discuss/-/vp2QABR9sV0J>.
>      >
>      > To post to this group, send email to
>     pylons-discuss@googlegroups.com
>     <mailto:pylons-discuss@googlegroups.com>.
>      > To unsubscribe from this group, send email to
>      > pylons-discuss+unsubscribe@googlegroups.com
>     <mailto:pylons-discuss%2Bunsu...@googlegroups.com>.
>      > For more options, visit this group at
>      > http://groups.google.com/group/pylons-discuss?hl=en
>     <http://groups.google.com/group/pylons-discuss?hl=en>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/uf3n-nRpxvYJ.
> To post to this group, send email to pylons-discuss@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discuss+unsubscribe@googlegroups.com.

Chris McDonough

unread,
Jun 21, 2012, 10:55:21 AM6/21/12
to pylons-...@googlegroups.com
On 06/21/2012 10:25 AM, Max Avanov wrote:
> I don't want to become a maintainer, for now. I'm a user. If I could
> provide a patch, I would have done it without any argument.
> On the other hand, you're already a maintainer. But you decline to
> accept that the current API is incomplete and leave me alone with my
> problem.
> I'd like to use the chained snippet if you ensure me that the API will
> be completed in the following releases.

If you want to see it happen but you're not willing to do it yourself,
you'll have to at least submit a feature request to
https://github.com/Pylons/pyramid/issues about it.

- C

Max Avanov

unread,
Jun 21, 2012, 2:38:21 PM6/21/12
to pylons-...@googlegroups.com
Done.
Reply all
Reply to author
Forward
0 new messages