Thanks to visit codestin.com
Credit goes to github.com

Skip to content

DEP: finish making all comparisons to NaT false #11948

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 2 commits into from
Sep 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion doc/release/1.16.0-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ Future Changes

* NumPy 1.17 will drop support for Python 2.7.

Expired deprecations
====================

* NaT comparisons now return ``False`` without a warning, finishing a
deprecation cycle begun in NumPy 1.11.

Compatibility notes
===================
Expand All @@ -54,6 +59,15 @@ whenever the ``Scripts`` directory is in the path. Folks needing compatibility
with earler versions of Numpy should run ``f2py`` as a module: ``python -m
numpy.f2py [...]``.

NaT comparisons
---------------
Consistent with the behavior of NaN, all comparisons other than inequality
checks with datetime64 or timedelta64 NaT ("not-a-time") values now always
return ``False``, and inequality checks with NaT now always return ``True``.
This includes comparisons beteween NaT values. For compatibility with the
old behavior, use ``np.isnat`` to explicitly check for NaT or convert
datetime64/timedelta64 arrays with ``.astype(np.int64)`` before making
comparisons.

C API changes
=============
Expand Down Expand Up @@ -149,4 +163,3 @@ modules, they are now python wrappers to the single `np.core/_multiarray_math`
c-extension module.

.. _`NEP 15` : http://www.numpy.org/neps/nep-0015-merge-multiarray-umath.html

41 changes: 6 additions & 35 deletions numpy/core/src/umath/loops.c.src
Original file line number Diff line number Diff line change
Expand Up @@ -1327,54 +1327,25 @@ NPY_NO_EXPORT void
NPY_NO_EXPORT void
@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
npy_bool give_future_warning = 0;
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
const @type@ in2 = *(@type@ *)ip2;
const npy_bool res = in1 @OP@ in2;
*((npy_bool *)op1) = res;

if ((in1 == NPY_DATETIME_NAT || in2 == NPY_DATETIME_NAT) && res) {
give_future_warning = 1;
}
}
if (give_future_warning) {
NPY_ALLOW_C_API_DEF
NPY_ALLOW_C_API;
/* 2016-01-18, 1.11 */
if (DEPRECATE_FUTUREWARNING(
"In the future, 'NAT @OP@ x' and 'x @OP@ NAT' "
"will always be False.") < 0) {
/* nothing to do, we return anyway */
}
NPY_DISABLE_C_API;
*((npy_bool *)op1) = (in1 @OP@ in2 &&
in1 != NPY_DATETIME_NAT &&
in2 != NPY_DATETIME_NAT);
}
}
/**end repeat1**/

NPY_NO_EXPORT void
@TYPE@_not_equal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
npy_bool give_future_warning = 0;
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
const @type@ in2 = *(@type@ *)ip2;
*((npy_bool *)op1) = in1 != in2;

if (in1 == NPY_DATETIME_NAT && in2 == NPY_DATETIME_NAT) {
give_future_warning = 1;
}
}
if (give_future_warning) {
NPY_ALLOW_C_API_DEF
NPY_ALLOW_C_API;
/* 2016-01-18, 1.11 */
if (DEPRECATE_FUTUREWARNING(
"In the future, NAT != NAT will be True "
"rather than False.") < 0) {
/* nothing to do, we return anyway */
}
NPY_DISABLE_C_API;
*((npy_bool *)op1) = (in1 != in2 ||
in1 == NPY_DATETIME_NAT ||
in2 == NPY_DATETIME_NAT);
}
}

Expand Down
67 changes: 20 additions & 47 deletions numpy/core/tests/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import datetime
import pytest
from numpy.testing import (
assert_, assert_equal, assert_raises, assert_warns, suppress_warnings
assert_, assert_equal, assert_raises, assert_warns, suppress_warnings,
)

# Use pytz to test out various time zones if available
Expand Down Expand Up @@ -130,13 +130,10 @@ def test_datetime_casting_rules(self):

def test_compare_generic_nat(self):
# regression tests for gh-6452
assert_equal(np.datetime64('NaT'),
np.datetime64('2000') + np.timedelta64('NaT'))
# nb. we may want to make NaT != NaT true in the future
with suppress_warnings() as sup:
sup.filter(FutureWarning, ".*NAT ==")
assert_(np.datetime64('NaT') == np.datetime64('NaT', 'us'))
assert_(np.datetime64('NaT', 'us') == np.datetime64('NaT'))
assert_(np.datetime64('NaT') !=
np.datetime64('2000') + np.timedelta64('NaT'))
assert_(np.datetime64('NaT') != np.datetime64('NaT', 'us'))
assert_(np.datetime64('NaT', 'us') != np.datetime64('NaT'))

def test_datetime_scalar_construction(self):
# Construct with different units
Expand Down Expand Up @@ -1154,47 +1151,23 @@ def test_datetime_compare_nat(self):
td_nat = np.timedelta64('NaT', 'h')
td_other = np.timedelta64(1, 'h')

with suppress_warnings() as sup:
# The assert warns contexts will again see the warning:
sup.filter(FutureWarning, ".*NAT")

for op in [np.equal, np.less, np.less_equal,
np.greater, np.greater_equal]:
if op(dt_nat, dt_nat):
assert_warns(FutureWarning, op, dt_nat, dt_nat)
if op(dt_nat, dt_other):
assert_warns(FutureWarning, op, dt_nat, dt_other)
if op(dt_other, dt_nat):
assert_warns(FutureWarning, op, dt_other, dt_nat)
if op(td_nat, td_nat):
assert_warns(FutureWarning, op, td_nat, td_nat)
if op(td_nat, td_other):
assert_warns(FutureWarning, op, td_nat, td_other)
if op(td_other, td_nat):
assert_warns(FutureWarning, op, td_other, td_nat)

assert_warns(FutureWarning, np.not_equal, dt_nat, dt_nat)
assert_warns(FutureWarning, np.not_equal, td_nat, td_nat)

with suppress_warnings() as sup:
sup.record(FutureWarning)
assert_(np.not_equal(dt_nat, dt_other))
assert_(np.not_equal(dt_other, dt_nat))
assert_(np.not_equal(td_nat, td_other))
assert_(np.not_equal(td_other, td_nat))
assert_equal(len(sup.log), 0)

def test_datetime_futurewarning_once_nat(self):
# Test that the futurewarning is only given once per inner loop
arr1 = np.array(['NaT', 'NaT', '2000-01-01'] * 2, dtype='M8[s]')
arr2 = np.array(['NaT', '2000-01-01', 'NaT'] * 2, dtype='M8[s]')
# All except less, because for less it can't be wrong (NaT is min)
for op in [np.equal, np.less, np.less_equal,
np.greater, np.greater_equal]:
with suppress_warnings() as sup:
rec = sup.record(FutureWarning, ".*NAT")
op(arr1, arr2)
assert_(len(rec) == 1, "failed for {}".format(op))
assert_(not op(dt_nat, dt_nat))
assert_(not op(dt_nat, dt_other))
assert_(not op(dt_other, dt_nat))

assert_(not op(td_nat, td_nat))
assert_(not op(td_nat, td_other))
assert_(not op(td_other, td_nat))

assert_(np.not_equal(dt_nat, dt_nat))
assert_(np.not_equal(dt_nat, dt_other))
assert_(np.not_equal(dt_other, dt_nat))

assert_(np.not_equal(td_nat, td_nat))
assert_(np.not_equal(td_nat, td_other))
assert_(np.not_equal(td_other, td_nat))

def test_datetime_minmax(self):
# The metadata of the result should become the GCD
Expand Down