-
-
Notifications
You must be signed in to change notification settings - Fork 5k
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
DEP: signal: raise error using medfilt and order_filter with float128 and object dtypes #19673
Conversation
… and object dtypes
@@ -1115,7 +1106,7 @@ def test_invalid_dtypes(self, dtype): | |||
def test_none(self): | |||
# gh-1651, trac #1124. Ensure this does not segfault. | |||
with pytest.warns(UserWarning): | |||
assert_raises(TypeError, signal.medfilt, None) | |||
assert_raises(ValueError, signal.medfilt, None) |
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.
Looks like there was some sort of special casing here for None. Have it lumped in with the others that raise ValueError but could special case so this remains a TypeError
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 mismatch between the PR title and the scope of what it does.
I'm also a bit confused since gh-18341 said "The goal here is to reduce duplication between ndimage and signal, and get rid of https://github.com/scipy/scipy/blob/main/scipy/signal/_lfilter.c.in entirely (700 LOC of fairly obscure C code). Cannot just remove them, so deprecate first." |
The point of the original deprecation was that we currently have two sets of C code for doing the same thing, one in |
There are some relevant test failures that need resolving though |
Ah okay, so does all of |
As far as I could tell it was still needed but I also might have just got lost the maze. Maybe @ev-br could confirm? |
scipy/signal/_signaltools.py
Outdated
if volume.dtype in [np.bool_, np.complex64, np.complex128, np.clongdouble, | ||
np.float16]: | ||
np.float16, np.object_, 'float128']: |
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.
Note that you want to use longdouble
as the dtype name, because that's the canonical one (float128
may not exist, and then the alias float96
will exist)
Indeed. Thank you Jake for chasing down where this dead code is despite the typo in the original PR which introduced the deprecation. |
Updated to use |
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.
Some relatively minor nits, otherwise looking good (thanks for the context on _order_filterND
).
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.
Last details. Not sure why the doc build is failing, but at least win/macos jobs need to be fixed.
scipy/signal/_signaltools.py
Outdated
if volume.dtype in [np.bool_, np.complex64, np.complex128, np.clongdouble, | ||
np.float16, np.object_, np.longdouble]: | ||
raise ValueError(f"dtype={volume.dtype} is not supported by medfilt") |
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 np.longdouble
here is incorrect, because on windows that just ends up being float64
and then causes
FAILED scipy\signal\tests\test_signaltools.py::TestMedFilt::test_types[float64] - ValueError: dtype=float64 is not supported by medfilt
IMO it would be better to formulate this as:
if volume.dtype in [np.bool_, np.complex64, np.complex128, np.clongdouble, | |
np.float16, np.object_, np.longdouble]: | |
raise ValueError(f"dtype={volume.dtype} is not supported by medfilt") | |
if volume.dtype not in <list_of_allowed_types>: | |
raise ValueError(f"dtype={volume.dtype} is not supported by medfilt") |
948529e
to
5713ab4
Compare
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 there, but still not yet. 🙃
scipy/signal/_signaltools.py
Outdated
if volume.dtype in [np.bool_, np.complex64, np.complex128, np.clongdouble, | ||
np.float16, np.object_, "float128", "float96"]: | ||
raise ValueError(f"dtype={volume.dtype} is not supported by medfilt") |
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 would still prefer explicitly naming the types for which we have support in medfilt (non-binding).
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.
If starting from scratch I would entirely agree with you however I am slightly hesitant to do this as, given all the longdouble confusion, I think it might be quite easy to mess up and introduce a change that was not within the scope of the original deprecation.
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.
My point is that it should be trivial to specify the types we support - those are the one we actually implement (resp. template over), and that's IMO easier and more useful than playing whack-a-mole with weird/rare types that we somehow forgot to mention 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.
Thanks for picking this up again! I just looked through again and it looks good, though I'd still want to allowlist certain types here, rather than blocklist an arbitrarily long list of dtypes (as an example taken at random, we're probably not failing correctly for datetime types)
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.
Thanks for taking a look, hopefully this has been addressed in the latest commit
if in_typed.dtype is np.float64: | ||
pytest.mark.skip("Platform does not support `float128`") |
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 combination of if-condition and skip-message makes no sense is confusing. It would be much better not to parametrize on an ambiguous type (np.longdouble
) in the first place, but if that's unavoidable, one way to clarify would be (feel free to rewrite):
if in_typed.dtype is np.float64: | |
pytest.mark.skip("Platform does not support `float128`") | |
if in_typed.dtype is np.float64: | |
pytest.mark.skip("Platform treats `np.longdouble` as `np.float64`; " | |
"we support the latter, but not the former (in general).") |
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.
Agh, the tests are still failing on windows and macos arm, neither of which I have access to, so this clearly is not quite right. @ev-br would you be able to point me in the right direction here as I am getting quite confused!
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 if dtype is np.float64
is correct really. I suspect you're hitting #18341 (comment), so can you dispatch on in_typed.dtype.char == 'g'
instead?
I can check it in a couple of days unless you beat me to it.
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.
Or just don't parametrize the test with np.longdouble
, but rather float96
& float128
.
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 I am misunderstanding but I don't think we can use float128
directly here as it doesn't exist on some platforms.
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, you'll need to skip it on platforms that don't have it. I made another suggestion that's IMO easier to follow (and allowing to delete the if...skip after in_typed
entirely), because there's no need to invert any logic (of the kind "we support everything but these types" or "we support np.longdouble
except when it's actually np.float64
).
np.clongdouble, np.float16, np.longdouble, | ||
np.object_]) | ||
def test_invalid_dtypes(self, dtype): | ||
in_typed = np.array(self.IN, dtype=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.
np.clongdouble, np.float16, np.longdouble, | |
np.object_]) | |
def test_invalid_dtypes(self, dtype): | |
in_typed = np.array(self.IN, dtype=dtype) | |
np.clongdouble, np.float16, | |
np.object_, "float96", "float128"]) | |
def test_invalid_dtypes(self, dtype): | |
if system_does_not_have_large_float and dtype in ["float96", "float128"]: | |
pytest.mark.skip("Platform does not support floating point types larger than 64bit") | |
in_typed = np.array(self.IN, dtype=dtype) |
system_does_not_have_large_float
is left as an exercise to the reader. ;-)
if in_typed.dtype is np.float64: | ||
pytest.mark.skip("Platform does not support `float128`") |
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, you'll need to skip it on platforms that don't have it. I made another suggestion that's IMO easier to follow (and allowing to delete the if...skip after in_typed
entirely), because there's no need to invert any logic (of the kind "we support everything but these types" or "we support np.longdouble
except when it's actually np.float64
).
I think we can wait for 1.14 with this? Unless you want to get this in urgently, I think we should give it a year as usual. |
Closing until we branch for 1.14 |
Branch has happened, reopening. |
@j-bowhay, do you think you'll be able to rebase this in the coming weeks? |
[skip ci] Co-authored-by: h-vetinari <h.vetinari@gmx.com>
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.
Thank you!
@j-bowhay, do you want to keep some of the commit granularity (would probably need a clean-up), or are you fine with a squash-merge? |
@h-vetinari happy to squash merge |
Reference issue
follow up to #18341
What does this implement/fix?
It has been two releases since float128 and object types were deprecated to deduplicate code, should be fine to raise an error now.
Additional information