From ed579575ca05f979dfc8d47e151f253429c57175 Mon Sep 17 00:00:00 2001 From: Jim Cipar Date: Sat, 29 Mar 2025 11:43:19 -0400 Subject: [PATCH] Fix recursion depth limit when hashing numpy.datetime64 This fixes the bug described in [issue 534](https://github.com/seperman/deepdiff/issues/534). --- deepdiff/helper.py | 7 +++++-- tests/test_diff_numpy.py | 19 +++++++++++++++++++ tests/test_hash.py | 13 +++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/deepdiff/helper.py b/deepdiff/helper.py index 63a4e315..9a25a59b 100644 --- a/deepdiff/helper.py +++ b/deepdiff/helper.py @@ -58,6 +58,7 @@ def __repr__(self): np_complex128 = np_type # pragma: no cover. np_cdouble = np_type # pragma: no cover. np_complexfloating = np_type # pragma: no cover. + np_datetime64 = np_type # pragma: no cover. else: np_array_factory = np.array np_ndarray = np.ndarray @@ -80,6 +81,7 @@ def __repr__(self): np_complex128 = np.complex128 np_cdouble = np.cdouble # np.complex_ is an alias for np.cdouble and is being removed by NumPy 2.0 np_complexfloating = np.complexfloating + np_datetime64 = np.datetime64 numpy_numbers = ( np_int8, np_int16, np_int32, np_int64, np_uint8, @@ -93,6 +95,7 @@ def __repr__(self): numpy_dtypes = set(numpy_numbers) numpy_dtypes.add(np_bool_) # type: ignore +numpy_dtypes.add(np_datetime64) # type: ignore numpy_dtype_str_to_type = { item.__name__: item for item in numpy_dtypes @@ -184,10 +187,10 @@ def get_semvar_as_integer(version): bytes_type = bytes only_complex_number = (complex,) + numpy_complex_numbers only_numbers = (int, float, complex, Decimal) + numpy_numbers -datetimes = (datetime.datetime, datetime.date, datetime.timedelta, datetime.time) +datetimes = (datetime.datetime, datetime.date, datetime.timedelta, datetime.time, np_datetime64) ipranges = (ipaddress.IPv4Interface, ipaddress.IPv6Interface, ipaddress.IPv4Network, ipaddress.IPv6Network) uuids = (uuid.UUID, ) -times = (datetime.datetime, datetime.time) +times = (datetime.datetime, datetime.time,np_datetime64) numbers: Tuple = only_numbers + datetimes booleans = (bool, np_bool_) diff --git a/tests/test_diff_numpy.py b/tests/test_diff_numpy.py index ad9ecb94..129500fb 100644 --- a/tests/test_diff_numpy.py +++ b/tests/test_diff_numpy.py @@ -143,6 +143,25 @@ } }, }, + 'numpy_datetime_equal': { + 't1': np.datetime64('2023-07-05T10:11:12'), + 't2': np.datetime64('2023-07-05T10:11:12'), + 'deepdiff_kwargs': {}, + 'expected_result': {}, + }, + 'numpy_datetime_unequal': { + 't1': np.datetime64('2023-07-05T10:11:12'), + 't2': np.datetime64('2024-07-05T10:11:12'), + 'deepdiff_kwargs': {}, + 'expected_result': { + 'values_changed': { + 'root': { + 'new_value': np.datetime64('2024-07-05T10:11:12'), + 'old_value': np.datetime64('2023-07-05T10:11:12'), + } + }, + }, + }, } diff --git a/tests/test_hash.py b/tests/test_hash.py index c57afee8..6d09a176 100755 --- a/tests/test_hash.py +++ b/tests/test_hash.py @@ -196,6 +196,19 @@ def test_numpy_bool(self): a_hash = DeepHash(a)[a] assert not( a_hash is unprocessed) + def test_numpy_datetime64(self): + now_dt = datetime.datetime.now() + now = np.datetime64(now_dt) + later = np.datetime64(now_dt + datetime.timedelta(seconds=10)) + a = b = now + a_hash = DeepHash(a) + b_hash = DeepHash(b) + assert a_hash[a] == b_hash[b] + + later_hash = DeepHash(later) + assert a_hash[a] != later_hash[later] + + class TestDeepHashPrep: """DeepHashPrep Tests covering object serialization."""