-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
ENH: Add isnat function and make comparison tests NAT specific #8421
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
There is an old PR (gh-7856), which implements |
numpy/testing/utils.py
Outdated
if isnat(desired) or isnat(actual): | ||
isdesnat = isnat(desired) | ||
isactnat = isnat(actual) | ||
if isdesnat or isactnat: |
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.
Could just do xor here: if isnat(desired) ^ isnat(actual):
.
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 possibly more clearly, if isdesnat != isactnat:
Looks like that. I think we need to distinguish the two. |
Otherwise, LGTM. |
Note that this function could be implemented in pure python using views and integer comparisons. That might be an easier way to go. Same with the isfinite function, although the latter might be faster as a ufunc. |
For |
☔ The latest upstream changes (presumably #8452) made this pull request unmergeable. Please resolve the merge conflicts. |
@seberg Needs rebase |
Rebased, and fixed the datetime vs. timedelta stuff, still needs a few tests for the array case, maybe will add them in a bit. |
restart tests. |
@seberg The test for complex equality is failing. I'm going to kick this on to 1.14 |
Oops, need this for the release to fix thread safety of comparison functions. |
@seberg Nag, nag. Consider yourself nagged ;) |
Yeah... well don't try funny refactoring then. We could still also do the private python version of isnat though. |
numpy/core/tests/test_datetime.py
Outdated
for t in np.typecodes["All"]: | ||
if t in np.typecodes["Datetime"]: | ||
continue | ||
|
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'd drop the blank line, but not worth fixing here.
@@ -144,7 +145,10 @@ def test_recarrays(self): | |||
c['floupipi'] = a['floupi'].copy() | |||
c['floupa'] = a['floupa'].copy() | |||
|
|||
self._test_not_equal(c, b) | |||
with suppress_warnings() as sup: |
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.
Unrelated fixup?
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 safe comparison/suppression in the test filtered a bit more then just the NaT stuff (actually may have been there originally not for NaT, but for ==
operator warnings), so (not actually remembering it) removing it, the tests need to filter these warnings explicitly now. Not sure why this is the only one specifically though.
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.
So this might cause some problems downstream? I'm not terribly concerned, the only way to find out is to try.
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.
Hmm, looks like the FutureWarning
will be gone in the 1.14 release.
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 might cause problems, but maybe its also good, since maybe some project might run into the future warning and did not notice because of this....
@@ -396,14 +397,24 @@ def assert_equal(actual,desired,err_msg='',verbose=True): | |||
except (TypeError, ValueError, NotImplementedError): | |||
pass | |||
|
|||
# Explicitly use __eq__ for comparison, ticket #2552 | |||
with suppress_warnings() as sup: |
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.
So this is the fix for thread safety?
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.
Yeah
except (TypeError, ValueError, NotImplementedError): | ||
pass | ||
|
||
# Explicitly use __eq__ for comparison, ticket #2552 |
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 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.
Dunno the comment was already there, probably ancient, maybe it was once np.equal
or so.
@@ -674,33 +685,12 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, | |||
x = array(x, copy=False, subok=True) | |||
y = array(y, copy=False, subok=True) | |||
|
|||
def safe_comparison(*args, **kwargs): |
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.
No longer needed? What replaces 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.
Only needed for time comparisons then?
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, it would filter a bit more (actuallylikely was first put here by Nathaniel or so for the ==
deprecations), but it seems the only test (after supporting NaT explicitely) that needed extra handling was this one test you comment on before. Not sure, maybe some of the deprecations are finished by now anyway?
Of course this might effect downstream a little here, which is why we did not go this way before after all.
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.
Heh, I am wondering if it should be worrisome that only one test needed fixup.... but my brain refuses to really think about it right now ;)
Looks good to me, just a few questions for clarification. Needs a 1.13 release note. |
Hmmm, I just found another one of these in the masked array testutils. But they don't seem to support NaNs either, so not sure I shouldn't just move the warning suppression to the affected test. Or otherwise call the |
Could probably implement that as a define to the relevant |
Still needs a release note. |
These warning filters are not threadsafe, while it is nicer if the comparison functions can be called in a threaded environment since they do no explicite warning checking. Less filters are also cleaner in general, though may also mean that downstream projects see warnings that were previously hidden.
This may show warnings in downstream projects, which should likely not be there. We could also drop in the normal assert_equal there, which would support NaT, and NaN, but checks for scalarness, which this currently does not (which also could create problems). Works around the only test with this problem, by using the normal assert_equal there.
Added some notes. I removed the NaT filter from the masked array tests (and moved it to the tests), this might also affect downstream. We could also call into the normal assert equal function (which would be cleaner), however currently that checks for scalar, which could be more disruptive then the possible NaT warning. Or we do that, and add a flag to assert equal to skip the scalar check EDIT: Anyway, there are few other options here (also adding a warning, that we will drop in assert_equal, which will change the scalar case). All of them should be pretty simple though. |
The masked testing utils are a bit of a mess anyway. In the future it would be nice if the testing functions were all clearly split between the usual numpy testing functions and those specific to masked arrays. I think what is done here is OK and we will deal with any problems that arise if/when they arise. |
Thanks Sebastian. |
Thanks! |
# If both are NaT (and have the same dtype -- datetime or timedelta) | ||
# they are considered equal. | ||
if (isnat(desired) == isnat(actual) and | ||
array(desired).dtype.type == array(actual).dtype.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.
This isn't right - it considers any two non-NAT times equal!
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.
ooopst....
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.
Fixed in #10096
Continuation of the discussion in gh-8413. First commit just adds a new
isnat
function, the second commit tries to clean up the warning filter in the comparison function.Cleaning those up may be noticed by downstream projects (I am not sure). Backporting that part would be possible by implementing a local python implemented
_isnat
function instead (which is rather simple).TODO:
assert_equal
function may say that a datetime NaT and a timedelta NaT are equal.