8

I want numba to be an optional dependency, so that it's fast if installed or slow if not. So when numba is not installed, I want @njit to be a dummy decorator that does nothing.

If I follow these directions and use:

def njit(func):
    return func

Then when the decorator is called like @njit(cache=True, nogil=True) I get errors about:

TypeError: njit() got an unexpected keyword argument 'cache'

If I try to catch the args and ignore them using

    def njit(func, *args, **kwargs):
        return func

then I get:

missing 1 required positional argument: 'func'

How do I just make a dummy decorator that does nothing and ignores kwargs?

endolith
  • 25,479
  • 34
  • 128
  • 192
  • 1
    Possible duplicate of [Decorators with parameters?](https://stackoverflow.com/questions/5929107/decorators-with-parameters) – walnut Sep 03 '19 at 15:14

3 Answers3

9

Think of decorators with arguments as decorator factory, they return a decorator. This way

def decorator(func):
    return func

The above is a decorator, now with arguments

def decorator_factory(a,b,c):
    def decorator(func):
        return func
    return decorator

The inner decorator has access to the a,b,c arguments because it is a closure. I hope that helps


So it can be defined as:

def njit(cache, nogil):
    def decorator(func):
        return func 
    return decorator
geckos
  • 5,687
  • 1
  • 41
  • 53
  • 1
    Yep that fixes it. ```def njit(*args, **kwargs): def decorator(func): return func return decorator``` – endolith Sep 03 '19 at 15:24
  • 2
    @endolith: Only if you always do `@njit()` and never `@njit`. It will silently do the wrong thing if you ever do `@njit`. – user2357112 Jul 05 '20 at 04:16
3

If you want to save some time and be able to do the same with all numba decorators, try numbasub. It provides exactly what you are asking for, and you can apply it to any project you want.

  • 1
    that would just be another dependency, though? – endolith Sep 03 '19 at 16:09
  • 2
    true. it's a very light dependency though since it has no dependencies itself. Plus it covers a lot of cases that are annoying to address one by one, e.g. if numba types are imported somewhere in the code you would have to mock them one by one. But if one only needs to create dummies for a couple of decorators, it might be overkill (it's even mentioned in the readme file). – Giorgio Balestrieri Sep 03 '19 at 23:34
1

Expanding on geckos' answer, we can adapt it to be compatible with @njit as well.

The code for jit can be found in https://github.com/numba/numba/blob/main/numba/core/decorators.py

What we need to do is to make jit act as a factory decorator when used as @jit() and as a simple decorator when used as @jit.

def njit(f=None, *args, **kwargs):
    def decorator(func):
        return func 

    if callable(f):
        return f
    else:
        return decorator

This should work in both cases.

jinawee
  • 492
  • 5
  • 16