Imported Upstream version 1.15.4 upstream/1.15.4
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 00:45:18 +0000 (09:45 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 00:45:18 +0000 (09:45 +0900)
18 files changed:
doc/changelog/1.15.4-changelog.rst [new file with mode: 0644]
doc/release/1.15.4-notes.rst [new file with mode: 0644]
doc/source/release.rst
numpy/core/einsumfunc.py
numpy/core/src/multiarray/arrayobject.c
numpy/core/src/multiarray/arraytypes.c.src
numpy/core/src/multiarray/buffer.c
numpy/core/src/multiarray/buffer.h
numpy/core/src/multiarray/common.c
numpy/core/src/multiarray/conversion_utils.c
numpy/core/src/multiarray/ctors.c
numpy/core/src/multiarray/descriptor.c
numpy/core/src/multiarray/getset.c
numpy/core/src/multiarray/scalartypes.c.src
numpy/ma/core.py
numpy/ma/tests/test_core.py
pavement.py
setup.py

diff --git a/doc/changelog/1.15.4-changelog.rst b/doc/changelog/1.15.4-changelog.rst
new file mode 100644 (file)
index 0000000..fbe71f4
--- /dev/null
@@ -0,0 +1,21 @@
+
+Contributors
+============
+
+A total of 4 people contributed to this release.  People with a "+" by their
+names contributed a patch for the first time.
+
+* Charles Harris
+* Matti Picus
+* Sebastian Berg
+* bbbbbbbbba +
+
+Pull requests merged
+====================
+
+A total of 4 pull requests were merged for this release.
+
+* `#12296 <https://github.com/numpy/numpy/pull/12296>`__: BUG: Dealloc cached buffer info (#12249)
+* `#12297 <https://github.com/numpy/numpy/pull/12297>`__: BUG: Fix fill value in masked array '==' and '!=' ops.
+* `#12307 <https://github.com/numpy/numpy/pull/12307>`__: DOC: Correct the default value of `optimize` in `numpy.einsum`
+* `#12320 <https://github.com/numpy/numpy/pull/12320>`__: REL: Prepare for the NumPy 1.15.4 release
diff --git a/doc/release/1.15.4-notes.rst b/doc/release/1.15.4-notes.rst
new file mode 100644 (file)
index 0000000..033bd58
--- /dev/null
@@ -0,0 +1,38 @@
+==========================
+NumPy 1.15.4 Release Notes
+==========================
+
+This is a bugfix release for bugs and regressions reported following the 1.15.3
+release.  The Python versions supported by this release are 2.7, 3.4-3.7. The
+wheels are linked with OpenBLAS v0.3.0, which should fix some of the linalg
+problems reported for NumPy 1.14.
+
+Compatibility Note
+==================
+
+The NumPy 1.15.x OS X wheels released on PyPI no longer contain 32-bit
+binaries.  That will also be the case in future releases. See
+`#11625 <https://github.com/numpy/numpy/issues/11625>`__ for the related
+discussion.  Those needing 32-bit support should look elsewhere or build
+from source.
+
+Contributors
+============
+
+A total of 4 people contributed to this release.  People with a "+" by their
+names contributed a patch for the first time.
+
+* Charles Harris
+* Matti Picus
+* Sebastian Berg
+* bbbbbbbbba +
+
+Pull requests merged
+====================
+
+A total of 4 pull requests were merged for this release.
+
+* `#12296 <https://github.com/numpy/numpy/pull/12296>`__: BUG: Dealloc cached buffer info
+* `#12297 <https://github.com/numpy/numpy/pull/12297>`__: BUG: Fix fill value in masked array '==' and '!=' ops.
+* `#12307 <https://github.com/numpy/numpy/pull/12307>`__: DOC: Correct the default value of `optimize` in `numpy.einsum`
+* `#12320 <https://github.com/numpy/numpy/pull/12320>`__: REL: Prepare for the NumPy 1.15.4 release
index cfd77e85340226174cf020d505946c035c62033a..28e9fd5beb9d834dfa0779e3eed3d3dccc73f2e0 100644 (file)
@@ -2,6 +2,7 @@
 Release Notes
 *************
 
+.. include:: ../release/1.15.4-notes.rst
 .. include:: ../release/1.15.3-notes.rst
 .. include:: ../release/1.15.2-notes.rst
 .. include:: ../release/1.15.1-notes.rst
index df2bf4a4eb03e75ffddded2a0fa82be2b0b85ec7..c22f2da422706235f26990623023670425654209 100644 (file)
@@ -1028,7 +1028,7 @@ def einsum(*operands, **kwargs):
         Controls if intermediate optimization should occur. No optimization
         will occur if False and True will default to the 'greedy' algorithm.
         Also accepts an explicit contraction list from the ``np.einsum_path``
-        function. See ``np.einsum_path`` for more details. Default is True.
+        function. See ``np.einsum_path`` for more details. Defaults to False.
 
     Returns
     -------
index 41748c7140c45a05c4f75bb315dbb646438984e8..8ba3f5310dccd3c5e495949112b3c406878d6b7e 100644 (file)
@@ -471,7 +471,7 @@ array_dealloc(PyArrayObject *self)
 {
     PyArrayObject_fields *fa = (PyArrayObject_fields *)self;
 
-    _array_dealloc_buffer_info(self);
+    _dealloc_cached_buffer_info((PyObject*)self);
 
     if (fa->weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *)self);
index 1055f6adc9c151ae2b6e2c3c2f045e5deb0cf659..553737a3a1375ec4a3fccaa74857a1940ffeccbe 100644 (file)
@@ -2,7 +2,8 @@
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
 #include "structmember.h"
-
+#include <limits.h>
+#include <assert.h>
 
 #define NPY_NO_DEPRECATED_API NPY_API_VERSION
 #define _MULTIARRAYMODULE
@@ -34,8 +35,7 @@
 
 #include "cblasfuncs.h"
 #include "npy_cblas.h"
-#include <limits.h>
-#include <assert.h>
+#include "buffer.h"
 
 /* check for sequences, but ignore the types numpy considers scalars */
 static NPY_INLINE npy_bool
@@ -947,6 +947,7 @@ VOID_setitem(PyObject *op, void *input, void *vap)
             memset(ip + view.len, 0, itemsize - view.len);
         }
         PyBuffer_Release(&view);
+        _dealloc_cached_buffer_info(op);
     }
 #else
     {
index c8e3da8bcda1d9210e6d355d6daea3651dcf2180..66393033709e8f94455bcbb056edf00b6b8b40ea 100644 (file)
@@ -884,7 +884,7 @@ fail:
  */
 
 NPY_NO_EXPORT void
-_array_dealloc_buffer_info(PyArrayObject *self)
+_dealloc_cached_buffer_info(PyObject *self)
 {
     int reset_error_state = 0;
     PyObject *ptype, *pvalue, *ptraceback;
@@ -898,7 +898,7 @@ _array_dealloc_buffer_info(PyArrayObject *self)
         PyErr_Fetch(&ptype, &pvalue, &ptraceback);
     }
 
-    _buffer_clear_info((PyObject*)self);
+    _buffer_clear_info(self);
 
     if (reset_error_state) {
         PyErr_Restore(ptype, pvalue, ptraceback);
index d5da8f440946d9c0e44b9c7a75534dd6999d725b..fae413c85e1c2d1e05666c0b8aa0353b216a4ee2 100644 (file)
@@ -4,7 +4,7 @@
 extern NPY_NO_EXPORT PyBufferProcs array_as_buffer;
 
 NPY_NO_EXPORT void
-_array_dealloc_buffer_info(PyArrayObject *self);
+_dealloc_cached_buffer_info(PyObject *self);
 
 NPY_NO_EXPORT PyArray_Descr*
 _descriptor_from_pep3118_format(char *s);
index c70f8526eb1c2853b68310c871fd3726d4f5e1cf..c6f4847b3616ce6a9b14109dc75e7c0d8c75d135 100644 (file)
@@ -311,6 +311,7 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
             PyErr_Clear();
             dtype = _descriptor_from_pep3118_format(buffer_view.format);
             PyBuffer_Release(&buffer_view);
+            _dealloc_cached_buffer_info(obj);
             if (dtype) {
                 goto promote_types;
             }
@@ -322,6 +323,7 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
             dtype = PyArray_DescrNewFromType(NPY_VOID);
             dtype->elsize = buffer_view.itemsize;
             PyBuffer_Release(&buffer_view);
+            _dealloc_cached_buffer_info(obj);
             goto promote_types;
         }
         else {
@@ -679,6 +681,14 @@ _IsWriteable(PyArrayObject *ap)
         return NPY_FALSE;
     }
     PyBuffer_Release(&view);
+    /*
+     * The first call to PyObject_GetBuffer stores a reference to a struct
+     * _buffer_info_t (from buffer.c, with format, ndim, strides and shape) in
+     * a static dictionary, with id(base) as the key. Usually we release it
+     * after the call to PyBuffer_Release, via a call to
+     * _dealloc_cached_buffer_info, but in this case leave it in the cache to
+     * speed up future calls to _IsWriteable.
+     */
 #else
     if (PyObject_AsWriteBuffer(base, &dummy, &n) < 0) {
         PyErr_Clear();
index 7e92e59916bd9bc5dbe7e5c31273bda42fcb7974..cef3c27ed7463855e9f65ae357defb7033c9671e 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "conversion_utils.h"
 #include "alloc.h"
+#include "buffer.h"
 
 static int
 PyArray_PyIntAsInt_ErrMsg(PyObject *o, const char * msg) NPY_GCC_NONNULL(2);
@@ -185,6 +186,7 @@ PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf)
      * sticks around after the release.
      */
     PyBuffer_Release(&view);
+    _dealloc_cached_buffer_info(obj);
 
     /* Point to the base of the buffer object if present */
     if (PyMemoryView_Check(obj)) {
index 28a41489227548881915b73a49d8a9835c30bf5b..3c61f3b2b862df4eb971f824d8843a3e031f66b3 100644 (file)
@@ -744,12 +744,14 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it,
                 d[i] = buffer_view.shape[i];
             }
             PyBuffer_Release(&buffer_view);
+            _dealloc_cached_buffer_info(obj);
             return 0;
         }
         else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) {
             d[0] = buffer_view.len;
             *maxndim = 1;
             PyBuffer_Release(&buffer_view);
+            _dealloc_cached_buffer_info(obj);
             return 0;
         }
         else {
@@ -2470,6 +2472,7 @@ PyArray_FromInterface(PyObject *origin)
          * sticks around after the release.
          */
         PyBuffer_Release(&view);
+        _dealloc_cached_buffer_info(base);
 #else
         res = PyObject_AsWriteBuffer(base, (void **)&data, &buffer_len);
         if (res < 0) {
@@ -3725,6 +3728,7 @@ PyArray_FromBuffer(PyObject *buf, PyArray_Descr *type,
      * sticks around after the release.
      */
     PyBuffer_Release(&view);
+    _dealloc_cached_buffer_info(buf);
 #else
     if (PyObject_AsWriteBuffer(buf, (void *)&data, &ts) == -1) {
         writeable = 0;
index a0dc98f0e424cff2792e51d7f1b7a4c27fb8e6c7..e3a018356529c011216b03e83679367ae5706a77 100644 (file)
@@ -19,6 +19,7 @@
 #include "descriptor.h"
 #include "alloc.h"
 #include "assert.h"
+#include "buffer.h"
 
 /*
  * offset:    A starting offset.
@@ -1764,6 +1765,7 @@ arraydescr_dealloc(PyArray_Descr *self)
         Py_INCREF(self);
         return;
     }
+    _dealloc_cached_buffer_info((PyObject*)self);
     Py_XDECREF(self->typeobj);
     Py_XDECREF(self->names);
     Py_XDECREF(self->fields);
index cae4273fffa96be9a1b8903f438f0d43be96c610..24962da8a74a337806040ccbeeb90fe2d15e75b9 100644 (file)
@@ -20,6 +20,7 @@
 #include "arrayobject.h"
 #include "mem_overlap.h"
 #include "alloc.h"
+#include "buffer.h"
 
 /*******************  array attribute get and set routines ******************/
 
@@ -143,6 +144,7 @@ array_strides_set(PyArrayObject *self, PyObject *obj)
         offset = PyArray_BYTES(self) - (char *)view.buf;
         numbytes = view.len + offset;
         PyBuffer_Release(&view);
+        _dealloc_cached_buffer_info((PyObject*)new);
     }
 #else
     if (PyArray_BASE(new) &&
@@ -376,6 +378,7 @@ array_data_set(PyArrayObject *self, PyObject *op)
      * sticks around after the release.
      */
     PyBuffer_Release(&view);
+    _dealloc_cached_buffer_info(op);
 #else
     if (PyObject_AsWriteBuffer(op, &buf, &buf_len) < 0) {
         PyErr_Clear();
index a32aa47ab6132c1fdfe4210acf46970aaa50c190..0d7db2d8feb5c49662066739e224fef44c8d1961 100644 (file)
@@ -139,6 +139,7 @@ gentype_alloc(PyTypeObject *type, Py_ssize_t nitems)
 static void
 gentype_dealloc(PyObject *v)
 {
+    _dealloc_cached_buffer_info(v);
     Py_TYPE(v)->tp_free(v);
 }
 
@@ -1863,6 +1864,7 @@ gentype_reduce(PyObject *self, PyObject *NPY_UNUSED(args))
          * sticks around after the release.
          */
         PyBuffer_Release(&view);
+        _dealloc_cached_buffer_info(self);
     }
     else {
         Py_DECREF(ret);
index 52039bd97986525fc9972307c7d8d0773dc68f53..a8cf02336083dfdcf3410597f4f43cd01ef4f425 100644 (file)
@@ -449,6 +449,7 @@ def _check_fill_value(fill_value, ndtype):
     If fill_value is not None, its value is forced to the given dtype.
 
     The result is always a 0d array.
+
     """
     ndtype = np.dtype(ndtype)
     fields = ndtype.fields
@@ -468,17 +469,19 @@ def _check_fill_value(fill_value, ndtype):
                                   dtype=ndtype)
     else:
         if isinstance(fill_value, basestring) and (ndtype.char not in 'OSVU'):
+            # Note this check doesn't work if fill_value is not a scalar
             err_msg = "Cannot set fill value of string with array of dtype %s"
             raise TypeError(err_msg % ndtype)
         else:
             # In case we want to convert 1e20 to int.
+            # Also in case of converting string arrays.
             try:
                 fill_value = np.array(fill_value, copy=False, dtype=ndtype)
-            except OverflowError:
-                # Raise TypeError instead of OverflowError. OverflowError
-                # is seldom used, and the real problem here is that the
-                # passed fill_value is not compatible with the ndtype.
-                err_msg = "Fill value %s overflows dtype %s"
+            except (OverflowError, ValueError):
+                # Raise TypeError instead of OverflowError or ValueError.
+                # OverflowError is seldom used, and the real problem here is
+                # that the passed fill_value is not compatible with the ndtype.
+                err_msg = "Cannot convert fill_value %s to dtype %s"
                 raise TypeError(err_msg % (fill_value, ndtype))
     return np.array(fill_value)
 
@@ -4017,6 +4020,16 @@ class MaskedArray(ndarray):
         check = check.view(type(self))
         check._update_from(self)
         check._mask = mask
+
+        # Cast fill value to bool_ if needed. If it cannot be cast, the
+        # default boolean fill value is used.
+        if check._fill_value is not None:
+            try:
+                fill = _check_fill_value(check._fill_value, np.bool_)
+            except (TypeError, ValueError):
+                fill = _check_fill_value(None, np.bool_)
+            check._fill_value = fill
+
         return check
 
     def __eq__(self, other):
index e935b65e3bbea05ce6778cd1d4e68725cd99298e..a39e7dd3d91b6f6626917f53541618614446e320 100644 (file)
@@ -60,6 +60,11 @@ suppress_copy_mask_on_assignment.filter(
     "setting an item on a masked array which has a shared mask will not copy")
 
 
+# For parametrized numeric testing
+num_dts = [np.dtype(dt_) for dt_ in '?bhilqBHILQefdgFD']
+num_ids = [dt_.char for dt_ in num_dts]
+
+
 class TestMaskedArray(object):
     # Base test class for MaskedArrays.
 
@@ -1413,23 +1418,34 @@ class TestMaskedArrayArithmetic(object):
         # Test the equality of structured arrays
         ndtype = [('A', int), ('B', int)]
         a = array([(1, 1), (2, 2)], mask=[(0, 1), (0, 0)], dtype=ndtype)
+
         test = (a == a)
         assert_equal(test.data, [True, True])
         assert_equal(test.mask, [False, False])
+        assert_(test.fill_value == True)
+
         test = (a == a[0])
         assert_equal(test.data, [True, False])
         assert_equal(test.mask, [False, False])
+        assert_(test.fill_value == True)
+
         b = array([(1, 1), (2, 2)], mask=[(1, 0), (0, 0)], dtype=ndtype)
         test = (a == b)
         assert_equal(test.data, [False, True])
         assert_equal(test.mask, [True, False])
+        assert_(test.fill_value == True)
+
         test = (a[0] == b)
         assert_equal(test.data, [False, False])
         assert_equal(test.mask, [True, False])
+        assert_(test.fill_value == True)
+
         b = array([(1, 1), (2, 2)], mask=[(0, 1), (1, 0)], dtype=ndtype)
         test = (a == b)
         assert_equal(test.data, [True, True])
         assert_equal(test.mask, [False, False])
+        assert_(test.fill_value == True)
+
         # complicated dtype, 2-dimensional array.
         ndtype = [('A', int), ('B', [('BA', int), ('BB', int)])]
         a = array([[(1, (1, 1)), (2, (2, 2))],
@@ -1439,28 +1455,40 @@ class TestMaskedArrayArithmetic(object):
         test = (a[0, 0] == a)
         assert_equal(test.data, [[True, False], [False, False]])
         assert_equal(test.mask, [[False, False], [False, True]])
+        assert_(test.fill_value == True)
 
     def test_ne_on_structured(self):
         # Test the equality of structured arrays
         ndtype = [('A', int), ('B', int)]
         a = array([(1, 1), (2, 2)], mask=[(0, 1), (0, 0)], dtype=ndtype)
+
         test = (a != a)
         assert_equal(test.data, [False, False])
         assert_equal(test.mask, [False, False])
+        assert_(test.fill_value == True)
+
         test = (a != a[0])
         assert_equal(test.data, [False, True])
         assert_equal(test.mask, [False, False])
+        assert_(test.fill_value == True)
+
         b = array([(1, 1), (2, 2)], mask=[(1, 0), (0, 0)], dtype=ndtype)
         test = (a != b)
         assert_equal(test.data, [True, False])
         assert_equal(test.mask, [True, False])
+        assert_(test.fill_value == True)
+
         test = (a[0] != b)
         assert_equal(test.data, [True, True])
         assert_equal(test.mask, [True, False])
+        assert_(test.fill_value == True)
+
         b = array([(1, 1), (2, 2)], mask=[(0, 1), (1, 0)], dtype=ndtype)
         test = (a != b)
         assert_equal(test.data, [False, False])
         assert_equal(test.mask, [False, False])
+        assert_(test.fill_value == True)
+
         # complicated dtype, 2-dimensional array.
         ndtype = [('A', int), ('B', [('BA', int), ('BB', int)])]
         a = array([[(1, (1, 1)), (2, (2, 2))],
@@ -1470,6 +1498,7 @@ class TestMaskedArrayArithmetic(object):
         test = (a[0, 0] != a)
         assert_equal(test.data, [[False, True], [True, True]])
         assert_equal(test.mask, [[False, False], [False, True]])
+        assert_(test.fill_value == True)
 
     def test_eq_ne_structured_extra(self):
         # ensure simple examples are symmetric and make sense.
@@ -1505,6 +1534,120 @@ class TestMaskedArrayArithmetic(object):
                 el_by_el = [m1[name] != m2[name] for name in dt.names]
                 assert_equal(array(el_by_el, dtype=bool).any(), ne_expected)
 
+    @pytest.mark.parametrize('dt', ['S', 'U'])
+    @pytest.mark.parametrize('fill', [None, 'A'])
+    def test_eq_for_strings(self, dt, fill):
+        # Test the equality of structured arrays
+        a = array(['a', 'b'], dtype=dt, mask=[0, 1], fill_value=fill)
+
+        test = (a == a)
+        assert_equal(test.data, [True, True])
+        assert_equal(test.mask, [False, True])
+        assert_(test.fill_value == True)
+
+        test = (a == a[0])
+        assert_equal(test.data, [True, False])
+        assert_equal(test.mask, [False, True])
+        assert_(test.fill_value == True)
+
+        b = array(['a', 'b'], dtype=dt, mask=[1, 0], fill_value=fill)
+        test = (a == b)
+        assert_equal(test.data, [False, False])
+        assert_equal(test.mask, [True, True])
+        assert_(test.fill_value == True)
+
+        # test = (a[0] == b)  # doesn't work in Python2
+        test = (b == a[0])
+        assert_equal(test.data, [False, False])
+        assert_equal(test.mask, [True, False])
+        assert_(test.fill_value == True)
+
+    @pytest.mark.parametrize('dt', ['S', 'U'])
+    @pytest.mark.parametrize('fill', [None, 'A'])
+    def test_ne_for_strings(self, dt, fill):
+        # Test the equality of structured arrays
+        a = array(['a', 'b'], dtype=dt, mask=[0, 1], fill_value=fill)
+
+        test = (a != a)
+        assert_equal(test.data, [False, False])
+        assert_equal(test.mask, [False, True])
+        assert_(test.fill_value == True)
+
+        test = (a != a[0])
+        assert_equal(test.data, [False, True])
+        assert_equal(test.mask, [False, True])
+        assert_(test.fill_value == True)
+
+        b = array(['a', 'b'], dtype=dt, mask=[1, 0], fill_value=fill)
+        test = (a != b)
+        assert_equal(test.data, [True, True])
+        assert_equal(test.mask, [True, True])
+        assert_(test.fill_value == True)
+
+        # test = (a[0] != b)  # doesn't work in Python2
+        test = (b != a[0])
+        assert_equal(test.data, [True, True])
+        assert_equal(test.mask, [True, False])
+        assert_(test.fill_value == True)
+
+    @pytest.mark.parametrize('dt1', num_dts, ids=num_ids)
+    @pytest.mark.parametrize('dt2', num_dts, ids=num_ids)
+    @pytest.mark.parametrize('fill', [None, 1])
+    def test_eq_for_numeric(self, dt1, dt2, fill):
+        # Test the equality of structured arrays
+        a = array([0, 1], dtype=dt1, mask=[0, 1], fill_value=fill)
+
+        test = (a == a)
+        assert_equal(test.data, [True, True])
+        assert_equal(test.mask, [False, True])
+        assert_(test.fill_value == True)
+
+        test = (a == a[0])
+        assert_equal(test.data, [True, False])
+        assert_equal(test.mask, [False, True])
+        assert_(test.fill_value == True)
+
+        b = array([0, 1], dtype=dt2, mask=[1, 0], fill_value=fill)
+        test = (a == b)
+        assert_equal(test.data, [False, False])
+        assert_equal(test.mask, [True, True])
+        assert_(test.fill_value == True)
+
+        # test = (a[0] == b)  # doesn't work in Python2
+        test = (b == a[0])
+        assert_equal(test.data, [False, False])
+        assert_equal(test.mask, [True, False])
+        assert_(test.fill_value == True)
+
+    @pytest.mark.parametrize('dt1', num_dts, ids=num_ids)
+    @pytest.mark.parametrize('dt2', num_dts, ids=num_ids)
+    @pytest.mark.parametrize('fill', [None, 1])
+    def test_ne_for_numeric(self, dt1, dt2, fill):
+        # Test the equality of structured arrays
+        a = array([0, 1], dtype=dt1, mask=[0, 1], fill_value=fill)
+
+        test = (a != a)
+        assert_equal(test.data, [False, False])
+        assert_equal(test.mask, [False, True])
+        assert_(test.fill_value == True)
+
+        test = (a != a[0])
+        assert_equal(test.data, [False, True])
+        assert_equal(test.mask, [False, True])
+        assert_(test.fill_value == True)
+
+        b = array([0, 1], dtype=dt2, mask=[1, 0], fill_value=fill)
+        test = (a != b)
+        assert_equal(test.data, [True, True])
+        assert_equal(test.mask, [True, True])
+        assert_(test.fill_value == True)
+
+        # test = (a[0] != b)  # doesn't work in Python2
+        test = (b != a[0])
+        assert_equal(test.data, [True, True])
+        assert_equal(test.mask, [True, False])
+        assert_(test.fill_value == True)
+
     def test_eq_with_None(self):
         # Really, comparisons with None should not be done, but check them
         # anyway. Note that pep8 will flag these tests.
@@ -5019,11 +5162,8 @@ def test_astype_mask_ordering():
     assert_(x_f2.mask.flags.f_contiguous)
 
 
-dts = [np.dtype(dt_) for dt_ in '?bhilqBHILQefdgFD']
-ids = [dt_.char for dt_ in dts]
-
-@pytest.mark.parametrize('dt1', dts, ids=ids)
-@pytest.mark.parametrize('dt2', dts, ids=ids)
+@pytest.mark.parametrize('dt1', num_dts, ids=num_ids)
+@pytest.mark.parametrize('dt2', num_dts, ids=num_ids)
 @pytest.mark.filterwarnings('ignore::numpy.ComplexWarning')
 def test_astype_basic(dt1, dt2):
     # See gh-12070
index c9a8f8f001486e89c02993fbff20e357019b4911..d0818e66b51ca1d25e15f48d7e097333685a74fe 100644 (file)
@@ -95,10 +95,10 @@ finally:
 #-----------------------------------
 
 # Source of the release notes
-RELEASE_NOTES = 'doc/release/1.15.3-notes.rst'
+RELEASE_NOTES = 'doc/release/1.15.4-notes.rst'
 
 # Start/end of the log (from git)
-LOG_START = 'v1.15.2'
+LOG_START = 'v1.15.3'
 LOG_END = 'maintenance/1.15.x'
 
 
index c48c4429cf7537c36126a4ce7887be9c88cb773c..060e82c547b03b2653c6cda0b75143c94738cf78 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -64,7 +64,7 @@ Operating System :: MacOS
 
 MAJOR               = 1
 MINOR               = 15
-MICRO               = 3
+MICRO               = 4
 ISRELEASED          = True
 VERSION             = '%d.%d.%d' % (MAJOR, MINOR, MICRO)