From 9c1005d1a38ba44ca83200ae274d8a1212354b76 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 6 Nov 2019 09:29:11 -0700 Subject: [PATCH 01/10] ENH: add isinf, isnan for datetine64, timedelta64, adjust tests --- numpy/core/code_generators/generate_umath.py | 8 +++--- numpy/core/src/umath/loops.c.src | 16 +++++++++++ numpy/core/src/umath/loops.h.src | 6 ++++ numpy/core/tests/test_datetime.py | 29 +++++++++++--------- numpy/testing/_private/utils.py | 2 +- numpy/testing/tests/test_utils.py | 4 +-- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index 9e67a45ef8f0..6d76f7ca21c4 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -858,8 +858,8 @@ def english_upper(s): 'isnan': Ufunc(1, 1, None, docstrings.get('numpy.core.umath.isnan'), - None, - TD(nodatetime_or_obj, out='?'), + 'PyUFunc_IsFiniteTypeResolver', + TD(noobj, out='?'), ), 'isnat': Ufunc(1, 1, None, @@ -870,8 +870,8 @@ def english_upper(s): 'isinf': Ufunc(1, 1, None, docstrings.get('numpy.core.umath.isinf'), - None, - TD(nodatetime_or_obj, out='?'), + 'PyUFunc_IsFiniteTypeResolver', + TD(noobj, out='?'), ), 'isfinite': Ufunc(1, 1, None, diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index e6d8eca0d5b7..08c0920bcded 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -1245,6 +1245,22 @@ NPY_NO_EXPORT void } } + +NPY_NO_EXPORT void +@TYPE@_isnan(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + *((npy_bool *)op1) = (in1 == NPY_DATETIME_NAT); + } +} + +NPY_NO_EXPORT void +@TYPE@_isinf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + UNARY_LOOP_FAST(npy_bool, npy_bool, (void)in; *out = NPY_FALSE); +} + NPY_NO_EXPORT void @TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)) { diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src index 0ef14a8098a8..d0b6b7c1f700 100644 --- a/numpy/core/src/umath/loops.h.src +++ b/numpy/core/src/umath/loops.h.src @@ -477,6 +477,12 @@ NPY_NO_EXPORT void NPY_NO_EXPORT void @TYPE@_isfinite(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void +@TYPE@_isinf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + +NPY_NO_EXPORT void +@TYPE@_isnan(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); + NPY_NO_EXPORT void @TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index a756dc7e7afb..4c8987cc6c24 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -2232,7 +2232,7 @@ def test_isnat_error(self): continue assert_raises(TypeError, np.isnat, np.zeros(10, t)) - def test_isfinite(self): + def test_isfinite_scalar(self): assert_(not np.isfinite(np.datetime64('NaT', 'ms'))) assert_(not np.isfinite(np.datetime64('NaT', 'ns'))) assert_(np.isfinite(np.datetime64('2038-01-19T03:14:07'))) @@ -2240,18 +2240,21 @@ def test_isfinite(self): assert_(not np.isfinite(np.timedelta64('NaT', "ms"))) assert_(np.isfinite(np.timedelta64(34, "ms"))) - res = np.array([True, True, False]) - for unit in ['Y', 'M', 'W', 'D', - 'h', 'm', 's', 'ms', 'us', - 'ns', 'ps', 'fs', 'as']: - arr = np.array([123, -321, "NaT"], dtype='M, m dtypes + ''' + arr_val = [123, -321, "NaT"] + dstr = ['datetime64[%s]', + 'timedelta64[%s]'] + for arr in [np.array(arr_val, dtype= s % unit) for s in dstr]: + pos = np.array([True, True, False]) + neg = np.array([False, False, True]) + false = np.array([False, False, False]) + assert_equal(np.isfinite(arr), pos) + assert_equal(np.isinf(arr), false) + assert_equal(np.isnan(arr), neg) def test_corecursive_input(self): # construct a co-recursive list diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 8a31fcf15af0..e7236b27ad68 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -386,7 +386,7 @@ def assert_equal(actual, desired, err_msg='', verbose=True): if not signbit(desired) == signbit(actual): raise AssertionError(msg) - except (TypeError, ValueError, NotImplementedError): + except (TypeError, ValueError, NotImplementedError, DeprecationWarning): pass try: diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py index 44f93a693d88..0fa2f8033979 100644 --- a/numpy/testing/tests/test_utils.py +++ b/numpy/testing/tests/test_utils.py @@ -300,9 +300,9 @@ def test_nat_items(self): self._test_not_equal([a], b) for a, b in itertools.product(tds, dts): - self._test_not_equal(a, b) + self._assert_func(a, b) self._test_not_equal(a, [b]) - self._test_not_equal([a], [b]) + self._assert_func([a], [b]) self._test_not_equal([a], np.datetime64("2017-01-01", "s")) self._test_not_equal([b], np.datetime64("2017-01-01", "s")) self._test_not_equal([a], np.timedelta64(123, "s")) From d593826ec3c8116741172ec371df575958726d19 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 6 Nov 2019 13:08:09 -0700 Subject: [PATCH 02/10] DOC: add release note --- doc/release/upcoming_changes/14841.compatibility.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/release/upcoming_changes/14841.compatibility.rst diff --git a/doc/release/upcoming_changes/14841.compatibility.rst b/doc/release/upcoming_changes/14841.compatibility.rst new file mode 100644 index 000000000000..5b7d1014fa09 --- /dev/null +++ b/doc/release/upcoming_changes/14841.compatibility.rst @@ -0,0 +1,6 @@ +Add ufunc loops to ``isinf`` and ``isnan`` for ``datetime64``, ``timedelta64`` +------------------------------------------------------------------------------ +Add needed infrastructure so ``np.isinf(a)`` and ``np.isnan(a)`` will run on +``datetime64`` and ``timedelta64`` dtypes. This may require adjustment to user- +facing code that either disallowed the calls or checked that they raised an +exception. From 259b6e3a877be62d5f65ff2e810e380251e5f855 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 7 Nov 2019 09:28:11 -0700 Subject: [PATCH 03/10] MAINT: changes from review --- numpy/core/src/umath/loops.c.src | 10 ---------- numpy/core/src/umath/loops.h.src | 3 +-- numpy/core/tests/test_datetime.py | 20 ++++++++++---------- numpy/testing/_private/utils.py | 5 +++++ 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index 08c0920bcded..a823413a59a7 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -1245,16 +1245,6 @@ NPY_NO_EXPORT void } } - -NPY_NO_EXPORT void -@TYPE@_isnan(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) -{ - UNARY_LOOP { - const @type@ in1 = *(@type@ *)ip1; - *((npy_bool *)op1) = (in1 == NPY_DATETIME_NAT); - } -} - NPY_NO_EXPORT void @TYPE@_isinf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src index d0b6b7c1f700..6209d2c87290 100644 --- a/numpy/core/src/umath/loops.h.src +++ b/numpy/core/src/umath/loops.h.src @@ -480,8 +480,7 @@ NPY_NO_EXPORT void NPY_NO_EXPORT void @TYPE@_isinf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); -NPY_NO_EXPORT void -@TYPE@_isnan(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); +#define @TYPE@_isnan @TYPE@_isnat NPY_NO_EXPORT void @TYPE@__ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data)); diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index 4c8987cc6c24..214181e6f51e 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -2242,19 +2242,19 @@ def test_isfinite_scalar(self): @pytest.mark.parametrize('unit', ['Y', 'M', 'W', 'D', 'h', 'm', 's', 'ms', 'us', 'ns', 'ps', 'fs', 'as']) - def test_isxx_units(self, unit): + @pytest.mark.parametrize('dstr', ['datetime64[%s]', + 'timedelta64[%s]']) + def test_isfinite_isinf_isnan_units(self, unit, dstr): '''check isfinite, isinf, isnan for all units of M, m dtypes ''' arr_val = [123, -321, "NaT"] - dstr = ['datetime64[%s]', - 'timedelta64[%s]'] - for arr in [np.array(arr_val, dtype= s % unit) for s in dstr]: - pos = np.array([True, True, False]) - neg = np.array([False, False, True]) - false = np.array([False, False, False]) - assert_equal(np.isfinite(arr), pos) - assert_equal(np.isinf(arr), false) - assert_equal(np.isnan(arr), neg) + arr = np.array(arr_val, dtype= dstr % unit) + pos = np.array([True, True, False]) + neg = np.array([False, False, True]) + false = np.array([False, False, False]) + assert_equal(np.isfinite(arr), pos) + assert_equal(np.isinf(arr), false) + assert_equal(np.isnan(arr), neg) def test_corecursive_input(self): # construct a co-recursive list diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index e7236b27ad68..07f4c924cbf1 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -387,6 +387,11 @@ def assert_equal(actual, desired, err_msg='', verbose=True): raise AssertionError(msg) except (TypeError, ValueError, NotImplementedError, DeprecationWarning): + # version 1.18: + # datetime64/timedelta64 used to raise since they had no isnan + # implementation. Now they do, but raise a DeprecationWarning when + # compared to 0. When that restriction is removed, they will still + # raise an error when signbit is called. pass try: From d6ad700affac69246f3bc297919f97db02215571 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 8 Nov 2019 09:46:17 -0700 Subject: [PATCH 04/10] ENH: test, add fmin, fmax loops for datetime64, teimedelta64 --- .../upcoming_changes/14841.compatibility.rst | 17 +++++++++----- numpy/core/src/umath/loops.c.src | 23 +++++++++++++++++++ numpy/core/src/umath/loops.h.src | 7 +----- numpy/core/tests/test_datetime.py | 4 ++++ 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/doc/release/upcoming_changes/14841.compatibility.rst b/doc/release/upcoming_changes/14841.compatibility.rst index 5b7d1014fa09..d44bc4e27d6a 100644 --- a/doc/release/upcoming_changes/14841.compatibility.rst +++ b/doc/release/upcoming_changes/14841.compatibility.rst @@ -1,6 +1,11 @@ -Add ufunc loops to ``isinf`` and ``isnan`` for ``datetime64``, ``timedelta64`` ------------------------------------------------------------------------------- -Add needed infrastructure so ``np.isinf(a)`` and ``np.isnan(a)`` will run on -``datetime64`` and ``timedelta64`` dtypes. This may require adjustment to user- -facing code that either disallowed the calls or checked that they raised an -exception. +Add more ufunc loops for ``datetime64``, ``timedelta64`` +-------------------------------------------------------- +``np.datetime('NaT')`` should behave more like ``float('Nan')``. Add needed +infrastructure so ``np.isinf(a)`` and ``np.isnan(a)`` will run on +``datetime64`` and ``timedelta64`` dtypes. Also added specific loops for +``fmin`` and ``fmax`` that mask ``NaT``. This may require adjustment to user- +facing code. Specifically, code that either disallowed the calls to `isinf`` or +``isnan`` or checked that they raised an exception will require adaptation, and +code that mistakenly called ``fmax`` and ``fmin`` instead of ``maximum`` or +``minimum`` respectively will requre adjustment. This also affects ``nanmax`` +and ``nanmin`` which may no longer return ``NaT``. diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index a823413a59a7..89a0708575f3 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -1312,6 +1312,29 @@ NPY_NO_EXPORT void } /**end repeat1**/ +/**begin repeat1 + * #kind = fmax, fmin# + * #OP = >=, <=# + **/ +NPY_NO_EXPORT void +@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) +{ + BINARY_LOOP { + const @type@ in1 = *(@type@ *)ip1; + const @type@ in2 = *(@type@ *)ip2; + if (in1 == NPY_DATETIME_NAT) { + *((@type@ *)op1) = in2; + } + else if (in2 == NPY_DATETIME_NAT) { + *((@type@ *)op1) = in1; + } + else { + *((@type@ *)op1) = in1 @OP@ in2 ? in1 : in2; + } + } +} +/**end repeat1**/ + /**end repeat**/ NPY_NO_EXPORT void diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src index 6209d2c87290..7558de0bbdfc 100644 --- a/numpy/core/src/umath/loops.h.src +++ b/numpy/core/src/umath/loops.h.src @@ -494,8 +494,7 @@ NPY_NO_EXPORT void /**end repeat1**/ /**begin repeat1 - * #kind = maximum, minimum# - * #OP = >, <# + * #kind = maximum, minimum, fmin, fmax# **/ NPY_NO_EXPORT void @TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); @@ -559,10 +558,6 @@ TIMEDELTA_mm_qm_divmod(char **args, npy_intp *dimensions, npy_intp *steps, void #define TIMEDELTA_mq_m_floor_divide TIMEDELTA_mq_m_divide #define TIMEDELTA_md_m_floor_divide TIMEDELTA_md_m_divide /* #define TIMEDELTA_mm_d_floor_divide TIMEDELTA_mm_d_divide */ -#define TIMEDELTA_fmin TIMEDELTA_minimum -#define TIMEDELTA_fmax TIMEDELTA_maximum -#define DATETIME_fmin DATETIME_minimum -#define DATETIME_fmax DATETIME_maximum /* ***************************************************************************** diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index 214181e6f51e..88a88cd3dd01 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -1361,6 +1361,10 @@ def test_datetime_minmax(self): assert_equal(np.minimum(dtnat, a), dtnat) assert_equal(np.maximum(a, dtnat), dtnat) assert_equal(np.maximum(dtnat, a), dtnat) + assert_equal(np.fmin(dtnat, a), a) + assert_equal(np.fmin(a, dtnat), a) + assert_equal(np.fmax(dtnat, a), a) + assert_equal(np.fmax(a, dtnat), a) # Also do timedelta a = np.array(3, dtype='m8[h]') From 166895afbd3af7631bacf7545610ab38a0536ed4 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 8 Nov 2019 09:46:50 -0700 Subject: [PATCH 05/10] MAINT: improve message in assert_equal (from review) --- numpy/testing/_private/utils.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 07f4c924cbf1..008765edd090 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -386,12 +386,13 @@ def assert_equal(actual, desired, err_msg='', verbose=True): if not signbit(desired) == signbit(actual): raise AssertionError(msg) - except (TypeError, ValueError, NotImplementedError, DeprecationWarning): - # version 1.18: - # datetime64/timedelta64 used to raise since they had no isnan - # implementation. Now they do, but raise a DeprecationWarning when - # compared to 0. When that restriction is removed, they will still - # raise an error when signbit is called. + except (TypeError, ValueError, NotImplementedError): + pass + except DeprecationWarning: + # version 1.18 + # gisnan used to raise for datetime64/timedelta64 (dt64) since they had + # no isnan implementation. That call no longer raises. However, a + # DeprecationWarning is raised when comparing dt64 to 0. pass try: From a7122fe29e357edcf7e95383c45b6e0074da3b5f Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 11 Nov 2019 17:18:37 -0700 Subject: [PATCH 06/10] BUG, MAINT: fixes from review --- .../upcoming_changes/14841.compatibility.rst | 2 +- numpy/core/tests/test_datetime.py | 4 ++ numpy/testing/_private/utils.py | 46 ++++++++++--------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/doc/release/upcoming_changes/14841.compatibility.rst b/doc/release/upcoming_changes/14841.compatibility.rst index d44bc4e27d6a..dbf3651914f9 100644 --- a/doc/release/upcoming_changes/14841.compatibility.rst +++ b/doc/release/upcoming_changes/14841.compatibility.rst @@ -8,4 +8,4 @@ facing code. Specifically, code that either disallowed the calls to `isinf`` or ``isnan`` or checked that they raised an exception will require adaptation, and code that mistakenly called ``fmax`` and ``fmin`` instead of ``maximum`` or ``minimum`` respectively will requre adjustment. This also affects ``nanmax`` -and ``nanmin`` which may no longer return ``NaT``. +and ``nanmin``. diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index 88a88cd3dd01..e8ffbbb9da9a 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -2260,6 +2260,10 @@ def test_isfinite_isinf_isnan_units(self, unit, dstr): assert_equal(np.isinf(arr), false) assert_equal(np.isnan(arr), neg) + def test_assert_equal(self): + assert_raises(AssertionError, assert_equal, + np.datetime64('nat'), np.timedelta64('nat')) + def test_corecursive_input(self): # construct a co-recursive list a, b = [], [] diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 008765edd090..9f1fbacbd55f 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -374,27 +374,6 @@ def assert_equal(actual, desired, err_msg='', verbose=True): if isscalar(desired) != isscalar(actual): raise AssertionError(msg) - # Inf/nan/negative zero handling - try: - isdesnan = gisnan(desired) - isactnan = gisnan(actual) - if isdesnan and isactnan: - return # both nan, so equal - - # handle signed zero specially for floats - if desired == 0 and actual == 0: - if not signbit(desired) == signbit(actual): - raise AssertionError(msg) - - except (TypeError, ValueError, NotImplementedError): - pass - except DeprecationWarning: - # version 1.18 - # gisnan used to raise for datetime64/timedelta64 (dt64) since they had - # no isnan implementation. That call no longer raises. However, a - # DeprecationWarning is raised when comparing dt64 to 0. - pass - try: isdesnat = isnat(desired) isactnat = isnat(actual) @@ -410,6 +389,31 @@ def assert_equal(actual, desired, err_msg='', verbose=True): except (TypeError, ValueError, NotImplementedError): pass + # Inf/nan/negative zero handling + try: + isdesnan = gisnan(desired) + isactnan = gisnan(actual) + if isdesnan and isactnan: + return # both nan, so equal + + # handle signed zero specially for floats + array_actual = array(actual) + array_desired = array(desired) + if (array_actual.dtype.char in 'Mm' or + array_desired.dtype.char in 'Mm'): + # version 1.18 + # until this version, gisnan failed for datetime64. Now + # it succeeds but comparison to 0 emits a DeprecationWarning + # Avoid that by skipping the next check + raise NotImplementedError('cannot compare datetime64 to 0') + + if desired == 0 and actual == 0: + if not signbit(desired) == signbit(actual): + raise AssertionError(msg) + + except (TypeError, ValueError, NotImplementedError): + pass + try: # Explicitly use __eq__ for comparison, gh-2552 if not (desired == actual): From 3483f8044efdd474e1af67fb725ccf9f1d388159 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 11 Nov 2019 20:19:10 -0700 Subject: [PATCH 07/10] BUG: timedelta64 also raises DeprecationWarning --- numpy/testing/_private/utils.py | 4 ++-- numpy/testing/tests/test_utils.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 9f1fbacbd55f..9c6338116c33 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -402,8 +402,8 @@ def assert_equal(actual, desired, err_msg='', verbose=True): if (array_actual.dtype.char in 'Mm' or array_desired.dtype.char in 'Mm'): # version 1.18 - # until this version, gisnan failed for datetime64. Now - # it succeeds but comparison to 0 emits a DeprecationWarning + # until this version, gisnan failed for datetime64 and timedelta64. + # Now it succeeds but comparison to 0 emits a DeprecationWarning # Avoid that by skipping the next check raise NotImplementedError('cannot compare datetime64 to 0') diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py index 0fa2f8033979..44f93a693d88 100644 --- a/numpy/testing/tests/test_utils.py +++ b/numpy/testing/tests/test_utils.py @@ -300,9 +300,9 @@ def test_nat_items(self): self._test_not_equal([a], b) for a, b in itertools.product(tds, dts): - self._assert_func(a, b) + self._test_not_equal(a, b) self._test_not_equal(a, [b]) - self._assert_func([a], [b]) + self._test_not_equal([a], [b]) self._test_not_equal([a], np.datetime64("2017-01-01", "s")) self._test_not_equal([b], np.datetime64("2017-01-01", "s")) self._test_not_equal([a], np.timedelta64(123, "s")) From 2e25313f098447a1f9d4aaaa1b68f71eb22c6474 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 15 Nov 2019 07:45:04 -0700 Subject: [PATCH 08/10] DOC: fixes from review --- doc/release/upcoming_changes/14841.compatibility.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/release/upcoming_changes/14841.compatibility.rst b/doc/release/upcoming_changes/14841.compatibility.rst index dbf3651914f9..51c32114a9b2 100644 --- a/doc/release/upcoming_changes/14841.compatibility.rst +++ b/doc/release/upcoming_changes/14841.compatibility.rst @@ -3,9 +3,9 @@ Add more ufunc loops for ``datetime64``, ``timedelta64`` ``np.datetime('NaT')`` should behave more like ``float('Nan')``. Add needed infrastructure so ``np.isinf(a)`` and ``np.isnan(a)`` will run on ``datetime64`` and ``timedelta64`` dtypes. Also added specific loops for -``fmin`` and ``fmax`` that mask ``NaT``. This may require adjustment to user- -facing code. Specifically, code that either disallowed the calls to `isinf`` or -``isnan`` or checked that they raised an exception will require adaptation, and -code that mistakenly called ``fmax`` and ``fmin`` instead of ``maximum`` or -``minimum`` respectively will requre adjustment. This also affects ``nanmax`` -and ``nanmin``. +`numpy.fmin` and `numpy.fmax` that mask ``NaT``. This may require adjustment to user- +facing code. Specifically, code that either disallowed the calls to +`numpy.isinf` or `numpy.isnan` or checked that they raised an exception will +require adaptation, and code that mistakenly called `numpy.fmax` and +`numpy.fmin` instead of `numpy.maximum` or `numpy.minimum` respectively will +requre adjustment. This also affects `numpy.nanmax` and `numpy.nanmin`. From 31c0971858d7a9f7a0b6dcceea34ae5ba77f1dea Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Thu, 21 Nov 2019 14:48:07 -0800 Subject: [PATCH 09/10] Update numpy/testing/_private/utils.py Co-Authored-By: Warren Weckesser --- numpy/testing/_private/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 9c6338116c33..ff72205297df 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -403,7 +403,8 @@ def assert_equal(actual, desired, err_msg='', verbose=True): array_desired.dtype.char in 'Mm'): # version 1.18 # until this version, gisnan failed for datetime64 and timedelta64. - # Now it succeeds but comparison to 0 emits a DeprecationWarning + # Now it succeeds but comparison to scalar with a different type + # emits a DeprecationWarning. # Avoid that by skipping the next check raise NotImplementedError('cannot compare datetime64 to 0') From 0a056ded3f3c936a2c06416642e63e6d1c21ef88 Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Thu, 21 Nov 2019 14:48:16 -0800 Subject: [PATCH 10/10] Update numpy/testing/_private/utils.py Co-Authored-By: Warren Weckesser --- numpy/testing/_private/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index ff72205297df..ff31dc945d87 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -406,7 +406,8 @@ def assert_equal(actual, desired, err_msg='', verbose=True): # Now it succeeds but comparison to scalar with a different type # emits a DeprecationWarning. # Avoid that by skipping the next check - raise NotImplementedError('cannot compare datetime64 to 0') + raise NotImplementedError('cannot compare to a scalar ' + 'with a different type') if desired == 0 and actual == 0: if not signbit(desired) == signbit(actual):