2 Star 0 Fork 0

mirrors_seperman/deepdiff

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
test_ignore_order.py 48.55 KB
一键复制 编辑 原始数据 按行查看 历史
Sep Dehpour 提交于 4个月前 . adding BaseOperatorPlus
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
import pytest
import re
import datetime
from unittest import mock
from deepdiff.helper import number_to_string, CannotCompare
from deepdiff import DeepDiff
from decimal import Decimal
from deepdiff.deephash import sha256hex
from tests import CustomClass2
class TestIgnoreOrder:
@pytest.mark.parametrize("t1, t2, significant_digits, ignore_order, result", [
(10, 10.0, 5, False, {}),
({10: 'a', 11.1: 'b'}, {10.0: 'a', Decimal('11.1000003'): 'b'}, 5, False, {}),
])
def test_type_change_numeric_ignored(self, t1, t2, significant_digits, ignore_order, result):
ddiff = DeepDiff(t1, t2, ignore_numeric_type_changes=True,
significant_digits=significant_digits, ignore_order=ignore_order)
assert result == ddiff
@pytest.mark.parametrize("t1, t2, expected_result",
[
(10, 10.0, {}),
(10, 10.2, {'values_changed': {'root': {'new_value': 10.2, 'old_value': 10}}}),
(Decimal(10), 10.0, {}),
({"a": Decimal(10), "b": 12, 11.0: None}, {b"b": 12, "a": 10.0, Decimal(11): None}, {}),
])
def test_type_change_numeric_when_ignore_order(self, t1, t2, expected_result):
ddiff = DeepDiff(t1, t2, ignore_order=True, ignore_numeric_type_changes=True, ignore_string_type_changes=True, threshold_to_diff_deeper=0)
assert expected_result == ddiff
def test_ignore_order_depth1(self):
t1 = [{1, 2, 3}, {4, 5}]
t2 = [{4, 5, 6}, {1, 2, 3}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {'set_item_added': ["root[1][6]"]} == ddiff
def test_ignore_order_depth2(self):
t1 = [[1, 2, 3], [4, 5]]
t2 = [[4, 5, 6], [1, 2, 3]]
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {'iterable_item_added': {'root[1][2]': 6}} == ddiff
def test_ignore_order_depth3(self):
t1 = [{1, 2, 3}, [{4, 5}]]
t2 = [[{4, 5, 6}], {1, 2, 3}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {'set_item_added': ["root[1][0][6]"]} == ddiff
assert {"root[1][0][6]"} == ddiff.affected_paths
def test_ignore_order_depth4(self):
t1 = [[1, 2, 3, 4], [4, 2, 2, 1]]
t2 = [[4, 1, 1, 1], [1, 3, 2, 4]]
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {'iterable_item_removed': {'root[1][1]': 2}} == ddiff
def test_ignore_order_depth5(self):
t1 = [4, 2, 2, 1]
t2 = [4, 1, 1, 1]
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True, cache_purge_level=0)
expected = {
'iterable_item_removed': {
'root[1]': 2,
'root[2]': 2
},
'repetition_change': {
'root[3]': {
'old_repeat': 1,
'new_repeat': 3,
'old_indexes': [3],
'new_indexes': [1, 2, 3],
'value': 1
}
}
}
assert expected == ddiff
assert {"root[1]", "root[2]", "root[3]"} == ddiff.affected_paths
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=False, cache_purge_level=0)
dist = ddiff._get_rough_distance()
assert 0.1 == dist
def test_ignore_order_depth6(self):
t1 = [[1, 2, 3, 4], [4, 2, 2, 1]]
t2 = [[4, 1, 1, 1], [1, 3, 2, 4]]
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
expected = {
'iterable_item_removed': {
'root[1][1]': 2,
'root[1][2]': 2
},
'repetition_change': {
'root[1][3]': {
'old_repeat': 1,
'new_repeat': 3,
'old_indexes': [3],
'new_indexes': [1, 2, 3],
'value': 1
}
}
}
assert expected == ddiff
def test_list_difference_ignore_order(self):
t1 = {1: 1, 4: {"a": "hello", "b": [1, 2, 3]}}
t2 = {1: 1, 4: {"a": "hello", "b": [1, 3, 2, 3]}}
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {} == ddiff
@pytest.mark.parametrize('t1_0, t2_0', [
(1, 2),
(True, False),
('a', 'b'),
])
def test_list_difference_of_bool_only_ignore_order(self, t1_0, t2_0):
t1 = [t1_0]
t2 = [t2_0]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {'values_changed': {'root[0]': {'new_value': t2_0, 'old_value': t1_0}}}
assert result == ddiff
def test_dictionary_difference_ignore_order(self):
t1 = {"a": [[{"b": 2, "c": 4}, {"b": 2, "c": 3}]]}
t2 = {"a": [[{"b": 2, "c": 3}, {"b": 2, "c": 4}]]}
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {} == ddiff
assert set() == ddiff.affected_paths
def test_nested_list_ignore_order(self):
t1 = [1, 2, [3, 4]]
t2 = [[4, 3, 3], 2, 1]
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {} == ddiff
def test_nested_list_difference_ignore_order(self):
t1 = [1, 2, [3, 4]]
t2 = [[4, 3], 2, 1]
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {} == ddiff
def test_nested_list_with_dictionarry_difference_ignore_order(self):
t1 = [1, 2, [3, 4, {1: 2}]]
t2 = [[4, 3, {1: 2}], 2, 1]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {}
assert result == ddiff
def test_list_difference_ignore_order_report_repetition1(self):
t1 = [1, 3, 1, 4]
t2 = [4, 4, 1]
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
result = {
'iterable_item_removed': {
'root[1]': 3
},
'repetition_change': {
'root[0]': {
'old_repeat': 2,
'old_indexes': [0, 2],
'new_indexes': [2],
'value': 1,
'new_repeat': 1
},
'root[3]': {
'old_repeat': 1,
'old_indexes': [3],
'new_indexes': [0, 1],
'value': 4,
'new_repeat': 2
}
}
}
assert result == ddiff
@pytest.mark.skip
def test_list_difference_ignore_order_report_repetition2(self):
t1 = [1, 1, 1]
t2 = [2, 2]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {'values_changed': {'root[0]': {'new_value': 2, 'old_value': 1}}}
assert result == ddiff
ddiff2 = DeepDiff(t1, t2, ignore_order=True, report_repetition=True, cutoff_intersection_for_pairs=1, cutoff_distance_for_pairs=1)
result2 = {
'iterable_item_removed': {
'root[0]': 1,
'root[1]': 1,
'root[2]': 1
},
'iterable_item_added': {
'root[0]': 2,
'root[1]': 2,
},
}
assert result2 == ddiff2
@pytest.mark.skip
def test_list_difference_ignore_order_report_repetition3(self):
t1 = [{"id": 1}, {"id": 1}, {"id": 1}]
t2 = [{"id": 1, "name": 1}]
ddiff2 = DeepDiff(t1, t2, ignore_order=True, report_repetition=True, cutoff_intersection_for_pairs=1, cutoff_distance_for_pairs=1)
result2 = {
'iterable_item_removed': {
'root[1]': {"id": 1},
'root[2]': {"id": 1},
},
'dictionary_item_added': ["root[0]['name']"]
}
assert result2 == ddiff2
@pytest.mark.skip
def test_list_difference_ignore_order_report_repetition4(self):
t1 = [{"id": 1}, {"id": 1}, {"id": 1}, {"name": "Joe"}, {"name": "Joe"}]
t2 = [{"id": 1, "name": 1}, {"id": 1, "name": "Joe"}]
ddiff2 = DeepDiff(t1, t2, ignore_order=True, report_repetition=True, cutoff_intersection_for_pairs=1, cutoff_distance_for_pairs=1)
result2 = {
'iterable_item_removed': {
'root[2]': {"id": 1},
'root[3]': {"name": "Joe"},
'root[4]': {"name": "Joe"},
},
'dictionary_item_added': ["root[0]['name']", "root[1]['name']"]
}
assert result2 == ddiff2
def test_nested_list_ignore_order_report_repetition(self):
t1 = [1, 2, [3, 4]]
t2 = [[4, 3, 3], 2, 1]
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=False)
assert not ddiff
ddiff2 = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
result = {
'repetition_change': {
'root[2][0]': {
'old_repeat': 1,
'new_repeat': 2,
'old_indexes': [0],
'new_indexes': [1, 2],
'value': 3
}
}
}
assert result == ddiff2
assert {"root[2][0]"} == ddiff2.affected_paths
@pytest.mark.skip
def test_nested_list_and_dict_ignore_order_report_repetition(self):
"""
This test shows that ignore order is not doing the right thing.
It should have said that root[1] and root[2] are removed.
"""
t1 = [{"id": 1}, {"id": 1}, {"id": 1}]
t2 = [{"id": 1, "name": 1}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {'dictionary_item_added': ["root[0]['name']"]}
assert result == ddiff
# Here there is nothing that is "repeated" in an iterable
ddiff2 = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
assert result == ddiff2
assert {"root[2][0]"} == ddiff2.affected_paths
def test_list_of_unhashable_difference_ignore_order(self):
t1 = [{"a": 2}, {"b": [3, 4, {1: 1}]}]
t2 = [{"b": [3, 4, {1: 1}]}, {"a": 2}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {} == ddiff
def test_list_of_unhashable_difference_ignore_order2(self):
t1 = [1, {"a": 2}, {"b": [3, 4, {1: 1}]}, "B"]
t2 = [{"b": [3, 4, {1: 1}]}, {"a": 2}, {1: 1}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {
'iterable_item_added': {
'root[2]': {
1: 1
}
},
'iterable_item_removed': {
'root[3]': 'B',
'root[0]': 1
}
}
assert result == ddiff
def test_list_of_unhashable_difference_ignore_order3(self):
t1 = [1, {"a": 2}, {"a": 2}, {"b": [3, 4, {1: 1}]}, "B"]
t2 = [{"b": [3, 4, {1: 1}]}, {1: 1}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {
'values_changed': {
'root[1]': {
'new_value': {
1: 1
},
'old_value': {
'a': 2
}
}
},
'iterable_item_removed': {
'root[0]': 1,
'root[4]': 'B'
}
}
assert result == ddiff
def test_list_of_unhashable_difference_ignore_order_report_repetition(
self):
t1 = [1, {"a": 2}, {"a": 2}, {"b": [3, 4, {1: 1}]}, "B"]
t2 = [{"b": [3, 4, {1: 1}]}, {1: 1}]
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True, threshold_to_diff_deeper=0)
result = {
'iterable_item_added': {
'root[1]': {
1: 1
}
},
'iterable_item_removed': {
'root[4]': 'B',
'root[0]': 1,
'root[1]': {
'a': 2
},
'root[2]': {
'a': 2
}
}
}
assert result == ddiff
def test_list_of_unhashable_difference_ignore_order4(self):
t1 = [{"a": 2}, {"a": 2}]
t2 = [{"a": 2}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {}
assert result == ddiff
def test_list_of_unhashable_difference_ignore_order_report_repetition2(
self):
t1 = [{"a": 2}, {"a": 2}]
t2 = [{"a": 2}]
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
result = {
'repetition_change': {
'root[0]': {
'old_repeat': 2,
'new_indexes': [0],
'old_indexes': [0, 1],
'value': {
'a': 2
},
'new_repeat': 1
}
}
}
assert result == ddiff
def test_list_ignore_order_report_repetition(self):
t1 = [5, 1, 3, 1, 4, 4, 6]
t2 = [7, 4, 4, 1, 3, 4, 8]
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
result = {
'values_changed': {
'root[6]': {
'new_value': 7,
'old_value': 6
},
'root[0]': {
'new_value': 8,
'old_value': 5
}
},
'repetition_change': {
'root[4]': {
'old_repeat': 2,
'new_repeat': 3,
'old_indexes': [4, 5],
'new_indexes': [1, 2, 5],
'value': 4
},
'root[1]': {
'old_repeat': 2,
'new_repeat': 1,
'old_indexes': [1, 3],
'new_indexes': [3],
'value': 1
}
}
}
assert result == ddiff
def test_list_of_sets_difference_ignore_order(self):
t1 = [{1}, {2}, {3}]
t2 = [{4}, {1}, {2}, {3}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {'iterable_item_added': {'root[0]': {4}}}
assert result == ddiff
def test_list_of_sets_difference_ignore_order_when_there_is_duplicate(
self):
t1 = [{1}, {2}, {3}]
t2 = [{4}, {1}, {2}, {3}, {3}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {'iterable_item_added': {'root[0]': {4}}}
assert result == ddiff
def test_list_of_sets_difference_ignore_order_when_there_is_duplicate_and_mix_of_hashable_unhashable(
self):
t1 = [1, 1, {2}, {3}]
t2 = [{4}, 1, {2}, {3}, {3}, 1, 1]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {'iterable_item_added': {'root[0]': {4}}}
assert result == ddiff
def test_dictionary_of_list_of_dictionary_ignore_order(self):
t1 = {
'item': [{
'title': 1,
'http://purl.org/rss/1.0/modules/content/:encoded': '1'
}, {
'title': 2,
'http://purl.org/rss/1.0/modules/content/:encoded': '2'
}]
}
t2 = {
'item': [{
'http://purl.org/rss/1.0/modules/content/:encoded': '1',
'title': 1
}, {
'http://purl.org/rss/1.0/modules/content/:encoded': '2',
'title': 2
}]
}
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {} == ddiff
def test_comprehensive_ignore_order(self):
t1 = {
'key1': 'val1',
'key2': [
{
'key3': 'val3',
'key4': 'val4',
},
{
'key5': 'val5',
'key6': 'val6',
},
],
}
t2 = {
'key1': 'val1',
'key2': [
{
'key5': 'val5',
'key6': 'val6',
},
{
'key3': 'val3',
'key4': 'val4',
},
],
}
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {} == ddiff
def test_ignore_order_when_objects_similar(self):
t1 = {
'key1': 'val1',
'key2': [
{
'key3': 'val3',
'key4': 'val4',
},
{
'key5': 'val5',
'key6': 'val6',
},
],
}
t2 = {
'key1': 'val1',
'key2': [
{
'key5': 'CHANGE',
'key6': 'val6',
},
{
'key3': 'val3',
'key4': 'val4',
},
],
}
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert {'values_changed': {"root['key2'][1]['key5']": {'new_value': 'CHANGE', 'old_value': 'val5'}}} == ddiff
def test_set_ignore_order_report_repetition(self):
"""
If this test fails, it means that DeepDiff is not checking
for set types before general iterables.
So it forces creating the hashtable because of report_repetition=True.
"""
t1 = {2, 1, 8}
t2 = {1, 2, 3, 5}
ddiff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
result = {
'set_item_added': {'root[3]', 'root[5]'},
'set_item_removed': {'root[8]'}
}
assert result == ddiff
def test_custom_objects2(self):
cc_a = CustomClass2(prop1=["a"], prop2=["b"])
cc_b = CustomClass2(prop1=["b"], prop2=["b"])
t1 = [cc_a, CustomClass2(prop1=["c"], prop2=["d"])]
t2 = [cc_b, CustomClass2(prop1=["c"], prop2=["d"])]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {'values_changed': {'root[0].prop1[0]': {'new_value': 'b', 'old_value': 'a'}}}
assert result == ddiff
def test_custom_object_type_change_when_ignore_order(self):
class Burrito:
bread = 'flour'
def __init__(self):
self.spicy = True
class Taco:
bread = 'flour'
def __init__(self):
self.spicy = True
burrito = Burrito()
taco = Taco()
burritos = [burrito]
tacos = [taco]
assert not DeepDiff(burritos, tacos, ignore_type_in_groups=[(Taco, Burrito)], ignore_order=True)
def test_decimal_ignore_order(self):
t1 = [{1: Decimal('10.1')}, {2: Decimal('10.2')}]
t2 = [{2: Decimal('10.2')}, {1: Decimal('10.1')}]
ddiff = DeepDiff(t1, t2, ignore_order=True)
result = {}
assert result == ddiff
@pytest.mark.parametrize('log_scale_similarity_threshold, expected', [
(
0.1,
{}
),
(
0.01,
{'values_changed': {'root[1][2]': {'new_value': Decimal('268'), 'old_value': Decimal('290.2')}}}
),
])
def test_decimal_log_scale_ignore_order1(self, log_scale_similarity_threshold, expected):
t1 = [{1: Decimal('10.143')}, {2: Decimal('290.2')}]
t2 = [{2: Decimal('268')}, {1: Decimal('10.23')}]
ddiff = DeepDiff(t1, t2, ignore_order=True, use_log_scale=True, log_scale_similarity_threshold=log_scale_similarity_threshold, cutoff_intersection_for_pairs=1)
assert expected == ddiff
@pytest.mark.parametrize("t1, t2, significant_digits, ignore_order", [
(100000, 100021, 3, False),
([10, 12, 100000], [50, 63, 100021], 3, False),
([10, 12, 100000], [50, 63, 100021], 3, True),
])
def test_number_to_string_func(self, t1, t2, significant_digits, ignore_order):
def custom_number_to_string(number, *args, **kwargs):
number = 100 if number < 100 else number
return number_to_string(number, *args, **kwargs)
ddiff = DeepDiff(t1, t2, significant_digits=3, number_format_notation="e",
number_to_string_func=custom_number_to_string)
assert {} == ddiff
def test_ignore_type_in_groups_numbers_and_strings_when_ignore_order(self):
t1 = [1, 2, 3, 'a']
t2 = [1.0, 2.0, 3.3, b'a']
ddiff = DeepDiff(t1, t2, ignore_numeric_type_changes=True, ignore_string_type_changes=True, ignore_order=True)
result = {'values_changed': {'root[2]': {'new_value': 3.3, 'old_value': 3}}}
assert result == ddiff
def test_ignore_string_type_changes_when_dict_keys_merge_is_not_deterministic(self):
t1 = {'a': 10, b'a': 20}
t2 = {'a': 11, b'a': 22}
ddiff = DeepDiff(t1, t2, ignore_numeric_type_changes=True, ignore_string_type_changes=True, ignore_order=True)
result = {'values_changed': {"root['a']": {'new_value': 22, 'old_value': 20}}}
alternative_result = {'values_changed': {"root['a']": {'new_value': 11, 'old_value': 10}}}
assert result == ddiff or alternative_result == ddiff
def test_skip_exclude_path5(self):
exclude_paths = ["root[0]['e']", "root[1]['e']"]
t1 = [{'a': 1, 'b': 'randomString', 'e': "1111"}]
t2 = [{'a': 1, 'b': 'randomString', 'e': "2222"}]
ddiff = DeepDiff(t1, t2, exclude_paths=exclude_paths,
ignore_order=True, report_repetition=False)
result = {}
assert result == ddiff
def test_skip_str_type_in_dict_on_list_when_ignored_order(self):
t1 = [{1: "a"}]
t2 = [{}]
ddiff = DeepDiff(t1, t2, exclude_types=[str], ignore_order=True)
result = {}
assert result == ddiff
@mock.patch('deepdiff.diff.logger')
@mock.patch('deepdiff.diff.DeepHash')
def test_diff_when_hash_fails(self, mock_DeepHash, mock_logger):
mock_DeepHash.side_effect = ValueError('Boom!')
t1 = {"blah": {4}, 2: 1337}
t2 = {"blah": {4}, 2: 1337}
with pytest.raises(ValueError) as exp:
DeepDiff(t1, t2, ignore_order=True)
assert 'Boom!' == str(exp.value)
def test_bool_vs_number(self):
t1 = {
"A List": [
{
"Value One": True,
"Value Two": 1
}
],
}
t2 = {
"A List": [
{
"Value Two": 1,
"Value One": True
}
],
}
ddiff = DeepDiff(t1, t2, ignore_order=True, cutoff_intersection_for_pairs=1)
assert ddiff == {}
@pytest.mark.parametrize('max_passes, expected', [
(0, {'values_changed': {'root[0]': {'new_value': {'key5': 'CHANGE', 'key6': 'val6'}, 'old_value': {'key3': [[[[[1, 2, 4, 5]]]]], 'key4': [7, 8]}}, 'root[1]': {'new_value': {'key3': [[[[[1, 3, 5, 4]]]]], 'key4': [7, 8]}, 'old_value': {'key5': 'val5', 'key6': 'val6'}}}}),
(1, {'values_changed': {"root[1]['key5']": {'new_value': 'CHANGE', 'old_value': 'val5', 'new_path': "root[0]['key5']"}, "root[0]['key3'][0]": {'new_value': [[[[1, 3, 5, 4]]]], 'old_value': [[[[1, 2, 4, 5]]]], 'new_path': "root[1]['key3'][0]"}}}),
(22, {'values_changed': {"root[1]['key5']": {'new_value': 'CHANGE', 'old_value': 'val5', 'new_path': "root[0]['key5']"}, "root[0]['key3'][0][0][0][0][1]": {'new_value': 3, 'old_value': 2, 'new_path': "root[1]['key3'][0][0][0][0][1]"}}})
])
def test_ignore_order_max_passes(self, max_passes, expected):
t1 = [
{
'key3': [[[[[1, 2, 4, 5]]]]],
'key4': [7, 8],
},
{
'key5': 'val5',
'key6': 'val6',
},
]
t2 = [
{
'key5': 'CHANGE',
'key6': 'val6',
},
{
'key3': [[[[[1, 3, 5, 4]]]]],
'key4': [7, 8],
},
]
ddiff = DeepDiff(t1, t2, ignore_order=True, max_passes=max_passes, verbose_level=2, cache_size=5000, cutoff_intersection_for_pairs=1, threshold_to_diff_deeper=0)
assert expected == ddiff
@pytest.mark.parametrize('max_diffs, expected', [
(1, {}),
(65, {'values_changed': {"root[1]['key5']": {'new_value': 'CHANGE', 'old_value': 'val5', 'new_path': "root[0]['key5']"}}}),
(80, {'values_changed': {"root[1]['key5']": {'new_value': 'CHANGE', 'old_value': 'val5', 'new_path': "root[0]['key5']"}, "root[0]['key3'][0][0][0][0][1]": {'new_value': 3, 'old_value': 2, 'new_path': "root[1]['key3'][0][0][0][0][1]"}}}),
])
def test_ignore_order_max_diffs(self, max_diffs, expected):
t1 = [
{
'key3': [[[[[1, 2, 4, 5]]]]],
'key4': [7, 8],
},
{
'key5': 'val5',
'key6': 'val6',
},
]
t2 = [
{
'key5': 'CHANGE',
'key6': 'val6',
},
{
'key3': [[[[[1, 3, 5, 4]]]]],
'key4': [7, 8],
},
]
# Note: these tests are not exactly deterministic
ddiff = DeepDiff(t1, t2, ignore_order=True, max_diffs=max_diffs, verbose_level=2, cache_size=5000, cutoff_intersection_for_pairs=1)
assert expected == ddiff
def test_stats_that_include_distance_cache_hits(self):
t1 = [
[1, 2, 3, 9], [9, 8, 5, 9]
]
t2 = [
[1, 2, 4, 10], [4, 2, 5]
]
diff = DeepDiff(t1, t2, ignore_order=True, cache_size=5000, cutoff_intersection_for_pairs=1)
expected = {
'PASSES COUNT': 7,
'DIFF COUNT': 37,
'DISTANCE CACHE HIT COUNT': 0,
'MAX PASS LIMIT REACHED': False,
'MAX DIFF LIMIT REACHED': False,
}
assert expected == diff.get_stats()
def test_ignore_order_report_repetition_and_self_loop(self):
t1 = [[1, 2, 1, 3]]
t1.append(t1)
t2 = [[1, 2, 2, 2, 4]]
t2.append(t2)
diff = DeepDiff(t1, t2, ignore_order=True, cutoff_intersection_for_pairs=1)
expected = {
'values_changed': {
'root[0][3]': {
'new_value': 4,
'old_value': 3
},
'root[1]': {
'new_value': t2,
'old_value': t1
}
}
}
assert expected == diff
diff2 = DeepDiff(t1, t2, ignore_order=True, cache_size=5000, cutoff_intersection_for_pairs=1)
assert expected == diff2
def test_ignore_order_with_sha256_hash(self):
t1 = [
[1, 2, 3, 9], [9, 8, 5, 9]
]
t2 = [
[1, 2, 3, 10], [8, 2, 5]
]
diff = DeepDiff(t1, t2, ignore_order=True, hasher=sha256hex, cutoff_intersection_for_pairs=1)
expected = {
'values_changed': {
'root[0][3]': {
'new_value': 10,
'old_value': 9
},
'root[1][0]': {
'new_value': 2,
'old_value': 9
}
}
}
assert expected == diff
def test_ignore_order_cache_for_individual_distances(self):
t1 = [[1, 2, 'B', 3], 'B']
t2 = [[1, 2, 3, 5], 5]
diff = DeepDiff(t1, t2, ignore_order=True, cache_size=5000, cutoff_intersection_for_pairs=1)
expected = {
'values_changed': {
'root[1]': {
'new_value': 5,
'old_value': 'B'
}
},
'iterable_item_added': {
'root[0][3]': 5
},
'iterable_item_removed': {
'root[0][2]': 'B'
}
}
assert expected == diff
stats = diff.get_stats()
expected_stats = {
'PASSES COUNT': 3,
'DIFF COUNT': 13,
'DISTANCE CACHE HIT COUNT': 1,
'MAX PASS LIMIT REACHED': False,
'MAX DIFF LIMIT REACHED': False
}
assert expected_stats == stats
t1 = [[1, 2, 'B', 3], 5]
t2 = [[1, 2, 3, 5], 'B']
diff2 = DeepDiff(t1, t2, ignore_order=True, cache_size=5000, cutoff_intersection_for_pairs=1)
assert expected_stats == diff2.get_stats()
def test_cutoff_distance_for_pairs(self):
t1 = [[1.0]]
t2 = [[20.0]]
diff1 = DeepDiff(t1, t2, ignore_order=True, cutoff_distance_for_pairs=0.3)
expected1 = {'values_changed': {'root[0][0]': {'new_value': 20.0, 'old_value': 1.0}}}
assert expected1 == diff1
diff2 = DeepDiff(t1, t2, ignore_order=True, cutoff_distance_for_pairs=0.1)
expected2 = {'values_changed': {'root[0]': {'new_value': [20.0], 'old_value': [1.0]}}}
assert expected2 == diff2
diff_with_dist = DeepDiff(1.0, 20.0, get_deep_distance=True)
expected = {'values_changed': {'root': {'new_value': 20.0, 'old_value': 1.0}}, 'deep_distance': 0.2714285714285714}
assert expected == diff_with_dist
def test_ignore_order_and_group_by1(self):
t1 = [
{'id': 'AA', 'name': 'Joe', 'ate': ['Nothing']},
{'id': 'BB', 'name': 'James', 'ate': ['Chips', 'Cheese']},
{'id': 'CC', 'name': 'Mike', 'ate': ['Apple']},
]
t2 = [
{'id': 'BB', 'name': 'James', 'ate': ['Chips', 'Brownies', 'Cheese']},
{'id': 'AA', 'name': 'Joe', 'ate': ['Nothing']},
{'id': 'CC', 'name': 'Mike', 'ate': ['Apple', 'Apple']},
]
diff = DeepDiff(t1, t2, group_by='id', ignore_order=False)
expected = {'iterable_item_added': {"root['BB']['ate'][1]": 'Brownies', "root['CC']['ate'][1]": 'Apple'}}
assert expected == diff
diff2 = DeepDiff(t1, t2, group_by='id', ignore_order=True)
expected2 = {'iterable_item_added': {"root['BB']['ate'][1]": 'Brownies'}}
assert expected2 == diff2
def test_ignore_order_and_group_by2(self):
t1_data = [{'id': '1', 'codes': ['1', '2', '3']}]
t2_data = [{'id': '1', 'codes': ['1', '2', '4']}]
diff = DeepDiff(t1_data, t2_data, group_by='id', ignore_order=True)
expected = {'values_changed': {"root['1']['codes'][2]": {'new_value': '4', 'old_value': '3'}}}
assert expected == diff
def test_ignore_order_and_group_by3(self):
t1 = [{
'id':
'5ec52e',
'products': [{
'lineNumber': 1,
'productPrice': '2.39',
'productQuantity': 2
}, {
'lineNumber': 2,
'productPrice': '4.44',
'productQuantity': 1
}],
}]
t2 = [{
'id':
'5ec52e',
'products': [
{
'lineNumber': 2,
'productPrice': '4.44',
'productQuantity': 1
},
{
'lineNumber': 1,
'productPrice': '2.39',
'productQuantity': 2
},
],
}]
diff = DeepDiff(t1, t2, group_by='id', ignore_order=True)
assert {} == diff
def test_ignore_order_and_group_by4(self):
t1 = [
{
"id": "1",
"field_01": {
"subfield_01": {
"subfield_02": {"subfield_03": "1"},
}
},
},
{"id": "2", "field_01": ["1", "2", "3"]},
{"id": "3", "field_01": ["1", "2", "3"]},
]
t2 = [
{
"id": "1",
"field_01": {
"subfield_01": {
"subfield_02": {"subfield_03": "2"},
}
},
},
{"id": "2", "field_01": ["4", "5", "6"]},
{"id": "3", "field_01": ["7", "8", "9"]},
]
diff = DeepDiff(t1, t2, group_by='id', ignore_order=True)
expected = {
'values_changed': {
"root['1']['field_01']['subfield_01']['subfield_02']['subfield_03']": {
'new_value': '2',
'old_value': '1'
},
"root['2']['field_01'][1]": {
'new_value': '5',
'old_value': '2'
},
"root['3']['field_01'][2]": {
'new_value': '9',
'old_value': '3'
},
"root['2']['field_01'][0]": {
'new_value': '4',
'old_value': '1'
},
"root['3']['field_01'][1]": {
'new_value': '8',
'old_value': '2'
},
"root['3']['field_01'][0]": {
'new_value': '7',
'old_value': '1'
},
"root['2']['field_01'][2]": {
'new_value': '6',
'old_value': '3'
}
}
}
assert expected == diff
def test_math_epsilon_when_ignore_order_in_dictionary(self):
a = {'x': 0.001}
b = {'x': 0.0011}
diff = DeepDiff(a, b, ignore_order=True)
assert {'values_changed': {"root['x']": {'new_value': 0.0011, 'old_value': 0.001}}} == diff
diff2 = DeepDiff(a, b, ignore_order=True, math_epsilon=0.01)
assert {} == diff2
def test_math_epsilon_when_ignore_order_in_list(self):
a = [0.001, 2]
b = [2, 0.0011]
diff = DeepDiff(a, b, ignore_order=True)
assert {'values_changed': {'root[0]': {'new_value': 0.0011, 'old_value': 0.001}}} == diff
diff2 = DeepDiff(a, b, ignore_order=True, math_epsilon=0.01)
assert {} == diff2
def test_math_epsilon_when_ignore_order_in_nested_list(self):
a = [{'x': 0.001}, {'y': 2.00002}]
b = [{'x': 0.0011}, {'y': 2}]
diff = DeepDiff(a, b, ignore_order=True, math_epsilon=0.01)
expected = {'values_changed': {'root[0]': {'new_value': {'x': 0.0011}, 'old_value': {'x': 0.001}}, 'root[1]': {'new_value': {'y': 2}, 'old_value': {'y': 2.00002}}}}
assert expected == diff
def test_datetime_and_ignore_order(self):
diff = DeepDiff(
[{'due_date': datetime.date(2024, 2, 1)}],
[{'due_date': datetime.date(2024, 2, 2)}],
ignore_order=True,
ignore_numeric_type_changes=True
)
assert {} != diff
class TestCompareFuncIgnoreOrder:
def test_ignore_order_with_compare_func_to_guide_comparison(self):
t1 = [
{
'id': 1,
'value': [1]
},
{
'id': 2,
'value': [7, 8, 1]
},
{
'id': 3,
'value': [7, 8],
},
]
t2 = [
{
'id': 2,
'value': [7, 8]
},
{
'id': 3,
'value': [7, 8, 1],
},
{
'id': 1,
'value': [1]
},
]
expected = {
'values_changed': {
"root[2]['id']": {
'new_value': 2,
'old_value': 3
},
"root[1]['id']": {
'new_value': 3,
'old_value': 2
}
}
}
expected_with_compare_func = {
'iterable_item_added': {
"root[2]['value'][2]": 1
},
'iterable_item_removed': {
"root[1]['value'][2]": 1
}
}
ddiff = DeepDiff(t1, t2, ignore_order=True)
assert expected == ddiff
def compare_func(x, y, level=None):
try:
return x['id'] == y['id']
except Exception:
raise CannotCompare() from None
ddiff2 = DeepDiff(t1, t2, ignore_order=True, iterable_compare_func=compare_func)
assert expected_with_compare_func == ddiff2
assert ddiff != ddiff2
ddiff3 = DeepDiff(t1, t2, ignore_order=True, iterable_compare_func=compare_func, view='tree')
assert 1 == ddiff3['iterable_item_removed'][0].t1
assert 1 == ddiff3['iterable_item_added'][0].t2
def test_ignore_order_with_compare_func_can_throw_cannot_compare(self):
t1 = [
{1},
{
'id': 2,
'value': [7, 8, 1]
},
{
'id': 3,
'value': [7, 8],
},
]
t2 = [
{
'id': 2,
'value': [7, 8]
},
{
'id': 3,
'value': [7, 8, 1],
},
{},
]
expected = {
'type_changes': {
'root[0]': {
'old_type': set,
'new_type': dict,
'old_value': {1},
'new_value': {}
}
},
'values_changed': {
"root[2]['id']": {
'new_value': 2,
'old_value': 3
},
"root[1]['id']": {
'new_value': 3,
'old_value': 2
}
}
}
expected_with_compare_func = {
'type_changes': {
'root[0]': {
'old_type': set,
'new_type': dict,
'old_value': {1},
'new_value': {}
}
},
'iterable_item_added': {
"root[2]['value'][2]": 1
},
'iterable_item_removed': {
"root[1]['value'][2]": 1
}
}
ddiff = DeepDiff(t1, t2, cutoff_intersection_for_pairs=1, cutoff_distance_for_pairs=1, ignore_order=True, threshold_to_diff_deeper=0)
assert expected == ddiff
def compare_func(x, y, level=None):
try:
return x['id'] == y['id']
except Exception:
raise CannotCompare() from None
ddiff2 = DeepDiff(t1, t2, ignore_order=True, cutoff_intersection_for_pairs=1, cutoff_distance_for_pairs=1, iterable_compare_func=compare_func, threshold_to_diff_deeper=0)
assert expected_with_compare_func == ddiff2
assert ddiff != ddiff2
def test_ignore_order_with_compare_func_with_one_each_hashes_added_hashes_removed(self):
"""
Scenario:
In this example which demonstrates the problem... We have two dictionaries containing lists for
individualNames. Each list contains exactly 2 elements. The effective change is that we are
replacing the 2nd element in the list.
NOTE: This is considered a REPLACEMENT of the second element and not an UPDATE of the element
because we are providing a custom compare_func which will determine matching elements based on
the value of the nameIdentifier field. If the custom compare_func is not used, then
deepdiff.diff will mistakenly treat the difference as being individual field updates for every
field in the second element of the list.
Intent:
Use our custom compare_func, since we have provided it.
We need to fall into self._precalculate_distance_by_custom_compare_func
To do this, we are proposing a change to deepdiff.diff line 1128:
Original:
if hashes_added and hashes_removed and self.iterable_compare_func and len(hashes_added) > 1 and len(hashes_removed) > 1:
Proposed/Updated:
if hashes_added and hashes_removed \
and self.iterable_compare_func \
and len(hashes_added) > 0 and len(hashes_removed) > 0:
NOTE: It is worth mentioning that deepdiff.diff line 1121, might also benefit by changing the length conditions
to evaluate for > 0 (rather than > 1).
"""
t1 = {
"individualNames": [
{
"firstName": "Johnathan",
"lastName": "Doe",
"prefix": "COLONEL",
"middleName": "A",
"primaryIndicator": True,
"professionalDesignation": "PHD",
"suffix": "SR",
"nameIdentifier": "00001"
},
{
"firstName": "John",
"lastName": "Doe",
"prefix": "",
"middleName": "",
"primaryIndicator": False,
"professionalDesignation": "",
"suffix": "SR",
"nameIdentifier": "00002"
}
]
}
t2 = {
"individualNames": [
{
"firstName": "Johnathan",
"lastName": "Doe",
"prefix": "COLONEL",
"middleName": "A",
"primaryIndicator": True,
"professionalDesignation": "PHD",
"suffix": "SR",
"nameIdentifier": "00001"
},
{
"firstName": "Johnny",
"lastName": "Doe",
"prefix": "",
"middleName": "A",
"primaryIndicator": False,
"professionalDesignation": "",
"suffix": "SR",
"nameIdentifier": "00003"
}
]
}
def compare_func(item1, item2, level=None):
print("*** inside compare ***")
it1_keys = item1.keys()
try:
# --- individualNames ---
if 'nameIdentifier' in it1_keys and 'lastName' in it1_keys:
match_result = item1['nameIdentifier'] == item2['nameIdentifier']
print("individualNames - matching result:", match_result)
return match_result
else:
print("Unknown list item...", "matching result:", item1 == item2)
return item1 == item2
except Exception:
raise CannotCompare() from None
# ---------------------------- End of nested function
actual_diff = DeepDiff(t1, t2, report_repetition=True,
ignore_order=True, iterable_compare_func=compare_func, cutoff_intersection_for_pairs=1)
old_invalid_diff = {
'values_changed': {"root['individualNames'][1]['firstName']": {'new_value': 'Johnny', 'old_value': 'John'},
"root['individualNames'][1]['middleName']": {'new_value': 'A', 'old_value': ''},
"root['individualNames'][1]['nameIdentifier']": {'new_value': '00003',
'old_value': '00002'}}}
new_expected_diff = {'iterable_item_added': {
"root['individualNames'][1]": {'firstName': 'Johnny', 'lastName': 'Doe', 'prefix': '', 'middleName': 'A',
'primaryIndicator': False, 'professionalDesignation': '', 'suffix': 'SR',
'nameIdentifier': '00003'}}, 'iterable_item_removed': {
"root['individualNames'][1]": {'firstName': 'John', 'lastName': 'Doe', 'prefix': '', 'middleName': '',
'primaryIndicator': False, 'professionalDesignation': '', 'suffix': 'SR',
'nameIdentifier': '00002'}}}
assert old_invalid_diff != actual_diff
assert new_expected_diff == actual_diff
class TestDynamicIgnoreOrder:
def test_ignore_order_func(self):
t1 = {
"order_matters": [
{1},
{
'id': 2,
'value': [7, 8, 1]
},
{
'id': 3,
'value': [7, 8],
},
],
"order_does_not_matter": [
{1},
{
'id': 2,
'value': [7, 8, 1]
},
{
'id': 3,
'value': [7, 8],
},
]
}
t2 = {
"order_matters": [
{
'id': 2,
'value': [7, 8]
},
{
'id': 3,
'value': [7, 8, 1],
},
{},
],
"order_does_not_matter": [
{
'id': 2,
'value': [7, 8]
},
{
'id': 3,
'value': [7, 8, 1],
},
{},
]
}
def ignore_order_func(level):
return "order_does_not_matter" in level.path()
ddiff = DeepDiff(t1, t2, cutoff_intersection_for_pairs=1, cutoff_distance_for_pairs=1, ignore_order_func=ignore_order_func, threshold_to_diff_deeper=0)
expected = {
'type_changes': {
"root['order_matters'][0]": {
'old_type': set,
'new_type': dict,
'old_value': {1},
'new_value': {'id': 2, 'value': [7, 8]}
},
"root['order_does_not_matter'][0]": {
'old_type': set,
'new_type': dict,
'old_value': {1},
'new_value': {}
}
},
'dictionary_item_removed': [
"root['order_matters'][2]['id']",
"root['order_matters'][2]['value']"
],
'values_changed': {
"root['order_matters'][1]['id']": {'new_value': 3, 'old_value': 2},
"root['order_does_not_matter'][2]['id']": {'new_value': 2, 'old_value': 3},
"root['order_does_not_matter'][1]['id']": {'new_value': 3, 'old_value': 2}
}
}
assert expected == ddiff
class TestDecodingErrorIgnoreOrder:
EXPECTED_MESSAGE1 = (
"'utf-8' codec can't decode byte 0xc3 in position 0: Can not produce a hash for root: invalid continuation byte in '('. "
"Please either pass ignore_encoding_errors=True or pass the encoding via encodings=['utf-8', '...'].")
EXPECTED_MESSAGE2 = (
"'utf-8' codec can't decode byte 0xbc in position 0: Can not produce a hash for root: invalid start byte in ' cup of flour'. "
"Please either pass ignore_encoding_errors=True or pass the encoding via encodings=['utf-8', '...'].")
@pytest.mark.parametrize('test_num, item, encodings, ignore_encoding_errors, expected_result, expected_message', [
(1, b'\xc3\x28', None, False, UnicodeDecodeError, EXPECTED_MESSAGE1),
(2, b'\xc3\x28', ['utf-8'], False, UnicodeDecodeError, EXPECTED_MESSAGE1),
(3, b'\xc3\x28', ['utf-8'], True, {'values_changed': {'root[0]': {'new_value': b'\xc3(', 'old_value': b'foo'}}}, None),
(4, b"\xbc cup of flour", ['utf-8'], False, UnicodeDecodeError, EXPECTED_MESSAGE2),
(5, b"\xbc cup of flour", ['utf-8'], True, {'values_changed': {'root[0]': {'new_value': b'\xbc cup of flour', 'old_value': b'foo'}}}, None),
(6, b"\xbc cup of flour", ['utf-8', 'latin-1'], False, {'values_changed': {'root[0]': {'new_value': b'\xbc cup of flour', 'old_value': b'foo'}}}, None),
])
@mock.patch('deepdiff.diff.logger')
def test_diff_encodings(self, mock_logger, test_num, item, encodings, ignore_encoding_errors, expected_result, expected_message):
if UnicodeDecodeError == expected_result:
with pytest.raises(expected_result) as exc_info:
DeepDiff([b'foo'], [item], encodings=encodings, ignore_encoding_errors=ignore_encoding_errors, ignore_order=True)
assert expected_message == str(exc_info.value), f"test_diff_encodings test #{test_num} failed."
else:
result = DeepDiff([b'foo'], [item], encodings=encodings, ignore_encoding_errors=ignore_encoding_errors, ignore_order=True)
assert expected_result == result, f"test_diff_encodings test #{test_num} failed."
class TestErrorMessagesWhenIgnoreOrder:
@mock.patch('deepdiff.diff.logger')
def test_error_messages_when_ignore_order(self, mock_logger):
t1 = {'x': 0, 'y': [0, 'a', 'b', 'c']}
t2 = {'x': 1, 'y': [1, 'c', 'b', 'a']}
exclude = [re.compile(r"\['x'\]"), re.compile(r"\['y'\]\[0\]")]
result = DeepDiff(t1, t2, ignore_order=True, exclude_regex_paths=exclude)
assert {} == result
assert not mock_logger.error.called
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirrors_seperman/deepdiff.git
git@gitee.com:mirrors_seperman/deepdiff.git
mirrors_seperman
deepdiff
deepdiff
master

搜索帮助