diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/__init__.py | 25 | ||||
-rw-r--r-- | numpy/core/src/multiarray/datetime.c | 5 | ||||
-rw-r--r-- | numpy/core/tests/test_datetime.py | 20 | ||||
-rw-r--r-- | numpy/linalg/tests/test_linalg.py | 36 | ||||
-rw-r--r-- | numpy/ma/core.py | 15 |
5 files changed, 88 insertions, 13 deletions
diff --git a/numpy/__init__.py b/numpy/__init__.py index d10a1ecd3..d250ed5ac 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -194,3 +194,28 @@ else: from numpy.testing._private.pytesttester import PytestTester test = PytestTester(__name__) del PytestTester + + + def _sanity_check(): + """ + Quick sanity checks for common bugs caused by environment. + There are some cases e.g. with wrong BLAS ABI that cause wrong + results under specific runtime conditions that are not necessarily + achieved during test suite runs, and it is useful to catch those early. + + See https://github.com/numpy/numpy/issues/8577 and other + similar bug reports. + + """ + try: + x = ones(2, dtype=float32) + if not abs(x.dot(x) - 2.0) < 1e-5: + raise AssertionError() + except AssertionError: + msg = ("The current Numpy installation ({!r}) fails to " + "pass simple sanity checks. This can be caused for example " + "by incorrect BLAS library being linked in.") + raise RuntimeError(msg.format(__file__)) + + _sanity_check() + del _sanity_check diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c index b026e5fae..af542aecc 100644 --- a/numpy/core/src/multiarray/datetime.c +++ b/numpy/core/src/multiarray/datetime.c @@ -2808,9 +2808,12 @@ convert_pyobject_to_timedelta(PyArray_DatetimeMetaData *meta, PyObject *obj, us_meta.base = NPY_FR_m; } else if (td % (24*60*60*1000000LL) != 0) { - us_meta.base = NPY_FR_D; + us_meta.base = NPY_FR_h; } else if (td % (7*24*60*60*1000000LL) != 0) { + us_meta.base = NPY_FR_D; + } + else { us_meta.base = NPY_FR_W; } us_meta.num = 1; diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index 43e8a3325..e433877e8 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -124,7 +124,7 @@ class TestDateTime(object): assert_(not np.can_cast('M8[h]', 'M8', casting='safe')) def test_compare_generic_nat(self): - # regression tests for GH6452 + # regression tests for gh-6452 assert_equal(np.datetime64('NaT'), np.datetime64('2000') + np.timedelta64('NaT')) # nb. we may want to make NaT != NaT true in the future @@ -331,6 +331,24 @@ class TestDateTime(object): a = np.timedelta64(1, 'Y') assert_raises(TypeError, np.timedelta64, a, 'D') assert_raises(TypeError, np.timedelta64, a, 'm') + a = datetime.timedelta(seconds=3) + assert_raises(TypeError, np.timedelta64, a, 'M') + assert_raises(TypeError, np.timedelta64, a, 'Y') + a = datetime.timedelta(weeks=3) + assert_raises(TypeError, np.timedelta64, a, 'M') + assert_raises(TypeError, np.timedelta64, a, 'Y') + a = datetime.timedelta() + assert_raises(TypeError, np.timedelta64, a, 'M') + assert_raises(TypeError, np.timedelta64, a, 'Y') + + def test_timedelta_object_array_conversion(self): + # Regression test for gh-11096 + inputs = [datetime.timedelta(28), + datetime.timedelta(30), + datetime.timedelta(31)] + expected = np.array([28, 30, 31], dtype='timedelta64[D]') + actual = np.array(inputs, dtype='timedelta64[D]') + assert_equal(expected, actual) def test_timedelta_scalar_construction_units(self): # String construction detecting units diff --git a/numpy/linalg/tests/test_linalg.py b/numpy/linalg/tests/test_linalg.py index 5ed1ff1c0..87dfe988a 100644 --- a/numpy/linalg/tests/test_linalg.py +++ b/numpy/linalg/tests/test_linalg.py @@ -7,6 +7,8 @@ import os import sys import itertools import traceback +import textwrap +import subprocess import pytest import numpy as np @@ -1761,6 +1763,40 @@ def test_xerbla_override(): raise SkipTest('Numpy xerbla not linked in.') +def test_sdot_bug_8577(): + # Regression test that loading certain other libraries does not + # result to wrong results in float32 linear algebra. + # + # There's a bug gh-8577 on OSX that can trigger this, and perhaps + # there are also other situations in which it occurs. + # + # Do the check in a separate process. + + bad_libs = ['PyQt5.QtWidgets', 'IPython'] + + template = textwrap.dedent(""" + import sys + {before} + try: + import {bad_lib} + except ImportError: + sys.exit(0) + {after} + x = np.ones(2, dtype=np.float32) + sys.exit(0 if np.allclose(x.dot(x), 2.0) else 1) + """) + + for bad_lib in bad_libs: + code = template.format(before="import numpy as np", after="", + bad_lib=bad_lib) + subprocess.check_call([sys.executable, "-c", code]) + + # Swapped import order + code = template.format(after="import numpy as np", before="", + bad_lib=bad_lib) + subprocess.check_call([sys.executable, "-c", code]) + + class TestMultiDot(object): def test_basic_function_with_three_arguments(self): diff --git a/numpy/ma/core.py b/numpy/ma/core.py index c0dda6f31..17682d13f 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -2799,13 +2799,8 @@ class MaskedArray(ndarray): # FIXME _sharedmask is never used. _sharedmask = True # Process mask. - # Number of named fields (or zero if none) - names_ = _data.dtype.names or () # Type of the mask - if names_: - mdtype = make_mask_descr(_data.dtype) - else: - mdtype = MaskType + mdtype = make_mask_descr(_data.dtype) if mask is nomask: # Case 1. : no mask in input. @@ -2831,14 +2826,12 @@ class MaskedArray(ndarray): _data._mask = mask _data._sharedmask = False else: + _data._sharedmask = not copy if copy: _data._mask = _data._mask.copy() - _data._sharedmask = False # Reset the shape of the original mask if getmask(data) is not nomask: data._mask.shape = data.shape - else: - _data._sharedmask = True else: # Case 2. : With a mask in input. # If mask is boolean, create an array of True or False @@ -2875,7 +2868,7 @@ class MaskedArray(ndarray): _data._mask = mask _data._sharedmask = not copy else: - if names_: + if _data.dtype.names: def _recursive_or(a, b): "do a|=b on each field of a, recursively" for name in a.dtype.names: @@ -2884,7 +2877,7 @@ class MaskedArray(ndarray): _recursive_or(af, bf) else: af |= bf - return + _recursive_or(_data._mask, mask) else: _data._mask = np.logical_or(mask, _data._mask) |