Skip to content

ENH, DEP refactor updateifcopy #9451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/release/1.14.0-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ let us know.
C API changes
=============

Change internal UPDATEIFCOPY semantics
--------------------------------------
When ndarrays are created with the ``UPDATEIFCOPY`` flag, a temporary copy of
the data is created. The writeback to the original data occurrs at ndarray
deallocation. Refactor the writeback into a new PyArray_ResolveUpdateIfCopy
function and use it internally wherever such an array is created. The only
visible change in behavior is that if compiled with ``-DDEPRECATE_UPDATEIFCOPY``
or if run on PyPy, and writeback resolution has not occurred before calling
``array_dealloc``, NumPy will now raise a DeprecationWarning.

Additionally, deprecrate the NPY_ARRAY_UPDATEIFCOPY flag, replace it with
NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT. This was done to encourage downstream
consumers of the C-API to properly use the PyArray_ResolveUpdateIfCopy
function. Calling ndarray creation functions such as PyArray_FromArray where
flags uses NPY_ARRAY_UPDATEIFCOPY will raise a DeprecationWarning.

New Features
============
Expand Down
2 changes: 1 addition & 1 deletion numpy/core/code_generators/cversions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@
0x0000000a = 9b8bce614655d3eb02acddcb508203cb

# Version 11 (NumPy 1.13) Added PyArray_MapIterArrayCopyIfOverlap
# Version 11 (NumPy 1.14) No Change
# Version 11 (NumPy 1.14) Added PyArray_ResolveUpdateIfCopy
0x0000000b = edb1ba83730c650fd9bc5772a919cda7
2 changes: 2 additions & 0 deletions numpy/core/code_generators/numpy_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@
# End 1.10 API
'PyArray_MapIterArrayCopyIfOverlap': (301,),
# End 1.13 API
'PyArray_ResolveUpdateIfCopy': (302,),
# End 1.14 API
}

