-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
MAINT/BUG: Improve error messages for dtype reassigment, fix missing DECREFs #9499
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
Conversation
@@ -461,14 +460,13 @@ array_descr_set(PyArrayObject *self, PyObject *arg) | |||
if (_may_have_objects(PyArray_DESCR(self)) || _may_have_objects(newtype)) { | |||
npy_cache_import("numpy.core._internal", "_view_is_safe", &checkfunc); | |||
if (checkfunc == NULL) { | |||
return -1; | |||
goto fail; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't previously decref
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. Have to say I continue to dislike if
-statements with side effects... (obviously outside of this PR, though)
if ((newtype->elsize != PyArray_DESCR(self)->elsize) && | ||
(PyArray_NDIM(self) == 0 || | ||
!PyArray_ISONESEGMENT(self) || | ||
PyDataType_HASSUBARRAY(newtype))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of unrelated failures in here that justify their own error message. PyArray_ISONESEGMENT
becomes the checks for F and C contiguity further down.
"array, use 'a.T.view(...).T' instead") < 0) { | ||
goto fail; | ||
} | ||
axis = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means the deprecation warning and the behavior being deprecated are now in the same place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never decided if we should be putting line endings in these error messages. Maybe we should have our own err calls that wrap the messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the line endings make things render more messily, especially since the first line gets an arbitrary prefix depending on whether its a warning or error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's why I think the error message formatter should take care of it. I don't expect anything in that direction to happen in the next decade...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, this is not our problem, and is the concern of things higher up in the stack, starting from the python exception-printing mechanism, and extending to a line-wrapping terminal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I'm happy with my line-wrapping terminal dealing with it at the moment :)
} | ||
PyArray_DIMS(self)[axis] = newdim / newtype->elsize; | ||
PyArray_STRIDES(self)[axis] = newtype->elsize; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two branches are unchanged other than in error message, but are moved within the elsize != elsize
check for clarity
numpy/core/src/multiarray/getset.c
Outdated
else if (PyArray_IS_F_CONTIGUOUS(self)) { | ||
/* 2015-11-27 1.11.0 */ | ||
if (DEPRECATE( | ||
"Changing the shape of an F-contiguous array by " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"non-C contiguous" → "F-contiguous". All other stride layouts were already caught by PyArray_ISONESEGMENT
anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't PyArray_ISONESEGMENT
gone?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also wondered that, or is it just caught by the else
clause below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PyArray_ISONESEGMENT == PyArray_IS_F_CONTIGUOUS | PyArray_IS_C_CONTIGUOUS | ZERO_DIM
, so this is covered by that else clause
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, as far as I can tell, zero dimensional always implies F_CONTIGUOUS && C_CONTIGUOUS
numpy/core/src/multiarray/getset.c
Outdated
if ((newdim % newtype->elsize) != 0) { | ||
PyErr_SetString(PyExc_ValueError, | ||
"When changing to a larger dtype, its size must be a " | ||
"multiple of the size of original dtype"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite accurate, what this looks like is that the new size must divide the total size of the axis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost seems too loose, although already the case. Could equally apply to the < case. Seems like it should also be a multiple of the original type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I'll update the message.
I don't think we can make it less loose without a deprecation cycle, and might be in favor of making the other case more loose (as in #6097). Having said that, I can't think of a single reason this would be useful)
@@ -573,12 +583,12 @@ array_descr_set(PyArrayObject *self, PyObject *arg) | |||
Py_DECREF(temp); | |||
} | |||
|
|||
Py_DECREF(PyArray_DESCR(self)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it safe to move this? It may have already have been overwritten. In any case, it is easier to be sure if it is left where it was.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand, leaving it where it was brings into question whether something was looking at a decref'd dtype.
Couple of guestions, generally looks good. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great to see the previous somewhat illogical behaviour of view
adjusted!
@@ -461,14 +460,13 @@ array_descr_set(PyArrayObject *self, PyObject *arg) | |||
if (_may_have_objects(PyArray_DESCR(self)) || _may_have_objects(newtype)) { | |||
npy_cache_import("numpy.core._internal", "_view_is_safe", &checkfunc); | |||
if (checkfunc == NULL) { | |||
return -1; | |||
goto fail; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. Have to say I continue to dislike if
-statements with side effects... (obviously outside of this PR, though)
numpy/core/src/multiarray/getset.c
Outdated
else if (PyArray_IS_F_CONTIGUOUS(self)) { | ||
/* 2015-11-27 1.11.0 */ | ||
if (DEPRECATE( | ||
"Changing the shape of an F-contiguous array by " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also wondered that, or is it just caught by the else
clause below?
axis = 0; | ||
} | ||
else { | ||
/* Don't mention the deprecated F-contiguous support */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this comment is not particularly helpful - it assumes a future reader knows that in the past these error messages were combined. I'd suggest to remove it or make it clear that this branch is for non-contiguous arrays.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's an else clause for if(c-contig) elseif (f-contif) else
, so the obvious conclusion is "must be c or f contig"
. But this would encourage the deprecated use.
As a MAINT PR, there is no (deliberate) behaviour change here - what change did you think this made? |
fdd3982
to
8cc4480
Compare
Updated with a fix to the error message noticed by @charris, and a slightly clearer message for the non-contiguous case |
Thanks Eric. |
Thanks for the fast merge - I'll rebase and reopen my other PR now |
No description provided.