def benchsuite(function, fraction_nan): # setup is called before each run of each function setup = """ from bottleneck import %s as bn_fn try: from numpy import %s as sl_fn except ImportError: from bottleneck.slow import %s as sl_fn # avoid all-nan slice warnings from np.median and np.nanmedian if "%s" == "median": from bottleneck.slow import median as sl_fn if "%s" == "nanmedian": from bottleneck.slow import nanmedian as sl_fn from numpy import array, nan from numpy.random import RandomState rand = RandomState(123).rand a = %s if %s != 0: a[a < %s] = nan """ setup = '\n'.join([s.strip() for s in setup.split('\n')]) # what kind of function signature do we need to use? if function in bn.get_functions('reduce', as_string=True): index = 0 elif function in ['rankdata', 'nanrankdata']: index = 0 elif function in bn.get_functions('move', as_string=True): index = 1 elif function in ['partition', 'argpartition', 'push']: index = 2 elif function == 'replace': index = 3 else: raise ValueError("`function` (%s) not recognized" % function) # create benchmark suite instructions = get_instructions() f = function suite = [] for instruction in instructions: signature = instruction[index + 1] if signature is None: continue array = instruction[0] repeat = instruction[-1] run = {} run['name'] = [f + signature, array] run['statements'] = ["bn_fn" + signature, "sl_fn" + signature] run['setup'] = setup % (f, f, f, f, f, array, fraction_nan, fraction_nan) run['repeat'] = repeat suite.append(run) return suite
def test_arg_parsing(): "test argument parsing in nonreduce_axis" for func in bn.get_functions('nonreduce_axis'): name = func.__name__ if name in ('partition', 'argpartition'): yield unit_maker_parse, func elif name in ('push'): yield unit_maker_parse, func elif name in ('rankdata', 'nanrankdata'): yield unit_maker_parse_rankdata, func else: fmt = "``%s` is an unknown nonreduce_axis function" raise ValueError(fmt % name) yield unit_maker_raises, func
def bench_detailed(function='nansum', fraction_nan=0.0): """ Benchmark a single function in detail or, optionally, all functions. Parameters ---------- function : str, optional Name of function, as a string, to benchmark. Default ('nansum') is to benchmark bn.nansum. If `function` is 'all' then detailed benchmarks are run on all bottleneck functions. fraction_nan : float, optional Fraction of array elements that should, on average, be NaN. The default (0.0) is not to set any elements to NaN. Returns ------- A benchmark report is printed to stdout. """ if function == 'all': # benchmark all bottleneck functions funcs = bn.get_functions('all', as_string=True) funcs.sort() for func in funcs: bench_detailed(func, fraction_nan) if fraction_nan < 0 or fraction_nan > 1: raise ValueError("`fraction_nan` must be between 0 and 1, inclusive") tab = ' ' # Header print('%s benchmark' % function) print("%sBottleneck %s; Numpy %s" % (tab, bn.__version__, np.__version__)) print("%sSpeed is NumPy time divided by Bottleneck time" % tab) if fraction_nan == 0: print("%sNone of the array elements are NaN" % tab) else: print("%s%.1f%% of the array elements are NaN (on average)" % (tab, fraction_nan * 100)) print("") print(" Speed Call Array") suite = benchsuite(function, fraction_nan) for test in suite: name = test["name"] speed = timer(test['statements'], test['setup'], test['repeat']) print("%8.1f %s %s" % (speed, name[0].ljust(27), name[1]))
def test_push(): """Test push""" ns = (0, 1, 2, 3, 4, 5, None) a = np.array([np.nan, 1, 2, np.nan, np.nan, np.nan, np.nan, 3, np.nan]) for n in ns: actual = bn.push(a.copy(), n=n) desired = bn.slow.push(a.copy(), n=n) assert_array_equal(actual, desired, "failed on n=%s" % str(n)) # --------------------------------------------------------------------------- # Test argument parsing @pytest.mark.parametrize("func", bn.get_functions("nonreduce_axis"), ids=lambda x: x.__name__) def test_arg_parsing(func): """test argument parsing in nonreduce_axis""" name = func.__name__ if name in ("partition", "argpartition"): return unit_maker_parse(func) elif name in ("push"): return unit_maker_parse(func) elif name in ("rankdata", "nanrankdata"): return unit_maker_parse_rankdata(func) else: fmt = "``%s` is an unknown nonreduce_axis function" raise ValueError(fmt % name)
"""Test replace().""" import warnings import numpy as np import pytest from numpy.testing import assert_array_equal, assert_equal, assert_raises import bottleneck as bn from .util import DTYPES, INT_DTYPES, array_order, arrays @pytest.mark.parametrize("func", bn.get_functions("nonreduce"), ids=lambda x: x.__name__) def test_nonreduce(func): """Test that bn.xxx gives the same output as np.xxx.""" msg = "\nfunc %s | input %s (%s) | shape %s | old %f | new %f | order %s\n" msg += "\nInput array:\n%s\n" name = func.__name__ func0 = eval("bn.slow.%s" % name) rs = np.random.RandomState([1, 2, 3]) news = [1, 0, np.nan, -np.inf] for i, arr in enumerate(arrays(name)): for idx in range(2): if arr.size == 0: old = 0 else: idx = rs.randint(max(arr.size, 1)) old = arr.flat[idx] for new in news:
def test_arg_parsing(): "test argument parsing" for func in bn.get_functions('reduce'): yield unit_maker_argparse, func
def test_move(): "test move functions" for func in bn.get_functions('move'): yield unit_maker, func
ss[1] = {"size": 4, "shapes": [(4, )]} ss[2] = {"size": 6, "shapes": [(1, 6), (2, 3)]} ss[3] = {"size": 6, "shapes": [(1, 2, 3)]} ss[4] = {"size": 24, "shapes": [(1, 2, 3, 4)]} for ndim in ss: size = ss[ndim]["size"] shapes = ss[ndim]["shapes"] a = np.arange(size) for shape in shapes: a = a.reshape(shape) for dtype in dtypes: yield a.astype(dtype).tolist() @pytest.mark.parametrize("func", bn.get_functions("all"), ids=lambda x: x.__name__) def test_list_input(func): """Test that bn.xxx gives the same output as bn.slow.xxx for list input.""" msg = "\nfunc %s | input %s (%s) | shape %s\n" msg += "\nInput array:\n%s\n" name = func.__name__ if name == "replace": return func0 = eval("bn.slow.%s" % name) for i, a in enumerate(lists()): with warnings.catch_warnings(): warnings.simplefilter("ignore") try: actual = func(a) desired = func0(a)
"""Test moving window functions.""" import numpy as np import pytest from numpy.testing import assert_array_almost_equal, assert_equal, assert_raises import bottleneck as bn from .util import array_order, arrays @pytest.mark.parametrize("func", bn.get_functions("move"), ids=lambda x: x.__name__) def test_move(func): """Test that bn.xxx gives the same output as a reference function.""" fmt = ("\nfunc %s | window %d | min_count %s | input %s (%s) | shape %s | " "axis %s | order %s\n") fmt += "\nInput array:\n%s\n" aaae = assert_array_almost_equal func_name = func.__name__ func0 = eval("bn.slow.%s" % func_name) if func_name == "move_var": decimal = 3 else: decimal = 5 for i, a in enumerate(arrays(func_name)): axes = range(-1, a.ndim) for axis in axes: windows = range(1, a.shape[axis]) for window in windows: min_counts = list(range(1, window + 1)) + [None]
def test_modification(): "Test for illegal inplace modification of input array" for func in bn.get_functions('all'): yield unit_maker, func
def test_push(): "Test push" ns = (0, 1, 2, 3, 4, 5, None) a = np.array([np.nan, 1, 2, np.nan, np.nan, np.nan, np.nan, 3, np.nan]) for n in ns: actual = bn.push(a.copy(), n=n) desired = bn.slow.push(a.copy(), n=n) assert_array_equal(actual, desired, "failed on n=%s" % str(n)) # --------------------------------------------------------------------------- # Test argument parsing @pytest.mark.parametrize("func", bn.get_functions('nonreduce_axis'), ids=lambda x: x.__name__) def test_arg_parsing(func): "test argument parsing in nonreduce_axis" name = func.__name__ if name in ('partition', 'argpartition'): return unit_maker_parse(func) elif name in ('push'): return unit_maker_parse(func) elif name in ('rankdata', 'nanrankdata'): return unit_maker_parse_rankdata(func) else: fmt = "``%s` is an unknown nonreduce_axis function" raise ValueError(fmt % name) return unit_maker_raises(func)
def test_list_input(): "Check that functions can handle list input" for func in bn.get_functions('all'): if func.__name__ != 'replace': yield unit_maker, func
def test_strides(): "test move functions with non-C ordered arrays" for func in bn.get_functions('move'): yield unit_maker_strides, func
"""Test replace().""" import warnings import numpy as np import pytest from numpy.testing import assert_array_equal, assert_equal, assert_raises import bottleneck as bn from .util import DTYPES, INT_DTYPES, array_order, arrays @pytest.mark.parametrize( "func", bn.get_functions("nonreduce"), ids=lambda x: x.__name__ ) def test_nonreduce(func) -> None: """Test that bn.xxx gives the same output as np.xxx.""" msg = "\nfunc %s | input %s (%s) | shape %s | old %f | new %f | order %s\n" msg += "\nInput array:\n%s\n" name = func.__name__ func0 = eval("bn.slow.%s" % name) rs = np.random.RandomState([1, 2, 3]) news = [1, 0, np.nan, -np.inf] for i, arr in enumerate(arrays(name)): for idx in range(2): if arr.size == 0: old = 0 else: idx = rs.randint(max(arr.size, 1)) old = arr.flat[idx] for new in news:
def benchsuite(shapes, dtype, nans, axes, order, functions): suite = [] def getsetups(setup, shapes, nans, axes, dtype, order): template = """ from bottleneck.benchmark.bench import getarray a = getarray(%s, '%s', %s, '%s') axis=%s %s""" setups = [] for shape, axis, nan in zip(shapes, axes, nans): s = template % (str(shape), str(dtype), str(nan), str(order), str(axis), setup) s = '\n'.join([line.strip() for line in s.split('\n')]) setups.append(s) return setups # non-moving window functions funcs = bn.get_functions("reduce", as_string=True) funcs += ['rankdata', 'nanrankdata'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, axis)", "sl_func(a, axis)"] setup = """ from bottleneck import %s as bn_func try: from numpy import %s as sl_func except ImportError: from bottleneck.slow import %s as sl_func if "%s" == "median": from bottleneck.slow import median as sl_func """ % (func, func, func, func) run['setups'] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) # partition, argpartition funcs = ['partition', 'argpartition'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, n, axis)", "sl_func(a, n, axis)"] setup = """ from bottleneck import %s as bn_func from bottleneck.slow import %s as sl_func if axis is None: n = a.size else: n = a.shape[axis] - 1 n = max(n // 2, 0) """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) # replace, push funcs = ['replace', 'push'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func if func == 'replace': run['statements'] = ["bn_func(a, nan, 0)", "slow_func(a, nan, 0)"] elif func == 'push': run['statements'] = ["bn_func(a, 5, axis)", "slow_func(a, 5, axis)"] else: raise ValueError('Unknow function name') setup = """ from numpy import nan from bottleneck import %s as bn_func from bottleneck.slow import %s as slow_func """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) # moving window functions funcs = bn.get_functions('move', as_string=True) for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, w, 1, axis)", "sw_func(a, w, 1, axis)"] setup = """ from bottleneck.slow.move import %s as sw_func from bottleneck import %s as bn_func w = a.shape[axis] // 5 """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) return suite
def test_scalar_input(): "Test scalar input" funcs = bn.get_functions('reduce') + bn.get_functions('nonreduce_axis') for func in funcs: if func.__name__ not in ('partition', 'argpartition', 'push'): yield unit_maker, func, eval('bn.slow.%s' % func.__name__)
def test_strides(): "test nonreducer_axis functions with non-C ordered arrays" for func in bn.get_functions('nonreduce_axis'): yield unit_maker_strides, func
@hypothesis.given(array=hy_int_array_gen) @hypothesis.settings(max_examples=500) def test_reduce_hypothesis_ints_only(func, array): _hypothesis_helper(func, array) @pytest.mark.parametrize("func", (bn.nanargmin, bn.nanargmax), ids=lambda x: x.__name__) @hypothesis.given(array=hy_array_gen) @hypothesis.settings(max_examples=500) def test_reduce_hypothesis_errata(func, array): _hypothesis_helper(func, array, skip_all_nans=True) @pytest.mark.parametrize("func", bn.get_functions("reduce"), ids=lambda x: x.__name__) def test_reduce(func): """test reduce functions""" return unit_maker(func) def unit_maker(func, decimal=5, skip_dtype=("nansum", "ss")): """Test that bn.xxx gives the same output as bn.slow.xxx.""" fmt = "\nfunc %s | input %s (%s) | shape %s | axis %s | order %s\n" fmt += "\nInput array:\n%s\n" name = func.__name__ func0 = eval("bn.slow.%s" % name) for i, a in enumerate(arrays(name)): if a.ndim == 0: axes = [None] # numpy can't handle e.g. np.nanmean(9, axis=-1)
def test_strides(): "test reduce functions with non-C ordered arrays" for func in bn.get_functions('reduce'): yield unit_maker_strides, func
shapes = ss[ndim]["shapes"] for dtype in dtypes: a = np.arange(size, dtype=dtype) if issubclass(a.dtype.type, np.inexact): idx = rs.rand(*a.shape) < 0.2 a[idx] = np.inf idx = rs.rand(*a.shape) < 0.2 a[idx] = np.nan idx = rs.rand(*a.shape) < 0.2 a[idx] *= -1 for shape in shapes: a = a.reshape(shape) yield a @pytest.mark.parametrize("func", bn.get_functions("all"), ids=lambda x: x.__name__) def test_modification(func): """Test that bn.xxx gives the same output as np.xxx.""" name = func.__name__ if name == "replace": return msg = "\nInput array modified by %s.\n\n" msg += "input array before:\n%s\nafter:\n%s\n" for i, a in enumerate(arrays(DTYPES)): axes = list(range(-a.ndim, a.ndim)) if all(x not in name for x in ["push", "move", "sort", "partition"]): axes += [None] second_arg = 1 if "partition" in name: second_arg = 0
"""Check that functions can handle scalar input""" from numpy.testing import assert_array_almost_equal import bottleneck as bn import pytest @pytest.mark.parametrize( "func", bn.get_functions("reduce") + bn.get_functions("nonreduce_axis"), # noqa: W504 ids=lambda x: x.__name__, ) def test_scalar_input(func, args=tuple()): """Test that bn.xxx gives the same output as bn.slow.xxx for scalar input.""" if func.__name__ in ("partition", "argpartition", "push"): return func0 = eval("bn.slow.%s" % func.__name__) msg = "\nfunc %s | input %s\n" a = -9 argsi = [a] + list(args) actual = func(*argsi) desired = func0(*argsi) err_msg = msg % (func.__name__, a) assert_array_almost_equal(actual, desired, err_msg=err_msg)
ss = {} ss[1] = {'size': 4, 'shapes': [(4,)]} ss[2] = {'size': 6, 'shapes': [(1, 6), (2, 3)]} ss[3] = {'size': 6, 'shapes': [(1, 2, 3)]} ss[4] = {'size': 24, 'shapes': [(1, 2, 3, 4)]} for ndim in ss: size = ss[ndim]['size'] shapes = ss[ndim]['shapes'] a = np.arange(size) for shape in shapes: a = a.reshape(shape) for dtype in dtypes: yield a.astype(dtype).tolist() @pytest.mark.parametrize("func", bn.get_functions('all'), ids=lambda x: x.__name__) def test_list_input(func): "Test that bn.xxx gives the same output as bn.slow.xxx for list input." msg = '\nfunc %s | input %s (%s) | shape %s\n' msg += '\nInput array:\n%s\n' name = func.__name__ if name == 'replace': return func0 = eval('bn.slow.%s' % name) for i, a in enumerate(lists()): with warnings.catch_warnings(): warnings.simplefilter("ignore") try: actual = func(a) desired = func0(a)
def test_reduce(): "test reduce functions" for func in bn.get_functions('reduce'): yield unit_maker, func
def benchsuite(shapes, dtype, nans, axes, order, functions): suite = [] def getsetups(setup, shapes, nans, axes, dtype, order, allnan=False): setups = [] for shape, axis, nan in zip(shapes, axes, nans): s = f""" from bottleneck.benchmark.bench import getarray a = getarray({shape}, '{dtype}', {nan}, '{order}', allnans={allnan}) axis={axis} {setup}""" s = "\n".join([line.strip() for line in s.split("\n")]) setups.append(s) return setups # non-moving window functions funcs = bn.get_functions("reduce", as_string=True) # Handle all/any separately funcs = sorted(set(funcs) - set(["allnan", "anynan"])) funcs += ["rankdata", "nanrankdata"] for func in funcs: if functions is not None and func not in functions: continue run = {} run["name"] = func run["statements"] = ["bn_func(a, axis)", "sl_func(a, axis)"] setup = """ from bottleneck import %s as bn_func try: from numpy import %s as sl_func except ImportError: from bottleneck.slow import %s as sl_func if "%s" == "median": from bottleneck.slow import median as sl_func """ % ( func, func, func, func, ) run["setups"] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) for func in ["allnan", "anynan"]: if functions is not None and func not in functions: continue for case in ["", "_fast", "_slow"]: run = {} run["name"] = func + case run["statements"] = ["bn_func(a, axis)", "sl_func(a, axis)"] setup = """ from bottleneck import %s as bn_func try: from numpy import %s as sl_func except ImportError: from bottleneck.slow import %s as sl_func if "%s" == "median": from bottleneck.slow import median as sl_func """ % ( func, func, func, func, ) if case: if func == "allnan": allnan_case = "slow" in case else: allnan_case = "fast" in case new_nans = [allnan_case] * len(nans) else: new_nans = nans allnan_case = False run["setups"] = getsetups(setup, shapes, new_nans, axes, dtype, order, allnan=allnan_case) suite.append(run) # partition, argpartition funcs = ["partition", "argpartition"] for func in funcs: if functions is not None and func not in functions: continue run = {} run["name"] = func run["statements"] = ["bn_func(a, n, axis)", "sl_func(a, n, axis)"] setup = """ from bottleneck import %s as bn_func from bottleneck.slow import %s as sl_func if axis is None: n = a.size else: n = a.shape[axis] - 1 n = max(n // 2, 0) """ % ( func, func, ) run["setups"] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) # replace, push funcs = ["replace", "push"] for func in funcs: if functions is not None and func not in functions: continue run = {} run["name"] = func if func == "replace": run["statements"] = ["bn_func(a, nan, 0)", "slow_func(a, nan, 0)"] elif func == "push": run["statements"] = [ "bn_func(a, 5, axis)", "slow_func(a, 5, axis)" ] else: raise ValueError("Unknow function name") setup = """ from numpy import nan from bottleneck import %s as bn_func from bottleneck.slow import %s as slow_func """ % ( func, func, ) run["setups"] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) # moving window functions funcs = bn.get_functions("move", as_string=True) for func in funcs: if functions is not None and func not in functions: continue run = {} run["name"] = func run["statements"] = [ "bn_func(a, w, 1, axis)", "sw_func(a, w, 1, axis)" ] setup = """ from bottleneck.slow.move import %s as sw_func from bottleneck import %s as bn_func w = a.shape[axis] // 5 """ % ( func, func, ) run["setups"] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) return suite
def test_arg_parse_raises(): "test argument parsing raises in reduce" for func in bn.get_functions('reduce'): yield unit_maker_argparse_raises, func
"Test moving window functions." import numpy as np from numpy.testing import (assert_equal, assert_array_almost_equal, assert_raises) import bottleneck as bn from .util import arrays, array_order import pytest @pytest.mark.parametrize("func", bn.get_functions('move'), ids=lambda x: x.__name__) def test_move(func): "Test that bn.xxx gives the same output as a reference function." fmt = ('\nfunc %s | window %d | min_count %s | input %s (%s) | shape %s | ' 'axis %s | order %s\n') fmt += '\nInput array:\n%s\n' aaae = assert_array_almost_equal func_name = func.__name__ func0 = eval('bn.slow.%s' % func_name) if func_name == "move_var": decimal = 3 else: decimal = 5 for i, a in enumerate(arrays(func_name)): axes = range(-1, a.ndim) for axis in axes: windows = range(1, a.shape[axis]) for window in windows: min_counts = list(range(1, window + 1)) + [None]
def benchsuite(shapes, dtype, axis, nans, order, functions): suite = [] def getsetups(setup, shapes, nans, order): template = """ from bottleneck.benchmark.bench import getarray a = getarray(%s, 'DTYPE', %s, '%s') %s""" setups = [] for shape, nan in zip(shapes, nans): setups.append(template % (str(shape), str(nan), order, setup)) return setups # non-moving window functions funcs = bn.get_functions("reduce", as_string=True) funcs += ['rankdata', 'nanrankdata'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, AXIS)", "sl_func(a, AXIS)"] setup = """ from bottleneck import %s as bn_func try: from numpy import %s as sl_func except ImportError: from bottleneck.slow import %s as sl_func if "%s" == "median": from bottleneck.slow import median as sl_func """ % (func, func, func, func) run['setups'] = getsetups(setup, shapes, nans, order) suite.append(run) # partition, argpartition funcs = ['partition', 'argpartition'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, n, AXIS)", "sl_func(a, n, AXIS)"] setup = """ from bottleneck import %s as bn_func from bottleneck.slow import %s as sl_func if AXIS is None: n = a.size else: n = a.shape[AXIS] - 1 n = max(n / 2, 0) """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, order) suite.append(run) # replace, push funcs = ['replace', 'push'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func if func == 'replace': run['statements'] = ["bn_func(a, nan, 0)", "slow_func(a, nan, 0)"] elif func == 'push': run['statements'] = ["bn_func(a, 5, AXIS)", "slow_func(a, 5, AXIS)"] else: raise ValueError('Unknow function name') setup = """ from numpy import nan from bottleneck import %s as bn_func from bottleneck.slow import %s as slow_func """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, order) suite.append(run) # moving window functions funcs = bn.get_functions('move', as_string=True) for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, w, 1, AXIS)", "sw_func(a, w, 1, AXIS)"] setup = """ from bottleneck.slow.move import %s as sw_func from bottleneck import %s as bn_func w = a.shape[AXIS] // 5 """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, order) if axis != 'None': suite.append(run) # Strip leading spaces from setup code for i, run in enumerate(suite): for j in range(len(run['setups'])): t = run['setups'][j] t = '\n'.join([z.strip() for z in t.split('\n')]) suite[i]['setups'][j] = t # Set dtype and axis in setups for i, run in enumerate(suite): for j in range(len(run['setups'])): t = run['setups'][j] t = t.replace('DTYPE', dtype) t = t.replace('AXIS', axis) suite[i]['setups'][j] = t # Set dtype and axis in statements for i, run in enumerate(suite): for j in range(2): t = run['statements'][j] t = t.replace('DTYPE', dtype) t = t.replace('AXIS', axis) suite[i]['statements'][j] = t return suite
def benchsuite(shapes, dtype, nans, axes, order, functions): suite = [] def getsetups(setup, shapes, nans, axes, dtype, order): template = """ from bottleneck.benchmark.bench import getarray a = getarray(%s, '%s', %s, '%s') axis=%s %s""" setups = [] for shape, axis, nan in zip(shapes, axes, nans): s = template % (str(shape), str(dtype), str(nan), str(order), str(axis), setup) s = '\n'.join([line.strip() for line in s.split('\n')]) setups.append(s) return setups # non-moving window functions funcs = bn.get_functions("reduce", as_string=True) funcs += ['rankdata', 'nanrankdata'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, axis)", "sl_func(a, axis)"] setup = """ from bottleneck import %s as bn_func try: from numpy import %s as sl_func except ImportError: from bottleneck.slow import %s as sl_func if "%s" == "median": from bottleneck.slow import median as sl_func """ % (func, func, func, func) run['setups'] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) # partition, argpartition funcs = ['partition', 'argpartition'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, n, axis)", "sl_func(a, n, axis)"] setup = """ from bottleneck import %s as bn_func from bottleneck.slow import %s as sl_func if axis is None: n = a.size else: n = a.shape[axis] - 1 n = max(n / 2, 0) """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) # replace, push funcs = ['replace', 'push'] for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func if func == 'replace': run['statements'] = ["bn_func(a, nan, 0)", "slow_func(a, nan, 0)"] elif func == 'push': run['statements'] = ["bn_func(a, 5, axis)", "slow_func(a, 5, axis)"] else: raise ValueError('Unknow function name') setup = """ from numpy import nan from bottleneck import %s as bn_func from bottleneck.slow import %s as slow_func """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) # moving window functions funcs = bn.get_functions('move', as_string=True) for func in funcs: if functions is not None and func not in functions: continue run = {} run['name'] = func run['statements'] = ["bn_func(a, w, 1, axis)", "sw_func(a, w, 1, axis)"] setup = """ from bottleneck.slow.move import %s as sw_func from bottleneck import %s as bn_func w = a.shape[axis] // 5 """ % (func, func) run['setups'] = getsetups(setup, shapes, nans, axes, dtype, order) suite.append(run) return suite
"Check that functions can handle scalar input" from numpy.testing import assert_array_almost_equal import bottleneck as bn import pytest @pytest.mark.parametrize( "func", bn.get_functions('reduce') + # noqa: W504 bn.get_functions('nonreduce_axis'), ids=lambda x: x.__name__) def test_scalar_input(func, args=tuple()): "Test that bn.xxx gives the same output as bn.slow.xxx for scalar input." if func.__name__ in ('partition', 'argpartition', 'push'): return func0 = eval('bn.slow.%s' % func.__name__) msg = '\nfunc %s | input %s\n' a = -9 argsi = [a] + list(args) actual = func(*argsi) desired = func0(*argsi) err_msg = msg % (func.__name__, a) assert_array_almost_equal(actual, desired, err_msg=err_msg)