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.

On Thursday, June 21, 2012 6:10:07 PM UTC+4, Chris Rossi wrote:

    Don't let the perfect be the enemy of the good.

    Chris

    On Thu, Jun 21, 2012 at 9:59 AM, Max Avanov <[email protected]
    <mailto:[email protected]>> 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,
    ...))
     >
     >
     >
     > On Thursday, June 21, 2012 4:21:24 PM UTC+4, Chris McDonough wrote:
     >>
     >> 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
    <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
     >>
     >>
     >>
     >> >
     >> >
     >> > On Thursday, June 21, 2012 2:39:57 AM UTC+4, Chris McDonough
    wrote:
     >> >
     >> > 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
    <http://micheles.googlecode.com/hg/decorator/documentation.html>
     >> >
    <http://micheles.googlecode.com/hg/decorator/documentation.html
    <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
     >> >
     >> > --
     >> > 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
    <https://groups.google.com/d/msg/pylons-discuss/-/fhyzewf5dfkJ>.
     >> > To post to this group, send email to
    [email protected]
    <mailto:[email protected]>.
     >> > To unsubscribe from this group, send email to
     >> > [email protected]
    <mailto:pylons-discuss%[email protected]>.
     >> > 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
    [email protected]
    <mailto:[email protected]>.
     > To unsubscribe from this group, send email to
     > [email protected]
    <mailto:pylons-discuss%[email protected]>.
     > 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 [email protected].
To unsubscribe from this group, send email to
[email protected].
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 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/pylons-discuss?hl=en.

Reply via email to