Skip to content

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

Merged
merged 1 commit into from
Jul 31, 2017

Conversation

eric-wieser
Copy link
Member

No description provided.

@@ -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;
Copy link
Member Author

Choose a reason for hiding this comment

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

Didn't previously decref

Copy link
Contributor

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))) {
Copy link
Member Author

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;
Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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...

Copy link
Member Author

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.

Copy link
Member

Choose a reason for hiding this comment

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

Exactly ;)

Copy link
Member Author

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;
}
Copy link
Member Author

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

else if (PyArray_IS_F_CONTIGUOUS(self)) {
/* 2015-11-27 1.11.0 */
if (DEPRECATE(
"Changing the shape of an F-contiguous array by "
Copy link
Member Author

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

Copy link
Member

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?

Copy link
Contributor

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?

Copy link
Member Author

@eric-wieser eric-wieser Jul 31, 2017

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

Copy link
Member Author

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

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");
Copy link
Member

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.

Copy link
Member

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.

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, 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));
Copy link
Member

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.

Copy link
Member Author

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.

@charris
Copy link
Member

charris commented Jul 31, 2017

Couple of guestions, generally looks good.

Copy link
Contributor

@mhvk mhvk left a 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;
Copy link
Contributor

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)

else if (PyArray_IS_F_CONTIGUOUS(self)) {
/* 2015-11-27 1.11.0 */
if (DEPRECATE(
"Changing the shape of an F-contiguous array by "
Copy link
Contributor

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 */
Copy link
Contributor

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.

Copy link
Member Author

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.

@eric-wieser
Copy link
Member Author

eric-wieser commented Jul 31, 2017

behaviour of view adjusted!

As a MAINT PR, there is no (deliberate) behaviour change here - what change did you think this made?

@eric-wieser
Copy link
Member Author

Updated with a fix to the error message noticed by @charris, and a slightly clearer message for the non-contiguous case

@charris charris merged commit be7266d into numpy:master Jul 31, 2017
@charris
Copy link
Member

charris commented Jul 31, 2017

Thanks Eric.

@eric-wieser
Copy link
Member Author

Thanks for the fast merge - I'll rebase and reopen my other PR now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants