@@ -1421,7 +1421,7 @@ _array_from_buffer_3118(PyObject *memoryview)
14211421 * DType may be used, but is not enforced.
14221422 * @param writeable whether the result must be writeable.
14231423 * @param context Unused parameter, must be NULL (should be removed later).
1424- * @param never_copy Specifies that a copy is not allowed .
1424+ * @param copy Specifies the copy behavior .
14251425 *
14261426 * @returns The array object, Py_NotImplemented if op is not array-like,
14271427 * or NULL with an error set. (A new reference to Py_NotImplemented
@@ -1430,7 +1430,7 @@ _array_from_buffer_3118(PyObject *memoryview)
14301430NPY_NO_EXPORT PyObject *
14311431_array_from_array_like (PyObject * op ,
14321432 PyArray_Descr * requested_dtype , npy_bool writeable , PyObject * context ,
1433- int never_copy ) {
1433+ int copy ) {
14341434 PyObject * tmp ;
14351435
14361436 /*
@@ -1478,7 +1478,7 @@ _array_from_array_like(PyObject *op,
14781478 }
14791479
14801480 if (tmp == Py_NotImplemented ) {
1481- tmp = PyArray_FromArrayAttr_int (op , requested_dtype , never_copy );
1481+ tmp = PyArray_FromArrayAttr_int (op , requested_dtype , copy );
14821482 if (tmp == NULL ) {
14831483 return NULL ;
14841484 }
@@ -1563,9 +1563,15 @@ PyArray_FromAny_int(PyObject *op, PyArray_Descr *in_descr,
15631563 return NULL ;
15641564 }
15651565
1566- ndim = PyArray_DiscoverDTypeAndShape (op ,
1567- NPY_MAXDIMS , dims , & cache , in_DType , in_descr , & dtype ,
1568- flags & NPY_ARRAY_ENSURENOCOPY );
1566+ // Default is copy = None
1567+ int copy = -1 ;
1568+
1569+ if (flags & NPY_ARRAY_ENSURENOCOPY ) {
1570+ copy = 0 ;
1571+ }
1572+
1573+ ndim = PyArray_DiscoverDTypeAndShape (
1574+ op , NPY_MAXDIMS , dims , & cache , in_DType , in_descr , & dtype , copy );
15691575
15701576 if (ndim < 0 ) {
15711577 return NULL ;
@@ -2408,15 +2414,16 @@ PyArray_FromInterface(PyObject *origin)
24082414 * @param op The Python object to convert to an array.
24092415 * @param descr The desired `arr.dtype`, passed into the `__array__` call,
24102416 * as information but is not checked/enforced!
2411- * @param never_copy Specifies that a copy is not allowed.
2412- * NOTE: For false it passes `op.__array__(copy=None)`,
2413- * for true: `op.__array__(copy=False)`.
2417+ * @param copy Specifies the copy behavior
2418+ * NOTE: For copy == -1 it passes `op.__array__(copy=None)`,
2419+ * for copy == 0, `op.__array__(copy=False)`, and
2420+ * for copy == 1, `op.__array__(copy=True).
24142421 * @returns NotImplemented if `__array__` is not defined or a NumPy array
24152422 * (or subclass). On error, return NULL.
24162423 */
24172424NPY_NO_EXPORT PyObject *
24182425PyArray_FromArrayAttr_int (
2419- PyObject * op , PyArray_Descr * descr , int never_copy )
2426+ PyObject * op , PyArray_Descr * descr , int copy )
24202427{
24212428 PyObject * new ;
24222429 PyObject * array_meth ;
@@ -2440,36 +2447,59 @@ PyArray_FromArrayAttr_int(
24402447 return Py_NotImplemented ;
24412448 }
24422449
2443- PyObject * copy = never_copy ? Py_False : Py_None ;
24442450 PyObject * kwargs = PyDict_New ();
2445- PyDict_SetItemString (kwargs , "copy" , copy );
2451+
2452+ /*
2453+ * Only if the value of `copy` isn't the default one, we try to pass it
2454+ * along; for backwards compatibility we then retry if it fails because the
2455+ * signature of the __array__ method being called does not have `copy`.
2456+ */
2457+ int copy_passed = 0 ;
2458+ if (copy != -1 ) {
2459+ copy_passed = 1 ;
2460+ PyObject * copy_obj = copy == 1 ? Py_True : Py_False ;
2461+ PyDict_SetItemString (kwargs , "copy" , copy_obj );
2462+ }
24462463 PyObject * args = descr != NULL ? PyTuple_Pack (1 , descr ) : PyTuple_New (0 );
24472464
24482465 new = PyObject_Call (array_meth , args , kwargs );
24492466
2450- if (PyErr_Occurred ()) {
2467+ if (new == NULL ) {
2468+ PyObject * errmsg_substr = PyUnicode_FromString (
2469+ "__array__() got an unexpected keyword argument 'copy'" );
2470+ if (errmsg_substr == NULL ) {
2471+ return NULL ;
2472+ }
24512473 PyObject * type , * value , * traceback ;
24522474 PyErr_Fetch (& type , & value , & traceback );
2453- if (PyUnicode_Check (value ) && PyUnicode_CompareWithASCIIString (value ,
2454- "__array__() got an unexpected keyword argument 'copy'" ) == 0 ) {
2475+ if (PyUnicode_Check (value ) && PyUnicode_Contains (value , errmsg_substr ) > 0 ) {
24552476 Py_DECREF (type );
24562477 Py_XDECREF (value );
24572478 Py_XDECREF (traceback );
2479+ Py_DECREF (errmsg_substr );
24582480 if (PyErr_WarnEx (PyExc_UserWarning ,
24592481 "__array__ should implement 'dtype' and 'copy' keywords" , 1 ) < 0 ) {
24602482 return NULL ;
24612483 }
2462- Py_SETREF (new , PyObject_Call (array_meth , args , NULL ));
2484+ if (copy_passed ) { /* try again */
2485+ PyDict_DelItemString (kwargs , "copy" );
2486+ new = PyObject_Call (array_meth , args , kwargs );
2487+ if (new == NULL ) {
2488+ Py_DECREF (kwargs );
2489+ return NULL ;
2490+ }
2491+ }
24632492 } else {
24642493 PyErr_Restore (type , value , traceback );
2494+ Py_DECREF (errmsg_substr );
2495+ Py_DECREF (kwargs );
24652496 return NULL ;
24662497 }
24672498 }
24682499
2500+ Py_DECREF (kwargs );
24692501 Py_DECREF (array_meth );
2470- if (new == NULL ) {
2471- return NULL ;
2472- }
2502+
24732503 if (!PyArray_Check (new )) {
24742504 PyErr_SetString (PyExc_ValueError ,
24752505 "object __array__ method not " \
0 commit comments