Skip to content

Commit e99d178

Browse files
committed
Make it possible for from_diff to support custom types (issue #107)
1 parent 91f6124 commit e99d178

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

jsonpatch.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def from_string(cls, patch_str):
258258
return cls(patch)
259259

260260
@classmethod
261-
def from_diff(cls, src, dst, optimization=True):
261+
def from_diff(cls, src, dst, optimization=True, dumps=json.dumps):
262262
"""Creates JsonPatch instance based on comparing of two document
263263
objects. Json patch would be created for `src` argument against `dst`
264264
one.
@@ -269,6 +269,10 @@ def from_diff(cls, src, dst, optimization=True):
269269
:param dst: Data source document object.
270270
:type dst: dict
271271
272+
:param dumps: A function of one argument that produces a serialized
273+
JSON string.
274+
:type dumps: function
275+
272276
:return: :class:`JsonPatch` instance.
273277
274278
>>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
@@ -279,7 +283,7 @@ def from_diff(cls, src, dst, optimization=True):
279283
True
280284
"""
281285

282-
builder = DiffBuilder()
286+
builder = DiffBuilder(dumps)
283287
builder._compare_values('', None, src, dst)
284288
ops = list(builder.execute())
285289
return cls(ops)
@@ -637,7 +641,8 @@ def apply(self, obj):
637641

638642
class DiffBuilder(object):
639643

640-
def __init__(self):
644+
def __init__(self, dumps):
645+
self.dumps = dumps
641646
self.index_storage = [{}, {}]
642647
self.index_storage2 = [[], []]
643648
self.__root = root = []
@@ -832,7 +837,7 @@ def _compare_values(self, path, key, src, dst):
832837
# and ignore those that don't. The performance of this could be
833838
# improved by doing more direct type checks, but we'd need to be
834839
# careful to accept type changes that don't matter when JSONified.
835-
elif json.dumps(src) == json.dumps(dst):
840+
elif self.dumps(src) == self.dumps(dst):
836841
return
837842

838843
else:

tests.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from __future__ import unicode_literals
55

66
import json
7+
import decimal
78
import doctest
89
import unittest
910
import jsonpatch
@@ -445,6 +446,20 @@ def test_issue103(self):
445446
self.assertEqual(res, dst)
446447
self.assertIsInstance(res['A'], float)
447448

449+
def test_custom_types(self):
450+
def default(obj):
451+
if isinstance(obj, decimal.Decimal):
452+
return str(obj)
453+
raise TypeError('Unknown type')
454+
455+
def dumps(obj):
456+
return json.dumps(obj, default=default)
457+
458+
old = {'value': decimal.Decimal('1.0')}
459+
new = {'value': decimal.Decimal('1.00')}
460+
patch = jsonpatch.JsonPatch.from_diff(old, new, dumps=dumps)
461+
new_from_patch = jsonpatch.apply_patch(old, patch)
462+
self.assertEqual(new, new_from_patch)
448463

449464

450465
class OptimizationTests(unittest.TestCase):

0 commit comments

Comments
 (0)