summaryrefslogtreecommitdiff
path: root/numpy/testing
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/testing')
-rw-r--r--numpy/testing/__init__.pyi44
-rw-r--r--numpy/testing/_private/decorators.py2
-rw-r--r--numpy/testing/_private/noseclasses.py4
-rw-r--r--numpy/testing/_private/nosetester.py18
-rw-r--r--numpy/testing/_private/parameterized.py2
-rw-r--r--numpy/testing/_private/utils.py89
-rwxr-xr-xnumpy/testing/print_coercion_tables.py110
-rwxr-xr-xnumpy/testing/setup.py1
-rw-r--r--numpy/testing/tests/test_utils.py2
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)