Skip to content

Commit

Permalink
better support for Pydantic models. Ignore model_fields_set when
Browse files Browse the repository at this point in the history
comparing pydantic objects
  • Loading branch information
seperman committed Dec 14, 2024
1 parent f86033f commit 051c6d8
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 4 deletions.
8 changes: 6 additions & 2 deletions deepdiff/deephash.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
convert_item_or_items_into_compiled_regexes_else_none,
get_id, type_is_subclass_of_type_group, type_in_type_group,
number_to_string, datetime_normalize, KEY_TO_VAL_STR, short_repr,
get_truncate_datetime, dict_, add_root_to_paths)
get_truncate_datetime, dict_, add_root_to_paths, PydanticBaseModel)
from deepdiff.base import Base

try:
Expand Down Expand Up @@ -331,13 +331,15 @@ def values(self):
def items(self):
return ((i, v[0]) for i, v in self.hashes.items())

def _prep_obj(self, obj, parent, parents_ids=EMPTY_FROZENSET, is_namedtuple=False):
def _prep_obj(self, obj, parent, parents_ids=EMPTY_FROZENSET, is_namedtuple=False, is_pydantic_object=False):
"""prepping objects"""
original_type = type(obj) if not isinstance(obj, type) else obj

obj_to_dict_strategies = []
if is_namedtuple:
obj_to_dict_strategies.append(lambda o: o._asdict())
elif is_pydantic_object:
obj_to_dict_strategies.append(lambda o: {k: v for (k, v) in o.__dict__.items() if v !="model_fields_set"})
else:
obj_to_dict_strategies.append(lambda o: o.__dict__)

Expand Down Expand Up @@ -562,6 +564,8 @@ def gen():

elif obj == BoolObj.TRUE or obj == BoolObj.FALSE:
result = 'bool:true' if obj is BoolObj.TRUE else 'bool:false'
elif isinstance(obj, PydanticBaseModel):
result, counts = self._prep_obj(obj=obj, parent=parent, parents_ids=parents_ids, is_pydantic_object=True)
else:
result, counts = self._prep_obj(obj=obj, parent=parent, parents_ids=parents_ids)

Expand Down
10 changes: 8 additions & 2 deletions deepdiff/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ def _report_progress(_stats, progress_logger, duration):
PURGE_LEVEL_RANGE_MSG = 'cache_purge_level should be 0, 1, or 2.'
_ENABLE_CACHE_EVERY_X_DIFF = '_ENABLE_CACHE_EVERY_X_DIFF'

model_fields_set = frozenset(["model_fields_set"])


# What is the threshold to consider 2 items to be pairs. Only used when ignore_order = True.
CUTOFF_DISTANCE_FOR_PAIRS_DEFAULT = 0.3

Expand Down Expand Up @@ -437,13 +440,16 @@ def _diff_enum(self, level, parents_ids=frozenset(), local_tree=None):
local_tree=local_tree,
)

def _diff_obj(self, level, parents_ids=frozenset(), is_namedtuple=False, local_tree=None):
def _diff_obj(self, level, parents_ids=frozenset(), is_namedtuple=False, local_tree=None, is_pydantic_object=False):
"""Difference of 2 objects"""
processing_error = False
try:
if is_namedtuple:
t1 = level.t1._asdict()
t2 = level.t2._asdict()
elif is_pydantic_object:
t1 = detailed__dict__(level.t1, ignore_private_variables=self.ignore_private_variables, ignore_keys=model_fields_set)
t2 = detailed__dict__(level.t2, ignore_private_variables=self.ignore_private_variables, ignore_keys=model_fields_set)
elif all('__dict__' in dir(t) for t in level):
t1 = detailed__dict__(level.t1, ignore_private_variables=self.ignore_private_variables)
t2 = detailed__dict__(level.t2, ignore_private_variables=self.ignore_private_variables)
Expand Down Expand Up @@ -1678,7 +1684,7 @@ def _diff(self, level, parents_ids=frozenset(), _original_type=None, local_tree=
self._diff_numpy_array(level, parents_ids, local_tree=local_tree)

elif isinstance(level.t1, PydanticBaseModel):
self._diff_obj(level, parents_ids, local_tree=local_tree)
self._diff_obj(level, parents_ids, local_tree=local_tree, is_pydantic_object=True)

elif isinstance(level.t1, Iterable):
self._diff_iterable(level, parents_ids, _original_type=_original_type, local_tree=local_tree)
Expand Down

0 comments on commit 051c6d8

Please sign in to comment.