Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(141)

Unified Diff: MoinMoin/util/diff_datastruct.py

Issue 11709044: Datastructure (usually meta rev) diff function (Closed)
Patch Set: Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « MoinMoin/util/_tests/test_diff_datastruct.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: MoinMoin/util/diff_datastruct.py
===================================================================
new file mode 100644
--- /dev/null
+++ b/MoinMoin/util/diff_datastruct.py
@@ -0,0 +1,80 @@
+# Copyright: 2013 MoinMoin:AnaBalica
+# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
+
+import difflib
+from types import NoneType
+from collections import Hashable
+
+INSERT = u"insert"
+DELETE = u"delete"
+REPLACE = u"replace"
+
+
+class UndefinedType(object):
+ """ Represents a non-existing value """
+
+
+Undefined = UndefinedType()
+
+
+def diff(d1, d2, basekeys=None):
+ """ Get the diff of 2 datastructures (usually 2 meta dicts)
+
+ :param d1: old datastructure
+ :param d2: new datastructure
+ :param basekeys: list of data keys' basenames (default: None, meaning [])
+ :return: a list of tuples of the format (<change type>, <basekeys>, <value>)
+ that can be used to format a diff
+ """
+ if basekeys is None:
+ basekeys = []
+ changes = []
+
+ if isinstance(d1, UndefinedType) and isinstance(d2, (dict, list, )):
+ d1 = type(d2)()
+ elif isinstance(d2, UndefinedType) and isinstance(d1, (dict, list, )):
+ d2 = type(d1)()
+ if isinstance(d1, dict) and isinstance(d2, dict):
+ added = set(d2) - set(d1)
+ removed = set(d1) - set(d2)
+ all_ = set(d1) | set(d2)
+ for key in sorted(all_):
+ keys = basekeys + [key]
+ if key in added:
+ changes.extend(diff(Undefined, d2[key], keys))
+ elif key in removed:
+ changes.extend(diff(d1[key], Undefined, keys))
+ else:
+ changes.extend(diff(d1[key], d2[key], keys))
+ elif isinstance(d1, list) and isinstance(d2, list):
+ hashable = all(isinstance(d1, unicode) or all(
+ isinstance(v, Hashable) for v in d) for d in [d1, d2])
+ if hashable:
+ matches = difflib.SequenceMatcher(None, d1, d2)
+ for tag, d1_start, d1_end, d2_start, d2_end in matches.get_opcodes():
+ if tag == REPLACE:
+ changes.extend([(DELETE, basekeys, d1[d1_start:d1_end]),
+ (INSERT, basekeys, d2[d2_start:d2_end])])
+ elif tag == DELETE:
+ changes.append((DELETE, basekeys, d1[d1_start:d1_end]))
+ elif tag == INSERT:
+ changes.append((INSERT, basekeys, d2[d2_start:d2_end]))
+ else:
+ changes.extend(diff(unicode(d1), unicode(d2), basekeys))
+ elif any(isinstance(d, (NoneType, bool, int, long, float, unicode, )) for d in (d1, d2)):
+ if isinstance(d1, UndefinedType):
+ changes.append((INSERT, basekeys, d2))
+ elif isinstance(d2, UndefinedType):
+ changes.append((DELETE, basekeys, d1))
+ elif type(d1) == type(d2):
+ if d1 != d2:
+ changes.extend([(DELETE, basekeys, d1), (INSERT, basekeys, d2)])
+ else:
+ raise TypeError(
+ "Unsupported diff between {0} and {1} data types".format(
+ type(d1), type(d2)))
+ else:
+ raise TypeError(
+ "Unsupported diff between {0} and {1} data types".format(
+ type(d1), type(d2)))
+ return changes
« no previous file with comments | « MoinMoin/util/_tests/test_diff_datastruct.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b