Skip to content

Commit b52efa1

Browse files
committed
finally the docs are ready
1 parent d6074cb commit b52efa1

File tree

3 files changed

+136
-7
lines changed

3 files changed

+136
-7
lines changed

deepdiff/delta.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def _get_elem_and_compare_to_old_value(self, obj, path_for_err_reporting, expect
155155
current_old_value = getattr(obj, elem)
156156
else:
157157
raise DeltaError(INVALID_ACTION_WHEN_CALLING_GET_ELEM.format(action))
158-
except (KeyError, IndexError, AttributeError, IndexError) as e:
158+
except (KeyError, IndexError, AttributeError, IndexError, TypeError) as e:
159159
current_old_value = not_found
160160
if isinstance(path_for_err_reporting, (list, tuple)):
161161
path_for_err_reporting = '.'.join([i[0] for i in path_for_err_reporting])

docs/delta_doc.rst

Lines changed: 120 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ serializer : Serializer function, default=pickle_dump
2828
:ref:`delta_serializer_label` is the function to serialize the delta content into a format that can be stored. The default is the pickle_dump function that comes with DeepDiff.
2929

3030
log_errors : Boolean, default=True
31-
Whether to log the errors or not.
31+
Whether to log the errors or not when applying the delta object.
32+
33+
raise_errors : Boolean, default=False
34+
:ref:`raise_errors_label`
35+
Whether to raise errors or not when applying a delta object.
3236

3337
mutate : Boolean, default=False.
3438
:ref:`delta_mutate_label` defines whether to mutate the original object when adding the delta to it or not.
@@ -55,8 +59,8 @@ verify_symmetry : Boolean, default=False
5559

5660
.. _delta_diff_label:
5761

58-
Diff
59-
----
62+
Diff to load in Delta
63+
---------------------
6064

6165
diff : Delta dictionary, Delta dump payload or a DeepDiff object, default=None.
6266
diff is the content to be loaded.
@@ -160,7 +164,14 @@ In fact only a few Python object types are allowed by default. The user of DeepD
160164
Delta Mutate parameter
161165
----------------------
162166

163-
Whether to mutate the original object when applying the delta or not.
167+
mutate : Boolean, default=False.
168+
delta_mutate defines whether to mutate the original object when adding the delta to it or not.
169+
Note that this parameter is not always successful in mutating. For example if your original object
170+
is an immutable type such as a frozenset or a tuple, mutation will not succeed.
171+
Hence it is recommended to keep this parameter as the default value of False unless you are sure
172+
that you do not have immutable objects. There is a small overhead of doing deepcopy on the original
173+
object when mutate=False. If performance is a concern and modifying the original object is not a big deal,
174+
set the mutate=True but always reassign the output back to the original object.
164175

165176
For example:
166177

@@ -228,17 +239,120 @@ array([ True, True, True, True])
228239

229240

230241
.. note::
231-
You can not apply a delta that was created from normal Python objects to Numpy arrays.
242+
You can apply a delta that was created from normal Python objects to Numpy arrays. But it is not recommended.
243+
244+
.. _raise_errors_label:
245+
246+
Delta Raise Errors parameter
247+
----------------------------
248+
249+
raise_errors : Boolean, default=False
250+
Whether to raise errors or not when applying a delta object.
251+
252+
>>> from deepdiff import DeepDiff, Delta
253+
>>> t1 = [1, 2, [3, 5, 6]]
254+
>>> t2 = [2, 3, [3, 6, 8]]
255+
>>> diff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
256+
>>> delta = Delta(diff, raise_errors=False)
257+
258+
Now let's apply the delta to a very different object:
259+
260+
>>> t3 = [1, 2, 3, 5]
261+
>>> t4 = t3 + delta
262+
Unable to get the item at root[2][1]
263+
264+
We get the above log message that it was unable to get the item at root[2][1]. We get the message since by default log_errors=True
265+
266+
Let's see what t4 is now:
267+
268+
>>> t4
269+
[3, 2, 3, 5]
270+
271+
So the delta was partially applied on t3.
232272

233-
>>>
273+
Now let's set the raise_errors=True
274+
275+
>>> delta2 = Delta(diff, raise_errors=True)
276+
>>>
277+
>>> t3 + delta2
278+
Unable to get the item at root[2][1]
279+
Traceback (most recent call last):
280+
current_old_value = obj[elem]
281+
TypeError: 'int' object is not subscriptable
282+
During handling of the above exception, another exception occurred:
283+
deepdiff.delta.DeltaError: Unable to get the item at root[2][1]
234284

235285

236286
.. _delta_safe_to_import_label:
237287

238288
Delta Safe To Import parameter
239289
------------------------------
240290

291+
safe_to_import : Set, default=None.
292+
safe_to_import is a set of modules that needs to be explicitly white listed to be loaded
293+
Example: {'mymodule.MyClass', 'decimal.Decimal'}
294+
Note that this set will be added to the basic set of modules that are already white listed.
295+
296+
297+
As noted in :ref:`delta_dump_safety_label` and :ref:`delta_deserializer_label`, DeepDiff's Delta takes safety very seriously and thus limits the globals that can be deserialized when importing. However on occasions that you need a specific type (class) that needs to be used in delta objects, you need to pass it to the Delta via safe_to_import parameter.
298+
299+
The set of what is already white listed can be found in deepdiff.serialization.SAFE_TO_IMPORT
300+
At the time of writing this document, this list consists of:
301+
302+
>>> from deepdiff.serialization import SAFE_TO_IMPORT
303+
>>> from pprint import pprint
304+
>>> pprint(SAFE_TO_IMPORT)
305+
{'builtins.None',
306+
'builtins.bin',
307+
'builtins.bool',
308+
'builtins.bytes',
309+
'builtins.complex',
310+
'builtins.dict',
311+
'builtins.float',
312+
'builtins.frozenset',
313+
'builtins.int',
314+
'builtins.list',
315+
'builtins.range',
316+
'builtins.set',
317+
'builtins.slice',
318+
'builtins.str',
319+
'builtins.tuple',
320+
'collections.namedtuple',
321+
'datetime.datetime',
322+
'datetime.time',
323+
'datetime.timedelta',
324+
'decimal.Decimal',
325+
'deepdiff.helper.OrderedDictPlus',
326+
'ordered_set.OrderedSet',
327+
're.Pattern'}
328+
329+
If you want to pass any other argument to safe_to_import, you will need to put the full path to the type as it appears in the sys.modules
330+
331+
For example let's say you have a package call mypackage and has a module called mymodule. If you check the sys.modules, the address to this module must be mypackage.mymodule. In order for Delta to be able to serialize this object, first of all it has to be `picklable <https://docs.python.org/3/library/pickle.html#object.__reduce__>`_. Then you can pass:
332+
333+
>>> delta = Delta(t1, t2, safe_to_import={'mypackage.mymodule'})
334+
241335
.. _delta_verify_symmetry_label:
242336

243337
Delta Verify Symmetry parameter
244338
-------------------------------
339+
340+
verify_symmetry : Boolean, default=False
341+
verify_symmetry is used to verify that the original value of items are the same as when the delta was created. Note that in order for this option to work, the delta object will need to store more data and thus the size of the object will increase. Let's say that the diff object says root[0] changed value from X to Y. If you create the delta with the default value of verify_symmetry=False, then what delta will store is root[0] = Y. And if this delta was applied to an object that has any root[0] value, it will still set the root[0] to Y. However if verify_symmetry=True, then the delta object will store also that the original value of root[0] was X and if you try to apply the delta to an object that has root[0] of any value other than X, it will notify you.
342+
343+
344+
345+
>>> from deepdiff import DeepDiff, Delta
346+
>>> t1 = [1]
347+
>>> t2 = [2]
348+
>>> t3 = [3]
349+
>>>
350+
>>> diff = DeepDiff(t1, t2)
351+
>>>
352+
>>> delta2 = Delta(diff, raise_errors=False, verify_symmetry=True)
353+
>>> t4 = delta2 + t3
354+
Expected the old value for root[0] to be 1 but it is 3. Error found on: while checking the symmetry of the delta. You have applied the delta to an object that has different values than the original object the delta was made from
355+
>>> t4
356+
[2]
357+
358+
And if you had set raise_errors=True, then it would have raised the error in addition to logging it.

tests/test_delta.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,21 @@ def test_simple_delete_elem(self):
139139
obj={}, elem=1, action=GET, path_for_err_reporting='mypath')
140140
assert "Failed to set mypath due to 1" == str(excinfo.value)
141141

142+
def test_raise_error(self):
143+
t1 = [1, 2, [3, 5, 6]]
144+
t2 = [2, 3, [3, 6, 8]]
145+
diff = DeepDiff(t1, t2, ignore_order=True, report_repetition=True)
146+
delta = Delta(diff, raise_errors=False)
147+
t3 = [1, 2, 3, 5]
148+
t4 = t3 + delta
149+
assert [3, 2, 3, 5] == t4
150+
151+
delta2 = Delta(diff, raise_errors=True)
152+
153+
with pytest.raises(DeltaError) as excinfo:
154+
t3 + delta2
155+
assert "Unable to get the item at root[2][1]" == str(excinfo.value)
156+
142157
def test_identical_delta(self):
143158
delta = Delta({})
144159

0 commit comments

Comments
 (0)