Skip to content

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

Merged
merged 4 commits into from
May 7, 2017

Conversation

seberg
Copy link
Member

@seberg seberg commented Dec 26, 2016

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:

  • I think the assert_equal function may say that a datetime NaT and a timedelta NaT are equal.

@seberg
Copy link
Member Author

seberg commented Dec 27, 2016

There is an old PR (gh-7856), which implements isfinite for all types including datetime, wondering whether we should do that instead, as well or not.

if isnat(desired) or isnat(actual):
isdesnat = isnat(desired)
isactnat = isnat(actual)
if isdesnat or isactnat:
Copy link
Member

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

Copy link
Member

@eric-wieser eric-wieser Jan 4, 2017

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:

@charris
Copy link
Member

charris commented Jan 2, 2017

I think the assert_equal function may say that a datetime NaT and a timedelta NaT are equal.

Looks like that. I think we need to distinguish the two.

@charris
Copy link
Member

charris commented Jan 2, 2017

Otherwise, LGTM.

@charris
Copy link
Member

charris commented Jan 3, 2017

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.

@seberg
Copy link
Member Author

seberg commented Jan 3, 2017

For isnat, agree we could make it a python function. The question I guess is whether having it a true ufunc is a good consistency gain. For isfininte, I would say its a no-go, since it already is a ufunc.

@homu
Copy link
Contributor

homu commented Jan 10, 2017

☔ The latest upstream changes (presumably #8452) made this pull request unmergeable. Please resolve the merge conflicts.

@charris
Copy link
Member

charris commented Jan 16, 2017

@seberg Needs rebase

@seberg
Copy link
Member Author

seberg commented Jan 21, 2017

Rebased, and fixed the datetime vs. timedelta stuff, still needs a few tests for the array case, maybe will add them in a bit.

@seberg seberg changed the title WIP: Add isnat function and make comparison tests NAT specific ENH: Add isnat function and make comparison tests NAT specific Jan 21, 2017
@charris
Copy link
Member

charris commented Apr 22, 2017

restart tests.

@charris charris closed this Apr 22, 2017
@charris charris reopened this Apr 22, 2017
@charris
Copy link
Member

charris commented May 5, 2017

@seberg The test for complex equality is failing. I'm going to kick this on to 1.14

@charris charris modified the milestones: 1.14.0 release, 1.13.0 release May 5, 2017
@charris
Copy link
Member

charris commented May 5, 2017

Oops, need this for the release to fix thread safety of comparison functions.

@charris charris modified the milestones: 1.13.0 release, 1.14.0 release May 5, 2017
@charris
Copy link
Member

charris commented May 5, 2017

@seberg Nag, nag. Consider yourself nagged ;)

@seberg
Copy link
Member Author

seberg commented May 6, 2017

Yeah... well don't try funny refactoring then. We could still also do the private python version of isnat though.

for t in np.typecodes["All"]:
if t in np.typecodes["Datetime"]:
continue

Copy link
Member

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:
Copy link
Member

Choose a reason for hiding this comment

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

Unrelated fixup?

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member

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.

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 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:
Copy link
Member

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?

Copy link
Member Author

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

Choose a reason for hiding this comment

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

?

Copy link
Member Author

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

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?

Copy link
Member

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?

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

Copy link
Member Author

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 ;)

@charris
Copy link
Member

charris commented May 6, 2017

Looks good to me, just a few questions for clarification. Needs a 1.13 release note.

@seberg
Copy link
Member Author

seberg commented May 6, 2017

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 assert_equal from here, which figures NaNs and NaTs are equal.

@charris
Copy link
Member

charris commented May 6, 2017

There is an old PR (gh-7856), which implements isfinite for all types including datetime,

Could probably implement that as a define to the relevant isnat after this.

@charris
Copy link
Member

charris commented May 6, 2017

Still needs a release note.

seberg added 4 commits May 7, 2017 16:21
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.
@seberg
Copy link
Member Author

seberg commented May 7, 2017

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.

@charris
Copy link
Member

charris commented May 7, 2017

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.

@charris charris merged commit 39aaa2d into numpy:master May 7, 2017
@charris
Copy link
Member

charris commented May 7, 2017

Thanks Sebastian.

@seberg seberg deleted the isnat branch May 7, 2017 16:07
@seberg
Copy link
Member Author

seberg commented May 7, 2017

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

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!

Copy link
Member Author

Choose a reason for hiding this comment

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

ooopst....

Copy link
Member

Choose a reason for hiding this comment

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

Fixed in #10096

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.

4 participants