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?
unittest.skipIf(condition, reason) Skip the decorated test if condition is true.
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.
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.
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.
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.
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.
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 .
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
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
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>
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"
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With