diff options
Diffstat (limited to 'numpy/testing')
-rw-r--r-- | numpy/testing/__init__.pyi | 44 | ||||
-rw-r--r-- | numpy/testing/_private/decorators.py | 2 | ||||
-rw-r--r-- | numpy/testing/_private/noseclasses.py | 4 | ||||
-rw-r--r-- | numpy/testing/_private/nosetester.py | 18 | ||||
-rw-r--r-- | numpy/testing/_private/parameterized.py | 2 | ||||
-rw-r--r-- | numpy/testing/_private/utils.py | 89 | ||||
-rwxr-xr-x | numpy/testing/print_coercion_tables.py | 110 | ||||
-rwxr-xr-x | numpy/testing/setup.py | 1 | ||||
-rw-r--r-- | numpy/testing/tests/test_utils.py | 2 |
9 files changed, 211 insertions, 61 deletions
diff --git a/numpy/testing/__init__.pyi b/numpy/testing/__init__.pyi new file mode 100644 index 000000000..c394a387d --- /dev/null +++ b/numpy/testing/__init__.pyi @@ -0,0 +1,44 @@ +from typing import Any + +assert_equal: Any +assert_almost_equal: Any +assert_approx_equal: Any +assert_array_equal: Any +assert_array_less: Any +assert_string_equal: Any +assert_array_almost_equal: Any +assert_raises: Any +build_err_msg: Any +decorate_methods: Any +jiffies: Any +memusage: Any +print_assert_equal: Any +raises: Any +rundocs: Any +runstring: Any +verbose: Any +measure: Any +assert_: Any +assert_array_almost_equal_nulp: Any +assert_raises_regex: Any +assert_array_max_ulp: Any +assert_warns: Any +assert_no_warnings: Any +assert_allclose: Any +IgnoreException: Any +clear_and_catch_warnings: Any +SkipTest: Any +KnownFailureException: Any +temppath: Any +tempdir: Any +IS_PYPY: Any +HAS_REFCOUNT: Any +suppress_warnings: Any +assert_array_compare: Any +_assert_valid_refcount: Any +_gen_alignment_data: Any +assert_no_gc_cycles: Any +break_cycles: Any +HAS_LAPACK64: Any +TestCase: Any +run_module_suite: Any diff --git a/numpy/testing/_private/decorators.py b/numpy/testing/_private/decorators.py index b4b6259a0..4c87d1a49 100644 --- a/numpy/testing/_private/decorators.py +++ b/numpy/testing/_private/decorators.py @@ -136,7 +136,7 @@ def skipif(skip_condition, msg=None): else: out = msg - return "Skipping test: %s: %s" % (func.__name__, out) + return f'Skipping test: {func.__name__}: {out}' # We need to define *two* skippers because Python doesn't allow both # return with value and yield inside the same function. diff --git a/numpy/testing/_private/noseclasses.py b/numpy/testing/_private/noseclasses.py index 69e19e959..48fa4dc1f 100644 --- a/numpy/testing/_private/noseclasses.py +++ b/numpy/testing/_private/noseclasses.py @@ -76,7 +76,7 @@ class NumpyDocTestFinder(doctest.DocTestFinder): # Look for tests in a module's contained objects. if ismodule(obj) and self._recurse: for valname, val in obj.__dict__.items(): - valname1 = '%s.%s' % (name, valname) + valname1 = f'{name}.{valname}' if ( (isroutine(val) or isclass(val)) and self._from_module(module, val)): @@ -96,7 +96,7 @@ class NumpyDocTestFinder(doctest.DocTestFinder): if ((isfunction(val) or isclass(val) or ismethod(val) or isinstance(val, property)) and self._from_module(module, val)): - valname = '%s.%s' % (name, valname) + valname = f'{name}.{valname}' self._find(tests, val, valname, module, source_lines, globs, seen) diff --git a/numpy/testing/_private/nosetester.py b/numpy/testing/_private/nosetester.py index 57691a448..bccec8236 100644 --- a/numpy/testing/_private/nosetester.py +++ b/numpy/testing/_private/nosetester.py @@ -233,20 +233,20 @@ class NoseTester: nose = import_nose() import numpy - print("NumPy version %s" % numpy.__version__) + print(f'NumPy version {numpy.__version__}') relaxed_strides = numpy.ones((10, 1), order="C").flags.f_contiguous print("NumPy relaxed strides checking option:", relaxed_strides) npdir = os.path.dirname(numpy.__file__) - print("NumPy is installed in %s" % npdir) + print(f'NumPy is installed in {npdir}') if 'scipy' in self.package_name: import scipy - print("SciPy version %s" % scipy.__version__) + print(f'SciPy version {scipy.__version__}') spdir = os.path.dirname(scipy.__file__) - print("SciPy is installed in %s" % spdir) + print(f'SciPy is installed in {spdir}') pyversion = sys.version.replace('\n', '') - print("Python version %s" % pyversion) + print(f'Python version {pyversion}') print("nose version %d.%d.%d" % nose.__versioninfo__) def _get_custom_doctester(self): @@ -278,7 +278,7 @@ class NoseTester: argv = self._test_argv(label, verbose, extra_argv) # our way of doing coverage if coverage: - argv += ['--cover-package=%s' % self.package_name, '--with-coverage', + argv += [f'--cover-package={self.package_name}', '--with-coverage', '--cover-tests', '--cover-erase'] if timer: @@ -403,9 +403,9 @@ class NoseTester: label, verbose, extra_argv, doctests, coverage, timer) if doctests: - print("Running unit tests and doctests for %s" % self.package_name) + print(f'Running unit tests and doctests for {self.package_name}') else: - print("Running unit tests for %s" % self.package_name) + print(f'Running unit tests for {self.package_name}') self._show_system_info() @@ -520,7 +520,7 @@ class NoseTester: """ - print("Running benchmarks for %s" % self.package_name) + print(f'Running benchmarks for {self.package_name}') self._show_system_info() argv = self._test_argv(label, verbose, extra_argv) diff --git a/numpy/testing/_private/parameterized.py b/numpy/testing/_private/parameterized.py index 3bd8ede91..ac7db6c40 100644 --- a/numpy/testing/_private/parameterized.py +++ b/numpy/testing/_private/parameterized.py @@ -205,7 +205,7 @@ def default_doc_func(func, num, p): all_args_with_values = parameterized_argument_value_pairs(func, p) # Assumes that the function passed is a bound method. - descs = ["%s=%s" %(n, short_repr(v)) for n, v in all_args_with_values] + descs = [f'{n}={short_repr(v)}' for n, v in all_args_with_values] # The documentation might be a multiline string, so split it # and just work with the first string, ignoring the period diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 3827b7505..e974bbd09 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -113,14 +113,14 @@ def gisnan(x): def gisfinite(x): - """like isfinite, but always raise an error if type not supported instead of - returning a TypeError object. + """like isfinite, but always raise an error if type not supported instead + of returning a TypeError object. Notes ----- - isfinite and other ufunc sometimes return a NotImplementedType object instead - of raising any exception. This function is a wrapper to make sure an - exception is always raised. + isfinite and other ufunc sometimes return a NotImplementedType object + instead of raising any exception. This function is a wrapper to make sure + an exception is always raised. This should be removed once this problem is solved at the Ufunc level.""" from numpy.core import isfinite, errstate @@ -160,12 +160,13 @@ if os.name == 'nt': # you should copy this function, but keep the counter open, and call # CollectQueryData() each time you need to know. # See http://msdn.microsoft.com/library/en-us/dnperfmo/html/perfmonpt2.asp (dead link) - # My older explanation for this was that the "AddCounter" process forced - # the CPU to 100%, but the above makes more sense :) + # My older explanation for this was that the "AddCounter" process + # forced the CPU to 100%, but the above makes more sense :) import win32pdh if format is None: format = win32pdh.PDH_FMT_LONG - path = win32pdh.MakeCounterPath( (machine, object, instance, None, inum, counter)) + path = win32pdh.MakeCounterPath( (machine, object, instance, None, + inum, counter)) hq = win32pdh.OpenQuery() try: hc = win32pdh.AddCounter(hq, path) @@ -186,7 +187,7 @@ if os.name == 'nt': win32pdh.PDH_FMT_LONG, None) elif sys.platform[:5] == 'linux': - def memusage(_proc_pid_stat='/proc/%s/stat' % (os.getpid())): + def memusage(_proc_pid_stat=f'/proc/{os.getpid()}/stat'): """ Return virtual memory size in bytes of the running python. @@ -207,8 +208,7 @@ else: if sys.platform[:5] == 'linux': - def jiffies(_proc_pid_stat='/proc/%s/stat' % (os.getpid()), - _load_time=[]): + def jiffies(_proc_pid_stat=f'/proc/{os.getpid()}/stat', _load_time=[]): """ Return number of jiffies elapsed. @@ -263,11 +263,11 @@ def build_err_msg(arrays, err_msg, header='Items are not equal:', try: r = r_func(a) except Exception as exc: - r = '[repr failed for <{}>: {}]'.format(type(a).__name__, exc) + r = f'[repr failed for <{type(a).__name__}>: {exc}]' if r.count('\n') > 3: r = '\n'.join(r.splitlines()[:3]) r += '...' - msg.append(' %s: %s' % (names[i], r)) + msg.append(f' {names[i]}: {r}') return '\n'.join(msg) @@ -329,12 +329,14 @@ def assert_equal(actual, desired, err_msg='', verbose=True): for k, i in desired.items(): if k not in actual: raise AssertionError(repr(k)) - assert_equal(actual[k], desired[k], 'key=%r\n%s' % (k, err_msg), verbose) + assert_equal(actual[k], desired[k], f'key={k!r}\n{err_msg}', + verbose) return if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)): assert_equal(len(actual), len(desired), err_msg, verbose) for k in range(len(desired)): - assert_equal(actual[k], desired[k], 'item=%r\n%s' % (k, err_msg), verbose) + assert_equal(actual[k], desired[k], f'item={k!r}\n{err_msg}', + verbose) return from numpy.core import ndarray, isscalar, signbit from numpy.lib import iscomplexobj, real, imag @@ -694,9 +696,8 @@ def assert_approx_equal(actual,desired,significant=7,err_msg='',verbose=True): raise AssertionError(msg) -def assert_array_compare(comparison, x, y, err_msg='', verbose=True, - header='', precision=6, equal_nan=True, - equal_inf=True): +def assert_array_compare(comparison, x, y, err_msg='', verbose=True, header='', + precision=6, equal_nan=True, equal_inf=True): __tracebackhide__ = True # Hide traceback for py.test from numpy.core import array, array2string, isnan, inf, bool_, errstate, all, max, object_ @@ -744,7 +745,7 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, # flag as it everywhere, so we should return the scalar flag. if isinstance(x_id, bool) or x_id.ndim == 0: return bool_(x_id) - elif isinstance(x_id, bool) or y_id.ndim == 0: + elif isinstance(y_id, bool) or y_id.ndim == 0: return bool_(y_id) else: return y_id @@ -754,8 +755,7 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, if not cond: msg = build_err_msg([x, y], err_msg - + '\n(shapes %s, %s mismatch)' % (x.shape, - y.shape), + + f'\n(shapes {x.shape}, {y.shape} mismatch)', verbose=verbose, header=header, names=('x', 'y'), precision=precision) raise AssertionError(msg) @@ -843,7 +843,7 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, except ValueError: import traceback efmt = traceback.format_exc() - header = 'error during assertion:\n\n%s\n\n%s' % (efmt, header) + header = f'error during assertion:\n\n{efmt}\n\n{header}' msg = build_err_msg([x, y], err_msg, verbose=verbose, header=header, names=('x', 'y'), precision=precision) @@ -1170,7 +1170,8 @@ def assert_string_equal(actual, desired): if desired == actual: return - diff = list(difflib.Differ().compare(actual.splitlines(True), desired.splitlines(True))) + diff = list(difflib.Differ().compare(actual.splitlines(True), + desired.splitlines(True))) diff_list = [] while diff: d1 = diff.pop(0) @@ -1198,7 +1199,7 @@ def assert_string_equal(actual, desired): raise AssertionError(repr(d1)) if not diff_list: return - msg = 'Differences in strings:\n%s' % (''.join(diff_list)).rstrip() + msg = f"Differences in strings:\n{''.join(diff_list).rstrip()}" if actual != desired: raise AssertionError(msg) @@ -1434,9 +1435,7 @@ def measure(code_str, times=1, label=None): frame = sys._getframe(1) locs, globs = frame.f_locals, frame.f_globals - code = compile(code_str, - 'Test name: %s ' % label, - 'exec') + code = compile(code_str, f'Test name: {label} ', 'exec') i = 0 elapsed = jiffies() while i < times: @@ -1525,7 +1524,7 @@ def assert_allclose(actual, desired, rtol=1e-7, atol=0, equal_nan=True, equal_nan=equal_nan) actual, desired = np.asanyarray(actual), np.asanyarray(desired) - header = 'Not equal to tolerance rtol=%g, atol=%g' % (rtol, atol) + header = f'Not equal to tolerance rtol={rtol:g}, atol={atol:g}' assert_array_compare(compare, actual, desired, err_msg=str(err_msg), verbose=verbose, header=header, equal_nan=equal_nan) @@ -1724,8 +1723,8 @@ def _integer_repr(x, vdt, comp): def integer_repr(x): - """Return the signed-magnitude interpretation of the binary representation of - x.""" + """Return the signed-magnitude interpretation of the binary representation + of x.""" import numpy as np if x.dtype == np.float16: return _integer_repr(x, np.int16, np.int16(-2**15)) @@ -1734,7 +1733,7 @@ def integer_repr(x): elif x.dtype == np.float64: return _integer_repr(x, np.int64, np.int64(-2**63)) else: - raise ValueError("Unsupported dtype %s" % x.dtype) + raise ValueError(f'Unsupported dtype {x.dtype}') @contextlib.contextmanager @@ -1744,7 +1743,7 @@ def _assert_warns_context(warning_class, name=None): l = sup.record(warning_class) yield if not len(l) > 0: - name_str = " when calling %s" % name if name is not None else "" + name_str = f' when calling {name}' if name is not None else '' raise AssertionError("No warning raised" + name_str) @@ -1809,8 +1808,8 @@ def _assert_no_warnings_context(name=None): warnings.simplefilter('always') yield if len(l) > 0: - name_str = " when calling %s" % name if name is not None else "" - raise AssertionError("Got warnings%s: %s" % (name_str, l)) + name_str = f' when calling {name}' if name is not None else '' + raise AssertionError(f'Got warnings{name_str}: {l}') def assert_no_warnings(*args, **kwargs): @@ -2322,8 +2321,8 @@ def _assert_no_gc_cycles_context(name=None): break else: raise RuntimeError( - "Unable to fully collect garbage - perhaps a __del__ method is " - "creating more reference cycles?") + "Unable to fully collect garbage - perhaps a __del__ method " + "is creating more reference cycles?") gc.set_debug(gc.DEBUG_SAVEALL) yield @@ -2337,7 +2336,7 @@ def _assert_no_gc_cycles_context(name=None): gc.enable() if n_objects_in_cycles: - name_str = " when calling %s" % name if name is not None else "" + name_str = f' when calling {name}' if name is not None else '' raise AssertionError( "Reference cycles were found{}: {} objects were collected, " "of which {} are shown below:{}" @@ -2403,7 +2402,8 @@ def break_cycles(): if IS_PYPY: # interpreter runs now, to call deleted objects' __del__ methods gc.collect() - # one more, just to make sure + # two more, just to make sure + gc.collect() gc.collect() @@ -2440,12 +2440,10 @@ def check_free_memory(free_bytes): try: mem_free = _parse_size(env_value) except ValueError as exc: - raise ValueError('Invalid environment variable {}: {!s}'.format( - env_var, exc)) + raise ValueError(f'Invalid environment variable {env_var}: {exc}') - msg = ('{0} GB memory required, but environment variable ' - 'NPY_AVAILABLE_MEM={1} set'.format( - free_bytes/1e9, env_value)) + msg = (f'{free_bytes/1e9} GB memory required, but environment variable ' + f'NPY_AVAILABLE_MEM={env_value} set') else: mem_free = _get_mem_available() @@ -2455,8 +2453,7 @@ def check_free_memory(free_bytes): "the test.") mem_free = -1 else: - msg = '{0} GB memory required, but {1} GB available'.format( - free_bytes/1e9, mem_free/1e9) + msg = f'{free_bytes/1e9} GB memory required, but {mem_free/1e9} GB available' return msg if mem_free < free_bytes else None @@ -2473,7 +2470,7 @@ def _parse_size(size_str): m = size_re.match(size_str.lower()) if not m or m.group(2) not in suffixes: - raise ValueError("value {!r} not a valid size".format(size_str)) + raise ValueError(f'value {size_str!r} not a valid size') return int(float(m.group(1)) * suffixes[m.group(2)]) diff --git a/numpy/testing/print_coercion_tables.py b/numpy/testing/print_coercion_tables.py index 8024df128..3a447cd2d 100755 --- a/numpy/testing/print_coercion_tables.py +++ b/numpy/testing/print_coercion_tables.py @@ -3,6 +3,7 @@ """ import numpy as np +from collections import namedtuple # Generic object that can be added, but doesn't do anything else class GenericObject: @@ -25,7 +26,17 @@ def print_cancast_table(ntypes): for row in ntypes: print(row, end=' ') for col in ntypes: - print(int(np.can_cast(row, col)), end=' ') + if np.can_cast(row, col, "equiv"): + cast = "#" + elif np.can_cast(row, col, "safe"): + cast = "=" + elif np.can_cast(row, col, "same_kind"): + cast = "~" + elif np.can_cast(row, col, "unsafe"): + cast = "." + else: + cast = " " + print(cast, end=' ') print() def print_coercion_table(ntypes, inputfirstvalue, inputsecondvalue, firstarray, use_promote_types=False): @@ -69,6 +80,101 @@ def print_coercion_table(ntypes, inputfirstvalue, inputsecondvalue, firstarray, print() +def print_new_cast_table(*, can_cast=True, legacy=False, flags=False): + """Prints new casts, the values given are default "can-cast" values, not + actual ones. + """ + from numpy.core._multiarray_tests import get_all_cast_information + + cast_table = { + 0 : "#", # No cast (classify as equivalent here) + 1 : "#", # equivalent casting + 2 : "=", # safe casting + 3 : "~", # same-kind casting + 4 : ".", # unsafe casting + } + flags_table = { + 0 : "▗", 7: "█", + 1: "▚", 2: "▐", 4: "▄", + 3: "▜", 5: "▙", + 6: "▟", + } + + cast_info = namedtuple("cast_info", ["can_cast", "legacy", "flags"]) + no_cast_info = cast_info(" ", " ", " ") + + casts = get_all_cast_information() + table = {} + dtypes = set() + for cast in casts: + dtypes.add(cast["from"]) + dtypes.add(cast["to"]) + + if cast["from"] not in table: + table[cast["from"]] = {} + to_dict = table[cast["from"]] + + can_cast = cast_table[cast["casting"]] + legacy = "L" if cast["legacy"] else "." + flags = 0 + if cast["requires_pyapi"]: + flags |= 1 + if cast["supports_unaligned"]: + flags |= 2 + if cast["no_floatingpoint_errors"]: + flags |= 4 + + flags = flags_table[flags] + to_dict[cast["to"]] = cast_info(can_cast=can_cast, legacy=legacy, flags=flags) + + # The np.dtype(x.type) is a bit strange, because dtype classes do + # not expose much yet. + types = np.typecodes["All"] + def sorter(x): + # This is a bit weird hack, to get a table as close as possible to + # the one printing all typecodes (but expecting user-dtypes). + dtype = np.dtype(x.type) + try: + indx = types.index(dtype.char) + except ValueError: + indx = np.inf + return (indx, dtype.char) + + dtypes = sorted(dtypes, key=sorter) + + def print_table(field="can_cast"): + print('X', end=' ') + for dt in dtypes: + print(np.dtype(dt.type).char, end=' ') + print() + for from_dt in dtypes: + print(np.dtype(from_dt.type).char, end=' ') + row = table.get(from_dt, {}) + for to_dt in dtypes: + print(getattr(row.get(to_dt, no_cast_info), field), end=' ') + print() + + if can_cast: + # Print the actual table: + print() + print("Casting: # is equivalent, = is safe, ~ is same-kind, and . is unsafe") + print() + print_table("can_cast") + + if legacy: + print() + print("L denotes a legacy cast . a non-legacy one.") + print() + print_table("legacy") + + if flags: + print() + print(f"{flags_table[0]}: no flags, {flags_table[1]}: PyAPI, " + f"{flags_table[2]}: supports unaligned, {flags_table[4]}: no-float-errors") + print() + print_table("flags") + + if __name__ == '__main__': print("can cast") print_cancast_table(np.typecodes['All']) @@ -89,3 +195,5 @@ if __name__ == '__main__': print() print("promote_types") print_coercion_table(np.typecodes['All'], 0, 0, False, True) + print("New casting type promotion:") + print_new_cast_table(can_cast=True, legacy=True, flags=True) diff --git a/numpy/testing/setup.py b/numpy/testing/setup.py index 13191f13f..7652a94a2 100755 --- a/numpy/testing/setup.py +++ b/numpy/testing/setup.py @@ -6,6 +6,7 @@ def configuration(parent_package='',top_path=None): config.add_subpackage('_private') config.add_subpackage('tests') + config.add_data_files('*.pyi') return config if __name__ == '__main__': diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py index 6a6cc664a..c3b9e04b6 100644 --- a/numpy/testing/tests/test_utils.py +++ b/numpy/testing/tests/test_utils.py @@ -1240,7 +1240,7 @@ def assert_warn_len_equal(mod, n_in_context, py34=None, py37=None): if sys.version_info[:2] >= (3, 7): if py37 is not None: n_in_context = py37 - elif sys.version_info[:2] >= (3, 4): + else: if py34 is not None: n_in_context = py34 assert_equal(num_warns, n_in_context) |