Skip to content

Commit

Permalink
API change: Tree view now represents non-existing objects by an insta…
Browse files Browse the repository at this point in the history
…nce of NotPresentHere instead of None. This fixes a regression when users actually add and remove None to containers.
  • Loading branch information
victorhahncastell committed Mar 4, 2017
1 parent 19d3b9b commit 8ee338b
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 16 deletions.
18 changes: 9 additions & 9 deletions deepdiff/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from collections import Mapping
from collections import Iterable

from deepdiff.helper import py3, strings, numbers, ListItemRemovedOrAdded, IndexedHash, Verbose
from deepdiff.helper import py3, strings, numbers, ListItemRemovedOrAdded, NotPresentHere, IndexedHash, Verbose
from deepdiff.model import RemapDict, ResultDict, TextResult, TreeResult, DiffLevel
from deepdiff.model import DictRelationship, AttributeRelationship # , REPORT_KEYS
from deepdiff.model import SubscriptableIterableRelationship, NonSubscriptableIterableRelationship, SetRelationship
Expand Down Expand Up @@ -791,7 +791,7 @@ def __diff_dict(self,

for key in t_keys_added:
change_level = level.branch_deeper(
None,
NotPresentHere(),
t2[key],
child_relationship_class=rel_class,
child_relationship_param=key)
Expand All @@ -800,7 +800,7 @@ def __diff_dict(self,
for key in t_keys_removed:
change_level = level.branch_deeper(
t1[key],
None,
NotPresentHere(),
child_relationship_class=rel_class,
child_relationship_param=key)
self.__report_result(item_removed_key, change_level)
Expand Down Expand Up @@ -868,14 +868,14 @@ def __diff_iterable(self, level, parents_ids=frozenset({})):
if y is ListItemRemovedOrAdded: # item removed completely
change_level = level.branch_deeper(
x,
None,
NotPresentHere(),
child_relationship_class=child_relationship_class,
child_relationship_param=i)
self.__report_result('iterable_item_removed', change_level)

elif x is ListItemRemovedOrAdded: # new item added
change_level = level.branch_deeper(
None,
NotPresentHere(),
y,
child_relationship_class=child_relationship_class,
child_relationship_param=i)
Expand Down Expand Up @@ -967,7 +967,7 @@ def __diff_iterable_with_contenthash(self, level):
for hash_value in hashes_added:
for i in t2_hashtable[hash_value].indexes:
change_level = level.branch_deeper(
None,
NotPresentHere(),
t2_hashtable[hash_value].item,
child_relationship_class=SubscriptableIterableRelationship, # TODO: that might be a lie!
child_relationship_param=i
Expand All @@ -978,7 +978,7 @@ def __diff_iterable_with_contenthash(self, level):
for i in t1_hashtable[hash_value].indexes:
change_level = level.branch_deeper(
t1_hashtable[hash_value].item,
None,
NotPresentHere(),
child_relationship_class=SubscriptableIterableRelationship, # TODO: that might be a lie!
child_relationship_param=i)
self.__report_result('iterable_item_removed', change_level)
Expand Down Expand Up @@ -1009,7 +1009,7 @@ def __diff_iterable_with_contenthash(self, level):
else:
for hash_value in hashes_added:
change_level = level.branch_deeper(
None,
NotPresentHere(),
t2_hashtable[hash_value].item,
child_relationship_class=SubscriptableIterableRelationship, # TODO: that might be a lie!
child_relationship_param=t2_hashtable[hash_value].indexes[
Expand All @@ -1019,7 +1019,7 @@ def __diff_iterable_with_contenthash(self, level):
for hash_value in hashes_removed:
change_level = level.branch_deeper(
t1_hashtable[hash_value].item,
None,
NotPresentHere(),
child_relationship_class=SubscriptableIterableRelationship, # TODO: that might be a lie!
child_relationship_param=t1_hashtable[hash_value].indexes[
0])
Expand Down
17 changes: 17 additions & 0 deletions deepdiff/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ class ListItemRemovedOrAdded(object): # pragma: no cover
pass


class NotPresentHere(object):
"""
In a change tree, this indicated that a previously existing object has been removed -- or will only be added
in the future.
We previously used None for this but this caused problem when users actually added and removed None. Srsly guys? :D
"""
def __repr__(self):
return "Not present"

def __eq__(self, other):
if isinstance(other, NotPresentHere):
return True
else:
return False



WARNING_NUM = 0


Expand Down
8 changes: 4 additions & 4 deletions deepdiff/model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

from deepdiff.helper import items, RemapDict, strings, short_repr, Verbose
from deepdiff.helper import items, RemapDict, strings, short_repr, Verbose, NotPresentHere
from ast import literal_eval
from copy import copy

Expand Down Expand Up @@ -95,7 +95,7 @@ def _from_tree_default(self, tree, report_type):
# determine change direction (added or removed)
# Report t2 (the new one) whenever possible.
# In cases where t2 doesn't exist (i.e. stuff removed), report t1.
if change.t2 is not None:
if not isinstance(change.t2, NotPresentHere):
item = change.t2
else:
item = change.t1
Expand Down Expand Up @@ -350,10 +350,10 @@ def auto_generate_child_rel(self, klass, param):
:param param: A ChildRelationship subclass-dependent parameter describing how to get from parent to child,
e.g. the key in a dict
"""
if self.down.t1 is not None:
if not isinstance(self.down.t1, NotPresentHere):
self.t1_child_rel = ChildRelationship.create(
klass=klass, parent=self.t1, child=self.down.t1, param=param)
if self.down.t2 is not None:
if not isinstance(self.down.t2, NotPresentHere):
self.t2_child_rel = ChildRelationship.create(
klass=klass, parent=self.t2, child=self.down.t2, param=param)

Expand Down
6 changes: 3 additions & 3 deletions tests/test_diff_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"""
import unittest
from deepdiff import DeepDiff
from deepdiff.helper import pypy3
from deepdiff.helper import pypy3, NotPresentHere
from deepdiff.model import DictRelationship, NonSubscriptableIterableRelationship

import logging
Expand Down Expand Up @@ -70,7 +70,7 @@ def test_item_added_extensive(self):
self.assertEqual(added1.up.t1, t1)
self.assertEqual(added1.up.t2, t2)

self.assertEqual(added1.t1, None)
self.assertEqual(added1.t1, NotPresentHere())
self.assertEqual(added1.t2, 1337)

# assert DiffLevel child relationships are correct
Expand Down Expand Up @@ -123,7 +123,7 @@ def test_non_subscriptable_iterable(self):
self.assertEqual(change.up.t2, t2)
self.assertEqual(change.report_type, 'iterable_item_removed')
self.assertEqual(change.t1, 31337)
self.assertIsNone(change.t2)
self.assertEqual(change.t2, NotPresentHere())

self.assertIsInstance(change.up.t1_child_rel,
NonSubscriptableIterableRelationship)
Expand Down

0 comments on commit 8ee338b

Please sign in to comment.