Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: How to ignore decorators during unit (nose) tests?

I want to ignore certain decorators on my code to have the associated functionality skipped, but only when running as a part of a unit test. Can this be done?

For example I have a function f, defined with a numba decorator like so:

@numba.jit
def f(a, b):
  return a + b

When I run a unit test that calls the above function I don't want the numba magic to happen, as it can slow things down and cause errors on some platforms. Is it possible to make a setting someplace that tells nose to run tests without any numba just-in-time (and/or all numba) decorators being applied?

like image 866
James Adams Avatar asked Dec 23 '17 21:12

James Adams


People also ask

Which of the following decorator is used to skip a test if a given condition is false with Unittest?

unittest.skipIf(condition, reason) Skip the decorated test if condition is true.

Are Python decorators necessary?

Python is praised for its clear and concise syntax, and decorators are no exceptions. If there is any behaviour that is common to more than one function, you probably need to make a decorator. Here are some examples when they might come in handy: Check arguments type at runtime.

Does decorator order matter Python?

The broader answer is that it depends on what each of the decorators are doing. You need to think about the flow of your program and whether it would make logical sense for one to come before the other. Show activity on this post. You should do it like below.

How do you test decorators in Python?

Python decorators can be easily tested by integration tests, but it is good practice to create some unit tests for them as well. You can easily unit test a decorator by applying it to a dummy function or mock.

What is decdecorators in Python?

Decorators in Python is one of the most useful concepts supported by Python. It takes functions as arguments and also has a nested function. They extend the functionality of the nested function.

How to write an integration test for decorators?

Writing an integration test is rather straightforward: you can just test your decorator together with the decorated function. It isn’t any different from testing a regular function. Let me demonstrate it using a bit more meaningful example.

How to test a decorator using black box testing?

This technique of writing tests is called “black box testing”. using_email_address takes one argument: a function. It also has a return value: a function. So to test a decorator we need to pass it a function and expect a function as a returned value. Keeping this in mind let’s start writing test case for using_email_address .


5 Answers

For numba only, you can set an environment variable (eg. export NUMBA_DISABLE_JIT=1) to make the jit decorators no-ops.

http://numba.pydata.org/numba-doc/dev/user/troubleshoot.html#disabling-jit-compilation

like image 61
Dunes Avatar answered Nov 14 '22 21:11

Dunes


You might be able to trick nose into using your own decorator that keeps the function unchanged. Write a file numba.py that contains this function:

def jit(func):
    return func

and placed in your PYTHONPATH. Either run your test from directory this file is located in or do this in your test file as the first line:

import sys

sys.path.insert(0, 'path/to/dir/with/myfile') 

Alternatively, you can set the environmental variable PYTHONPATH to the directory where your file is located.

Windows:

set PYTHONPATH=%PYTHONPATH%;path/to/dir/with/myfile

Unix/Mac:

export PYTHONPATH=$PYTHONPATH$:path/to/dir/with/myfile
like image 39
Mike Müller Avatar answered Nov 14 '22 23:11

Mike Müller


You could patch the decorator with a new decorator which you could control:

import functools

def patch(parent, obj_name, switch_reg, switch_name):
    def gen_switcher():
        def wrapper(func):
            ori_wrapped = ori_decorator(func)
            @functools.wraps(func)
            def _(*args, **kwargs):
                if switch_reg.get(switch_name, False):
                    func_to_call = func
                else:
                    func_to_call = ori_wrapped
                print(func_to_call)
                return func_to_call(*args, **kwargs)
            return _
        return wrapper
    ori_decorator = getattr(parent, obj_name)
    setattr(parent, obj_name, gen_switcher())

with:

# have to patch the decorator before applying it
import numba
switchs = {}
patch(numba, 'jit', switchs, 'DISABLE_NUMBA_JIT')

@numba.jit
def f(a, b):
  return a + b

f(1, 2)

yields:

CPUDispatcher(<function f at 0x10a5f90d0>)

then with:

# this part could be rewrited as a context manager    
switchs['DISABLE_NUMBA_JIT'] = True
f(1, 2)

get:

<function f at 0x10a5f90d0>
like image 26
georgexsh Avatar answered Nov 14 '22 21:11

georgexsh


If you're using coverage, you can modify your CI .yml file by adding NUMBA_DISABLE_JIT=1 right before your coverage command:

NUMBA_DISABLE_JIT=1 coverage run -p "test_*.py"
like image 41
dopexxx Avatar answered Nov 14 '22 22:11

dopexxx


I would separate the function into a non-decorated part that you unit test -- and then make your real function have the decorator and simply call the helper function:

@numba.jit
def f(a, b):
  return f_undecorated(a, b)

def f_undecorated(a, b):
  return a + b

Write the unit tests only for f_undecorated.

like image 30
Harald Nordgren Avatar answered Nov 14 '22 23:11

Harald Nordgren