summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/upcoming_changes/15118.change.rst7
-rw-r--r--doc/source/reference/c-api/array.rst21
-rw-r--r--numpy/core/src/multiarray/ctors.c37
-rw-r--r--numpy/core/src/multiarray/datetime_busday.c10
-rw-r--r--numpy/core/src/multiarray/datetime_busdaycal.c2
-rw-r--r--numpy/core/src/umath/ufunc_object.c29
-rw-r--r--numpy/core/tests/test_umath.py26
7 files changed, 46 insertions, 86 deletions
diff --git a/doc/release/upcoming_changes/15118.change.rst b/doc/release/upcoming_changes/15118.change.rst
new file mode 100644
index 000000000..f14beebbe
--- /dev/null
+++ b/doc/release/upcoming_changes/15118.change.rst
@@ -0,0 +1,7 @@
+Remove handling of extra argument to ``__array__``
+--------------------------------------------------
+A code path and test have been in the code since NumPy 0.4 for a two-argument
+variant of ``__array__(dtype=None, context=None)``. It was activated when
+calling ``ufunc(op)`` or ``ufunc.reduce(op)`` if ``op.__array__`` existed.
+However that variant is not documented, and it is not clear what the intention
+was for its use. It has been removed.
diff --git a/doc/source/reference/c-api/array.rst b/doc/source/reference/c-api/array.rst
index e396ee020..ce8671a51 100644
--- a/doc/source/reference/c-api/array.rst
+++ b/doc/source/reference/c-api/array.rst
@@ -426,10 +426,8 @@ From other objects
may be 0. Also, if *op* is not already an array (or does not
expose the array interface), then a new array will be created (and
filled from *op* using the sequence protocol). The new array will
- have :c:data:`NPY_ARRAY_DEFAULT` as its flags member. The *context* argument
- is passed to the :obj:`~numpy.class.__array__` method of *op* and is only used if
- the array is constructed that way. Almost always this
- parameter is ``NULL``.
+ have :c:data:`NPY_ARRAY_DEFAULT` as its flags member. The *context*
+ argument is unused.
.. c:var:: NPY_ARRAY_C_CONTIGUOUS
@@ -574,6 +572,8 @@ From other objects
:c:data:`NPY_ARRAY_WRITEABLE` to PyArray_FromAny, where the writeable array may
be a copy of the input.
+ `context` is not used.
+
When success (0 return value) is returned, either out_arr
is filled with a non-NULL PyArrayObject and
the rest of the parameters are untouched, or out_arr is
@@ -677,10 +677,8 @@ From other objects
PyObject* op, PyArray_Descr* dtype, PyObject* context)
Return an ndarray object from a Python object that exposes the
- :obj:`~numpy.class.__array__` method. The :obj:`~numpy.class.__array__` method can take 0, 1, or 2
- arguments ([dtype, context]) where *context* is used to pass
- information about where the :obj:`~numpy.class.__array__` method is being called
- from (currently only used in ufuncs).
+ :obj:`~numpy.class.__array__` method. The :obj:`~numpy.class.__array__`
+ method can take 0, or 1 argument ``([dtype])``. ``context`` is unused.
.. c:function:: PyObject* PyArray_ContiguousFromAny( \
PyObject* op, int typenum, int min_depth, int max_depth)
@@ -859,15 +857,16 @@ General check of Python Type
conversion occurs. Otherwise, out will contain a borrowed
reference to :c:data:`Py_NotImplemented` and no error condition is set.
-.. c:function:: PyArray_HasArrayInterfaceType(op, type, context, out)
+.. c:function:: PyArray_HasArrayInterfaceType(op, dtype, context, out)
If ``op`` implements any part of the array interface, then ``out``
will contain a new reference to the newly created ndarray using
the interface or ``out`` will contain ``NULL`` if an error during
conversion occurs. Otherwise, out will contain a borrowed
reference to Py_NotImplemented and no error condition is set.
- This version allows setting of the type and context in the part of
- the array interface that looks for the :obj:`~numpy.class.__array__` attribute.
+ This version allows setting of the dtype in the part of the array interface
+ that looks for the :obj:`~numpy.class.__array__` attribute. `context` is
+ unused.
.. c:function:: PyArray_IsZeroDim(op)
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 41dcaf3bb..bf90142e1 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -1623,6 +1623,8 @@ fail:
* validate and possibly copy arr itself ...
* }
* ... use arr ...
+ * context is passed to PyArray_FromArrayAttr, which ignores it. Since this is
+ * a NUMPY_API function, we cannot remove it.
*/
NPY_NO_EXPORT int
PyArray_GetArrayParamsFromObject(PyObject *op,
@@ -1875,6 +1877,10 @@ PyArray_GetArrayParamsFromObject(PyObject *op,
/*NUMPY_API
* Does not check for NPY_ARRAY_ENSURECOPY and NPY_ARRAY_NOTSWAPPED in flags
* Steals a reference to newtype --- which can be NULL
+ *
+ * context is passed to PyArray_GetArrayParamsFromObject, which passes it to
+ * PyArray_FromArrayAttr, which raises if it is not NULL. Since this is a
+ * NUMPY_API function, we cannot remove it.
*/
NPY_NO_EXPORT PyObject *
PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
@@ -2648,13 +2654,18 @@ PyArray_FromInterface(PyObject *origin)
return NULL;
}
-/*NUMPY_API*/
+/*NUMPY_API
+ */
NPY_NO_EXPORT PyObject *
PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context)
{
PyObject *new;
PyObject *array_meth;
+ if (context != NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "'context' must be NULL");
+ return NULL;
+ }
array_meth = PyArray_LookupSpecial_OnInstance(op, "__array__");
if (array_meth == NULL) {
if (PyErr_Occurred()) {
@@ -2662,29 +2673,11 @@ PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context)
}
return Py_NotImplemented;
}
- if (context == NULL) {
- if (typecode == NULL) {
- new = PyObject_CallFunction(array_meth, NULL);
- }
- else {
- new = PyObject_CallFunction(array_meth, "O", typecode);
- }
+ if (typecode == NULL) {
+ new = PyObject_CallFunction(array_meth, NULL);
}
else {
- if (typecode == NULL) {
- new = PyObject_CallFunction(array_meth, "OO", Py_None, context);
- if (new == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) {
- PyErr_Clear();
- new = PyObject_CallFunction(array_meth, "");
- }
- }
- else {
- new = PyObject_CallFunction(array_meth, "OO", typecode, context);
- if (new == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) {
- PyErr_Clear();
- new = PyObject_CallFunction(array_meth, "O", typecode);
- }
- }
+ new = PyObject_CallFunction(array_meth, "O", typecode);
}
Py_DECREF(array_meth);
if (new == NULL) {
diff --git a/numpy/core/src/multiarray/datetime_busday.c b/numpy/core/src/multiarray/datetime_busday.c
index cdeb65d0e..d3cce8a37 100644
--- a/numpy/core/src/multiarray/datetime_busday.c
+++ b/numpy/core/src/multiarray/datetime_busday.c
@@ -1012,7 +1012,7 @@ array_busday_offset(PyObject *NPY_UNUSED(self),
/* This steals the datetime_dtype reference */
dates = (PyArrayObject *)PyArray_FromAny(dates_in, datetime_dtype,
- 0, 0, 0, dates_in);
+ 0, 0, 0, NULL);
if (dates == NULL) {
goto fail;
}
@@ -1021,7 +1021,7 @@ array_busday_offset(PyObject *NPY_UNUSED(self),
/* Make 'offsets' into an array */
offsets = (PyArrayObject *)PyArray_FromAny(offsets_in,
PyArray_DescrFromType(NPY_INT64),
- 0, 0, 0, offsets_in);
+ 0, 0, 0, NULL);
if (offsets == NULL) {
goto fail;
}
@@ -1142,7 +1142,7 @@ array_busday_count(PyObject *NPY_UNUSED(self),
/* This steals the datetime_dtype reference */
dates_begin = (PyArrayObject *)PyArray_FromAny(dates_begin_in,
datetime_dtype,
- 0, 0, 0, dates_begin_in);
+ 0, 0, 0, NULL);
if (dates_begin == NULL) {
goto fail;
}
@@ -1165,7 +1165,7 @@ array_busday_count(PyObject *NPY_UNUSED(self),
/* This steals the datetime_dtype reference */
dates_end = (PyArrayObject *)PyArray_FromAny(dates_end_in,
datetime_dtype,
- 0, 0, 0, dates_end_in);
+ 0, 0, 0, NULL);
if (dates_end == NULL) {
goto fail;
}
@@ -1286,7 +1286,7 @@ array_is_busday(PyObject *NPY_UNUSED(self),
/* This steals the datetime_dtype reference */
dates = (PyArrayObject *)PyArray_FromAny(dates_in,
datetime_dtype,
- 0, 0, 0, dates_in);
+ 0, 0, 0, NULL);
if (dates == NULL) {
goto fail;
}
diff --git a/numpy/core/src/multiarray/datetime_busdaycal.c b/numpy/core/src/multiarray/datetime_busdaycal.c
index eb6ef04be..1aa5f6ab1 100644
--- a/numpy/core/src/multiarray/datetime_busdaycal.c
+++ b/numpy/core/src/multiarray/datetime_busdaycal.c
@@ -293,7 +293,7 @@ PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays)
/* This steals the datetime_dtype reference */
dates = (PyArrayObject *)PyArray_FromAny(dates_in, datetime_dtype,
- 0, 0, 0, dates_in);
+ 0, 0, 0, NULL);
if (dates == NULL) {
goto fail;
}
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index db2842542..66d52cf92 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -1034,7 +1034,7 @@ get_ufunc_arguments(PyUFuncObject *ufunc,
int nin = ufunc->nin;
int nout = ufunc->nout;
int nop = ufunc->nargs;
- PyObject *obj, *context;
+ PyObject *obj;
PyArray_Descr *dtype = NULL;
/*
* Initialize output objects so caller knows when outputs and optional
@@ -1071,22 +1071,8 @@ get_ufunc_arguments(PyUFuncObject *ufunc,
out_op[i] = (PyArrayObject *)PyArray_FromArray(obj_a, NULL, 0);
}
else {
- if (!PyArray_IsScalar(obj, Generic)) {
- /*
- * TODO: There should be a comment here explaining what
- * context does.
- */
- context = Py_BuildValue("OOi", ufunc, args, i);
- if (context == NULL) {
- goto fail;
- }
- }
- else {
- context = NULL;
- }
out_op[i] = (PyArrayObject *)PyArray_FromAny(obj,
- NULL, 0, 0, 0, context);
- Py_XDECREF(context);
+ NULL, 0, 0, 0, NULL);
}
if (out_op[i] == NULL) {
@@ -4401,7 +4387,7 @@ PyUFunc_GenericReduction(PyUFuncObject *ufunc, PyObject *args,
PyObject *axes_in = NULL;
PyArrayObject *mp = NULL, *wheremask = NULL, *ret = NULL;
PyObject *op;
- PyObject *obj_ind, *context;
+ PyObject *obj_ind;
PyArrayObject *indices = NULL;
PyArray_Descr *otype = NULL;
PyArrayObject *out = NULL;
@@ -4495,14 +4481,7 @@ PyUFunc_GenericReduction(PyUFuncObject *ufunc, PyObject *args,
}
}
/* Ensure input is an array */
- if (!PyArray_Check(op) && !PyArray_IsScalar(op, Generic)) {
- context = Py_BuildValue("O(O)i", ufunc, op, 0);
- }
- else {
- context = NULL;
- }
- mp = (PyArrayObject *)PyArray_FromAny(op, NULL, 0, 0, 0, context);
- Py_XDECREF(context);
+ mp = (PyArrayObject *)PyArray_FromAny(op, NULL, 0, 0, 0, NULL);
if (mp == NULL) {
goto fail;
}
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index 0ab029988..b7baa16e1 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -1848,32 +1848,14 @@ class TestSpecialMethods:
a = A()
assert_raises(RuntimeError, ncu.maximum, a, a)
- def test_array_with_context(self):
+ def test_array_too_many_args(self):
- class A:
- def __array__(self, dtype=None, context=None):
- func, args, i = context
- self.func = func
- self.args = args
- self.i = i
- return np.zeros(1)
-
- class B:
- def __array__(self, dtype=None):
- return np.zeros(1, dtype)
-
- class C:
- def __array__(self):
+ class A(object):
+ def __array__(self, dtype, context):
return np.zeros(1)
a = A()
- ncu.maximum(np.zeros(1), a)
- assert_(a.func is ncu.maximum)
- assert_equal(a.args[0], 0)
- assert_(a.args[1] is a)
- assert_(a.i == 1)
- assert_equal(ncu.maximum(a, B()), 0)
- assert_equal(ncu.maximum(a, C()), 0)
+ assert_raises_regex(TypeError, '2 required positional', np.sum, a)
def test_ufunc_override(self):
# check override works even with instance with high priority.