diff options
author | Matti Picus <matti.picus@gmail.com> | 2021-03-21 07:48:10 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-21 07:48:10 +0200 |
commit | 9e47444aa66ae055c3ef5a01d579d2eb52606f20 (patch) | |
tree | f96ff12e2a8072d3ea47624922914f44aa463f00 | |
parent | 9629cd9221766b087478d3dceca8c260b76e82b7 (diff) | |
parent | 40b8ba3f43e28cb543bbb1d5aff095da264bafd8 (diff) | |
download | numpy-9e47444aa66ae055c3ef5a01d579d2eb52606f20.tar.gz |
Merge pull request #18642 from seberg/splitup-faster-argparsing-optimize-asarray
ENH: Use new argument parsing for array creation functions
-rw-r--r-- | numpy/core/_add_newdocs.py | 236 | ||||
-rw-r--r-- | numpy/core/_asarray.py | 275 | ||||
-rw-r--r-- | numpy/core/_asarray.pyi | 4 | ||||
-rw-r--r-- | numpy/core/_methods.py | 2 | ||||
-rw-r--r-- | numpy/core/fromnumeric.py | 3 | ||||
-rw-r--r-- | numpy/core/multiarray.py | 7 | ||||
-rw-r--r-- | numpy/core/numeric.py | 9 | ||||
-rw-r--r-- | numpy/core/shape_base.py | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarray/arrayfunction_override.c | 105 | ||||
-rw-r--r-- | numpy/core/src/multiarray/arrayfunction_override.h | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 516 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 27 | ||||
-rw-r--r-- | numpy/core/tests/test_overrides.py | 3 | ||||
-rw-r--r-- | numpy/ctypeslib.py | 4 | ||||
-rw-r--r-- | numpy/lib/function_base.py | 9 | ||||
-rw-r--r-- | numpy/lib/shape_base.py | 2 | ||||
-rw-r--r-- | numpy/ma/core.py | 2 | ||||
-rw-r--r-- | numpy/ma/testutils.py | 4 | ||||
-rw-r--r-- | numpy/testing/_private/utils.py | 24 |
19 files changed, 694 insertions, 545 deletions
diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index fb2930143..bba9f95fc 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -904,6 +904,242 @@ add_newdoc('numpy.core.multiarray', 'array', array_function_like_doc, )) +add_newdoc('numpy.core.multiarray', 'asarray', + """ + asarray(a, dtype=None, order=None, *, like=None) + + Convert the input to an array. + + Parameters + ---------- + a : array_like + Input data, in any form that can be converted to an array. This + includes lists, lists of tuples, tuples, tuples of tuples, tuples + of lists and ndarrays. + dtype : data-type, optional + By default, the data-type is inferred from the input data. + order : {'C', 'F', 'A', 'K'}, optional + Memory layout. 'A' and 'K' depend on the order of input array a. + 'C' row-major (C-style), + 'F' column-major (Fortran-style) memory representation. + 'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise + 'K' (keep) preserve input order + Defaults to 'C'. + ${ARRAY_FUNCTION_LIKE} + + .. versionadded:: 1.20.0 + + Returns + ------- + out : ndarray + Array interpretation of `a`. No copy is performed if the input + is already an ndarray with matching dtype and order. If `a` is a + subclass of ndarray, a base class ndarray is returned. + + See Also + -------- + asanyarray : Similar function which passes through subclasses. + ascontiguousarray : Convert input to a contiguous array. + asfarray : Convert input to a floating point ndarray. + asfortranarray : Convert input to an ndarray with column-major + memory order. + asarray_chkfinite : Similar function which checks input for NaNs and Infs. + fromiter : Create an array from an iterator. + fromfunction : Construct an array by executing a function on grid + positions. + + Examples + -------- + Convert a list into an array: + + >>> a = [1, 2] + >>> np.asarray(a) + array([1, 2]) + + Existing arrays are not copied: + + >>> a = np.array([1, 2]) + >>> np.asarray(a) is a + True + + If `dtype` is set, array is copied only if dtype does not match: + + >>> a = np.array([1, 2], dtype=np.float32) + >>> np.asarray(a, dtype=np.float32) is a + True + >>> np.asarray(a, dtype=np.float64) is a + False + + Contrary to `asanyarray`, ndarray subclasses are not passed through: + + >>> issubclass(np.recarray, np.ndarray) + True + >>> a = np.array([(1.0, 2), (3.0, 4)], dtype='f4,i4').view(np.recarray) + >>> np.asarray(a) is a + False + >>> np.asanyarray(a) is a + True + + """.replace( + "${ARRAY_FUNCTION_LIKE}", + array_function_like_doc, + )) + +add_newdoc('numpy.core.multiarray', 'asanyarray', + """ + asanyarray(a, dtype=None, order=None, *, like=None) + + Convert the input to an ndarray, but pass ndarray subclasses through. + + Parameters + ---------- + a : array_like + Input data, in any form that can be converted to an array. This + includes scalars, lists, lists of tuples, tuples, tuples of tuples, + tuples of lists, and ndarrays. + dtype : data-type, optional + By default, the data-type is inferred from the input data. + order : {'C', 'F', 'A', 'K'}, optional + Memory layout. 'A' and 'K' depend on the order of input array a. + 'C' row-major (C-style), + 'F' column-major (Fortran-style) memory representation. + 'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise + 'K' (keep) preserve input order + Defaults to 'C'. + ${ARRAY_FUNCTION_LIKE} + + .. versionadded:: 1.20.0 + + Returns + ------- + out : ndarray or an ndarray subclass + Array interpretation of `a`. If `a` is an ndarray or a subclass + of ndarray, it is returned as-is and no copy is performed. + + See Also + -------- + asarray : Similar function which always returns ndarrays. + ascontiguousarray : Convert input to a contiguous array. + asfarray : Convert input to a floating point ndarray. + asfortranarray : Convert input to an ndarray with column-major + memory order. + asarray_chkfinite : Similar function which checks input for NaNs and + Infs. + fromiter : Create an array from an iterator. + fromfunction : Construct an array by executing a function on grid + positions. + + Examples + -------- + Convert a list into an array: + + >>> a = [1, 2] + >>> np.asanyarray(a) + array([1, 2]) + + Instances of `ndarray` subclasses are passed through as-is: + + >>> a = np.array([(1.0, 2), (3.0, 4)], dtype='f4,i4').view(np.recarray) + >>> np.asanyarray(a) is a + True + + """.replace( + "${ARRAY_FUNCTION_LIKE}", + array_function_like_doc, + )) + +add_newdoc('numpy.core.multiarray', 'ascontiguousarray', + """ + ascontiguousarray(a, dtype=None, *, like=None) + + Return a contiguous array (ndim >= 1) in memory (C order). + + Parameters + ---------- + a : array_like + Input array. + dtype : str or dtype object, optional + Data-type of returned array. + ${ARRAY_FUNCTION_LIKE} + + .. versionadded:: 1.20.0 + + Returns + ------- + out : ndarray + Contiguous array of same shape and content as `a`, with type `dtype` + if specified. + + See Also + -------- + asfortranarray : Convert input to an ndarray with column-major + memory order. + require : Return an ndarray that satisfies requirements. + ndarray.flags : Information about the memory layout of the array. + + Examples + -------- + >>> x = np.arange(6).reshape(2,3) + >>> np.ascontiguousarray(x, dtype=np.float32) + array([[0., 1., 2.], + [3., 4., 5.]], dtype=float32) + >>> x.flags['C_CONTIGUOUS'] + True + + Note: This function returns an array with at least one-dimension (1-d) + so it will not preserve 0-d arrays. + + """.replace( + "${ARRAY_FUNCTION_LIKE}", + array_function_like_doc, + )) + +add_newdoc('numpy.core.multiarray', 'asfortranarray', + """ + asfortranarray(a, dtype=None, *, like=None) + + Return an array (ndim >= 1) laid out in Fortran order in memory. + + Parameters + ---------- + a : array_like + Input array. + dtype : str or dtype object, optional + By default, the data-type is inferred from the input data. + ${ARRAY_FUNCTION_LIKE} + + .. versionadded:: 1.20.0 + + Returns + ------- + out : ndarray + The input `a` in Fortran, or column-major, order. + + See Also + -------- + ascontiguousarray : Convert input to a contiguous (C order) array. + asanyarray : Convert input to an ndarray with either row or + column-major memory order. + require : Return an ndarray that satisfies requirements. + ndarray.flags : Information about the memory layout of the array. + + Examples + -------- + >>> x = np.arange(6).reshape(2,3) + >>> y = np.asfortranarray(x) + >>> x.flags['F_CONTIGUOUS'] + False + >>> y.flags['F_CONTIGUOUS'] + True + + Note: This function returns an array with at least one-dimension (1-d) + so it will not preserve 0-d arrays. + + """.replace( + "${ARRAY_FUNCTION_LIKE}", + array_function_like_doc, + )) + add_newdoc('numpy.core.multiarray', 'empty', """ empty(shape, dtype=float, order='C', *, like=None) diff --git a/numpy/core/_asarray.py b/numpy/core/_asarray.py index a406308f3..ecb4e7c39 100644 --- a/numpy/core/_asarray.py +++ b/numpy/core/_asarray.py @@ -8,283 +8,12 @@ from .overrides import ( set_array_function_like_doc, set_module, ) -from .multiarray import array +from .multiarray import array, asanyarray -__all__ = [ - "asarray", "asanyarray", "ascontiguousarray", "asfortranarray", "require", -] +__all__ = ["require"] -def _asarray_dispatcher(a, dtype=None, order=None, *, like=None): - return (like,) - - -@set_array_function_like_doc -@set_module('numpy') -def asarray(a, dtype=None, order=None, *, like=None): - """Convert the input to an array. - - Parameters - ---------- - a : array_like - Input data, in any form that can be converted to an array. This - includes lists, lists of tuples, tuples, tuples of tuples, tuples - of lists and ndarrays. - dtype : data-type, optional - By default, the data-type is inferred from the input data. - order : {'C', 'F', 'A', 'K'}, optional - Memory layout. 'A' and 'K' depend on the order of input array a. - 'C' row-major (C-style), - 'F' column-major (Fortran-style) memory representation. - 'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise - 'K' (keep) preserve input order - Defaults to 'C'. - ${ARRAY_FUNCTION_LIKE} - - .. versionadded:: 1.20.0 - - Returns - ------- - out : ndarray - Array interpretation of `a`. No copy is performed if the input - is already an ndarray with matching dtype and order. If `a` is a - subclass of ndarray, a base class ndarray is returned. - - See Also - -------- - asanyarray : Similar function which passes through subclasses. - ascontiguousarray : Convert input to a contiguous array. - asfarray : Convert input to a floating point ndarray. - asfortranarray : Convert input to an ndarray with column-major - memory order. - asarray_chkfinite : Similar function which checks input for NaNs and Infs. - fromiter : Create an array from an iterator. - fromfunction : Construct an array by executing a function on grid - positions. - - Examples - -------- - Convert a list into an array: - - >>> a = [1, 2] - >>> np.asarray(a) - array([1, 2]) - - Existing arrays are not copied: - - >>> a = np.array([1, 2]) - >>> np.asarray(a) is a - True - - If `dtype` is set, array is copied only if dtype does not match: - - >>> a = np.array([1, 2], dtype=np.float32) - >>> np.asarray(a, dtype=np.float32) is a - True - >>> np.asarray(a, dtype=np.float64) is a - False - - Contrary to `asanyarray`, ndarray subclasses are not passed through: - - >>> issubclass(np.recarray, np.ndarray) - True - >>> a = np.array([(1.0, 2), (3.0, 4)], dtype='f4,i4').view(np.recarray) - >>> np.asarray(a) is a - False - >>> np.asanyarray(a) is a - True - - """ - if like is not None: - return _asarray_with_like(a, dtype=dtype, order=order, like=like) - - return array(a, dtype, copy=False, order=order) - - -_asarray_with_like = array_function_dispatch( - _asarray_dispatcher -)(asarray) - - -@set_array_function_like_doc -@set_module('numpy') -def asanyarray(a, dtype=None, order=None, *, like=None): - """Convert the input to an ndarray, but pass ndarray subclasses through. - - Parameters - ---------- - a : array_like - Input data, in any form that can be converted to an array. This - includes scalars, lists, lists of tuples, tuples, tuples of tuples, - tuples of lists, and ndarrays. - dtype : data-type, optional - By default, the data-type is inferred from the input data. - order : {'C', 'F', 'A', 'K'}, optional - Memory layout. 'A' and 'K' depend on the order of input array a. - 'C' row-major (C-style), - 'F' column-major (Fortran-style) memory representation. - 'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise - 'K' (keep) preserve input order - Defaults to 'C'. - ${ARRAY_FUNCTION_LIKE} - - .. versionadded:: 1.20.0 - - Returns - ------- - out : ndarray or an ndarray subclass - Array interpretation of `a`. If `a` is an ndarray or a subclass - of ndarray, it is returned as-is and no copy is performed. - - See Also - -------- - asarray : Similar function which always returns ndarrays. - ascontiguousarray : Convert input to a contiguous array. - asfarray : Convert input to a floating point ndarray. - asfortranarray : Convert input to an ndarray with column-major - memory order. - asarray_chkfinite : Similar function which checks input for NaNs and - Infs. - fromiter : Create an array from an iterator. - fromfunction : Construct an array by executing a function on grid - positions. - - Examples - -------- - Convert a list into an array: - - >>> a = [1, 2] - >>> np.asanyarray(a) - array([1, 2]) - - Instances of `ndarray` subclasses are passed through as-is: - - >>> a = np.array([(1.0, 2), (3.0, 4)], dtype='f4,i4').view(np.recarray) - >>> np.asanyarray(a) is a - True - - """ - if like is not None: - return _asanyarray_with_like(a, dtype=dtype, order=order, like=like) - - return array(a, dtype, copy=False, order=order, subok=True) - - -_asanyarray_with_like = array_function_dispatch( - _asarray_dispatcher -)(asanyarray) - - -def _asarray_contiguous_fortran_dispatcher(a, dtype=None, *, like=None): - return (like,) - - -@set_array_function_like_doc -@set_module('numpy') -def ascontiguousarray(a, dtype=None, *, like=None): - """ - Return a contiguous array (ndim >= 1) in memory (C order). - - Parameters - ---------- - a : array_like - Input array. - dtype : str or dtype object, optional - Data-type of returned array. - ${ARRAY_FUNCTION_LIKE} - - .. versionadded:: 1.20.0 - - Returns - ------- - out : ndarray - Contiguous array of same shape and content as `a`, with type `dtype` - if specified. - - See Also - -------- - asfortranarray : Convert input to an ndarray with column-major - memory order. - require : Return an ndarray that satisfies requirements. - ndarray.flags : Information about the memory layout of the array. - - Examples - -------- - >>> x = np.arange(6).reshape(2,3) - >>> np.ascontiguousarray(x, dtype=np.float32) - array([[0., 1., 2.], - [3., 4., 5.]], dtype=float32) - >>> x.flags['C_CONTIGUOUS'] - True - - Note: This function returns an array with at least one-dimension (1-d) - so it will not preserve 0-d arrays. - - """ - if like is not None: - return _ascontiguousarray_with_like(a, dtype=dtype, like=like) - - return array(a, dtype, copy=False, order='C', ndmin=1) - - -_ascontiguousarray_with_like = array_function_dispatch( - _asarray_contiguous_fortran_dispatcher -)(ascontiguousarray) - - -@set_array_function_like_doc -@set_module('numpy') -def asfortranarray(a, dtype=None, *, like=None): - """ - Return an array (ndim >= 1) laid out in Fortran order in memory. - - Parameters - ---------- - a : array_like - Input array. - dtype : str or dtype object, optional - By default, the data-type is inferred from the input data. - ${ARRAY_FUNCTION_LIKE} - - .. versionadded:: 1.20.0 - - Returns - ------- - out : ndarray - The input `a` in Fortran, or column-major, order. - - See Also - -------- - ascontiguousarray : Convert input to a contiguous (C order) array. - asanyarray : Convert input to an ndarray with either row or - column-major memory order. - require : Return an ndarray that satisfies requirements. - ndarray.flags : Information about the memory layout of the array. - - Examples - -------- - >>> x = np.arange(6).reshape(2,3) - >>> y = np.asfortranarray(x) - >>> x.flags['F_CONTIGUOUS'] - False - >>> y.flags['F_CONTIGUOUS'] - True - - Note: This function returns an array with at least one-dimension (1-d) - so it will not preserve 0-d arrays. - - """ - if like is not None: - return _asfortranarray_with_like(a, dtype=dtype, like=like) - - return array(a, dtype, copy=False, order='F', ndmin=1) - - -_asfortranarray_with_like = array_function_dispatch( - _asarray_contiguous_fortran_dispatcher -)(asfortranarray) - def _require_dispatcher(a, dtype=None, requirements=None, *, like=None): return (like,) diff --git a/numpy/core/_asarray.pyi b/numpy/core/_asarray.pyi index 8c200ba22..ee21fc0f1 100644 --- a/numpy/core/_asarray.pyi +++ b/numpy/core/_asarray.pyi @@ -11,6 +11,10 @@ else: _ArrayType = TypeVar("_ArrayType", bound=ndarray) +# TODO: The following functions are now defined in C, so should be defined +# in a (not yet existing) `multiarray.pyi`. +# (with the exception of `require`) + def asarray( a: object, dtype: DTypeLike = ..., diff --git a/numpy/core/_methods.py b/numpy/core/_methods.py index 09147fe5b..e475b94df 100644 --- a/numpy/core/_methods.py +++ b/numpy/core/_methods.py @@ -8,7 +8,7 @@ from contextlib import nullcontext from numpy.core import multiarray as mu from numpy.core import umath as um -from numpy.core._asarray import asanyarray +from numpy.core.multiarray import asanyarray from numpy.core import numerictypes as nt from numpy.core import _exceptions from numpy._globals import _NoValue diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py index bb736d1a0..3646b39b0 100644 --- a/numpy/core/fromnumeric.py +++ b/numpy/core/fromnumeric.py @@ -10,8 +10,7 @@ from . import multiarray as mu from . import overrides from . import umath as um from . import numerictypes as nt -from ._asarray import asarray, array, asanyarray -from .multiarray import concatenate +from .multiarray import asarray, array, asanyarray, concatenate from . import _methods _dt_ = nt.sctype2char diff --git a/numpy/core/multiarray.py b/numpy/core/multiarray.py index b7277ac24..b7a3a8d67 100644 --- a/numpy/core/multiarray.py +++ b/numpy/core/multiarray.py @@ -26,7 +26,8 @@ __all__ = [ 'MAY_SHARE_BOUNDS', 'MAY_SHARE_EXACT', 'NEEDS_INIT', 'NEEDS_PYAPI', 'RAISE', 'USE_GETITEM', 'USE_SETITEM', 'WRAP', '_fastCopyAndTranspose', '_flagdict', '_insert', '_reconstruct', '_vec_string', '_monotonicity', - 'add_docstring', 'arange', 'array', 'bincount', 'broadcast', + 'add_docstring', 'arange', 'array', 'asarray', 'asanyarray', + 'ascontiguousarray', 'asfortranarray', 'bincount', 'broadcast', 'busday_count', 'busday_offset', 'busdaycalendar', 'can_cast', 'compare_chararrays', 'concatenate', 'copyto', 'correlate', 'correlate2', 'count_nonzero', 'c_einsum', 'datetime_as_string', 'datetime_data', @@ -49,6 +50,10 @@ scalar.__module__ = 'numpy.core.multiarray' arange.__module__ = 'numpy' array.__module__ = 'numpy' +asarray.__module__ = 'numpy' +asanyarray.__module__ = 'numpy' +ascontiguousarray.__module__ = 'numpy' +asfortranarray.__module__ = 'numpy' datetime_data.__module__ = 'numpy' empty.__module__ = 'numpy' frombuffer.__module__ = 'numpy' diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index a6ee9eba9..8bb37e291 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -10,7 +10,8 @@ from . import multiarray from .multiarray import ( _fastCopyAndTranspose as fastCopyAndTranspose, ALLOW_THREADS, BUFSIZE, CLIP, MAXDIMS, MAY_SHARE_BOUNDS, MAY_SHARE_EXACT, RAISE, - WRAP, arange, array, broadcast, can_cast, compare_chararrays, + WRAP, arange, array, asarray, asanyarray, ascontiguousarray, + asfortranarray, broadcast, can_cast, compare_chararrays, concatenate, copyto, dot, dtype, empty, empty_like, flatiter, frombuffer, fromfile, fromiter, fromstring, inner, lexsort, matmul, may_share_memory, @@ -26,7 +27,6 @@ from .umath import (multiply, invert, sin, PINF, NAN) from . import numerictypes from .numerictypes import longlong, intc, int_, float_, complex_, bool_ from ._exceptions import TooHardError, AxisError -from ._asarray import asarray, asanyarray from ._ufunc_config import errstate bitwise_not = invert @@ -39,7 +39,8 @@ array_function_dispatch = functools.partial( __all__ = [ 'newaxis', 'ndarray', 'flatiter', 'nditer', 'nested_iters', 'ufunc', - 'arange', 'array', 'zeros', 'count_nonzero', 'empty', 'broadcast', 'dtype', + 'arange', 'array', 'asarray', 'asanyarray', 'ascontiguousarray', + 'asfortranarray', 'zeros', 'count_nonzero', 'empty', 'broadcast', 'dtype', 'fromstring', 'fromfile', 'frombuffer', 'where', 'argwhere', 'copyto', 'concatenate', 'fastCopyAndTranspose', 'lexsort', 'set_numeric_ops', 'can_cast', 'promote_types', 'min_scalar_type', @@ -2349,7 +2350,7 @@ def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): # Although, the default tolerances are unlikely to be useful if y.dtype.kind != "m": dt = multiarray.result_type(y, 1.) - y = array(y, dtype=dt, copy=False, subok=True) + y = asanyarray(y, dtype=dt) xfin = isfinite(x) yfin = isfinite(y) diff --git a/numpy/core/shape_base.py b/numpy/core/shape_base.py index 89e98ab30..a81a04f7f 100644 --- a/numpy/core/shape_base.py +++ b/numpy/core/shape_base.py @@ -8,8 +8,7 @@ import warnings from . import numeric as _nx from . import overrides -from ._asarray import array, asanyarray -from .multiarray import normalize_axis_index +from .multiarray import array, asanyarray, normalize_axis_index from . import fromnumeric as _from_nx diff --git a/numpy/core/src/multiarray/arrayfunction_override.c b/numpy/core/src/multiarray/arrayfunction_override.c index 2c07cdebc..31415e4f2 100644 --- a/numpy/core/src/multiarray/arrayfunction_override.c +++ b/numpy/core/src/multiarray/arrayfunction_override.c @@ -213,7 +213,7 @@ call_array_function(PyObject* argument, PyObject* method, * to NotImplemented to indicate the default implementation should * be used. */ -NPY_NO_EXPORT PyObject * +static PyObject * array_implement_array_function_internal( PyObject *public_api, PyObject *relevant_args, PyObject *args, PyObject *kwargs) @@ -364,66 +364,101 @@ array_implement_array_function( return res; } - /* * Implements the __array_function__ protocol for C array creation functions * only. Added as an extension to NEP-18 in an effort to bring NEP-35 to * life with minimal dispatch overhead. + * + * The caller must ensure that `like != NULL`. */ NPY_NO_EXPORT PyObject * array_implement_c_array_function_creation( - const char *function_name, PyObject *args, PyObject *kwargs) + const char *function_name, PyObject *like, + PyObject *args, PyObject *kwargs, + PyObject *const *fast_args, Py_ssize_t len_args, PyObject *kwnames) { - if (kwargs == NULL) { - return Py_NotImplemented; + PyObject *relevant_args = NULL; + PyObject *numpy_module = NULL; + PyObject *public_api = NULL; + PyObject *result = NULL; + + if (!get_array_function(like)) { + return PyErr_Format(PyExc_TypeError, + "The `like` argument must be an array-like that implements " + "the `__array_function__` protocol."); } - /* Remove `like=` kwarg, which is NumPy-exclusive and thus not present - * in downstream libraries. If that key isn't present, return NULL and - * let originating call to continue. If the key is present but doesn't - * implement `__array_function__`, raise a `TypeError`. - */ - if (!PyDict_Contains(kwargs, npy_ma_str_like)) { - return Py_NotImplemented; + if (fast_args != NULL) { + /* + * Convert from vectorcall convention, since the protocol requires + * the normal convention. We have to do this late to ensure the + * normal path where NotImplemented is returned is fast. + */ + assert(args == NULL); + assert(kwargs == NULL); + args = PyTuple_New(len_args); + if (args == NULL) { + return NULL; + } + for (Py_ssize_t i = 0; i < len_args; i++) { + Py_INCREF(fast_args[i]); + PyTuple_SET_ITEM(args, i, fast_args[i]); + } + if (kwnames != NULL) { + kwargs = PyDict_New(); + if (kwargs == NULL) { + Py_DECREF(args); + return NULL; + } + Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames); + for (Py_ssize_t i = 0; i < nkwargs; i++) { + PyObject *key = PyTuple_GET_ITEM(kwnames, i); + PyObject *value = fast_args[i+len_args]; + if (PyDict_SetItem(kwargs, key, value) < 0) { + Py_DECREF(args); + Py_DECREF(kwargs); + return NULL; + } + } + } } - PyObject *like_arg = PyDict_GetItem(kwargs, npy_ma_str_like); - if (like_arg == NULL) { - return NULL; + relevant_args = PyTuple_Pack(1, like); + if (relevant_args == NULL) { + goto finish; } - else if (!get_array_function(like_arg)) { - return PyErr_Format(PyExc_TypeError, - "The `like` argument must be an array-like that implements " - "the `__array_function__` protocol."); + /* The like argument must be present in the keyword arguments, remove it */ + if (PyDict_DelItem(kwargs, npy_ma_str_like) < 0) { + goto finish; } - PyObject *relevant_args = PyTuple_Pack(1, like_arg); - PyDict_DelItem(kwargs, npy_ma_str_like); - PyObject *numpy_module = PyImport_Import(npy_ma_str_numpy); + numpy_module = PyImport_Import(npy_ma_str_numpy); if (numpy_module == NULL) { - Py_DECREF(relevant_args); - return NULL; + goto finish; } - PyObject *public_api = PyObject_GetAttrString(numpy_module, function_name); + public_api = PyObject_GetAttrString(numpy_module, function_name); Py_DECREF(numpy_module); if (public_api == NULL) { - Py_DECREF(relevant_args); - return NULL; + goto finish; } if (!PyCallable_Check(public_api)) { - Py_DECREF(relevant_args); - Py_DECREF(public_api); - return PyErr_Format(PyExc_RuntimeError, - "numpy.%s is not callable.", - function_name); + PyErr_Format(PyExc_RuntimeError, + "numpy.%s is not callable.", function_name); + goto finish; } - PyObject* result = array_implement_array_function_internal( + result = array_implement_array_function_internal( public_api, relevant_args, args, kwargs); - Py_DECREF(relevant_args); - Py_DECREF(public_api); + finish: + if (kwnames != NULL) { + /* args and kwargs were converted from vectorcall convention */ + Py_XDECREF(args); + Py_XDECREF(kwargs); + } + Py_XDECREF(relevant_args); + Py_XDECREF(public_api); return result; } diff --git a/numpy/core/src/multiarray/arrayfunction_override.h b/numpy/core/src/multiarray/arrayfunction_override.h index fdcf1746d..fdf0dfcaf 100644 --- a/numpy/core/src/multiarray/arrayfunction_override.h +++ b/numpy/core/src/multiarray/arrayfunction_override.h @@ -11,7 +11,9 @@ array__get_implementing_args( NPY_NO_EXPORT PyObject * array_implement_c_array_function_creation( - const char *function_name, PyObject *args, PyObject *kwargs); + const char *function_name, PyObject *like, + PyObject *args, PyObject *kwargs, + PyObject *const *fast_args, Py_ssize_t len_args, PyObject *kwnames); NPY_NO_EXPORT PyObject * array_function_method_impl(PyObject *func, PyObject *types, PyObject *args, diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 12705dc19..953e2b4cf 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -1556,135 +1556,23 @@ _prepend_ones(PyArrayObject *arr, int nd, int ndmin, NPY_ORDER order) ((order) == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(op)) || \ ((order) == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(op))) -static PyObject * -_array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) +static NPY_INLINE PyObject * +_array_fromobject_generic( + PyObject *op, PyArray_Descr *type, npy_bool copy, NPY_ORDER order, + npy_bool subok, int ndmin) { - PyObject *op; PyArrayObject *oparr = NULL, *ret = NULL; - npy_bool subok = NPY_FALSE; - npy_bool copy = NPY_TRUE; - int ndmin = 0, nd; - PyObject* like; - PyArray_Descr *type = NULL; PyArray_Descr *oldtype = NULL; - NPY_ORDER order = NPY_KEEPORDER; - int flags = 0; - - PyObject* array_function_result = NULL; - - static char *kwd[] = {"object", "dtype", "copy", "order", "subok", - "ndmin", "like", NULL}; - - if (PyTuple_GET_SIZE(args) > 2) { - PyErr_Format(PyExc_TypeError, - "array() takes from 1 to 2 positional arguments but " - "%zd were given", PyTuple_GET_SIZE(args)); - return NULL; - } - - array_function_result = array_implement_c_array_function_creation( - "array", args, kws); - if (array_function_result != Py_NotImplemented) { - return array_function_result; - } - - /* super-fast path for ndarray argument calls */ - if (PyTuple_GET_SIZE(args) == 0) { - goto full_path; - } - op = PyTuple_GET_ITEM(args, 0); - if (PyArray_CheckExact(op)) { - PyObject * dtype_obj = Py_None; - oparr = (PyArrayObject *)op; - /* get dtype which can be positional */ - if (PyTuple_GET_SIZE(args) == 2) { - dtype_obj = PyTuple_GET_ITEM(args, 1); - } - else if (kws) { - dtype_obj = PyDict_GetItemWithError(kws, npy_ma_str_dtype); - if (dtype_obj == NULL && PyErr_Occurred()) { - return NULL; - } - if (dtype_obj == NULL) { - dtype_obj = Py_None; - } - } - if (dtype_obj != Py_None) { - goto full_path; - } - - /* array(ndarray) */ - if (kws == NULL) { - ret = (PyArrayObject *)PyArray_NewCopy(oparr, order); - goto finish; - } - else { - /* fast path for copy=False rest default (np.asarray) */ - PyObject * copy_obj, * order_obj, *ndmin_obj; - copy_obj = PyDict_GetItemWithError(kws, npy_ma_str_copy); - if (copy_obj == NULL && PyErr_Occurred()) { - return NULL; - } - if (copy_obj != Py_False) { - goto full_path; - } - copy = NPY_FALSE; - - /* order does not matter for contiguous 1d arrays */ - if (PyArray_NDIM((PyArrayObject*)op) > 1 || - !PyArray_IS_C_CONTIGUOUS((PyArrayObject*)op)) { - order_obj = PyDict_GetItemWithError(kws, npy_ma_str_order); - if (order_obj == NULL && PyErr_Occurred()) { - return NULL; - } - else if (order_obj != Py_None && order_obj != NULL) { - goto full_path; - } - } - - ndmin_obj = PyDict_GetItemWithError(kws, npy_ma_str_ndmin); - if (ndmin_obj == NULL && PyErr_Occurred()) { - return NULL; - } - else if (ndmin_obj) { - long t = PyLong_AsLong(ndmin_obj); - if (error_converting(t)) { - goto clean_type; - } - else if (t > NPY_MAXDIMS) { - goto full_path; - } - ndmin = t; - } - - /* copy=False with default dtype, order (any is OK) and ndim */ - ret = oparr; - Py_INCREF(ret); - goto finish; - } - } - -full_path: - if (!PyArg_ParseTupleAndKeywords(args, kws, "O|O&O&O&O&i$O:array", kwd, - &op, - PyArray_DescrConverter2, &type, - PyArray_BoolConverter, ©, - PyArray_OrderConverter, &order, - PyArray_BoolConverter, &subok, - &ndmin, - &like)) { - goto clean_type; - } + int nd, flags = 0; if (ndmin > NPY_MAXDIMS) { PyErr_Format(PyExc_ValueError, "ndmin bigger than allowable number of dimensions " "NPY_MAXDIMS (=%d)", NPY_MAXDIMS); - goto clean_type; + return NULL; } /* fast exit if simple call */ - if ((subok && PyArray_Check(op)) || - (!subok && PyArray_CheckExact(op))) { + if (PyArray_CheckExact(op) || (subok && PyArray_Check(op))) { oparr = (PyArrayObject *)op; if (type == NULL) { if (!copy && STRIDING_OK(oparr, order)) { @@ -1739,8 +1627,7 @@ full_path: ret = (PyArrayObject *)PyArray_CheckFromAny(op, type, 0, 0, flags, NULL); - finish: - Py_XDECREF(type); +finish: if (ret == NULL) { return NULL; } @@ -1754,16 +1641,215 @@ full_path: * steals a reference to ret */ return _prepend_ones(ret, nd, ndmin, order); +} + +#undef STRIDING_OK + -clean_type: +static PyObject * +array_array(PyObject *NPY_UNUSED(ignored), + PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) +{ + PyObject *op; + npy_bool subok = NPY_FALSE; + npy_bool copy = NPY_TRUE; + int ndmin = 0; + PyArray_Descr *type = NULL; + NPY_ORDER order = NPY_KEEPORDER; + PyObject *like = NULL; + NPY_PREPARE_ARGPARSER; + + if (len_args != 1 || (kwnames != NULL)) { + if (npy_parse_arguments("array", args, len_args, kwnames, + "object", NULL, &op, + "|dtype", &PyArray_DescrConverter2, &type, + "$copy", &PyArray_BoolConverter, ©, + "$order", &PyArray_OrderConverter, &order, + "$subok", &PyArray_BoolConverter, &subok, + "$ndmin", &PyArray_PythonPyIntFromInt, &ndmin, + "$like", NULL, &like, + NULL, NULL, NULL) < 0) { + Py_XDECREF(type); + return NULL; + } + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "array", like, NULL, NULL, args, len_args, kwnames); + if (deferred != Py_NotImplemented) { + Py_XDECREF(type); + return deferred; + } + } + } + else { + /* Fast path for symmetry (we copy by default which is slow) */ + op = args[0]; + } + + PyObject *res = _array_fromobject_generic( + op, type, copy, order, subok, ndmin); Py_XDECREF(type); - return NULL; + return res; } static PyObject * -array_copyto(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +array_asarray(PyObject *NPY_UNUSED(ignored), + PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) +{ + PyObject *op; + PyArray_Descr *type = NULL; + NPY_ORDER order = NPY_KEEPORDER; + PyObject *like = NULL; + NPY_PREPARE_ARGPARSER; + + if (len_args != 1 || (kwnames != NULL)) { + if (npy_parse_arguments("asarray", args, len_args, kwnames, + "a", NULL, &op, + "|dtype", &PyArray_DescrConverter2, &type, + "|order", &PyArray_OrderConverter, &order, + "$like", NULL, &like, + NULL, NULL, NULL) < 0) { + Py_XDECREF(type); + return NULL; + } + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "asarray", like, NULL, NULL, args, len_args, kwnames); + if (deferred != Py_NotImplemented) { + Py_XDECREF(type); + return deferred; + } + } + } + else { + op = args[0]; + } + + PyObject *res = _array_fromobject_generic( + op, type, NPY_FALSE, order, NPY_FALSE, 0); + Py_XDECREF(type); + return res; +} + +static PyObject * +array_asanyarray(PyObject *NPY_UNUSED(ignored), + PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) +{ + PyObject *op; + PyArray_Descr *type = NULL; + NPY_ORDER order = NPY_KEEPORDER; + PyObject *like = NULL; + NPY_PREPARE_ARGPARSER; + + if (len_args != 1 || (kwnames != NULL)) { + if (npy_parse_arguments("asanyarray", args, len_args, kwnames, + "a", NULL, &op, + "|dtype", &PyArray_DescrConverter2, &type, + "|order", &PyArray_OrderConverter, &order, + "$like", NULL, &like, + NULL, NULL, NULL) < 0) { + Py_XDECREF(type); + return NULL; + } + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "asanyarray", like, NULL, NULL, args, len_args, kwnames); + if (deferred != Py_NotImplemented) { + Py_XDECREF(type); + return deferred; + } + } + } + else { + op = args[0]; + } + + PyObject *res = _array_fromobject_generic( + op, type, NPY_FALSE, order, NPY_TRUE, 0); + Py_XDECREF(type); + return res; +} + + +static PyObject * +array_ascontiguousarray(PyObject *NPY_UNUSED(ignored), + PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) +{ + PyObject *op; + PyArray_Descr *type = NULL; + PyObject *like = NULL; + NPY_PREPARE_ARGPARSER; + + if (len_args != 1 || (kwnames != NULL)) { + if (npy_parse_arguments("ascontiguousarray", args, len_args, kwnames, + "a", NULL, &op, + "|dtype", &PyArray_DescrConverter2, &type, + "$like", NULL, &like, + NULL, NULL, NULL) < 0) { + Py_XDECREF(type); + return NULL; + } + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "ascontiguousarray", like, NULL, NULL, args, len_args, kwnames); + if (deferred != Py_NotImplemented) { + Py_XDECREF(type); + return deferred; + } + } + } + else { + op = args[0]; + } + + PyObject *res = _array_fromobject_generic( + op, type, NPY_FALSE, NPY_CORDER, NPY_FALSE, 1); + Py_XDECREF(type); + return res; +} + + +static PyObject * +array_asfortranarray(PyObject *NPY_UNUSED(ignored), + PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) { + PyObject *op; + PyArray_Descr *type = NULL; + PyObject *like = NULL; + NPY_PREPARE_ARGPARSER; + + if (len_args != 1 || (kwnames != NULL)) { + if (npy_parse_arguments("asfortranarray", args, len_args, kwnames, + "a", NULL, &op, + "|dtype", &PyArray_DescrConverter2, &type, + "$like", NULL, &like, + NULL, NULL, NULL) < 0) { + Py_XDECREF(type); + return NULL; + } + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "asfortranarray", like, NULL, NULL, args, len_args, kwnames); + if (deferred != Py_NotImplemented) { + Py_XDECREF(type); + return deferred; + } + } + } + else { + op = args[0]; + } + + PyObject *res = _array_fromobject_generic( + op, type, NPY_FALSE, NPY_FORTRANORDER, NPY_FALSE, 1); + Py_XDECREF(type); + return res; +} + +static PyObject * +array_copyto(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +{ static char *kwlist[] = {"dst", "src", "casting", "where", NULL}; PyObject *wheremask_in = NULL; PyArrayObject *dst = NULL, *src = NULL, *wheremask = NULL; @@ -1806,32 +1892,34 @@ fail: } static PyObject * -array_empty(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +array_empty(PyObject *NPY_UNUSED(ignored), + PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) { - - static char *kwlist[] = {"shape", "dtype", "order", "like", NULL}; PyArray_Descr *typecode = NULL; PyArray_Dims shape = {NULL, 0}; NPY_ORDER order = NPY_CORDER; - PyObject *like = NULL; npy_bool is_f_order; - PyObject *array_function_result = NULL; PyArrayObject *ret = NULL; + PyObject *like = NULL; + NPY_PREPARE_ARGPARSER; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&$O:empty", kwlist, - PyArray_IntpConverter, &shape, - PyArray_DescrConverter, &typecode, - PyArray_OrderConverter, &order, - &like)) { + if (npy_parse_arguments("empty", args, len_args, kwnames, + "shape", &PyArray_IntpConverter, &shape, + "|dtype", &PyArray_DescrConverter, &typecode, + "|order", &PyArray_OrderConverter, &order, + "$like", NULL, &like, + NULL, NULL, NULL) < 0) { goto fail; } - array_function_result = array_implement_c_array_function_creation( - "empty", args, kwds); - if (array_function_result != Py_NotImplemented) { - Py_XDECREF(typecode); - npy_free_cache_dim_obj(shape); - return array_function_result; + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "empty", like, NULL, NULL, args, len_args, kwnames); + if (deferred != Py_NotImplemented) { + Py_XDECREF(typecode); + npy_free_cache_dim_obj(shape); + return deferred; + } } switch (order) { @@ -2006,31 +2094,35 @@ array_scalar(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) } static PyObject * -array_zeros(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) +array_zeros(PyObject *NPY_UNUSED(ignored), + PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) { - static char *kwlist[] = {"shape", "dtype", "order", "like", NULL}; PyArray_Descr *typecode = NULL; PyArray_Dims shape = {NULL, 0}; NPY_ORDER order = NPY_CORDER; - PyObject *like = NULL; npy_bool is_f_order = NPY_FALSE; - PyObject *array_function_result = NULL; PyArrayObject *ret = NULL; + PyObject *like = NULL; + NPY_PREPARE_ARGPARSER; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&$O:zeros", kwlist, - PyArray_IntpConverter, &shape, - PyArray_DescrConverter, &typecode, - PyArray_OrderConverter, &order, - &like)) { + if (npy_parse_arguments("zeros", args, len_args, kwnames, + "shape", &PyArray_IntpConverter, &shape, + "|dtype", &PyArray_DescrConverter, &typecode, + "|order", &PyArray_OrderConverter, &order, + "$like", NULL, &like, + NULL, NULL, NULL) < 0) { goto fail; } - array_function_result = array_implement_c_array_function_creation( - "zeros", args, kwds); - if (array_function_result != Py_NotImplemented) { - Py_XDECREF(typecode); - npy_free_cache_dim_obj(shape); - return array_function_result; + + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "zeros", like, NULL, NULL, args, len_args, kwnames); + if (deferred != Py_NotImplemented) { + Py_XDECREF(typecode); + npy_free_cache_dim_obj(shape); + return deferred; + } } switch (order) { @@ -2088,7 +2180,6 @@ array_fromstring(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds static char *kwlist[] = {"string", "dtype", "count", "sep", "like", NULL}; PyObject *like = NULL; PyArray_Descr *descr = NULL; - PyObject *array_function_result = NULL; if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#|O&" NPY_SSIZE_T_PYFMT "s$O:fromstring", kwlist, @@ -2096,11 +2187,13 @@ array_fromstring(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds Py_XDECREF(descr); return NULL; } - - array_function_result = array_implement_c_array_function_creation( - "fromstring", args, keywds); - if (array_function_result != Py_NotImplemented) { - return array_function_result; + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "fromstring", like, args, keywds, NULL, 0, NULL); + if (deferred != Py_NotImplemented) { + Py_XDECREF(descr); + return deferred; + } } /* binary mode, condition copied from PyArray_FromString */ @@ -2128,7 +2221,6 @@ array_fromfile(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) static char *kwlist[] = {"file", "dtype", "count", "sep", "offset", "like", NULL}; PyObject *like = NULL; PyArray_Descr *type = NULL; - PyObject *array_function_result = NULL; int own; npy_off_t orig_pos = 0, offset = 0; FILE *fp; @@ -2140,11 +2232,13 @@ array_fromfile(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) return NULL; } - array_function_result = array_implement_c_array_function_creation( - "fromfile", args, keywds); - if (array_function_result != Py_NotImplemented) { - Py_XDECREF(type); - return array_function_result; + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "fromfile", like, args, keywds, NULL, 0, NULL); + if (deferred != Py_NotImplemented) { + Py_XDECREF(type); + return deferred; + } } file = NpyPath_PathlikeToFspath(file); @@ -2217,7 +2311,6 @@ array_fromiter(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) static char *kwlist[] = {"iter", "dtype", "count", "like", NULL}; PyObject *like = NULL; PyArray_Descr *descr = NULL; - PyObject *array_function_result = NULL; if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO&|" NPY_SSIZE_T_PYFMT "$O:fromiter", kwlist, @@ -2225,12 +2318,13 @@ array_fromiter(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) Py_XDECREF(descr); return NULL; } - - array_function_result = array_implement_c_array_function_creation( - "fromiter", args, keywds); - if (array_function_result != Py_NotImplemented) { - Py_DECREF(descr); - return array_function_result; + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "fromiter", like, args, keywds, NULL, 0, NULL); + if (deferred != Py_NotImplemented) { + Py_XDECREF(descr); + return deferred; + } } return PyArray_FromIter(iter, descr, (npy_intp)nin); @@ -2244,7 +2338,6 @@ array_frombuffer(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds static char *kwlist[] = {"buffer", "dtype", "count", "offset", "like", NULL}; PyObject *like = NULL; PyArray_Descr *type = NULL; - PyObject *array_function_result = NULL; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|O&" NPY_SSIZE_T_PYFMT NPY_SSIZE_T_PYFMT "$O:frombuffer", kwlist, @@ -2253,11 +2346,13 @@ array_frombuffer(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds return NULL; } - array_function_result = array_implement_c_array_function_creation( - "frombuffer", args, keywds); - if (array_function_result != Py_NotImplemented) { - Py_XDECREF(type); - return array_function_result; + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "frombuffer", like, args, keywds, NULL, 0, NULL); + if (deferred != Py_NotImplemented) { + Py_XDECREF(type); + return deferred; + } } if (type == NULL) { @@ -2865,25 +2960,35 @@ array_correlate2(PyObject *NPY_UNUSED(dummy), } static PyObject * -array_arange(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) { +array_arange(PyObject *NPY_UNUSED(ignored), + PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) +{ PyObject *o_start = NULL, *o_stop = NULL, *o_step = NULL, *range=NULL; - PyObject *like = NULL; - PyObject *array_function_result = NULL; - static char *kwd[] = {"start", "stop", "step", "dtype", "like", NULL}; PyArray_Descr *typecode = NULL; + PyObject *like = NULL; + NPY_PREPARE_ARGPARSER; - if (!PyArg_ParseTupleAndKeywords(args, kws, "|OOOO&$O:arange", kwd, - &o_start, - &o_stop, - &o_step, - PyArray_DescrConverter2, &typecode, - &like)) { + if (npy_parse_arguments("arange", args, len_args, kwnames, + "|start", NULL, &o_start, + "|stop", NULL, &o_stop, + "|step", NULL, &o_step, + "|dtype", &PyArray_DescrConverter2, &typecode, + "$like", NULL, &like, + NULL, NULL, NULL) < 0) { Py_XDECREF(typecode); return NULL; } + if (like != NULL) { + PyObject *deferred = array_implement_c_array_function_creation( + "arange", like, NULL, NULL, args, len_args, kwnames); + if (deferred != Py_NotImplemented) { + Py_XDECREF(typecode); + return deferred; + } + } if (o_stop == NULL) { - if (args == NULL || PyTuple_GET_SIZE(args) == 0){ + if (len_args == 0){ PyErr_SetString(PyExc_TypeError, "arange() requires stop to be specified."); Py_XDECREF(typecode); @@ -2895,13 +3000,6 @@ array_arange(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) { o_stop = NULL; } - array_function_result = array_implement_c_array_function_creation( - "arange", args, kws); - if (array_function_result != Py_NotImplemented) { - Py_XDECREF(typecode); - return array_function_result; - } - range = PyArray_ArangeObj(o_start, o_stop, o_step, typecode); Py_XDECREF(typecode); @@ -4149,8 +4247,20 @@ static struct PyMethodDef array_module_methods[] = { (PyCFunction)array_set_typeDict, METH_VARARGS, NULL}, {"array", - (PyCFunction)_array_fromobject, - METH_VARARGS|METH_KEYWORDS, NULL}, + (PyCFunction)array_array, + METH_FASTCALL | METH_KEYWORDS, NULL}, + {"asarray", + (PyCFunction)array_asarray, + METH_FASTCALL | METH_KEYWORDS, NULL}, + {"asanyarray", + (PyCFunction)array_asanyarray, + METH_FASTCALL | METH_KEYWORDS, NULL}, + {"ascontiguousarray", + (PyCFunction)array_ascontiguousarray, + METH_FASTCALL | METH_KEYWORDS, NULL}, + {"asfortranarray", + (PyCFunction)array_asfortranarray, + METH_FASTCALL | METH_KEYWORDS, NULL}, {"copyto", (PyCFunction)array_copyto, METH_VARARGS|METH_KEYWORDS, NULL}, @@ -4159,16 +4269,16 @@ static struct PyMethodDef array_module_methods[] = { METH_VARARGS|METH_KEYWORDS, NULL}, {"arange", (PyCFunction)array_arange, - METH_VARARGS|METH_KEYWORDS, NULL}, + METH_FASTCALL | METH_KEYWORDS, NULL}, {"zeros", (PyCFunction)array_zeros, - METH_VARARGS|METH_KEYWORDS, NULL}, + METH_FASTCALL | METH_KEYWORDS, NULL}, {"count_nonzero", (PyCFunction)array_count_nonzero, METH_VARARGS|METH_KEYWORDS, NULL}, {"empty", (PyCFunction)array_empty, - METH_VARARGS|METH_KEYWORDS, NULL}, + METH_FASTCALL | METH_KEYWORDS, NULL}, {"empty_like", (PyCFunction)array_empty_like, METH_VARARGS|METH_KEYWORDS, NULL}, diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index ddd0e31c5..269e144d9 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -484,6 +484,33 @@ class TestArrayConstruction: assert_(np.ascontiguousarray(d).flags.c_contiguous) assert_(np.asfortranarray(d).flags.f_contiguous) + @pytest.mark.parametrize("func", + [np.array, + np.asarray, + np.asanyarray, + np.ascontiguousarray, + np.asfortranarray]) + def test_bad_arguments_error(self, func): + with pytest.raises(TypeError): + func(3, dtype="bad dtype") + with pytest.raises(TypeError): + func() # missing arguments + with pytest.raises(TypeError): + func(1, 2, 3, 4, 5, 6, 7, 8) # too many arguments + + @pytest.mark.parametrize("func", + [np.array, + np.asarray, + np.asanyarray, + np.ascontiguousarray, + np.asfortranarray]) + def test_array_as_keyword(self, func): + # This should likely be made positional only, but do not change + # the name accidentally. + if func is np.array: + func(object=3) + else: + func(a=3) class TestAssignment: def test_assignment_broadcasting(self): diff --git a/numpy/core/tests/test_overrides.py b/numpy/core/tests/test_overrides.py index 6862fca03..0809e1e92 100644 --- a/numpy/core/tests/test_overrides.py +++ b/numpy/core/tests/test_overrides.py @@ -577,5 +577,6 @@ class TestArrayLike: ref = self.MyArray.array() - with assert_raises(ValueError): + with assert_raises(TypeError): + # Raises the error about `value_error` being invalid first np.array(1, value_error=True, like=ref) diff --git a/numpy/ctypeslib.py b/numpy/ctypeslib.py index dbc683a6b..8ba6f15e5 100644 --- a/numpy/ctypeslib.py +++ b/numpy/ctypeslib.py @@ -54,7 +54,7 @@ __all__ = ['load_library', 'ndpointer', 'c_intp', 'as_ctypes', 'as_array', import os from numpy import ( - integer, ndarray, dtype as _dtype, array, frombuffer + integer, ndarray, dtype as _dtype, asarray, frombuffer ) from numpy.core.multiarray import _flagdict, flagsobj @@ -515,7 +515,7 @@ if ctypes is not None: p_arr_type = ctypes.POINTER(_ctype_ndarray(obj._type_, shape)) obj = ctypes.cast(obj, p_arr_type).contents - return array(obj, copy=False) + return asarray(obj) def as_ctypes(obj): diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index c6db42ce4..44eac31ef 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -593,7 +593,7 @@ def piecewise(x, condlist, funclist, *args, **kw): not isinstance(condlist[0], (list, ndarray)) and x.ndim != 0): condlist = [condlist] - condlist = array(condlist, dtype=bool) + condlist = asarray(condlist, dtype=bool) n = len(condlist) if n == n2 - 1: # compute the "otherwise" condition. @@ -2191,15 +2191,14 @@ class vectorize: ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args) # Convert args to object arrays first - inputs = [array(a, copy=False, subok=True, dtype=object) - for a in args] + inputs = [asanyarray(a, dtype=object) for a in args] outputs = ufunc(*inputs) if ufunc.nout == 1: - res = array(outputs, copy=False, subok=True, dtype=otypes[0]) + res = asanyarray(outputs, dtype=otypes[0]) else: - res = tuple([array(x, copy=False, subok=True, dtype=t) + res = tuple([asanyarray(x, dtype=t) for x, t in zip(outputs, otypes)]) return res diff --git a/numpy/lib/shape_base.py b/numpy/lib/shape_base.py index d19bfb8f8..a3fbee3d5 100644 --- a/numpy/lib/shape_base.py +++ b/numpy/lib/shape_base.py @@ -649,7 +649,7 @@ def column_stack(tup): arrays = [] for v in tup: - arr = array(v, copy=False, subok=True) + arr = asanyarray(v) if arr.ndim < 2: arr = array(arr, copy=False, subok=True, ndmin=2).T arrays.append(arr) diff --git a/numpy/ma/core.py b/numpy/ma/core.py index cebacf5e1..14dc21804 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -3895,7 +3895,7 @@ class MaskedArray(ndarray): # Force the condition to a regular ndarray and forget the missing # values. - condition = np.array(condition, copy=False, subok=False) + condition = np.asarray(condition) _new = _data.compress(condition, axis=axis, out=out).view(type(self)) _new._update_from(self) diff --git a/numpy/ma/testutils.py b/numpy/ma/testutils.py index 8d55e1763..2dd479abe 100644 --- a/numpy/ma/testutils.py +++ b/numpy/ma/testutils.py @@ -134,8 +134,8 @@ def assert_equal(actual, desired, err_msg=''): msg = build_err_msg([actual, desired], err_msg, header='', names=('x', 'y')) raise ValueError(msg) - actual = np.array(actual, copy=False, subok=True) - desired = np.array(desired, copy=False, subok=True) + actual = np.asanyarray(actual) + desired = np.asanyarray(desired) (actual_dtype, desired_dtype) = (actual.dtype, desired.dtype) if actual_dtype.char == "S" and desired_dtype.char == "S": return _assert_equal_on_sequences(actual.tolist(), diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 5b87d0a06..1bdb00fd5 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -17,6 +17,7 @@ from unittest.case import SkipTest from warnings import WarningMessage import pprint +import numpy as np from numpy.core import( intp, float32, empty, arange, array_repr, ndarray, isnat, array) import numpy.linalg.lapack_lite @@ -378,7 +379,8 @@ def assert_equal(actual, desired, err_msg='', verbose=True): try: isdesnat = isnat(desired) isactnat = isnat(actual) - dtypes_match = array(desired).dtype.type == array(actual).dtype.type + dtypes_match = (np.asarray(desired).dtype.type == + np.asarray(actual).dtype.type) if isdesnat and isactnat: # If both are NaT (and have the same dtype -- datetime or # timedelta) they are considered equal. @@ -398,8 +400,8 @@ def assert_equal(actual, desired, err_msg='', verbose=True): return # both nan, so equal # handle signed zero specially for floats - array_actual = array(actual) - array_desired = array(desired) + array_actual = np.asarray(actual) + array_desired = np.asarray(desired) if (array_actual.dtype.char in 'Mm' or array_desired.dtype.char in 'Mm'): # version 1.18 @@ -701,8 +703,8 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, header='', __tracebackhide__ = True # Hide traceback for py.test 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) + x = np.asanyarray(x) + y = np.asanyarray(y) # original array for output formatting ox, oy = x, y @@ -1033,7 +1035,7 @@ def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True): # make sure y is an inexact type to avoid abs(MIN_INT); will cause # casting of x later. dtype = result_type(y, 1.) - y = array(y, dtype=dtype, copy=False, subok=True) + y = np.asanyarray(y, dtype) z = abs(x - y) if not issubdtype(z.dtype, number): @@ -1678,11 +1680,11 @@ def nulp_diff(x, y, dtype=None): """ import numpy as np if dtype: - x = np.array(x, dtype=dtype) - y = np.array(y, dtype=dtype) + x = np.asarray(x, dtype=dtype) + y = np.asarray(y, dtype=dtype) else: - x = np.array(x) - y = np.array(y) + x = np.asarray(x) + y = np.asarray(y) t = np.common_type(x, y) if np.iscomplexobj(x) or np.iscomplexobj(y): @@ -1699,7 +1701,7 @@ def nulp_diff(x, y, dtype=None): (x.shape, y.shape)) def _diff(rx, ry, vdt): - diff = np.array(rx-ry, dtype=vdt) + diff = np.asarray(rx-ry, dtype=vdt) return np.abs(diff) rx = integer_repr(x) |