diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/_add_newdocs.py | 33 | ||||
-rw-r--r-- | numpy/core/numeric.py | 29 | ||||
-rw-r--r-- | numpy/core/records.py | 28 | ||||
-rw-r--r-- | numpy/core/src/multiarray/arrayobject.c | 7 | ||||
-rw-r--r-- | numpy/core/src/multiarray/conversion_utils.c | 14 | ||||
-rw-r--r-- | numpy/core/src/multiarray/conversion_utils.h | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 8 | ||||
-rw-r--r-- | numpy/core/src/multiarray/getset.c | 7 | ||||
-rw-r--r-- | numpy/core/src/multiarray/methods.c | 19 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 5 | ||||
-rw-r--r-- | numpy/core/src/multiarray/nditer_pywrap.c | 11 | ||||
-rw-r--r-- | numpy/core/tests/test_deprecations.py | 17 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 11 | ||||
-rw-r--r-- | numpy/core/tests/test_nditer.py | 10 | ||||
-rw-r--r-- | numpy/core/tests/test_numeric.py | 13 |
15 files changed, 154 insertions, 61 deletions
diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index 253ff64b0..18ab10078 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -152,6 +152,8 @@ add_newdoc('numpy.core', 'flatiter', ('copy', add_newdoc('numpy.core', 'nditer', """ + nditer(op, flags=None, op_flags=None, op_dtypes=None, order='K', casting='safe', op_axes=None, itershape=None, buffersize=0) + Efficient multi-dimensional iterator object to iterate over arrays. To get started using this object, see the :ref:`introductory guide to array iteration <arrays.nditer>`. @@ -3930,8 +3932,8 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('tolist', """)) -tobytesdoc = """ - a.{name}(order='C') +add_newdoc('numpy.core.multiarray', 'ndarray', ('tobytes', """ + a.tobytes(order='C') Construct Python bytes containing the raw data bytes in the array. @@ -3941,11 +3943,11 @@ tobytesdoc = """ unless the F_CONTIGUOUS flag in the array is set, in which case it means 'Fortran' order. - {deprecated} + .. versionadded:: 1.9.0 Parameters ---------- - order : {{'C', 'F', None}}, optional + order : {'C', 'F', None}, optional Order of the data for multidimensional arrays: C, Fortran, or the same as for the original array. @@ -3964,18 +3966,19 @@ tobytesdoc = """ >>> x.tobytes('F') b'\\x00\\x00\\x02\\x00\\x01\\x00\\x03\\x00' - """ + """)) + + +add_newdoc('numpy.core.multiarray', 'ndarray', ('tostring', r""" + a.tostring(order='C') + + A compatibility alias for `tobytes`, with exactly the same behavior. + + Despite its name, it returns `bytes` not `str`\ s. + + .. deprecated:: 1.19.0 + """)) -add_newdoc('numpy.core.multiarray', 'ndarray', - ('tostring', tobytesdoc.format(name='tostring', - deprecated= - 'This function is a compatibility ' - 'alias for tobytes. Despite its ' - 'name it returns bytes not ' - 'strings.'))) -add_newdoc('numpy.core.multiarray', 'ndarray', - ('tobytes', tobytesdoc.format(name='tobytes', - deprecated='.. versionadded:: 1.9.0'))) add_newdoc('numpy.core.multiarray', 'ndarray', ('trace', """ diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index 5e8151e68..83d985a7c 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -384,12 +384,12 @@ def full_like(a, fill_value, dtype=None, order='K', subok=True, shape=None): return res -def _count_nonzero_dispatcher(a, axis=None): +def _count_nonzero_dispatcher(a, axis=None, *, keepdims=None): return (a,) @array_function_dispatch(_count_nonzero_dispatcher) -def count_nonzero(a, axis=None): +def count_nonzero(a, axis=None, *, keepdims=False): """ Counts the number of non-zero values in the array ``a``. @@ -414,6 +414,13 @@ def count_nonzero(a, axis=None): .. versionadded:: 1.12.0 + keepdims : bool, optional + If this is set to True, the axes that are counted are left + in the result as dimensions with size one. With this option, + the result will broadcast correctly against the input array. + + .. versionadded:: 1.19.0 + Returns ------- count : int or array of int @@ -429,15 +436,19 @@ def count_nonzero(a, axis=None): -------- >>> np.count_nonzero(np.eye(4)) 4 - >>> np.count_nonzero([[0,1,7,0,0],[3,0,0,2,19]]) + >>> a = np.array([[0, 1, 7, 0], + ... [3, 0, 2, 19]]) + >>> np.count_nonzero(a) 5 - >>> np.count_nonzero([[0,1,7,0,0],[3,0,0,2,19]], axis=0) - array([1, 1, 1, 1, 1]) - >>> np.count_nonzero([[0,1,7,0,0],[3,0,0,2,19]], axis=1) + >>> np.count_nonzero(a, axis=0) + array([1, 1, 2, 1]) + >>> np.count_nonzero(a, axis=1) array([2, 3]) - + >>> np.count_nonzero(a, axis=1, keepdims=True) + array([[2], + [3]]) """ - if axis is None: + if axis is None and not keepdims: return multiarray.count_nonzero(a) a = asanyarray(a) @@ -448,7 +459,7 @@ def count_nonzero(a, axis=None): else: a_bool = a.astype(np.bool_, copy=False) - return a_bool.sum(axis=axis, dtype=np.intp) + return a_bool.sum(axis=axis, dtype=np.intp, keepdims=keepdims) @set_module('numpy') diff --git a/numpy/core/records.py b/numpy/core/records.py index b1ee1aa11..9c3530787 100644 --- a/numpy/core/records.py +++ b/numpy/core/records.py @@ -157,8 +157,7 @@ class format_parser: def __init__(self, formats, names, titles, aligned=False, byteorder=None): self._parseFormats(formats, aligned) self._setfieldnames(names, titles) - self._createdescr(byteorder) - self.dtype = self._descr + self._createdtype(byteorder) def _parseFormats(self, formats, aligned=False): """ Parse the field formats """ @@ -217,8 +216,8 @@ class format_parser: if self._nfields > len(titles): self._titles += [None] * (self._nfields - len(titles)) - def _createdescr(self, byteorder): - descr = sb.dtype({ + def _createdtype(self, byteorder): + dtype = sb.dtype({ 'names': self._names, 'formats': self._f_formats, 'offsets': self._offsets, @@ -226,9 +225,10 @@ class format_parser: }) if byteorder is not None: byteorder = _byteorderconv[byteorder[0]] - descr = descr.newbyteorder(byteorder) + dtype = dtype.newbyteorder(byteorder) + + self.dtype = dtype - self._descr = descr class record(nt.void): """A data-type scalar that allows field access as attribute lookup. @@ -432,7 +432,7 @@ class recarray(ndarray): if dtype is not None: descr = sb.dtype(dtype) else: - descr = format_parser(formats, names, titles, aligned, byteorder)._descr + descr = format_parser(formats, names, titles, aligned, byteorder).dtype if buf is None: self = ndarray.__new__(subtype, shape, (record, descr), order=order) @@ -625,11 +625,9 @@ def fromarrays(arrayList, dtype=None, shape=None, formats=None, if dtype is not None: descr = sb.dtype(dtype) - _names = descr.names else: - parsed = format_parser(formats, names, titles, aligned, byteorder) - _names = parsed._names - descr = parsed._descr + descr = format_parser(formats, names, titles, aligned, byteorder).dtype + _names = descr.names # Determine shape from data-type. if len(descr) != len(arrayList): @@ -694,7 +692,7 @@ def fromrecords(recList, dtype=None, shape=None, formats=None, names=None, if dtype is not None: descr = sb.dtype((record, dtype)) else: - descr = format_parser(formats, names, titles, aligned, byteorder)._descr + descr = format_parser(formats, names, titles, aligned, byteorder).dtype try: retval = sb.array(recList, dtype=descr) @@ -737,7 +735,7 @@ def fromstring(datastring, dtype=None, shape=None, offset=0, formats=None, if dtype is not None: descr = sb.dtype(dtype) else: - descr = format_parser(formats, names, titles, aligned, byteorder)._descr + descr = format_parser(formats, names, titles, aligned, byteorder).dtype itemsize = descr.itemsize @@ -810,7 +808,7 @@ def fromfile(fd, dtype=None, shape=None, offset=0, formats=None, if dtype is not None: descr = sb.dtype(dtype) else: - descr = format_parser(formats, names, titles, aligned, byteorder)._descr + descr = format_parser(formats, names, titles, aligned, byteorder).dtype itemsize = descr.itemsize @@ -851,7 +849,7 @@ def array(obj, dtype=None, shape=None, offset=0, strides=None, formats=None, dtype = sb.dtype(dtype) elif formats is not None: dtype = format_parser(formats, names, titles, - aligned, byteorder)._descr + aligned, byteorder).dtype else: kwds = {'formats': formats, 'names': names, diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c index 16896aa12..dedaf38eb 100644 --- a/numpy/core/src/multiarray/arrayobject.c +++ b/numpy/core/src/multiarray/arrayobject.c @@ -41,6 +41,7 @@ maintainer email: oliphant.travis@ieee.org #include "arraytypes.h" #include "scalartypes.h" #include "arrayobject.h" +#include "conversion_utils.h" #include "ctors.h" #include "methods.h" #include "descriptor.h" @@ -1624,7 +1625,7 @@ array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) PyArray_Descr *descr = NULL; int itemsize; PyArray_Dims dims = {NULL, 0}; - PyArray_Dims strides = {NULL, 0}; + PyArray_Dims strides = {NULL, -1}; PyArray_Chunk buffer; npy_longlong offset = 0; NPY_ORDER order = NPY_CORDER; @@ -1645,7 +1646,7 @@ array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) PyArray_BufferConverter, &buffer, &offset, - &PyArray_IntpConverter, + &PyArray_OptionalIntpConverter, &strides, &PyArray_OrderConverter, &order)) { @@ -1660,7 +1661,7 @@ array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) itemsize = descr->elsize; - if (strides.ptr != NULL) { + if (strides.len != -1) { npy_intp nb, off; if (strides.len != dims.len) { PyErr_SetString(PyExc_ValueError, diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index 484a13134..260ae7080 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -137,6 +137,20 @@ PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq) return NPY_SUCCEED; } +/* + * Like PyArray_IntpConverter, but leaves `seq` untouched if `None` is passed + * rather than treating `None` as `()`. + */ +NPY_NO_EXPORT int +PyArray_OptionalIntpConverter(PyObject *obj, PyArray_Dims *seq) +{ + if (obj == Py_None) { + return NPY_SUCCEED; + } + + return PyArray_IntpConverter(obj, seq); +} + /*NUMPY_API * Get buffer chunk from object * diff --git a/numpy/core/src/multiarray/conversion_utils.h b/numpy/core/src/multiarray/conversion_utils.h index 9bf712c3b..bee0c6064 100644 --- a/numpy/core/src/multiarray/conversion_utils.h +++ b/numpy/core/src/multiarray/conversion_utils.h @@ -7,6 +7,9 @@ NPY_NO_EXPORT int PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq); NPY_NO_EXPORT int +PyArray_OptionalIntpConverter(PyObject *obj, PyArray_Dims *seq); + +NPY_NO_EXPORT int PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf); NPY_NO_EXPORT int diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index a23510c8b..12bf9eace 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -1211,8 +1211,8 @@ PyArray_NewFromDescrAndBase( * NPY_ANYORDER - Fortran if prototype is Fortran, C otherwise. * NPY_KEEPORDER - Keeps the axis ordering of prototype. * dtype - If not NULL, overrides the data type of the result. - * ndim - If not 0 and dims not NULL, overrides the shape of the result. - * dims - If not NULL and ndim not 0, overrides the shape of the result. + * ndim - If not -1, overrides the shape of the result. + * dims - If ndim is not -1, overrides the shape of the result. * subok - If 1, use the prototype's array subtype, otherwise * always create a base-class array. * @@ -1225,7 +1225,7 @@ PyArray_NewLikeArrayWithShape(PyArrayObject *prototype, NPY_ORDER order, { PyObject *ret = NULL; - if (dims == NULL) { + if (ndim == -1) { ndim = PyArray_NDIM(prototype); dims = PyArray_DIMS(prototype); } @@ -1322,7 +1322,7 @@ NPY_NO_EXPORT PyObject * PyArray_NewLikeArray(PyArrayObject *prototype, NPY_ORDER order, PyArray_Descr *dtype, int subok) { - return PyArray_NewLikeArrayWithShape(prototype, order, dtype, 0, NULL, subok); + return PyArray_NewLikeArrayWithShape(prototype, order, dtype, -1, NULL, subok); } /*NUMPY_API diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c index 8c1b7f943..80a1cd4a1 100644 --- a/numpy/core/src/multiarray/getset.c +++ b/numpy/core/src/multiarray/getset.c @@ -13,6 +13,7 @@ #include "npy_import.h" #include "common.h" +#include "conversion_utils.h" #include "ctors.h" #include "scalartypes.h" #include "descriptor.h" @@ -110,7 +111,7 @@ array_strides_get(PyArrayObject *self) static int array_strides_set(PyArrayObject *self, PyObject *obj) { - PyArray_Dims newstrides = {NULL, 0}; + PyArray_Dims newstrides = {NULL, -1}; PyArrayObject *new; npy_intp numbytes = 0; npy_intp offset = 0; @@ -123,8 +124,8 @@ array_strides_set(PyArrayObject *self, PyObject *obj) "Cannot delete array strides"); return -1; } - if (!PyArray_IntpConverter(obj, &newstrides) || - newstrides.ptr == NULL) { + if (!PyArray_OptionalIntpConverter(obj, &newstrides) || + newstrides.len == -1) { PyErr_SetString(PyExc_TypeError, "invalid strides"); return -1; } diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c index ebdf8a4cd..7bfbeca15 100644 --- a/numpy/core/src/multiarray/methods.c +++ b/numpy/core/src/multiarray/methods.c @@ -566,6 +566,23 @@ array_tobytes(PyArrayObject *self, PyObject *args, PyObject *kwds) return PyArray_ToString(self, order); } +static PyObject * +array_tostring(PyArrayObject *self, PyObject *args, PyObject *kwds) +{ + NPY_ORDER order = NPY_CORDER; + static char *kwlist[] = {"order", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:tostring", kwlist, + PyArray_OrderConverter, &order)) { + return NULL; + } + /* 2020-03-30, NumPy 1.19 */ + if (DEPRECATE("tostring() is deprecated. Use tobytes() instead.") < 0) { + return NULL; + } + return PyArray_ToString(self, order); +} + /* This should grow an order= keyword to be consistent */ @@ -2844,7 +2861,7 @@ NPY_NO_EXPORT PyMethodDef array_methods[] = { (PyCFunction)array_tolist, METH_VARARGS, NULL}, {"tostring", - (PyCFunction)array_tobytes, + (PyCFunction)array_tostring, METH_VARARGS | METH_KEYWORDS, NULL}, {"trace", (PyCFunction)array_trace, diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 2856a123f..9e8022abd 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -1857,14 +1857,15 @@ array_empty_like(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) NPY_ORDER order = NPY_KEEPORDER; PyArrayObject *ret = NULL; int subok = 1; - PyArray_Dims shape = {NULL, 0}; + /* -1 is a special value meaning "not specified" */ + PyArray_Dims shape = {NULL, -1}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&iO&:empty_like", kwlist, &PyArray_Converter, &prototype, &PyArray_DescrConverter2, &dtype, &PyArray_OrderConverter, &order, &subok, - &PyArray_IntpConverter, &shape)) { + &PyArray_OptionalIntpConverter, &shape)) { goto fail; } /* steals the reference to dtype if it's not NULL */ diff --git a/numpy/core/src/multiarray/nditer_pywrap.c b/numpy/core/src/multiarray/nditer_pywrap.c index add40f460..505c5a841 100644 --- a/numpy/core/src/multiarray/nditer_pywrap.c +++ b/numpy/core/src/multiarray/nditer_pywrap.c @@ -17,6 +17,7 @@ #include "npy_pycompat.h" #include "alloc.h" #include "common.h" +#include "conversion_utils.h" #include "ctors.h" /* Functions not part of the public NumPy C API */ @@ -748,7 +749,7 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds) int oa_ndim = -1; int op_axes_arrays[NPY_MAXARGS][NPY_MAXDIMS]; int *op_axes[NPY_MAXARGS]; - PyArray_Dims itershape = {NULL, 0}; + PyArray_Dims itershape = {NULL, -1}; int buffersize = 0; if (self->iter != NULL) { @@ -765,7 +766,7 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds) npyiter_order_converter, &order, PyArray_CastingConverter, &casting, &op_axes_in, - PyArray_IntpConverter, &itershape, + PyArray_OptionalIntpConverter, &itershape, &buffersize)) { npy_free_cache_dim_obj(itershape); return -1; @@ -800,7 +801,7 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds) } } - if (itershape.len > 0) { + if (itershape.len != -1) { if (oa_ndim == -1) { oa_ndim = itershape.len; memset(op_axes, 0, sizeof(op_axes[0]) * nop); @@ -812,10 +813,6 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds) goto fail; } } - else if (itershape.ptr != NULL) { - npy_free_cache_dim_obj(itershape); - itershape.ptr = NULL; - } self->iter = NpyIter_AdvancedNew(nop, op, flags, order, casting, op_flags, op_request_dtypes, diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index d2cf315a9..5d35bde6c 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -8,6 +8,7 @@ import operator import warnings import pytest import tempfile +import re import numpy as np from numpy.testing import ( @@ -548,6 +549,22 @@ def test_deprecate_ragged_arrays(): np.array(arg) +class TestToString(_DeprecationTestCase): + # 2020-03-06 1.19.0 + message = re.escape("tostring() is deprecated. Use tobytes() instead.") + + def test_tostring(self): + arr = np.array(list(b"test\xFF"), dtype=np.uint8) + self.assert_deprecated(arr.tostring) + + def test_tostring_matches_tobytes(self): + arr = np.array(list(b"test\xFF"), dtype=np.uint8) + b = arr.tobytes() + with assert_warns(DeprecationWarning): + s = arr.tostring() + assert s == b + + class TestDTypeCoercion(_DeprecationTestCase): # 2020-02-06 1.19.0 message = "Converting .* to a dtype .*is deprecated" diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 0d035388d..5515ff446 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -356,6 +356,11 @@ class TestAttributes: a.strides = 1 a[::2].strides = 2 + # test 0d + arr_0d = np.array(0) + arr_0d.strides = () + assert_raises(TypeError, set_strides, arr_0d, None) + def test_fill(self): for t in "?bhilqpBHILQPfdgFDGO": x = np.empty((3, 2, 1), t) @@ -679,6 +684,12 @@ class TestZeroRank: y[()] = 6 assert_equal(x[()], 6) + # strides and shape must be the same length + with pytest.raises(ValueError): + np.ndarray((2,), strides=()) + with pytest.raises(ValueError): + np.ndarray((), strides=(2,)) + def test_output(self): x = np.array(2) assert_raises(ValueError, np.add, x, [1], x) diff --git a/numpy/core/tests/test_nditer.py b/numpy/core/tests/test_nditer.py index 24272bb0d..c106c528d 100644 --- a/numpy/core/tests/test_nditer.py +++ b/numpy/core/tests/test_nditer.py @@ -2688,7 +2688,15 @@ def test_0d_iter(): i = nditer(np.arange(5), ['multi_index'], [['readonly']], op_axes=[()]) assert_equal(i.ndim, 0) assert_equal(len(i), 1) - # note that itershape=(), still behaves like None due to the conversions + + i = nditer(np.arange(5), ['multi_index'], [['readonly']], + op_axes=[()], itershape=()) + assert_equal(i.ndim, 0) + assert_equal(len(i), 1) + + # passing an itershape alone is not enough, the op_axes are also needed + with assert_raises(ValueError): + nditer(np.arange(5), ['multi_index'], [['readonly']], itershape=()) # Test a more complex buffered casting case (same as another test above) sdt = [('a', 'f4'), ('b', 'i8'), ('c', 'c8', (2, 3)), ('d', 'O')] diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 05f59d9dc..1bcfe50a4 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -1201,6 +1201,17 @@ class TestNonzero: a = np.array([[0, 0, 1], [1, 0, 1]]) assert_equal(np.count_nonzero(a, axis=()), a.astype(bool)) + def test_countnonzero_keepdims(self): + a = np.array([[0, 0, 1, 0], + [0, 3, 5, 0], + [7, 9, 2, 0]]) + assert_equal(np.count_nonzero(a, axis=0, keepdims=True), + [[1, 2, 3, 0]]) + assert_equal(np.count_nonzero(a, axis=1, keepdims=True), + [[1], [2], [3]]) + assert_equal(np.count_nonzero(a, keepdims=True), + [[6]]) + def test_array_method(self): # Tests that the array method # call to nonzero works @@ -2457,7 +2468,7 @@ class TestLikeFuncs: (np.arange(24).reshape(2, 3, 4).swapaxes(0, 1), None), (np.arange(24).reshape(4, 3, 2).swapaxes(0, 1), '?'), ] - self.shapes = [(5,), (5,6,), (5,6,7,)] + self.shapes = [(), (5,), (5,6,), (5,6,7,)] def compare_array_value(self, dz, value, fill_value): if value is not None: |