Search code examples
pythoncythonpython-decoratorscythonize

Cython does not work with double decorators with argument. Is there a workaround?


I have a problem cythonizing my python code. I tried to reproduce the most simple case of the error i'm getting.

Here is the illustration of the code i want to cythonize:

     def some_decorator_with_arg(arg):
         def decorator(func):
             def wrapper(x):
                 return func(x) + arg
             return wrapper
         return decorator
 
     class some_class():
         def __init__(self):
             pass
 
         @staticmethod
         @some_decorator_with_arg(1)
         def some_method(a):
             return a
    print(some_class().some_method(1))        

This works without problems in pure python. But when i cythonize this code it throws an error on the run time:

print(some_class().some_method(1))

TypeError: wrapper() takes exactly one argument (2 given)

Compilation runs without problem. If i write @some_decorator_with_arg(arg=1) I get another error:

@some_decorator_with_arg(arg=1)

TypeError: some_decorator_with_arg() takes no keyword arguments

Does someone know a workaround this problem?


Solution

  • I found the simplest way to solve the problem - combine the functionality of the two (or more) decorators into one, then cython does not have a problem. For example for the case above, i would do the following:

    def some_decorator_with_arg(arg):
         def decorator(func):
             def wrapper(x):
                 return func(x) + arg
             return wrapper
         return decorator
    
    #combine the created decorator with the staticmethod functionality
    def staticmethod_combined(*args,**kwargs):
        return lambda func: staticmethod(some_decorator_with_arg(*args,**kwargs)(func))
    
    class some_class():
         def __init__(self):
             pass
    
         @staticmethod_combined(1)
         def some_method(a):
             return a
    
    print(some_class().some_method(1))        
    

    The problem with keyword arguments can be solved by providing the flag at the time of cythonizing always_allow_keywords=True