Skip to content

Commit 1dcb450

Browse files
committedJan 7, 2024
allow to define custom serialiser
1 parent e0f0e25 commit 1dcb450

File tree

3 files changed

+47
-5
lines changed

3 files changed

+47
-5
lines changed
 

‎nested_diff/__init__.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
"""Recursive diff and patch for nested structures."""
1818

19+
import pickle
20+
1921
import nested_diff.handlers
2022

2123
__all__ = ['Differ', 'Iterator', 'Patcher', 'diff', 'patch']
@@ -101,7 +103,7 @@ class Differ():
101103
default_differ = DEFAULT_HANDLER.diff
102104

103105
def __init__(self, A=True, N=True, O=True, R=True, U=True, # noqa: E501 E741 N803
104-
trimR=False, handlers=None):
106+
trimR=False, dumper=None, handlers=None):
105107
"""Initialize Differ.
106108
107109
Args:
@@ -111,6 +113,7 @@ def __init__(self, A=True, N=True, O=True, R=True, U=True, # noqa: E501 E741 N8
111113
R: Enable/disable removed items.
112114
U: Enable/disable unchanged items.
113115
trimR: When enabled will replace removed data by None.
116+
dumper: Optional objects serialiser.
114117
handlers: A list of type handlers.
115118
116119
"""
@@ -121,6 +124,8 @@ def __init__(self, A=True, N=True, O=True, R=True, U=True, # noqa: E501 E741 N8
121124
self.op_u = U
122125
self.op_trim_r = trimR
123126

127+
self.dump = dumper or pickle.dumps
128+
124129
self._differs = {}
125130

126131
for handler in TYPE_HANDLERS if handlers is None else handlers:

‎nested_diff/handlers.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
from difflib import SequenceMatcher
2020
from math import isnan
21-
from pickle import dumps
2221

2322

2423
class TypeHandler():
@@ -50,7 +49,7 @@ def diff(self, differ, a, b):
5049
diff = {}
5150
equal = True
5251

53-
if dumps(a, -1) == dumps(b, -1):
52+
if differ.dump(a) == differ.dump(b):
5453
if differ.op_u:
5554
diff['U'] = a
5655
else:
@@ -342,8 +341,8 @@ def diff(self, differ, a, b):
342341
(False, {'D': [{'R': 0}, {'N': 4, 'I': 3}, {'A': 5}]})
343342
>>>
344343
"""
345-
self.lcs.set_seq1(tuple(dumps(i, -1) for i in a))
346-
self.lcs.set_seq2(tuple(dumps(i, -1) for i in b))
344+
self.lcs.set_seq1(tuple(differ.dump(i) for i in a))
345+
self.lcs.set_seq2(tuple(differ.dump(i) for i in b))
347346

348347
diff = []
349348
equal = True

‎tests/test_diff.py

+38
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
import sys
23

34
from nested_diff import Differ, diff, handlers
45

@@ -74,6 +75,43 @@ def test_different_object_attributes():
7475
assert got == expected
7576

7677

78+
@pytest.mark.skipif(sys.version_info < (3, 8),
79+
reason='reducer_override appeared in 3.8')
80+
def test_custom_dumper():
81+
import io
82+
import pickle
83+
84+
class ClassToTestDiff:
85+
pass
86+
87+
class _Pickler(pickle.Pickler):
88+
def reducer_override(self, obj):
89+
if type(obj) is ClassToTestDiff:
90+
return str, tuple('ClassToTestDiff obj, id: ' + str(id(obj)))
91+
92+
return NotImplemented
93+
94+
def _dumper(obj):
95+
buf = io.BytesIO()
96+
pickler = _Pickler(buf)
97+
pickler.dump(obj)
98+
return buf.getvalue()
99+
100+
a = ClassToTestDiff()
101+
b = ClassToTestDiff()
102+
103+
expected = {
104+
'D': [
105+
{'U': a},
106+
{'O': a, 'N': b},
107+
{'U': 42},
108+
],
109+
}
110+
_, got = Differ(dumper=_dumper).diff([a, a, 42], [a, b, 42])
111+
112+
assert got == expected
113+
114+
77115
def test_dicts_with_same_data_but_different_sequence_u_disabled():
78116
# for example pickle.dumps({1: 1, 2: 2}) != pickle.dumps({2: 2, 1: 1})
79117
a = {1: 1, 2: 2}

0 commit comments

Comments
 (0)
Failed to load comments.