On 13 Apr, 11:11, Michel Albert <exh...@gmail.com> wrote: > A small foreword: This might look like a cherrypy-oriented post, and > should therefore go to the cherrypy group, but if you read to the end, > you'll see it's a more basic python problem, with cherrypy only as an > example. ;) > > From the decorator PEP (318) I get it that you can /add/ parameters to > a call. Say you do something like this: > > @mydeco( foo="bar" ) > def myfunc( hello ): > print foo, foo > > However, this is not what I would like to do. I would like to take > away one or more attributes using a decorator. My goal is to > centralize the logic associated with that parameter. In my particular > example, I am writing a cherrypy application (more specifically, > turbogears1) and I would like all controller method to accept a "lang" > and a "skin" attribute. As a simple, but hands-on example, imagine > code like this (http://python.pastebin.com/f25f2429b): > > class MyController(Controller): > > @expose() > def index(self, skin="default", lang="en"): > set_skin( skin ) > set_language( lang ) > return "Hello skinned world" > > @expose() > def foo(self, skin="default", lang="en"): > set_skin( skin ) > set_language( lang ) > return "bar" > > This becomes cumbersome however for a large application with many > controllers and methods. Always adding the parameters to the methods > and function calls into the method bodies looks way to repetitive for > my taste. > > Currently I solve this by using a cherrypy filter which removes those > parameters from the HTTP-Request and puts them into the session > object. This looked wrong to me though right from the start. Also, the > cherrypy docs advise against the use of "filters" for application > logic. But this looks pretty much like that to me.... somewhat. Worse > yet, filters are not supported in Turbogears2 any longer. Which makes > porting my app not straight-forward, as I have to port my filters and > write WSGI middleware instead. > > I would prefer a syntax like this (http://python.pastebin.com/ > f462bc29c) > > class MyController(Controller): > > @expose() > @skinnable > @translatable > def index(self): > return "Hello skinned world" > > @expose() > @skinnable > @translatable > def foo(self): > return "bar" > > This, to me has several advantages: The logic is "encapsulated" in the > application code itself. I do not need to rely on framework specific > features (be it cherrypy or wsgi). This would make the application > more self-contained and hence more future proof. > > But right here lies my problem. If you are not familiar with CherryPy, > let me digress for a tiny bit to give you the necessary backgroud: > > Inside a controller, an "exposed" method is reachable via HTTP > requests. It's possible to force request parameters. If that is the > case (as in my case it is), then the call will only be successful, if > all parameters received a vaule and no unknown parameters have been > passed. Assume the following signature: > > def index(self) > > This will successfully return an HTTP Response when the client > requested the resource on the URL "/index". If the client adds a query > string, say "/index?lang=en" the call will *fail* as this parameter is > unkown. For this to work the signature must read: > > def index(self, lang) > > or > > def index(self, lang="en") > > Right.... end of digression, back to topic:
Haven't finished coffee yet, plus it's a bank holiday! [/excuse] Can't that be changed to def index(self, **kwdargs) -- then your decorators can operate something like set_language(kwdargs.get('lang', 'en')) and then delete the key.... Anyway, back to more coffee! > > My ultimate question is: Is it possible to write a decorator that > removes a parameter from a call and return a function without that > parameter? Something along the lines (http://python.pastebin.com/ > f257877cd): > > def translatable(f): > "Note that this code is only an example and will not work!" > lang = f.__get_parameter_value__("lang") > f.__remove_parameter__("lang") > do_something_with_lang(lang) > return f > > I am aware, that this depends on *when* the decorator call is > executed. If its called whenever the decorated function is called, > then there should be some way to handle this. If it's called at > "compile-time", then I suppose it's not going to be possible. > > A usage scenario would be this: > > # --- definition --------------- > @translatable > def index(self): > return _("Hello", lang) > > # --- call ---------------------- > obj.index( lang="de") > obj.index() > > As you can see, the method definition does not contain the "lang" > parameter in the signature, but I want to be able to (optionally) set > it during a call. > > I hope I made my ideas clear enough. I would be very positively > surprised if this worked. It would make my application code much > easier to read, understand and follow. The filters currently do a lot > of magic "behind-the-scenes" and if somebody else needs to jump in and > code on that application they will surely ask themselves "where the > ****** is that ***** lang variable set?" :) And I'd like to make it as > easy as possible for everyone :) > > Or, maybe you even have a better solution in mind? I'm open for > suggestions. -- http://mail.python.org/mailman/listinfo/python-list