[Formed-commits] r393 - in trunk: . contrib

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Tue Aug 10 17:53:42 CEST 2010


Author: torsten
Date: 2010-08-10 17:53:42 +0200 (Tue, 10 Aug 2010)
New Revision: 393

Added:
   trunk/contrib/diff_formed.py
Modified:
   trunk/ChangeLog
Log:
Added helper script to diff to given formedtree files.


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2010-08-10 09:24:01 UTC (rev 392)
+++ trunk/ChangeLog	2010-08-10 15:53:42 UTC (rev 393)
@@ -1,3 +1,8 @@
+2010-08-10  Torsten Irländer <torsten.irlaender at intevation.de>
+
+	* contrib/diff_formed.py: New helperscript to diff to given
+	  formedtrees
+
 2010-08-09	Roland Geider <roland.geider at intevation.de>
 
 	* formed/model/exprtree.py: fixed typo

Added: trunk/contrib/diff_formed.py
===================================================================
--- trunk/contrib/diff_formed.py	2010-08-10 09:24:01 UTC (rev 392)
+++ trunk/contrib/diff_formed.py	2010-08-10 15:53:42 UTC (rev 393)
@@ -0,0 +1,222 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/python
+"""\n
+Diffs to given formedtrees.  Note that currently no checks on external choice
+lists are done.  Furter checks on Repeatgroups are very simple for now.
+Warning: If a field with the same name is moved from master_tbl into a RG, it will not be
+noticed, as we do not diff strutural changes.
+
+Usage: diff_formed.py old new 
+
+Options:
+    -h / --help         Print this message and exit.
+    -e / --elements     comma-seperated list of elements to check
+    --check-attributes  Check changes in attributes (changed descriptions, target...)
+
+"""
+# 20100810 Torsten Irlaender <torsten.irlaender at intevation.de>
+#
+# This program is free software under the GNU GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+
+import sys 
+import getopt
+import logging
+
+from lxml import etree
+
+logging.basicConfig(level=logging.ERROR)
+log = logging.getLogger('diff_formed')
+
+class AttributeChangeException(Exception):
+    def __init__(self, n, c, d):
+        self.new = n
+        self.changed = c
+        self.deleted = d
+
+        msg = []
+        if self.new:
+            msg.append('New: %s' % ",".join(self.new))
+        if self.changed:
+            msg.append('Changed: %s' % ",".join(self.changed))
+        if self.deleted:
+            msg.append('Deleted: %s' % ",".join(self.deleted))
+        self.message = " | ".join(msg)
+
+class Inspector():
+
+    def __init__(self, filename_old, filename_new):
+
+        self.old_xml_doc = None
+        self.new_xml_doc = None
+        self.elements_old = {}
+        self.elements_new = {}
+        self.elements = ['choice', 'text', 'textarea', 'repeat']
+
+        # Open files and load xml
+        try:
+            f1 = None
+            f2 = None
+            log.debug('Old: %s'% filename_old)
+            f1 = open(filename_old, "r")
+            log.debug('New: %s'% filename_new)
+            f2 = open(filename_new, "r")
+            self.old_xml_doc = etree.parse(f1)
+            self.new_xml_doc = etree.parse(f2)
+        except:
+            log.exception('Error while opening file')
+        finally:
+            if f1 is not None:
+                f1.close()
+            if f2 is not None:
+                f2.close()
+
+    def perform(self, elements=None, check_attributes=False):
+        log.info('Only checking %s elements' % ",".join(elements))
+        for element in self.elements:
+            if elements is not None:
+                if element not in elements: continue 
+            self.elements_old[element] = []
+            self.elements_new[element] = []
+            for e in self.old_xml_doc.findall("//%s" % element):
+                self.elements_old[element].append(e)
+            for e in self.new_xml_doc.findall("//%s" % element):
+                self.elements_new[element].append(e)
+            self.diff_element(element, check_attributes)
+
+    def diff_element(self, element, check_attributes):
+        log.debug('Checking %s elements' % element)
+        out = []
+
+        # Search for old field in new 
+        for o in self.elements_old.get(element):
+            error = []
+            name = o.attrib.get('name')
+            found = False
+            for n in self.elements_new.get(element):
+                if name == n.attrib.get('name'):
+                    found = True
+                    try:
+                        if check_attributes:
+                            self.diff_attributes(o, n)
+                    except AttributeChangeException, e:
+                        error.append("Attributes changed for '%s': %s" % (name, e.message))
+                    if element == 'choice':
+                        error.extend(self.diff_choicelist(o, n, check_attributes))
+                    break
+            if not found:
+                error.append("Deleted")
+
+            if error:
+                out.append("Field: %s (%s)" % (name, element))
+                out.append('---')
+                out.append('Changes:')
+                for num, err in enumerate(error):
+                    out.append('%s. %s' % (num, err))
+                out.append('===')
+
+        # Searching for new fields in old
+        for o in self.elements_new.get(element):
+            error = []
+            name = o.attrib.get('name')
+            # Search for element in new
+            found = False
+            for n in self.elements_old.get(element):
+                if name == n.attrib.get('name'):
+                    found = True
+                    break
+            if not found:
+                    error.append("New")
+
+            if error:
+                out.append("Field: %s (%s)" % (name, element))
+                out.append('---')
+                out.append('Changes:')
+                for num, err in enumerate(error):
+                    out.append('%s. %s' % (num, err))
+                out.append('===')
+
+        for o in out:
+            print unicode(o).encode("utf-8")
+    
+    def diff_choicelist(self, o, n, check_attributes):
+        old = {}
+        new = {}
+        errors = []
+        for c in o.getchildren():
+            old[c.attrib.get('value')] = c
+        for c in n.getchildren():
+            new[c.attrib.get('value')] = c
+
+        for key in old.keys():
+            if new.has_key(key):
+                try:
+                    if check_attributes:
+                        self.diff_attributes(old.get(key), new.get(key))
+                except AttributeChangeException, e:
+                    errors.append("Attributes changed for '%s': %s " % (key, e.message) )
+            else:
+                errors.append("Deleted option: '%s' value: '%s'" % (old.get(key).attrib.get('description'), key))
+        for key in new.keys():
+            if not old.has_key(key):
+                errors.append("New option: '%s' value: '%s'" % (new.get(key).attrib.get('description'), key))
+
+        return errors
+
+    def diff_attributes(self, o, n):
+        ok = False
+        new = []
+        changed = []
+        deleted = []
+        for key, value in o.attrib.iteritems():
+            if n.attrib.has_key(key):
+                if n.get(key) == value:
+                    pass #Ok
+                else:
+                    changed.append(key)
+            else:
+                deleted.append(key)
+        for key, value in n.attrib.iteritems():
+            if not o.attrib.has_key(key):
+                new.append(key)
+
+        if len(new) > 0 or len(changed) > 0 or len(deleted) > 0:
+            raise AttributeChangeException(new, changed, deleted)
+
+def usage(code, msg=''):
+    print >> sys.stderr, __doc__
+    if msg:
+        print >> sys.stderr, msg
+    sys.exit(code)
+
+def main():
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], 'hvVe:',
+        ['elements=', 'check-attributes'])
+   
+    except getopt.error, msg:
+        usage(1, msg)
+    
+    elements = None
+    check_attributes = False
+    for opt, arg in opts:
+        if opt in ('-v'):
+            log.setLevel(logging.INFO)
+        if opt in ('-V'):
+            log.setLevel(logging.DEBUG)
+        if opt in ('-h', '--help'):
+            usage(0)
+        if opt in ('-e', '--elements'):
+            elements = arg.split(',')
+            log.debug('Elements: %s' % elements)
+        if opt in ('--check-attributes'):
+            check_attributes = True
+    if len(args) < 2:
+        usage(1)
+
+    ins = Inspector(args[0], args[1])
+    ins.perform(elements, check_attributes)
+
+if __name__ == '__main__':
+    main()



More information about the Formed-commits mailing list