-
-
Notifications
You must be signed in to change notification settings - Fork 12k
BUG: Ensure __array_finalize__ cannot back-mangle shape
#10314
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
numpy/ma/core.py
Outdated
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.
Might be clearer to add dtype and shape @properties that fall back on ndarray.shape.__get__ etc
numpy/ma/tests/test_old_ma.py
Outdated
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.
Hmmm... I'd actually expect the stronger result of y1a is y1 here
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 is #4043, I think
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.
Maybe add a comment referencing that issue here?
numpy/ma/tests/test_core.py
Outdated
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.
Wait, what? This doesn't seem sensible to me at all (#10318)
|
@eric-wieser - I agree the changes in behaviour for Also agreed that setters for |
e39107a to
97628c2
Compare
|
@eric-wieser - your comment reminded me about the existence of this branch... I now added a second commit replacing I also still need to think of a test case that shows this actually prevents any problems! |
numpy/ma/core.py
Outdated
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 should be just super(MaskedArray).shape or perhaps just ndarray.shape
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.
Edit: I'm wrong. TIL how super(cls, cls) works
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.
Yes, this annoyance is in part why I wondered if it was a good idea to replace __setattr__ with this...
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.
The advantage is that subclasses are now able to call Maskedarray.shape.__set__ in the unlikely even they override shape, and it won't accidentally call ndarray.shape.__set__
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.
Actually, I think this should be super(MaskedArray, type(self)), which correctly walks the MRO.
|
Is this enough for a test? On >>> a = np.ma.array([1, 2, 3, 4], mask=True)
>>> d = a.data
>>> m = a.mask
>>> a.shape = (2, 2)
>>> d
array([1, 2, 3, 4])
>>> m # your patch stops this changing shape, which is consistent with d
array([[ True, True],
[ True, True]], dtype=bool) |
|
Hmm, that particular case is not solved by this PR - it needs your original one, where the mask is always viewed. Indeed, I found it very hard to far to get to a case where my PR matters... I'll try a bit more, but if it fails, perhaps best to split it into two - and at least get rid of the |
|
Ok, we now have a concrete problem caused by this, as documented in #3140 |
Since dtype and shape are properties, this needs a somewhat ugly super construction; see https://bugs.python.org/issue14965
97628c2 to
b779bae
Compare
|
Thanks for realizing there was a test case after all! I now added it, and rebased for good measure (and fixed the |
|
|
||
| @property | ||
| def shape(self): | ||
| return super(MaskedArray, self).shape |
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.
Pretty sure this needs to be super(MaskedArray, type(self)).shape.__get__(self, type(self)), unless there's something weird about base classes in C
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.
Ok, seems there's something weird about base classes. If this were shadowing another property (rather than a getset_descriptor) , you'd need what I have above.
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 don't think that's true - I;m fairly sure one can shadow a property getter as I have it above, just not the setter.
|
Thanks @mhvk! |
__array_finalize__ cannot back-mangle shape
Just a small step, but
__array_finalize__should not be allowed to change the shape of anyobjpassed in. Arguably, it should not change the shape of the mask at all, but removing that currently breaks quite a bit more, so perhaps it is best to try to remedy that in a second step.Need to think a bit about a test case that shows that this actually prevents problems.