Back to index

plone3  3.1.7
FieldDiff.py
Go to the documentation of this file.
00001 import difflib
00002 from Globals import InitializeClass
00003 from Products.CMFDiffTool.BaseDiff import BaseDiff, _getValue
00004 
00005 class FieldDiff(BaseDiff):
00006     """Text difference"""
00007 
00008     meta_type = "Field Diff"
00009 
00010     def _parseField(self, value):
00011         """Parse a field value in preparation for diffing"""
00012         # Since we only want to compare a single field, make a
00013         # one-item list out of it
00014         return [value]
00015 
00016     def getLineDiffs(self):
00017         a = self._parseField(self.oldValue)
00018         b = self._parseField(self.newValue)        
00019         return difflib.SequenceMatcher(None, a, b).get_opcodes()
00020 
00021     def testChanges(self, ob):
00022         """Test the specified object to determine if the change set will apply without errors"""
00023         value = _getValue(ob, self.field)
00024         if not self.same and value != self.oldValue:
00025             raise ValueError, ("Conflict Error during merge", self.field, value, self.oldValue)
00026         
00027     def applyChanges(self, ob):
00028         """Update the specified object with the difference"""
00029         # Simplistic update
00030         self.testChanges(ob)
00031         if not self.same:
00032             setattr(ob, self.field, self.newValue)
00033 
00034     def ndiff(self):
00035         """Return a textual diff"""
00036         r=[]
00037         a = self._parseField(self.oldValue)
00038         b = self._parseField(self.newValue)        
00039         for tag, alo, ahi, blo, bhi in self.getLineDiffs():
00040             if tag == 'replace':
00041                 plain_replace(a, alo, ahi, b, blo, bhi, r)
00042             elif tag == 'delete':
00043                 dump('-', a, alo, ahi, r)
00044             elif tag == 'insert':
00045                 dump('+', b, blo, bhi, r)
00046             elif tag == 'equal':
00047                 dump(' ', a, alo, ahi, r)
00048             else:
00049                 raise ValueError, 'unknown tag ' + `tag`
00050         return '\n'.join(r)
00051 
00052 InitializeClass(FieldDiff)
00053 
00054 def dump(tag, x, lo, hi, r):
00055     for i in xrange(lo, hi):
00056         r.append(tag +' ' + str(x[i]))
00057 
00058 def plain_replace(a, alo, ahi, b, blo, bhi, r):
00059     assert alo < ahi and blo < bhi
00060     # dump the shorter block first -- reduces the burden on short-term
00061     # memory if the blocks are of very different sizes
00062     if bhi - blo < ahi - alo:
00063         dump('+', b, blo, bhi, r)
00064         dump('-', a, alo, ahi, r)
00065     else:
00066         dump('-', a, alo, ahi, r)
00067         dump('+', b, blo, bhi, r)