diff options
-rw-r--r-- | doc/release/1.10.3-notes.rst | 39 | ||||
-rw-r--r-- | doc/release/1.11.0-notes.rst | 7 | ||||
-rw-r--r-- | numpy/add_newdocs.py | 31 | ||||
-rw-r--r-- | numpy/core/fromnumeric.py | 6 | ||||
-rw-r--r-- | numpy/core/records.py | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarray/datetime_busday.c | 2 | ||||
-rw-r--r-- | numpy/core/tests/test_datetime.py | 6 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 102 | ||||
-rw-r--r-- | numpy/core/tests/test_records.py | 9 | ||||
-rw-r--r-- | numpy/lib/user_array.py | 17 | ||||
-rw-r--r-- | numpy/ma/core.py | 6 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 1 | ||||
-rw-r--r-- | numpy/random/mtrand/mtrand.pyx | 10 | ||||
-rw-r--r-- | numpy/testing/utils.py | 3 | ||||
-rwxr-xr-x | tools/travis-test.sh | 3 |
15 files changed, 216 insertions, 32 deletions
diff --git a/doc/release/1.10.3-notes.rst b/doc/release/1.10.3-notes.rst new file mode 100644 index 000000000..77b4d0a58 --- /dev/null +++ b/doc/release/1.10.3-notes.rst @@ -0,0 +1,39 @@ +NumPy 1.10.3 Release Notes +************************** + +This release is a bugfix source release motivated by a segfault regression. +No windows binaries are provided for this release, as there appear to be +bugs in the toolchain we use to generate those files. Hopefully that +problem will be fixed for the next release. In the meantime, we suggest +using one of the providers of windows binaries. + +Compatibility notes +=================== + +* The trace function now calls the trace method on subclasses of ndarray, + except for matrix, for which the current behavior is preserved. This is + to help with the units package of AstroPy and hopefully will not cause + problems. + +Issues Fixed +============ + +* gh-6922 BUG: numpy.recarray.sort segfaults on Windows. +* gh-6937 BUG: busday_offset does the wrong thing with modifiedpreceding roll. +* gh-6949 BUG: Type is lost when slicing a subclass of recarray. + +Merged PRs +========== + +The following PRs have been merged into 1.10.3. When the PR is a backport, +the PR number for the original PR against master is listed. + +* gh-6840 TST: Update travis testing script in 1.10.x +* gh-6843 BUG: Fix use of python 3 only FileNotFoundError in test_f2py. +* gh-6884 REL: Update pavement.py and setup.py to reflect current version. +* gh-6916 BUG: Fix test_f2py so it runs correctly in runtests.py. +* gh-6924 BUG: Fix segfault gh-6922. +* gh-6942 Fix datetime roll='modifiedpreceding' bug. +* gh-6943 DOC,BUG: Fix some latex generation problems. +* gh-6950 BUG trace is not subclass aware, np.trace(ma) != ma.trace(). +* gh-6952 BUG recarray slices should preserve subclass. diff --git a/doc/release/1.11.0-notes.rst b/doc/release/1.11.0-notes.rst index da8ec3470..e66e680d3 100644 --- a/doc/release/1.11.0-notes.rst +++ b/doc/release/1.11.0-notes.rst @@ -169,3 +169,10 @@ parameter in methods like ```array.flatten``` or ```array.ravel``` that were not one of the following: 'C', 'F', 'A', 'K' (note that all of these possible values are unicode- and case-insensitive). Such behaviour will not be allowed in future releases. + +Random number generator in the ``testing`` namespace +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Python standard library random number generator was previously exposed in the +``testing`` namespace as ``testing.rand``. Using this generator is not +recommended and it will be removed in a future release. Use generators from +``numpy.random`` namespace instead. diff --git a/numpy/add_newdocs.py b/numpy/add_newdocs.py index 7eef07c4a..e79720c77 100644 --- a/numpy/add_newdocs.py +++ b/numpy/add_newdocs.py @@ -3888,13 +3888,13 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('newbyteorder', ---------- new_order : string, optional Byte order to force; a value from the byte order specifications - above. `new_order` codes can be any of:: + below. `new_order` codes can be any of: - * 'S' - swap dtype from current to opposite endian - * {'<', 'L'} - little endian - * {'>', 'B'} - big endian - * {'=', 'N'} - native order - * {'|', 'I'} - ignore (no change to byte order) + * 'S' - swap dtype from current to opposite endian + * {'<', 'L'} - little endian + * {'>', 'B'} - big endian + * {'=', 'N'} - native order + * {'|', 'I'} - ignore (no change to byte order) The default value ('S') results in swapping the current byte order. The code does a case-insensitive check on the first @@ -6359,16 +6359,15 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('newbyteorder', Parameters ---------- new_order : string, optional - Byte order to force; a value from the byte order - specifications below. The default value ('S') results in - swapping the current byte order. - `new_order` codes can be any of:: + Byte order to force; a value from the byte order specifications + below. The default value ('S') results in swapping the current + byte order. `new_order` codes can be any of: - * 'S' - swap dtype from current to opposite endian - * {'<', 'L'} - little endian - * {'>', 'B'} - big endian - * {'=', 'N'} - native order - * {'|', 'I'} - ignore (no change to byte order) + * 'S' - swap dtype from current to opposite endian + * {'<', 'L'} - little endian + * {'>', 'B'} - big endian + * {'=', 'N'} - native order + * {'|', 'I'} - ignore (no change to byte order) The code does a case-insensitive check on the first letter of `new_order` for these alternatives. For example, any of '>' @@ -7231,10 +7230,10 @@ add_newdoc('numpy.core.numerictypes', 'generic', ('newbyteorder', The `new_order` code can be any from the following: + * 'S' - swap dtype from current to opposite endian * {'<', 'L'} - little endian * {'>', 'B'} - big endian * {'=', 'N'} - native order - * 'S' - swap dtype from current to opposite endian * {'|', 'I'} - ignore (no change to byte order) Parameters diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py index 362c29cb8..a2937c5c5 100644 --- a/numpy/core/fromnumeric.py +++ b/numpy/core/fromnumeric.py @@ -1367,7 +1367,11 @@ def trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None): (2, 3) """ - return asarray(a).trace(offset, axis1, axis2, dtype, out) + if isinstance(a, np.matrix): + # Get trace of matrix via an array to preserve backward compatibility. + return asarray(a).trace(offset, axis1, axis2, dtype, out) + else: + return asanyarray(a).trace(offset, axis1, axis2, dtype, out) def ravel(a, order='C'): diff --git a/numpy/core/records.py b/numpy/core/records.py index ca6070cf7..9f5dcc811 100644 --- a/numpy/core/records.py +++ b/numpy/core/records.py @@ -425,7 +425,7 @@ class recarray(ndarray): def __array_finalize__(self, obj): if self.dtype.type is not record: - # if self.dtype is not np.record, invoke __setattr__ which will + # if self.dtype is not np.record, invoke __setattr__ which will # convert it to a record if it is a void dtype. self.dtype = self.dtype @@ -496,13 +496,13 @@ class recarray(ndarray): return self.setfield(val, *res) def __getitem__(self, indx): - obj = ndarray.__getitem__(self, indx) + obj = super(recarray, self).__getitem__(indx) # copy behavior of getattr, except that here # we might also be returning a single element if isinstance(obj, ndarray): if obj.dtype.fields: - obj = obj.view(recarray) + obj = obj.view(type(self)) if issubclass(obj.dtype.type, nt.void): return obj.view(dtype=(self.dtype.type, obj.dtype)) return obj diff --git a/numpy/core/src/multiarray/datetime_busday.c b/numpy/core/src/multiarray/datetime_busday.c index 331e10496..4fade4d20 100644 --- a/numpy/core/src/multiarray/datetime_busday.c +++ b/numpy/core/src/multiarray/datetime_busday.c @@ -889,7 +889,7 @@ PyArray_BusDayRollConverter(PyObject *roll_in, NPY_BUSDAY_ROLL *roll) break; case 'p': if (strcmp(str, "modifiedpreceding") == 0) { - *roll = NPY_BUSDAY_MODIFIEDFOLLOWING; + *roll = NPY_BUSDAY_MODIFIEDPRECEDING; goto finish; } break; diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index 563aa48fb..8a8eafee8 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -1524,6 +1524,12 @@ class TestDateTime(TestCase): assert_equal( np.busday_offset('2010-10-30', 0, roll='modifiedpreceding'), np.datetime64('2010-10-29')) + assert_equal( + np.busday_offset('2010-10-16', 0, roll='modifiedfollowing'), + np.datetime64('2010-10-18')) + assert_equal( + np.busday_offset('2010-10-16', 0, roll='modifiedpreceding'), + np.datetime64('2010-10-15')) # roll='raise' by default assert_raises(ValueError, np.busday_offset, '2011-06-04', 0) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index d03c5f547..c66e49e5f 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1936,7 +1936,80 @@ class TestMethods(TestCase): a = np.array([[1, 0], [0, 1]]) b = np.array([[0, 1], [1, 0]]) c = np.array([[9, 1], [1, -9]]) - + d = np.arange(24).reshape(4, 6) + ddt = np.array( + [[ 55, 145, 235, 325], + [ 145, 451, 757, 1063], + [ 235, 757, 1279, 1801], + [ 325, 1063, 1801, 2539]] + ) + dtd = np.array( + [[504, 540, 576, 612, 648, 684], + [540, 580, 620, 660, 700, 740], + [576, 620, 664, 708, 752, 796], + [612, 660, 708, 756, 804, 852], + [648, 700, 752, 804, 856, 908], + [684, 740, 796, 852, 908, 964]] + ) + + + # gemm vs syrk optimizations + for et in [np.float32, np.float64, np.complex64, np.complex128]: + eaf = a.astype(et) + assert_equal(np.dot(eaf, eaf), eaf) + assert_equal(np.dot(eaf.T, eaf), eaf) + assert_equal(np.dot(eaf, eaf.T), eaf) + assert_equal(np.dot(eaf.T, eaf.T), eaf) + assert_equal(np.dot(eaf.T.copy(), eaf), eaf) + assert_equal(np.dot(eaf, eaf.T.copy()), eaf) + assert_equal(np.dot(eaf.T.copy(), eaf.T.copy()), eaf) + + # syrk validations + for et in [np.float32, np.float64, np.complex64, np.complex128]: + eaf = a.astype(et) + ebf = b.astype(et) + assert_equal(np.dot(ebf, ebf), eaf) + assert_equal(np.dot(ebf.T, ebf), eaf) + assert_equal(np.dot(ebf, ebf.T), eaf) + assert_equal(np.dot(ebf.T, ebf.T), eaf) + + # syrk - different shape, stride, and view validations + for et in [np.float32, np.float64, np.complex64, np.complex128]: + edf = d.astype(et) + assert_equal( + np.dot(edf[::-1, :], edf.T), + np.dot(edf[::-1, :].copy(), edf.T.copy()) + ) + assert_equal( + np.dot(edf[:, ::-1], edf.T), + np.dot(edf[:, ::-1].copy(), edf.T.copy()) + ) + assert_equal( + np.dot(edf, edf[::-1, :].T), + np.dot(edf, edf[::-1, :].T.copy()) + ) + assert_equal( + np.dot(edf, edf[:, ::-1].T), + np.dot(edf, edf[:, ::-1].T.copy()) + ) + assert_equal( + np.dot(edf[:edf.shape[0] // 2, :], edf[::2, :].T), + np.dot(edf[:edf.shape[0] // 2, :].copy(), edf[::2, :].T.copy()) + ) + assert_equal( + np.dot(edf[::2, :], edf[:edf.shape[0] // 2, :].T), + np.dot(edf[::2, :].copy(), edf[:edf.shape[0] // 2, :].T.copy()) + ) + + # syrk - different shape + for et in [np.float32, np.float64, np.complex64, np.complex128]: + edf = d.astype(et) + eddtf = ddt.astype(et) + edtdf = dtd.astype(et) + assert_equal(np.dot(edf, edf.T), eddtf) + assert_equal(np.dot(edf.T, edf), edtdf) + + # function versus methods assert_equal(np.dot(a, b), a.dot(b)) assert_equal(np.dot(np.dot(a, b), c), a.dot(b).dot(c)) @@ -2010,6 +2083,33 @@ class TestMethods(TestCase): a.diagonal() assert_(sys.getrefcount(a) < 50) + def test_trace(self): + a = np.arange(12).reshape((3, 4)) + assert_equal(a.trace(), 15) + assert_equal(a.trace(0), 15) + assert_equal(a.trace(1), 18) + assert_equal(a.trace(-1), 13) + + b = np.arange(8).reshape((2, 2, 2)) + assert_equal(b.trace(), [6, 8]) + assert_equal(b.trace(0), [6, 8]) + assert_equal(b.trace(1), [2, 3]) + assert_equal(b.trace(-1), [4, 5]) + assert_equal(b.trace(0, 0, 1), [6, 8]) + assert_equal(b.trace(0, 0, 2), [5, 9]) + assert_equal(b.trace(0, 1, 2), [3, 11]) + assert_equal(b.trace(offset=1, axis1=0, axis2=2), [1, 3]) + + def test_trace_subclass(self): + # The class would need to overwrite trace to ensure single-element + # output also has the right subclass. + class MyArray(np.ndarray): + pass + + b = np.arange(8).reshape((2, 2, 2)).view(MyArray) + t = b.trace() + assert isinstance(t, MyArray) + def test_put(self): icodes = np.typecodes['AllInteger'] fcodes = np.typecodes['AllFloat'] diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py index e0f0a3a8f..9fbdf51d6 100644 --- a/numpy/core/tests/test_records.py +++ b/numpy/core/tests/test_records.py @@ -122,13 +122,20 @@ class TestFromrecords(TestCase): assert_equal(rv.dtype.type, np.record) #check that getitem also preserves np.recarray and np.record - r = np.rec.array(np.ones(4, dtype=[('a', 'i4'), ('b', 'i4'), + r = np.rec.array(np.ones(4, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'i4,i4')])) assert_equal(r['c'].dtype.type, np.record) assert_equal(type(r['c']), np.recarray) assert_equal(r[['a', 'b']].dtype.type, np.record) assert_equal(type(r[['a', 'b']]), np.recarray) + #and that it preserves subclasses (gh-6949) + class C(np.recarray): + pass + + c = r.view(C) + assert_equal(type(c['c']), C) + # check that accessing nested structures keep record type, but # not for subarrays, non-void structures, non-structured voids test_dtype = [('a', 'f4,f4'), ('b', 'V8'), ('c', ('f4',2)), diff --git a/numpy/lib/user_array.py b/numpy/lib/user_array.py index bb5bec628..3103da57b 100644 --- a/numpy/lib/user_array.py +++ b/numpy/lib/user_array.py @@ -1,5 +1,6 @@ """ Standard container-class for easy multiple-inheritance. + Try to inherit from the ndarray instead of using this class as this is not complete. @@ -16,7 +17,19 @@ from numpy.compat import long class container(object): + """ + container(data, dtype=None, copy=True) + + Standard container-class for easy multiple-inheritance. + + Methods + ------- + copy + tostring + byteswap + astype + """ def __init__(self, data, dtype=None, copy=True): self.array = array(data, dtype, copy=copy) @@ -219,15 +232,19 @@ class container(object): return self._rc(greater_equal(self.array, other)) def copy(self): + "" return self._rc(self.array.copy()) def tostring(self): + "" return self.array.tostring() def byteswap(self): + "" return self._rc(self.array.byteswap()) def astype(self, typecode): + "" return self._rc(self.array.astype(typecode)) def _rc(self, a): diff --git a/numpy/ma/core.py b/numpy/ma/core.py index de716a669..9b0b1cc79 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -3526,6 +3526,8 @@ class MaskedArray(ndarray): def filled(self, fill_value=None): """ Return a copy of self, with masked values filled with a given value. + **However**, if there are no masked values to fill, self will be + returned instead as an ndarray. Parameters ---------- @@ -3537,7 +3539,9 @@ class MaskedArray(ndarray): ------- filled_array : ndarray A copy of ``self`` with invalid entries replaced by *fill_value* - (be it the function argument or the attribute of ``self``. + (be it the function argument or the attribute of ``self``), or + ``self`` itself as an ndarray if there are no invalid entries to + be replaced. Notes ----- diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index 020bf1e62..adbbb26d1 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -3198,6 +3198,7 @@ class TestMaskedArrayMathMethods(TestCase): assert_almost_equal(mX.trace(), X.trace() - sum(mXdiag.mask * X.diagonal(), axis=0)) + assert_equal(np.trace(mX), mX.trace()) def test_dot(self): # Tests dot on MaskedArrays. diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx index 489cc9e6e..3a4e132ec 100644 --- a/numpy/random/mtrand/mtrand.pyx +++ b/numpy/random/mtrand/mtrand.pyx @@ -681,19 +681,15 @@ def _rand_int32(low, high, size, rngstate): Return random np.int32 integers between `low` and `high`, inclusive. Return random integers from the "discrete uniform" distribution in the - closed interval [`low`, `high`). If `high` is None (the default), - then results are from [0, `low`). On entry the arguments are presumed + closed interval [`low`, `high`]. On entry the arguments are presumed to have been validated for size and order for the np.int32 type. Parameters ---------- low : int - Lowest (signed) integer to be drawn from the distribution (unless - ``high=None``, in which case this parameter is the *highest* such - integer). + Lowest (signed) integer to be drawn from the distribution. high : int - If provided, the largest (signed) integer to be drawn from the - distribution (see above for behavior if ``high=None``). + Highest (signed) integer to be drawn from the distribution. size : int or tuple of ints Output shape. If the given shape is, e.g., ``(m, n, k)``, then ``m * n * k`` samples are drawn. Default is None, in which case a diff --git a/numpy/testing/utils.py b/numpy/testing/utils.py index 0c4ebe1b9..f545cd3c2 100644 --- a/numpy/testing/utils.py +++ b/numpy/testing/utils.py @@ -16,6 +16,7 @@ from tempfile import mkdtemp, mkstemp from .nosetester import import_nose from numpy.core import float32, empty, arange, array_repr, ndarray +from numpy.lib.utils import deprecate if sys.version_info[0] >= 3: from io import StringIO @@ -122,6 +123,8 @@ def gisinf(x): raise TypeError("isinf not supported for this type") return st +@deprecate(message="numpy.testing.rand is deprecated in numpy 1.11. " + "Use numpy.random.rand instead.") def rand(*args): """Returns an array of random numbers with the given shape. diff --git a/tools/travis-test.sh b/tools/travis-test.sh index 40e266b26..d105c15c7 100755 --- a/tools/travis-test.sh +++ b/tools/travis-test.sh @@ -25,7 +25,8 @@ if [ -n "$PYTHON_OO" ]; then fi # make some warnings fatal, mostly to match windows compilers -werrors="-Werror=declaration-after-statement -Werror=vla -Werror=nonnull" +werrors="-Werror=declaration-after-statement -Werror=vla " +werrors+="-Werror=nonnull -Werror=pointer-arith" setup_base() { |