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.
On Thursday, June 21, 2012 6:28:00 PM UTC+4, Chris McDonough wrote: > > 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 view this discussion on the web visit https://groups.google.com/d/msg/pylons-discuss/-/NRuV692Zy5wJ. 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.
