Gaudi Framework, version v23r3

Home   Generated: Thu Jun 28 2012

xmlModule.py

Go to the documentation of this file.
00001 '''
00002 Created on Jul 2, 2011
00003 
00004 @author: mplajner
00005 '''
00006 
00007 from xml.dom import minidom
00008 import Variable
00009 import logging.config
00010 import os
00011 
00012 class XMLFile():
00013     '''Takes care of XML file operations such as reading and writing.'''
00014 
00015     def __init__(self):
00016         self.xmlResult = '<?xml version="1.0" encoding="UTF-8"?><env:config xmlns:env="EnvSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="EnvSchema ./EnvSchema.xsd ">\n'
00017         self.declaredVars = []
00018         logConf = os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + '/log.conf')
00019         if not logging.getLogger('envLogger').handlers and os.path.exists(logConf):
00020             logging.config.fileConfig(logConf)
00021         self.logger = logging.getLogger('envLogger')
00022 
00023 
00024     def variable(self, path, namespace='EnvSchema' ,name=''):
00025         '''Returns list containing name of variable, action and value
00026 
00027         If no name given, returns list of lists of all variables and locals(instead of action 'local' is filled).
00028         '''
00029         if not os.path.isfile(path):
00030             raise IOError('No such file.')
00031         '''Get file'''
00032         self.doc = minidom.parse(path)
00033         if namespace == '':
00034             namespace = None
00035 
00036         '''Get all variables'''
00037         nodes = self.doc.getElementsByTagNameNS(namespace, "config")[0].childNodes
00038         variables = []
00039         nodeNum = 0
00040         for node in nodes:
00041             '''if it is an element node'''
00042             if node.nodeType == 1:
00043                 nodeNum += 1
00044                 if name != '':
00045                     if node.getAttribute('variable') != name:
00046                         continue
00047 
00048                 if node.localName == 'declare':
00049                     variables.append([node.getAttribute('variable'), 'declare', node.getAttribute('type'), node.getAttribute('local'), nodeNum])
00050                 else:
00051                     if len(node.childNodes) > 0:
00052                         value = node.childNodes[0].data
00053                     else:
00054                         value = ''
00055                     variables.append([node.getAttribute('variable'), node.localName, value, '' , nodeNum])
00056 
00057         return variables
00058 
00059 
00060     def resetWriter(self):
00061         '''resets the buffer of writer'''
00062         self.xmlResult = '<?xml version="1.0" encoding="UTF-8"?><env:config xmlns:env="EnvSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="EnvSchema ./EnvSchema.xsd ">\n'
00063         self.declaredVars = []
00064 
00065     def writeToFile(self, outputFile = ''):
00066         '''Finishes the XML input and writes XML to file.'''
00067         if(outputFile == ''):
00068             raise IOError("No output file given")
00069         self.xmlResult += '</env:config>'
00070 
00071         doc = minidom.parseString(self.xmlResult)
00072         with open(outputFile, "w") as f:
00073             f.write( doc.toxml() )
00074 
00075         f.close()
00076         return outputFile
00077 
00078     def writeVar(self, varName, action, value, type='list', local='false'):
00079         '''Writes a action to a file. Declare undeclared elements (not local List is default type).'''
00080         if action == 'declare':
00081             self.xmlResult += '<env:declare variable="'+varName+'" type="'+ type.lower() +'" local="'+(str(local)).lower()+'" />\n'
00082             self.declaredVars.append(varName)
00083             return
00084 
00085         if varName not in self.declaredVars:
00086             self.xmlResult += '<env:declare variable="'+varName+'" type="'+ type +'" local="'+(str(local)).lower()+'" />\n'
00087             self.declaredVars.append(varName)
00088         self.xmlResult += '<env:'+action+' variable="'+ varName +'">'+value+'</env:'+action+'>\n'
00089 
00090 
00091 class Report():
00092     '''This class is used to catch errors and warnings from XML file processing to allow better managing and testing.'''
00093 
00094     '''Sequence of levels: warn - warning - info - error'''
00095     def __init__(self, level = 1, reportOutput = False):
00096         self.errors = []
00097         self.warns = []
00098         self.info = []
00099         self.warnings = []
00100         self.level = level
00101 
00102         if not reportOutput:
00103             self.reportOutput = False
00104         else:
00105             self.reportOutput = open(reportOutput, 'w')
00106 
00107         logConf = os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + '/log.conf')
00108         if not logging.getLogger('envLogger').handlers and os.path.exists(logConf):
00109             logging.config.fileConfig(logConf)
00110         self.logger = logging.getLogger('envLogger')
00111 
00112     def addError(self, message, varName = '', action = '', varValue = '', procedure = ''):
00113         error = [message, varName, action, varValue, procedure]
00114         if self.level < 4:
00115             if not self.reportOutput:
00116                 print 'Error: ' + error[0]
00117             else:
00118                 self.reportOutput.write('Error: ' + error[0] + '\n')
00119         self.errors.append(error)
00120         self.logger.error(message)
00121 
00122     def addWarn(self, message, varName = '', action = '', varValue = '', procedure = ''):
00123         error = [message, varName, action, varValue, procedure]
00124         if self.level < 1:
00125             if not self.reportOutput:
00126                 print 'Warn: ' + error[0]
00127             else:
00128                 self.reportOutput.write('Warn: ' + error[0] + '\n')
00129         self.warns.append(error)
00130         self.logger.warn(message)
00131 
00132     def addWarning(self, message, varName = '', action = '', varValue = '', procedure = ''):
00133         error = [message, varName, action, varValue, procedure]
00134         if self.level < 2:
00135             if not self.reportOutput:
00136                 print 'Warning: ' + error[0]
00137             else:
00138                 self.reportOutput.write('Warning: ' + error[0] + '\n')
00139         self.warnings.append(error)
00140         self.logger.warning(message)
00141 
00142     def addInfo(self, message, varName = '', action = '', varValue = '', procedure = ''):
00143         error = [message, varName, action, varValue, procedure]
00144         if self.level < 3:
00145             if not self.reportOutput:
00146                 print 'Info: ' + error[0]
00147             else:
00148                 self.reportOutput.write('Info: ' + error[0] + '\n')
00149         self.warnings.append(error)
00150         self.logger.info(message)
00151 
00152     def clear(self):
00153         self.errors = []
00154         self.warns = []
00155         self.info = []
00156         self.warnings = []
00157 
00158     def closeFile(self):
00159         if self.reportOutput:
00160             self.reportOutput.close()
00161 
00162     def numErrors(self):
00163         return len(self.errors)
00164 
00165     def numWarnings(self):
00166         return len(self.warns) + len(self.warnings)
00167 
00168     def error(self, key):
00169         return self.errors[key]
00170 
00171     def warn(self, key):
00172         return self.warns[key]
00173 
00174 
00175 class XMLOperations():
00176     '''This class is for checking and merging XML files.
00177 
00178     Variables are stored in a double dictionary with keys of names and then actions.
00179     '''
00180     def __init__(self, separator=':', reportLevel = 0, reportOutput = False):
00181         self.posActions = ['append','prepend','set','unset', 'remove', 'remove-regexp', 'declare']
00182         self.separator = separator
00183         self.report = Report(reportLevel, reportOutput = reportOutput)
00184 
00185     def errors(self):
00186         return self.report.numErrors()
00187 
00188     def warnings(self):
00189         return self.report.numWarnings()
00190 
00191     def check(self, xmlFile):
00192         '''Runs a check through file
00193 
00194         First check is made on wrong action parameter.
00195         All valid actions are checked after and duplicated variables as well.
00196         '''
00197         #self.local = Variable.Local()
00198         self.varNames = []
00199         self.realVariables = {}
00200         self.variables = {}
00201 
00202         '''load variables and resolve references to locals and then variables'''
00203         self._loadVariables(xmlFile)
00204 
00205         '''report'''
00206         if (self.warnings() > 0 or self.errors() > 0):
00207             self.report.addInfo('Encountered '+ (str)(self.warnings()) +' warnings and ' + (str)(self.errors()) + ' errors.')
00208             return [self.warnings(), self.errors()]
00209         else:
00210             return True
00211 
00212         self.report.closeFile()
00213 
00214 
00215     def merge(self, xmlDoc1, xmlDoc2, outputFile = '', reportCheck = False):
00216         '''Merges two files together. Files are checked first during variables loading process.
00217 
00218         Second file is processed first, then the first file and after that they are merged together.
00219         '''
00220         self.output = outputFile
00221         self.file = XMLFile()
00222         self.variables = {}
00223 
00224         variables = self.file.variable(xmlDoc1)
00225         self._processVars(variables)
00226         variables = self.file.variable(xmlDoc2)
00227         self._processVars(variables)
00228 
00229         if not reportCheck:
00230             self.report.level = 5
00231 
00232         self.file.writeToFile(outputFile)
00233 
00234         self.report.addInfo('Files merged. Running check on the result.')
00235         self.check(self.output)
00236         self.report.closeFile()
00237 
00238     def _processVars(self, variables):
00239         for variable in variables:
00240             if variable[1] == 'declare':
00241                 if variable[0] in self.variables.keys():
00242                     if variable[2].lower() != self.variables[variable[0]][0]:
00243                         raise Variable.EnvironmentError(variable[0], 'redeclaration')
00244                     else:
00245                         if variable[3].lower() != self.variables[variable[0]][1]:
00246                             raise Variable.EnvironmentError(variable[0], 'redeclaration')
00247                 else:
00248                     self.file.writeVar(variable[0], 'declare', '', variable[2], variable[3])
00249                     self.variables[variable[0]] = [variable[2].lower(), variable[3].lower()]
00250             else:
00251                 self.file.writeVar(variable[0], variable[1], variable[2])
00252 
00253 
00254     def _checkVariable(self, varName, action, local, value, nodeNum):
00255         '''Tries to add to variables dict, checks for errors during process'''
00256 
00257         if varName not in self.variables:
00258             self.variables[varName] = []
00259             self.variables[varName].append(action)
00260 
00261             '''If variable is in dict, check if this is not an unset command'''
00262         elif action == 'unset':
00263             if 'unset' in self.variables[varName]:
00264                 self.report.addWarn('Multiple "unset" actions found for variable: "'+varName+'".', varName, 'multiple unset','', 'checkVariable')
00265             if not('unset' in self.variables[varName] and len(self.variables[varName]) == 1):
00266                 self.report.addError('Node '+str(nodeNum)+': "unset" action found for variable "'+varName+'" after previous command(s). Any previous commands are overridden.', varName, 'unset overwrite')
00267 
00268                 '''or set command'''
00269         elif action == 'set':
00270             if len(self.variables[varName]) == 1 and 'unset' in self.variables[varName]:
00271                 self.report.addWarn('Node '+str(nodeNum)+': "set" action found for variable "'+varName+'" after unset. Can be merged to one set only.')
00272             else:
00273                 self.report.addError('Node '+str(nodeNum)+': "set" action found for variable "'+varName+'" after previous command(s). Any previous commands are overridden.', varName, 'set overwrite')
00274                 if 'set' in self.variables[varName]:
00275                     self.report.addWarn('Multiple "set" actions found for variable: "'+varName+'".', varName, 'multiple set','', 'checkVariable')
00276 
00277         if action not in self.variables[varName]:
00278             self.variables[varName].append(action)
00279 
00280         try:
00281             if action == 'remove-regexp':
00282                 action = 'remove_regexp'
00283             eval('(self.realVariables[varName]).'+action+'(value)')
00284         except Variable.EnvironmentError as e:
00285             if e.code == 'undefined':
00286                 self.report.addWarn('Referenced variable "' +e.val+ '" is not defined.')
00287             elif e.code == 'ref2var':
00288                 self.report.addError('Reference to list from the middle of string.')
00289             elif e.code == 'redeclaration':
00290                 self.report.addError('Redeclaration of variable "'+e.val+'".')
00291             else:
00292                 self.report.addError('Unknown environment error occured.')
00293 
00294 
00295     def _loadVariables(self, fileName):
00296         '''loads XML file for input variables'''
00297         XMLfile = XMLFile()
00298         variables = XMLfile.variable(fileName)
00299         for variable in variables:
00300             undeclared = False
00301             if variable[0] == '':
00302                 raise RuntimeError('Empty variable or local name is not allowed.')
00303 
00304             if variable[0] not in self.realVariables.keys():
00305                 if variable[1] != 'declare':
00306                     self.report.addInfo('Node '+str(variable[4])+': Variable '+variable[0]+' is used before declaration. Treated as an unlocal list furthermore.')
00307                     undeclared = True
00308                     self.realVariables[variable[0]] = Variable.List(variable[0], False, report=self.report)
00309                 else:
00310                     self.varNames.append(variable[0])
00311                     if variable[2] == 'list':
00312                         self.realVariables[variable[0]] = Variable.List(variable[0], variable[3], report=self.report)
00313                     else:
00314                         self.realVariables[variable[0]] = Variable.Scalar(variable[0], variable[3], report=self.report)
00315                     if not undeclared:
00316                         continue
00317 
00318             if variable[1] not in self.posActions:
00319                 self.report.addError('Node '+str(variable[4])+': Action "'+variable[1]+'" which is not implemented found. Variable "'+variable[0]+'".', variable[0], variable[1] ,variable[2])
00320                 continue
00321 
00322             else:
00323                 if variable[1] == 'declare':
00324                     self.report.addError('Node '+str(variable[4])+': Variable '+variable[0]+' is redeclared.')
00325                 else:
00326                     self._checkVariable(variable[0], variable[1], self.realVariables[variable[0]].local, (str)(variable[2]), variable[4])
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Thu Jun 28 2012 12:29:50 for Gaudi Framework, version v23r3 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004