diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/records.py | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 10 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.c.src | 7 | ||||
-rw-r--r-- | numpy/distutils/misc_util.py | 7 | ||||
-rw-r--r-- | numpy/ma/mrecords.py | 3 | ||||
-rw-r--r-- | numpy/random/common.pxd | 2 | ||||
-rw-r--r-- | numpy/random/setup.py | 7 | ||||
-rw-r--r-- | numpy/random/src/bitgen.h (renamed from numpy/core/include/numpy/random/bitgen.h) | 0 | ||||
-rw-r--r-- | numpy/random/src/distributions/distributions.h | 2 | ||||
-rw-r--r-- | numpy/testing/_private/utils.py | 89 | ||||
-rw-r--r-- | numpy/testing/tests/test_utils.py | 52 |
11 files changed, 125 insertions, 57 deletions
diff --git a/numpy/core/records.py b/numpy/core/records.py index 2b31625c3..8a5fee541 100644 --- a/numpy/core/records.py +++ b/numpy/core/records.py @@ -496,8 +496,7 @@ class recarray(ndarray): except Exception: fielddict = ndarray.__getattribute__(self, 'dtype').fields or {} if attr not in fielddict: - exctype, value = sys.exc_info()[:2] - raise exctype(value) + raise else: fielddict = ndarray.__getattribute__(self, 'dtype').fields or {} if attr not in fielddict: diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 413decd9d..084a5dd46 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -1581,8 +1581,7 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) PyArrayObject *oparr = NULL, *ret = NULL; npy_bool subok = NPY_FALSE; npy_bool copy = NPY_TRUE; - int nd; - npy_intp ndmin = 0; + int ndmin = 0, nd; PyArray_Descr *type = NULL; PyArray_Descr *oldtype = NULL; NPY_ORDER order = NPY_KEEPORDER; @@ -1644,13 +1643,14 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) ndmin_obj = PyDict_GetItem(kws, npy_ma_str_ndmin); if (ndmin_obj) { - ndmin = PyLong_AsLong(ndmin_obj); - if (error_converting(ndmin)) { + long t = PyLong_AsLong(ndmin_obj); + if (error_converting(t)) { goto clean_type; } - else if (ndmin > NPY_MAXDIMS) { + else if (t > NPY_MAXDIMS) { goto full_path; } + ndmin = t; } /* copy=False with default dtype, order (any is OK) and ndim */ diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index f84d74efe..1931cd100 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -384,7 +384,11 @@ PyUFunc_O_O_method(char **args, npy_intp *dimensions, npy_intp *steps, void *fun PyObject **out = (PyObject **)op1; PyObject *ret, *func; func = PyObject_GetAttrString(in1 ? in1 : Py_None, meth); - if (func == NULL || !PyCallable_Check(func)) { + if (func != NULL && !PyCallable_Check(func)) { + Py_DECREF(func); + func = NULL; + } + if (func == NULL) { PyObject *exc, *val, *tb; PyTypeObject *type = in1 ? Py_TYPE(in1) : Py_TYPE(Py_None); PyErr_Fetch(&exc, &val, &tb); @@ -397,6 +401,7 @@ PyUFunc_O_O_method(char **args, npy_intp *dimensions, npy_intp *steps, void *fun return; } ret = PyObject_Call(func, tup, NULL); + Py_DECREF(func); if (ret == NULL) { Py_DECREF(tup); return; diff --git a/numpy/distutils/misc_util.py b/numpy/distutils/misc_util.py index 89171eede..2a6472b95 100644 --- a/numpy/distutils/misc_util.py +++ b/numpy/distutils/misc_util.py @@ -2281,8 +2281,11 @@ def generate_config_py(target): extra_dll_dir = os.path.join(os.path.dirname(__file__), '.libs') if sys.platform == 'win32' and os.path.isdir(extra_dll_dir): - os.environ.setdefault('PATH', '') - os.environ['PATH'] += os.pathsep + extra_dll_dir + if sys.version_info >= (3, 8): + os.add_dll_directory(extra_dll_dir) + else: + os.environ.setdefault('PATH', '') + os.environ['PATH'] += os.pathsep + extra_dll_dir """)) diff --git a/numpy/ma/mrecords.py b/numpy/ma/mrecords.py index 826fb0f64..ae1a12c2c 100644 --- a/numpy/ma/mrecords.py +++ b/numpy/ma/mrecords.py @@ -260,8 +260,7 @@ class MaskedRecords(MaskedArray, object): fielddict = ndarray.__getattribute__(self, 'dtype').fields or {} optinfo = ndarray.__getattribute__(self, '_optinfo') or {} if not (attr in fielddict or attr in optinfo): - exctype, value = sys.exc_info()[:2] - raise exctype(value) + raise else: # Get the list of names fielddict = ndarray.__getattribute__(self, 'dtype').fields or {} diff --git a/numpy/random/common.pxd b/numpy/random/common.pxd index 2f7baa06e..ac0a94bb0 100644 --- a/numpy/random/common.pxd +++ b/numpy/random/common.pxd @@ -5,7 +5,7 @@ from libc.stdint cimport (uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t) from libc.math cimport sqrt -cdef extern from "numpy/random/bitgen.h": +cdef extern from "src/bitgen.h": struct bitgen: void *state uint64_t (*next_uint64)(void *st) nogil diff --git a/numpy/random/setup.py b/numpy/random/setup.py index f0ebe331f..52e020e58 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -34,8 +34,6 @@ def configuration(parent_package='', top_path=None): defs.append(('NPY_NO_DEPRECATED_API', 0)) config.add_data_dir('tests') - config.add_data_files('common.pxd') - config.add_data_files('bit_generator.pxd') EXTRA_LINK_ARGS = [] # Math lib @@ -49,11 +47,6 @@ def configuration(parent_package='', top_path=None): elif not is_msvc: # Some bit generators require c99 EXTRA_COMPILE_ARGS += ['-std=c99'] - INTEL_LIKE = any(arch in platform.machine() - for arch in ('x86', 'i686', 'i386', 'amd64')) - if INTEL_LIKE: - # Assumes GCC or GCC-like compiler - EXTRA_COMPILE_ARGS += ['-msse2'] # Use legacy integer variable sizes LEGACY_DEFS = [('NP_RANDOM_LEGACY', '1')] diff --git a/numpy/core/include/numpy/random/bitgen.h b/numpy/random/src/bitgen.h index 0adaaf2ee..0adaaf2ee 100644 --- a/numpy/core/include/numpy/random/bitgen.h +++ b/numpy/random/src/bitgen.h diff --git a/numpy/random/src/distributions/distributions.h b/numpy/random/src/distributions/distributions.h index f2c370c07..b778968d7 100644 --- a/numpy/random/src/distributions/distributions.h +++ b/numpy/random/src/distributions/distributions.h @@ -9,7 +9,7 @@ #include "Python.h" #include "numpy/npy_common.h" #include "numpy/npy_math.h" -#include "numpy/random/bitgen.h" +#include "src/bitgen.h" /* * RAND_INT_TYPE is used to share integer generators with RandomState which diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 09fe85e5f..306967216 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -301,6 +301,10 @@ def assert_equal(actual, desired, err_msg='', verbose=True): check that all elements of these objects are equal. An exception is raised at the first conflicting values. + When one of `actual` and `desired` is a scalar and the other is array_like, + the function checks that each element of the array_like object is equal to + the scalar. + This function handles NaN comparisons as if NaN was a "normal" number. That is, no assertion is raised if both objects have NaNs in the same positions. This is in contrast to the IEEE standard on NaNs, which says @@ -391,21 +395,6 @@ def assert_equal(actual, desired, err_msg='', verbose=True): if isscalar(desired) != isscalar(actual): raise AssertionError(msg) - # Inf/nan/negative zero handling - try: - isdesnan = gisnan(desired) - isactnan = gisnan(actual) - if isdesnan and isactnan: - return # both nan, so equal - - # handle signed zero specially for floats - if desired == 0 and actual == 0: - if not signbit(desired) == signbit(actual): - raise AssertionError(msg) - - except (TypeError, ValueError, NotImplementedError): - pass - try: isdesnat = isnat(desired) isactnat = isnat(actual) @@ -421,6 +410,33 @@ def assert_equal(actual, desired, err_msg='', verbose=True): except (TypeError, ValueError, NotImplementedError): pass + # Inf/nan/negative zero handling + try: + isdesnan = gisnan(desired) + isactnan = gisnan(actual) + if isdesnan and isactnan: + return # both nan, so equal + + # handle signed zero specially for floats + array_actual = array(actual) + array_desired = array(desired) + if (array_actual.dtype.char in 'Mm' or + array_desired.dtype.char in 'Mm'): + # version 1.18 + # until this version, gisnan failed for datetime64 and timedelta64. + # Now it succeeds but comparison to scalar with a different type + # emits a DeprecationWarning. + # Avoid that by skipping the next check + raise NotImplementedError('cannot compare to a scalar ' + 'with a different type') + + if desired == 0 and actual == 0: + if not signbit(desired) == signbit(actual): + raise AssertionError(msg) + + except (TypeError, ValueError, NotImplementedError): + pass + try: # Explicitly use __eq__ for comparison, gh-2552 if not (desired == actual): @@ -703,7 +719,7 @@ 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 + from numpy.core import array, array2string, isnan, inf, bool_, errstate, all, max, object_ x = array(x, copy=False, subok=True) y = array(y, copy=False, subok=True) @@ -804,15 +820,19 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, # do not trigger a failure (np.ma.masked != True evaluates as # np.ma.masked, which is falsy). if cond != True: - mismatch = 100. * (reduced.size - reduced.sum(dtype=intp)) / ox.size - remarks = ['Mismatch: {:.3g}%'.format(mismatch)] + n_mismatch = reduced.size - reduced.sum(dtype=intp) + n_elements = flagged.size if flagged.ndim != 0 else reduced.size + percent_mismatch = 100 * n_mismatch / n_elements + remarks = [ + 'Mismatched elements: {} / {} ({:.3g}%)'.format( + n_mismatch, n_elements, percent_mismatch)] with errstate(invalid='ignore', divide='ignore'): # ignore errors for non-numeric types with contextlib.suppress(TypeError): error = abs(x - y) - max_abs_error = error.max() - if error.dtype == 'object': + max_abs_error = max(error) + if getattr(error, 'dtype', object_) == object_: remarks.append('Max absolute difference: ' + str(max_abs_error)) else: @@ -826,8 +846,8 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, if all(~nonzero): max_rel_error = array(inf) else: - max_rel_error = (error[nonzero] / abs(y[nonzero])).max() - if error.dtype == 'object': + max_rel_error = max(error[nonzero] / abs(y[nonzero])) + if getattr(error, 'dtype', object_) == object_: remarks.append('Max relative difference: ' + str(max_rel_error)) else: @@ -854,10 +874,11 @@ def assert_array_equal(x, y, err_msg='', verbose=True): Raises an AssertionError if two array_like objects are not equal. Given two array_like objects, check that the shape is equal and all - elements of these objects are equal. An exception is raised at - shape mismatch or conflicting values. In contrast to the standard usage - in numpy, NaNs are compared like numbers, no assertion is raised if - both objects have NaNs in the same positions. + elements of these objects are equal (but see the Notes for the special + handling of a scalar). An exception is raised at shape mismatch or + conflicting values. In contrast to the standard usage in numpy, NaNs + are compared like numbers, no assertion is raised if both objects have + NaNs in the same positions. The usual caution for verifying equality with floating point numbers is advised. @@ -884,6 +905,12 @@ def assert_array_equal(x, y, err_msg='', verbose=True): relative and/or absolute precision. assert_array_almost_equal_nulp, assert_array_max_ulp, assert_equal + Notes + ----- + When one of `x` and `y` is a scalar and the other is array_like, the + function checks that each element of the array_like object is equal to + the scalar. + Examples -------- The first assert does not raise an exception: @@ -891,7 +918,7 @@ def assert_array_equal(x, y, err_msg='', verbose=True): >>> np.testing.assert_array_equal([1.0,2.33333,np.nan], ... [np.exp(0),2.33333, np.nan]) - Assert fails with numerical inprecision with floats: + Assert fails with numerical imprecision with floats: >>> np.testing.assert_array_equal([1.0,np.pi,np.nan], ... [1, np.sqrt(np.pi)**2, np.nan]) @@ -912,6 +939,12 @@ def assert_array_equal(x, y, err_msg='', verbose=True): ... [1, np.sqrt(np.pi)**2, np.nan], ... rtol=1e-10, atol=0) + As mentioned in the Notes section, `assert_array_equal` has special + handling for scalars. Here the test checks that each value in `x` is 3: + + >>> x = np.full((2, 5), fill_value=3) + >>> np.testing.assert_array_equal(x, 3) + """ __tracebackhide__ = True # Hide traceback for py.test assert_array_compare(operator.__eq__, x, y, err_msg=err_msg, @@ -1150,7 +1183,7 @@ def assert_string_equal(actual, desired): if desired == actual: return - diff = list(difflib.Differ().compare(actual.splitlines(1), desired.splitlines(1))) + diff = list(difflib.Differ().compare(actual.splitlines(True), desired.splitlines(True))) diff_list = [] while diff: d1 = diff.pop(0) diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py index 76c842f25..ad72b9199 100644 --- a/numpy/testing/tests/test_utils.py +++ b/numpy/testing/tests/test_utils.py @@ -90,6 +90,21 @@ class TestArrayEqual(_GenericTest): for t in ['S1', 'U1']: foo(t) + def test_0_ndim_array(self): + x = np.array(473963742225900817127911193656584771) + y = np.array(18535119325151578301457182298393896) + assert_raises(AssertionError, self._assert_func, x, y) + + y = x + self._assert_func(x, y) + + x = np.array(43) + y = np.array(10) + assert_raises(AssertionError, self._assert_func, x, y) + + y = x + self._assert_func(x, y) + def test_generic_rank3(self): """Test rank 3 array for all dtypes.""" def foo(t): @@ -520,7 +535,7 @@ class TestAlmostEqual(_GenericTest): with pytest.raises(AssertionError) as exc_info: self._assert_func(x, y, decimal=12) msgs = str(exc_info.value).split('\n') - assert_equal(msgs[3], 'Mismatch: 100%') + assert_equal(msgs[3], 'Mismatched elements: 3 / 3 (100%)') assert_equal(msgs[4], 'Max absolute difference: 1.e-05') assert_equal(msgs[5], 'Max relative difference: 3.33328889e-06') assert_equal( @@ -536,7 +551,7 @@ class TestAlmostEqual(_GenericTest): with pytest.raises(AssertionError) as exc_info: self._assert_func(x, y) msgs = str(exc_info.value).split('\n') - assert_equal(msgs[3], 'Mismatch: 33.3%') + assert_equal(msgs[3], 'Mismatched elements: 1 / 3 (33.3%)') assert_equal(msgs[4], 'Max absolute difference: 1.e-05') assert_equal(msgs[5], 'Max relative difference: 3.33328889e-06') assert_equal(msgs[6], ' x: array([1. , 2. , 3.00003])') @@ -548,7 +563,7 @@ class TestAlmostEqual(_GenericTest): with pytest.raises(AssertionError) as exc_info: self._assert_func(x, y) msgs = str(exc_info.value).split('\n') - assert_equal(msgs[3], 'Mismatch: 50%') + assert_equal(msgs[3], 'Mismatched elements: 1 / 2 (50%)') assert_equal(msgs[4], 'Max absolute difference: 1.') assert_equal(msgs[5], 'Max relative difference: 1.') assert_equal(msgs[6], ' x: array([inf, 0.])') @@ -560,10 +575,30 @@ class TestAlmostEqual(_GenericTest): with pytest.raises(AssertionError) as exc_info: self._assert_func(x, y) msgs = str(exc_info.value).split('\n') - assert_equal(msgs[3], 'Mismatch: 100%') + assert_equal(msgs[3], 'Mismatched elements: 2 / 2 (100%)') assert_equal(msgs[4], 'Max absolute difference: 2') assert_equal(msgs[5], 'Max relative difference: inf') + def test_error_message_2(self): + """Check the message is formatted correctly when either x or y is a scalar.""" + x = 2 + y = np.ones(20) + with pytest.raises(AssertionError) as exc_info: + self._assert_func(x, y) + msgs = str(exc_info.value).split('\n') + assert_equal(msgs[3], 'Mismatched elements: 20 / 20 (100%)') + assert_equal(msgs[4], 'Max absolute difference: 1.') + assert_equal(msgs[5], 'Max relative difference: 1.') + + y = 2 + x = np.ones(20) + with pytest.raises(AssertionError) as exc_info: + self._assert_func(x, y) + msgs = str(exc_info.value).split('\n') + assert_equal(msgs[3], 'Mismatched elements: 20 / 20 (100%)') + assert_equal(msgs[4], 'Max absolute difference: 1.') + assert_equal(msgs[5], 'Max relative difference: 0.5') + def test_subclass_that_cannot_be_bool(self): # While we cannot guarantee testing functions will always work for # subclasses, the tests should ideally rely only on subclasses having @@ -588,9 +623,9 @@ class TestApproxEqual(object): def setup(self): self._assert_func = assert_approx_equal - def test_simple_arrays(self): - x = np.array([1234.22]) - y = np.array([1234.23]) + def test_simple_0d_arrays(self): + x = np.array(1234.22) + y = np.array(1234.23) self._assert_func(x, y, significant=5) self._assert_func(x, y, significant=6) @@ -855,7 +890,8 @@ class TestAssertAllclose(object): with pytest.raises(AssertionError) as exc_info: assert_allclose(a, b) msg = str(exc_info.value) - assert_('Mismatch: 25%\nMax absolute difference: 1\n' + assert_('Mismatched elements: 1 / 4 (25%)\n' + 'Max absolute difference: 1\n' 'Max relative difference: 0.5' in msg) def test_equal_nan(self): |