Skip to content

Fix TypeError for datetime dict keys with key-cleaning flags (fixes #550)#599

Open
gaoflow wants to merge 1 commit into
qlustered:devfrom
gaoflow:fix/number-to-string-datetime-key
Open

Fix TypeError for datetime dict keys with key-cleaning flags (fixes #550)#599
gaoflow wants to merge 1 commit into
qlustered:devfrom
gaoflow:fix/number-to-string-datetime-key

Conversation

@gaoflow
Copy link
Copy Markdown

@gaoflow gaoflow commented Jun 1, 2026

Summary

Using a datetime/date as a dict key together with one of the
key-cleaning flags raised a TypeError:

import datetime
from deepdiff import DeepDiff

dt = datetime.datetime(2020, 5, 17, 22, 15)
DeepDiff({dt: 10.0}, {dt: 10}, ignore_numeric_type_changes=True)
# TypeError: type datetime.datetime doesn't define __round__ method

The same happens with ignore_string_case and ignore_string_type_changes
(any flag that routes dict keys through _get_clean_to_keys_mapping), and with
datetime.date keys.

Root cause

_get_clean_to_keys_mapping cleans numeric keys via number_to_string, whose
type guard is:

if not isinstance(number, numbers):
    return number

numbers is defined as only_numbers + datetimes (datetimes are included
because they are orderable). So a datetime key passes the guard and falls
through to round(number, ndigits=significant_digits), which datetimes do not
implement → TypeError.

Fix

Guard on only_numbers instead. Datetimes/dates (and anything else that is not
a real, round()-able number) are returned unchanged, exactly like every other
non-numeric value — which is what the early-return branch is for. Numeric
behaviour (int/float/Decimal/Fraction/complex/numpy, significant-digit
rounding) is unchanged.

Verification

dt = datetime.datetime(2020, 5, 17, 22, 15)
DeepDiff({dt: 10.0}, {dt: 10}, ignore_numeric_type_changes=True)   # {}  (was TypeError)

Added test_datetime_dict_key_with_ignore_flags to
tests/test_diff_datetime.py. It fails on dev
(TypeError ... __round__) and passes with this change. The existing
tests/test_diff_datetime.py and tests/test_helper.py suites (168 tests)
still pass.

Fixes #550.

… flags

number_to_string guards on `numbers`, which includes the datetime types
(they are orderable). Datetimes therefore passed the guard and reached
`round(number, ...)`, which they do not support. Using a datetime/date as a
dict key together with a flag that cleans keys (ignore_numeric_type_changes,
ignore_string_case, ignore_string_type_changes) raised:

    TypeError: type datetime.datetime doesn't define __round__ method

Guard on `only_numbers` instead so non-round()-able values (datetimes,
dates, ...) are returned unchanged, like every other non-numeric value.
Adds a regression test. Fixes qlustered#550.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant