-5

I have the following method in my API, and I want to make the serve function a decorator so it can be used like so: @api.serve.

def add_rule(self, func, methods):    
    for item in methods:
        if item in self._config["MAP"]:
            raise RuntimeError("Cannot override functions.")
        self._config["MAP"][item] = func

def serve(self, methods=["POST","GET","HEAD"]):
    def wrapper(func):
        self.add_rule(func, methods)
        return func

    return wrapper

However, everything doesn't seem to work, i.e. set items within the _config["MAP"] dictionary. There are no errors, but it isn't doing what it's supposed to do. Can someone give me a hand?

Eugene
  • 161
  • 1
  • 1
  • 8
  • I think you might have a problem with the reference to `self` see http://stackoverflow.com/questions/1263451/python-decorators-in-classes – Matti Lyra Aug 19 '13 at 09:52
  • For your code to work, you would need to use `@api.serve()`; note the added parens. You must call `serve` which then returns `wrapper` which is then used to decorate the function. Without the parens, you replace the decorated functions with (broken) variants of the `wrapper` function. – l4mpi Aug 19 '13 at 09:58
  • No, it actually works perfectly when I use the non-decorator version: doing ``api.add_rule(serve, ["POST"])`` gives me ``{'POST': }`` but I need to make a decorator version of it. – Eugene Aug 19 '13 at 09:58
  • @l4mpi oh I see... thanks! But why do I have to use the parentheses? – Eugene Aug 19 '13 at 10:00
  • @Eugene Did you get this code from somewhere else? The actual decorator you want to use is the `wrapper` function; which is returned by _calling_ `serve`. In this case it's useful because you can change the `methods` list in cases you don't want the default; e.g. `@api.serve(["GET"])` results in a decorator that only registers the `GET` method. – l4mpi Aug 19 '13 at 10:08
  • @l4mpi No,I did not get the code from somewhere else. The entire thing was written by me. Thanks for the reply. – Eugene Aug 20 '13 at 04:35

1 Answers1

0

1) Your serve function doesn't look like a decorator. You should do like this... Write this function outside of your class definition.

def serve(func):
    def wrapper(*args,**kwargs):
        func(*agrs,**kwargs) 
    return wrapper

2) you can also do like this.

def serve(self,func):
    def wrapper(self,*args,**kwargs):
        func(self,*args,**kwargs)
    return wrapper

you should call your add_rule method inside func method definition.

tailor_raj
  • 1,037
  • 2
  • 9
  • 19
  • Yeah, your decorator is a No-OP. Also, you completely missed the point of what OP is trying to do. Furthermore, you're missing a `)`. And how does OPs code not look like a decorator? It returns a function... – l4mpi Aug 19 '13 at 10:04
  • thnx @l4mpi for correction.. And you asked how that code doesn't look like a decorator? because that function doesn't return the wrapper for the function which passed as a argument, It is not necessary to return a function, but to return a function which is passed as a argument. see this link.. http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python#1594484 – tailor_raj Aug 19 '13 at 10:12
  • I know how a decorator works, thank you. But you seem to be confused. OP uses the decorator for the side effect of registering the functions in a map, he's not interested in wrapping the function with anything. So it's perfectly reasonable to just return the original function... just because decorators are usually used for function wrappers doesn't mean you can't do other nice things with them. Regarding your proposed decorator, _it doesn't do anything_ and is thus useless; and your whole answer completely misses the point of what OP wants to do. – l4mpi Aug 19 '13 at 10:19
  • @tailor_raj: Add self.add_rule(func, methods) before calling func(..). – rajpy Aug 19 '13 at 10:24
  • @rajpy That is still not what OP wants to do. Don't people actually read the questions anymore? Can't figure out how this completely wrong answer got an upvote otherwise. Your suggestion would lead to `add_rule` being called every time `func` is invoked, which would throw an exception from the second call onwards. I'll say it again, maybe capslock will help people understand it this time: OP WANTS TO CALL `add_rule` EXACTLY ONCE TO REGISTER `func` IN A MAP AND USES A DECORATOR FOR ITS SIDE EFFECT; HE DOES NOT WANT TO WRAP `func` WITH ANYTHING. – l4mpi Aug 19 '13 at 10:29
  • @l4mpi Then Y don't you give an answer with implementation, so that everyone can understand...?? – tailor_raj Aug 19 '13 at 10:51
  • Because OPs code is the correct implementation, he just used it wrong and didn't call `serve`. I've already explained an hour ago what's going on; read the comments to the question. And I recommend you delete this answer while you're at it. – l4mpi Aug 19 '13 at 11:05
  • So you mean to say that he should use decorator with argument and then before returning decorator function from that function, he should call add_rule method..?? – tailor_raj Aug 19 '13 at 11:09
  • 1
    No. He calls `serve`, which _returns_ the actual decorator (the `wrapper` function). Then `wrapper` adds some data about `func` to his map and then _returns the original function unchanged_. A decorator is just syntactic sugar for a function call and assignment anyways; in OPs case he uses it purely for the side effects of the function call. – l4mpi Aug 19 '13 at 11:23
  • So thats why you said him to call @api.server() , so that it will not return the wrapper, instead it will call the wrapper and return the actual function `func`...??? – tailor_raj Aug 19 '13 at 11:28