Skip to content

Commit dea3615

Browse files
committed
dealing with enums and py 3.11
1 parent 90be53b commit dea3615

File tree

7 files changed

+67
-31
lines changed

7 files changed

+67
-31
lines changed

deepdiff/diff.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# However the docstring expects it in a specific order in order to pass!
88
import difflib
99
import logging
10+
from enum import Enum
1011
from copy import deepcopy
1112
from math import isclose as is_close
1213
from collections.abc import Mapping, Iterable
@@ -21,7 +22,7 @@
2122
number_to_string, datetime_normalize, KEY_TO_VAL_STR, booleans,
2223
np_ndarray, get_numpy_ndarray_rows, OrderedSetPlus, RepeatedTimer,
2324
TEXT_VIEW, TREE_VIEW, DELTA_VIEW, detailed__dict__,
24-
np, get_truncate_datetime, dict_, CannotCompare)
25+
np, get_truncate_datetime, dict_, CannotCompare, ENUM_IGNORE_KEYS)
2526
from deepdiff.serialization import SerializationMixin
2627
from deepdiff.distance import DistanceMixin
2728
from deepdiff.model import (
@@ -388,8 +389,19 @@ def unmangle(attribute):
388389

389390
return {i: getattr(object, unmangle(i)) for i in all_slots}
390391

391-
def _diff_obj(self, level, parents_ids=frozenset(),
392-
is_namedtuple=False):
392+
def _diff_enum(self, level, parents_ids=frozenset()):
393+
t1 = detailed__dict__(level.t1, ignore_private_variables=self.ignore_private_variables, ignore_keys=ENUM_IGNORE_KEYS)
394+
t2 = detailed__dict__(level.t2, ignore_private_variables=self.ignore_private_variables, ignore_keys=ENUM_IGNORE_KEYS)
395+
396+
self._diff_dict(
397+
level,
398+
parents_ids,
399+
print_as_attribute=True,
400+
override=True,
401+
override_t1=t1,
402+
override_t2=t2)
403+
404+
def _diff_obj(self, level, parents_ids=frozenset(), is_namedtuple=False):
393405
"""Difference of 2 objects"""
394406
try:
395407
if is_namedtuple:
@@ -1356,6 +1368,9 @@ def _diff(self, level, parents_ids=frozenset(), _original_type=None):
13561368
elif isinstance(level.t1, Iterable):
13571369
self._diff_iterable(level, parents_ids, _original_type=_original_type)
13581370

1371+
elif isinstance(level.t1, Enum):
1372+
self._diff_enum(level, parents_ids)
1373+
13591374
else:
13601375
self._diff_obj(level, parents_ids)
13611376

deepdiff/helper.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class np_type:
123123
TEXT_VIEW = 'text'
124124
DELTA_VIEW = '_delta'
125125

126+
ENUM_IGNORE_KEYS = frozenset(['_name_', '_value_', '_sort_order_'])
127+
126128

127129
def short_repr(item, max_length=15):
128130
"""Short representation of item if it is too long"""
@@ -584,21 +586,27 @@ def get_homogeneous_numpy_compatible_type_of_seq(seq):
584586
return False
585587

586588

587-
def detailed__dict__(obj, ignore_private_variables=True):
589+
def detailed__dict__(obj, ignore_private_variables=True, ignore_keys=frozenset()):
588590
"""
589591
Get the detailed dictionary of an object.
590592
591593
This is used so we retrieve object properties too.
592594
"""
593595
result = obj.__dict__.copy() # A shallow copy
594596
private_var_prefix = f"_{obj.__class__.__name__}__" # The semi private variables in Python get this prefix
597+
for key in ignore_keys:
598+
if key in result or (
599+
ignore_private_variables and key.startswith('__') and not key.startswith(private_var_prefix)
600+
):
601+
del result[key]
595602
for key in dir(obj):
596-
if key not in result and (
603+
if key not in result and key not in ignore_keys and (
597604
not ignore_private_variables or (
598605
ignore_private_variables and not key.startswith('__') and not key.startswith(private_var_prefix)
599606
)
600607
):
601608
value = getattr(obj, key)
602609
if not callable(value):
610+
print(f"{key}: {value}")
603611
result[key] = value
604612
return result

requirements-cli.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
click==8.0.3
2-
pyyaml==5.4.1
1+
click==8.1.3
2+
pyyaml==6.0
33
toml==0.10.2
4-
clevercsv==0.7.1
4+
clevercsv==0.7.4

requirements-dev.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ wheel==0.37.0
22
-r requirements.txt
33
-r requirements-cli.txt
44
bump2version==1.0.1
5-
jsonpickle==2.0.0
6-
coverage==6.0.2
5+
jsonpickle==2.2.0
6+
coverage==6.4.3
77
ipdb==0.13.9
8-
numpy==1.21.2
9-
pytest==6.2.5
8+
numpy==1.23.1
9+
pytest==7.1.2
1010
pytest-cov==3.0.0
11-
python-dotenv==0.19.1
12-
watchdog==2.1.6
13-
Sphinx==4.2.0
11+
python-dotenv==0.20.0
12+
watchdog==2.1.9
13+
Sphinx==5.1.1
1414
sphinx-sitemap==2.2.0
15-
flake8==4.0.1
15+
flake8==5.0.4

tests/test_diff_text.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44
import logging
55
import uuid
6-
import numpy as np
6+
from enum import Enum
77
from decimal import Decimal
88
from deepdiff import DeepDiff
99
from deepdiff.helper import pypy3
@@ -550,7 +550,6 @@ def test_named_tuples(self):
550550
assert result == ddiff
551551

552552
def test_enums(self):
553-
from enum import Enum
554553

555554
class MyEnum(Enum):
556555
A = 1
@@ -563,14 +562,6 @@ class MyEnum(Enum):
563562
ddiff = DeepDiff(MyEnum.A, MyEnum.B)
564563
result = {
565564
'values_changed': {
566-
'root._name_': {
567-
'old_value': 'A',
568-
'new_value': 'B'
569-
},
570-
'root._value_': {
571-
'old_value': 1,
572-
'new_value': 2
573-
},
574565
'root.name': {
575566
'old_value': 'A',
576567
'new_value': 'B'

tests/test_hash.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
from enum import Enum
99
from deepdiff import DeepHash
1010
from deepdiff.deephash import (
11-
prepare_string_for_hashing, unprocessed, UNPROCESSED_KEY, BoolObj, HASH_LOOKUP_ERR_MSG, combine_hashes_lists)
12-
from deepdiff.helper import pypy3, get_id, number_to_string, np
11+
prepare_string_for_hashing, unprocessed,
12+
UNPROCESSED_KEY, BoolObj, HASH_LOOKUP_ERR_MSG, combine_hashes_lists)
13+
from deepdiff.helper import pypy3, get_id, number_to_string, np, py_current_version
1314
from tests import CustomClass2
1415

1516
logging.disable(logging.CRITICAL)
@@ -261,12 +262,15 @@ def test_named_tuples(self):
261262
}
262263
assert expected_result == result
263264

264-
def test_enum(self):
265+
def test_hash_enum(self):
265266
class MyEnum(Enum):
266267
A = 1
267268
B = 2
268269

269-
assert DeepHashPrep(MyEnum.A)[MyEnum.A] == r'objMyEnum:{str:_name_:str:A;str:_value_:int:1}'
270+
if py_current_version >= 3.11:
271+
assert DeepHashPrep(MyEnum.A)[MyEnum.A] == r'objMyEnum:{str:_name_:str:A;str:_sort_order_:int:0;str:_value_:int:1}'
272+
else:
273+
assert DeepHashPrep(MyEnum.A)[MyEnum.A] == r'objMyEnum:{str:_name_:str:A;str:_value_:int:1}'
270274
assert DeepHashPrep(MyEnum.A) == DeepHashPrep(MyEnum(1))
271275
assert DeepHashPrep(MyEnum.A) != DeepHashPrep(MyEnum.A.name)
272276
assert DeepHashPrep(MyEnum.A) != DeepHashPrep(MyEnum.A.value)

tests/test_helper.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,22 @@
22
import pytest
33
import datetime
44
import numpy as np
5+
from enum import Enum
56
from decimal import Decimal
67
from deepdiff.helper import (
78
short_repr, number_to_string, get_numpy_ndarray_rows,
89
cartesian_product_of_shape, literal_eval_extended,
910
not_found, OrderedSetPlus, diff_numpy_array, cartesian_product_numpy,
10-
get_truncate_datetime, datetime_normalize
11+
get_truncate_datetime, datetime_normalize,
12+
detailed__dict__, ENUM_IGNORE_KEYS,
1113
)
1214

1315

16+
class MyEnum(Enum):
17+
A = 1
18+
B = 2
19+
20+
1421
class TestHelper:
1522
"""Helper Tests."""
1623

@@ -140,3 +147,14 @@ def test_get_truncate_datetime(self):
140147
def test_datetime_normalize(self, truncate_datetime, obj, expected):
141148
result = datetime_normalize(truncate_datetime, obj)
142149
assert expected == result
150+
151+
@pytest.mark.parametrize('obj, ignore_keys, expected', [
152+
(
153+
MyEnum.A,
154+
ENUM_IGNORE_KEYS,
155+
{'__objclass__': MyEnum, 'name': 'A', 'value': 1},
156+
)
157+
])
158+
def test_detailed__dict__(self, obj, ignore_keys, expected):
159+
result = detailed__dict__(obj, ignore_private_variables=True, ignore_keys=ignore_keys)
160+
assert expected == result, f"test_detailed__dict__ failed for {obj}"

0 commit comments

Comments
 (0)