ufunc_types_api = {
Expand Down
4 changes: 2 additions & 2 deletions numpy/core/include/numpy/ndarrayobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@ static NPY_INLINE void
PyArray_XDECREF_ERR(PyArrayObject *arr)
{
if (arr != NULL) {
if (PyArray_FLAGS(arr) & NPY_ARRAY_UPDATEIFCOPY) {
if (PyArray_FLAGS(arr) & NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT) {
PyArrayObject *base = (PyArrayObject *)PyArray_BASE(arr);
PyArray_ENABLEFLAGS(base, NPY_ARRAY_WRITEABLE);
PyArray_CLEARFLAGS(arr, NPY_ARRAY_UPDATEIFCOPY);
PyArray_CLEARFLAGS(arr, NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT);
}
Py_DECREF(arr);
}
Expand Down
7 changes: 4 additions & 3 deletions numpy/core/include/numpy/ndarraytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,8 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
* This flag may be requested in constructor functions.
* This flag may be tested for in PyArray_FLAGS(arr).
*/
#define NPY_ARRAY_UPDATEIFCOPY 0x1000
#define NPY_ARRAY_UPDATEIFCOPY 0x1000 /* Deprecated in 1.14 */
#define NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT 0x2000

/*
* NOTE: there are also internal flags defined in multiarray/arrayobject.h,
Expand All @@ -894,11 +895,11 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
#define NPY_ARRAY_IN_ARRAY (NPY_ARRAY_CARRAY_RO)
#define NPY_ARRAY_OUT_ARRAY (NPY_ARRAY_CARRAY)
#define NPY_ARRAY_INOUT_ARRAY (NPY_ARRAY_CARRAY | \
NPY_ARRAY_UPDATEIFCOPY)
NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT)
#define NPY_ARRAY_IN_FARRAY (NPY_ARRAY_FARRAY_RO)
#define NPY_ARRAY_OUT_FARRAY (NPY_ARRAY_FARRAY)
#define NPY_ARRAY_INOUT_FARRAY (NPY_ARRAY_FARRAY | \
NPY_ARRAY_UPDATEIFCOPY)
NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT)

#define NPY_ARRAY_UPDATE_ALL (NPY_ARRAY_C_CONTIGUOUS | \
NPY_ARRAY_F_CONTIGUOUS | \
Expand Down
2 changes: 1 addition & 1 deletion numpy/core/include/numpy/npy_1_7_deprecated_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#define NPY_ALIGNED NPY_ARRAY_ALIGNED
#define NPY_NOTSWAPPED NPY_ARRAY_NOTSWAPPED
#define NPY_WRITEABLE NPY_ARRAY_WRITEABLE
#define NPY_UPDATEIFCOPY NPY_ARRAY_UPDATEIFCOPY
#define NPY_UPDATEIFCOPY NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be reverted -- if someone's using the deprecated NPY_UPDATEIFCOPY alias, then they should get NPY_ARRAY_UPDATEIFCOPY semantics.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

#define NPY_BEHAVED NPY_ARRAY_BEHAVED
#define NPY_BEHAVED_NS NPY_ARRAY_BEHAVED_NS
#define NPY_CARRAY NPY_ARRAY_CARRAY
Expand Down
94 changes: 71 additions & 23 deletions numpy/core/src/multiarray/arrayobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ PyArray_SetUpdateIfCopyBase(PyArrayObject *arr, PyArrayObject *base)
* references.
*/
((PyArrayObject_fields *)arr)->base = (PyObject *)base;
PyArray_ENABLEFLAGS(arr, NPY_ARRAY_UPDATEIFCOPY);
PyArray_ENABLEFLAGS(arr, NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, this is dubious. PyArray_SetUpdateIfCopyBase is public, so there might be third-party code that uses it and expects the GC to resolve the UPDATEIFCOPY. I guess we need to make PyArray_SetUpdateIfCopyBase keep using NPY_ARRAY_UPDATEIFCOPY and issue a deprecation warning, and add a new function PyArray_SetUpdateIfCopyBaseWithExplicitResolve or something like that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, will add a PyArray_CopyDataFromBase that will set the new flag, and use it instead across the code base

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't understand the naming scheme here. IIRC (from my phone), PyArray_SetUpdateIfCopyBase sets the UPDATEIFCOPY flag and sets the ->base member, but it doesn't copy any data does it? I was suggesting having a version that's identical except that it sets the new flag instead of the old one and doesn't warn. What does PyArray_CopyDataFromBase do?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct, so maybe PyArray_SetUpToCopyData?

PyArray_CLEARFLAGS(base, NPY_ARRAY_WRITEABLE);

return 0;
Expand Down Expand Up @@ -372,10 +372,63 @@ PyArray_TypeNumFromName(char *str)
return NPY_NOTYPE;
}

/*NUMPY_API
*
* If UPDATEIFCOPY and self has data, reset the base WRITEABLE flag,
* copy the local data to base, release the local data, and set flags
* appropriately. Return 0 if not relevant, 1 if success, < 0 on failure
*/
NPY_NO_EXPORT int
PyArray_ResolveUpdateIfCopy(PyArrayObject * self)
{
PyArrayObject_fields *fa = (PyArrayObject_fields *)self;
if (fa && fa->base) {
if (fa->flags & NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT) {
/*
* UPDATEIFCOPY means that fa->base's data
* should be updated with the contents
* of self.
* fa->base->flags is not WRITEABLE to protect the relationship
* unlock it.
*/
int retval = 0;
PyArray_ENABLEFLAGS(((PyArrayObject *)fa->base),
NPY_ARRAY_WRITEABLE);
PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT);
retval = PyArray_CopyAnyInto((PyArrayObject *)fa->base, self);
if (retval < 0) {
/* this should never happen, how did the two copies of data
* get out of sync?
*/
return retval;
}
if ((fa->flags & NPY_ARRAY_OWNDATA) && fa->data) {
/* Free internal references if an Object array */
if (PyDataType_FLAGCHK(fa->descr, NPY_ITEM_REFCOUNT)) {
Py_INCREF(self); /*hold on to self */
PyArray_XDECREF(self);
Py_DECREF(self);
}
npy_free_cache(fa->data, PyArray_NBYTES(self));
fa->data = NULL;
PyArray_CLEARFLAGS(self, NPY_ARRAY_OWNDATA);
}
return 1;
}
}
return 0;
}

/*********************** end C-API functions **********************/

/* array object functions */

#ifdef PYPY_VERSION
#ifndef DEPRECATE_UPDATEIFCOPY
#define DEPRECATE_UPDATEIFCOPY
#endif
#endif

static void
array_dealloc(PyArrayObject *self)
{
Expand All @@ -387,27 +440,24 @@ array_dealloc(PyArrayObject *self)
PyObject_ClearWeakRefs((PyObject *)self);
}
if (fa->base) {
/*
* UPDATEIFCOPY means that base points to an
* array that should be updated with the contents
* of this array upon destruction.
* fa->base->flags must have been WRITEABLE
* (checked previously) and it was locked here
* thus, unlock it.
*/
if (fa->flags & NPY_ARRAY_UPDATEIFCOPY) {
PyArray_ENABLEFLAGS(((PyArrayObject *)fa->base),
NPY_ARRAY_WRITEABLE);
Py_INCREF(self); /* hold on to self in next call */
if (PyArray_CopyAnyInto((PyArrayObject *)fa->base, self) < 0) {
PyErr_Print();
PyErr_Clear();
}
/*
* Don't need to DECREF -- because we are deleting
*self already...
int retval;
Py_INCREF(self); /* hold on to self in next call */
retval = PyArray_ResolveUpdateIfCopy(self);
if (retval < 0)
{
PyErr_Print();
PyErr_Clear();
}
#ifdef DEPRECATE_UPDATEIFCOPY
if (retval > 0) {
DEPRECATE("UPDATEIFCOPY resolution in array_dealloc is "
"incompatible with PyPy and will be removed in "
"the future");
/* dealloc must not raise an error, even if warning filters are set
*/
PyErr_Clear();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should use PyErr_WriteUnraisable() or similar – otherwise when someone sets a warning filter to deprecations into errors, then the effect will be to hide this warning entirely!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, will add a test as well

}
#endif
/*
* In any case base is pointing to something that we need
* to DECREF -- either a view or a buffer object
Expand Down Expand Up @@ -482,7 +532,7 @@ PyArray_DebugPrint(PyArrayObject *obj)
printf(" NPY_ALIGNED");
if (fobj->flags & NPY_ARRAY_WRITEABLE)
printf(" NPY_WRITEABLE");
if (fobj->flags & NPY_ARRAY_UPDATEIFCOPY)
if (fobj->flags & NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT)
printf(" NPY_UPDATEIFCOPY");
printf("\n");

Expand All @@ -507,8 +557,6 @@ PyArray_SetDatetimeParseFunction(PyObject *op)
{
}



/*NUMPY_API
*/
NPY_NO_EXPORT int
Expand Down
9 changes: 6 additions & 3 deletions numpy/core/src/multiarray/calculation.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ PyArray_ArgMax(PyArrayObject *op, int axis, PyArrayObject *out)
}
rp = (PyArrayObject *)PyArray_FromArray(out,
PyArray_DescrFromType(NPY_INTP),
NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY);
NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT);
if (rp == NULL) {
goto fail;
}
Expand All @@ -136,6 +136,7 @@ PyArray_ArgMax(PyArrayObject *op, int axis, PyArrayObject *out)
Py_DECREF(ap);
/* Trigger the UPDATEIFCOPY if necessary */
if (out != NULL && out != rp) {
PyArray_ResolveUpdateIfCopy(rp);
Py_DECREF(rp);
rp = out;
Py_INCREF(rp);
Expand Down Expand Up @@ -233,7 +234,7 @@ PyArray_ArgMin(PyArrayObject *op, int axis, PyArrayObject *out)
}
rp = (PyArrayObject *)PyArray_FromArray(out,
PyArray_DescrFromType(NPY_INTP),
NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY);
NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT);
if (rp == NULL) {
goto fail;
}
Expand All @@ -251,6 +252,7 @@ PyArray_ArgMin(PyArrayObject *op, int axis, PyArrayObject *out)
Py_DECREF(ap);
/* Trigger the UPDATEIFCOPY if necessary */
if (out != NULL && out != rp) {
PyArray_ResolveUpdateIfCopy(rp);
Py_DECREF(rp);
rp = out;
Py_INCREF(rp);
Expand Down Expand Up @@ -1117,7 +1119,7 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o
oflags = NPY_ARRAY_FARRAY;
else
oflags = NPY_ARRAY_CARRAY;
oflags |= NPY_ARRAY_UPDATEIFCOPY | NPY_ARRAY_FORCECAST;
oflags |= NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT | NPY_ARRAY_FORCECAST;
Py_INCREF(indescr);
newout = (PyArrayObject*)PyArray_FromArray(out, indescr, oflags);
if (newout == NULL) {
Expand Down Expand Up @@ -1153,6 +1155,7 @@ PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *o
Py_XDECREF(maxa);
Py_DECREF(newin);
/* Copy back into out if out was not already a nice array. */
PyArray_ResolveUpdateIfCopy(newout);
Py_DECREF(newout);
return (PyObject *)out;

Expand Down
1 change: 1 addition & 0 deletions numpy/core/src/multiarray/cblasfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,7 @@ cblas_matrixproduct(int typenum, PyArrayObject *ap1, PyArrayObject *ap2,
Py_DECREF(ap2);

/* Trigger possible copyback into `result` */
PyArray_ResolveUpdateIfCopy(out_buf);
Py_DECREF(out_buf);

return PyArray_Return(result);
Expand Down
3 changes: 2 additions & 1 deletion numpy/core/src/multiarray/compiled_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ arr_insert(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
}

array = (PyArrayObject *)PyArray_FromArray((PyArrayObject *)array0, NULL,
NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY);
NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT);
if (array == NULL) {
goto fail;
}
Expand Down Expand Up @@ -402,6 +402,7 @@ arr_insert(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)

Py_XDECREF(values);
Py_XDECREF(mask);
PyArray_ResolveUpdateIfCopy(array);
Py_DECREF(array);
Py_RETURN_NONE;

Expand Down
28 changes: 21 additions & 7 deletions numpy/core/src/multiarray/ctors.c
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ PyArray_NewFromDescr_int(PyTypeObject *subtype, PyArray_Descr *descr, int nd,
}
}
else {
fa->flags = (flags & ~NPY_ARRAY_UPDATEIFCOPY);
fa->flags = (flags & ~NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should clear both versions of the flag, I think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}
fa->descr = descr;
fa->base = (PyObject *)NULL;
Expand Down Expand Up @@ -1703,7 +1703,8 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,

/* If we got dimensions and dtype instead of an array */
if (arr == NULL) {
if (flags & NPY_ARRAY_UPDATEIFCOPY) {
if ((flags & NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT) ||
(flags & NPY_ARRAY_UPDATEIFCOPY)) {
Py_XDECREF(newtype);
PyErr_SetString(PyExc_TypeError,
"UPDATEIFCOPY used for non-array input.");
Expand Down Expand Up @@ -1811,6 +1812,7 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
* NPY_ARRAY_NOTSWAPPED,
* NPY_ARRAY_ENSURECOPY,
* NPY_ARRAY_UPDATEIFCOPY,
* NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT,
* NPY_ARRAY_FORCECAST,
* NPY_ARRAY_ENSUREARRAY,
* NPY_ARRAY_ELEMENTSTRIDES
Expand All @@ -1835,10 +1837,13 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
* Fortran arrays are always behaved (aligned,
* notswapped, and writeable) and not (C) CONTIGUOUS (if > 1d).
*
* NPY_ARRAY_UPDATEIFCOPY flag sets this flag in the returned array if a copy
* is made and the base argument points to the (possibly) misbehaved array.
* When the new array is deallocated, the original array held in base
* is updated with the contents of the new array.
* NPY_ARRAY_UPDATEIFCOPY is deprecated in favor of
* NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT in 1.14

* NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT flag sets this flag in the returned
* array if a copy is made and the base argument points to the (possibly)
* misbehaved array. Before returning to python, PyArray_ResolveUpdateIfCopy
* must be called to update the contents of the orignal array from the copy.
*
* NPY_ARRAY_FORCECAST will cause a cast to occur regardless of whether or not
* it is safe.
Expand Down Expand Up @@ -2005,7 +2010,16 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags)
return NULL;
}

if (flags & NPY_ARRAY_UPDATEIFCOPY) {
if ((flags & NPY_ARRAY_UPDATEIFCOPY) ||
(flags & NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT)) {
if (flags & NPY_ARRAY_UPDATEIFCOPY) {
if (DEPRECATE("Use NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT and"
" be sure to call PyArray_ResolveUpdateIfCopy") < 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this have an #ifdef around it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of #ifdef?
We do not wish to issue a DeprecationWarning in the current version of NumPy?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ultimately yeah it should be deprecated, but I thought your plan was to initially introduce this with all the warnings hidden behind a DEPRECATE_UPDATEIFCOPY ifdef.

/* 2017-07-24, 1.14 */
Py_DECREF(ret);
return NULL;
}
}
Py_INCREF(arr);
if (PyArray_SetUpdateIfCopyBase(ret, arr) < 0) {
Py_DECREF(ret);
Expand Down
4 changes: 2 additions & 2 deletions numpy/core/src/multiarray/flagsobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ arrayflags_dealloc(PyArrayFlagsObject *self)

_define_get(NPY_ARRAY_C_CONTIGUOUS, contiguous)
_define_get(NPY_ARRAY_F_CONTIGUOUS, fortran)
_define_get(NPY_ARRAY_UPDATEIFCOPY, updateifcopy)
_define_get(NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT, updateifcopy)
_define_get(NPY_ARRAY_OWNDATA, owndata)
_define_get(NPY_ARRAY_ALIGNED, aligned)
_define_get(NPY_ARRAY_WRITEABLE, writeable)
Expand Down Expand Up @@ -595,7 +595,7 @@ arrayflags_print(PyArrayFlagsObject *self)
"OWNDATA", _torf_(fl, NPY_ARRAY_OWNDATA),
"WRITEABLE", _torf_(fl, NPY_ARRAY_WRITEABLE),
"ALIGNED", _torf_(fl, NPY_ARRAY_ALIGNED),
"UPDATEIFCOPY", _torf_(fl, NPY_ARRAY_UPDATEIFCOPY));
"UPDATEIFCOPY", _torf_(fl, NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT));
}


Expand Down
6 changes: 3 additions & 3 deletions numpy/core/src/multiarray/getset.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,10 @@ array_data_set(PyArrayObject *self, PyObject *op)
PyDataMem_FREE(PyArray_DATA(self));
}
if (PyArray_BASE(self)) {
if (PyArray_FLAGS(self) & NPY_ARRAY_UPDATEIFCOPY) {
if (PyArray_FLAGS(self) & NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT) {
PyArray_ENABLEFLAGS((PyArrayObject *)PyArray_BASE(self),
NPY_ARRAY_WRITEABLE);
PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY);
PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT);
}
Py_DECREF(PyArray_BASE(self));
((PyArrayObject_fields *)self)->base = NULL;
Expand Down Expand Up @@ -604,7 +604,7 @@ array_struct_get(PyArrayObject *self)
inter->itemsize = PyArray_DESCR(self)->elsize;
inter->flags = PyArray_FLAGS(self);
/* reset unused flags */
inter->flags &= ~(NPY_ARRAY_UPDATEIFCOPY | NPY_ARRAY_OWNDATA);
inter->flags &= ~(NPY_ARRAY_UPDATEIFCOPY_CLEAR_B4_EXIT | NPY_ARRAY_OWNDATA);
if (PyArray_ISNOTSWAPPED(self)) inter->flags |= NPY_ARRAY_NOTSWAPPED;
/*
* Copy shape and strides over since these can be reset
Expand Down
Loading