# Top class: # read xml file # generate html headers # get root node # pass node to container element # Container class: # loop over elements # pass each element to appropriate subclass # Table class: # produce table # Graph class: # produce graph # Text class: # produce text #Questions: does reading cause formatting straight away? #Or do we store the content for later? Yes. from lxml import etree from StringIO import StringIO import os from core.CCP4ErrorHandling import * XRTNS = "{http://www.ccp4.ac.uk/xrt}" CCP4NS = "http://www.ccp4.ac.uk/ccp4ns" # From http://www.w3.org/QA/2002/04/valid-dtd-list.html DOCTYPE = ''' ''' #DOCTYPE = '''\n''' XHTMLNS = "{http://www.w3.org/1999/xhtml}" CURRENT_CSS_VERSION = '0.1.0' USEQTICONS = True def htmlBase(): # This is a bad i2 dependence which we are trying to avoid in the Reportparser # Needed to support use of images for Reference icon etc from core import CCP4Modules port = CCP4Modules.HTTPSERVER().port if port is None: port = 43434 htmlBase = 'http://127.0.0.1:'+str(port)+'/report_files/'+CURRENT_CSS_VERSION return htmlBase def htmlDoc(htmlBase=None,cssVersion=None,cssFile=None,jsFile=None,title=None, additionalJsFiles=None, additionalCssFiles=None, requireDataMain=None, additionalScript=None): from core import CCP4Utils import sys if cssFile is None:cssFile = 'xreport.css' if jsFile is None: jsFile = 'xreport.js' doc = etree.parse(StringIO(DOCTYPE)) html = doc.getroot() if htmlBase is None: htmlBase = '../../report_files' # Default ot latest htmlBaseVersion or get the latest minor version # for the version proposed if cssVersion is not None: cssVersion = getLastestMinorVersion(cssVersion) if htmlBase.endswith('report_files'): if cssVersion is None: cssVersion = CURRENT_CSS_VERSION #print 'htmlDoc cssVersion',cssVersion htmlBase = htmlBase + '/'+cssVersion head = etree.Element('head') if title is not None: titleEle = etree.Element('title') titleEle.text=title head.append(titleEle) allJsFiles = [jsFile] if additionalJsFiles is not None: allJsFiles += additionalJsFiles for aJsFile in allJsFiles: script = etree.Element('script') script.set('src',htmlBase+'/'+aJsFile) head.append(script) allCssFiles= [cssFile,'jspimple.css'] if additionalCssFiles is not None: allCssFiles += additionalCssFiles for aCssFile in allCssFiles: link = etree.Element('link') link.set('rel','stylesheet') link.set('type','text/css') link.set('href',htmlBase+'/'+aCssFile) head.append(link) if additionalScript is not None: script = etree.Element('script') script.text = additionalScript head.append(script) if requireDataMain is not None: script = etree.Element('script') script.set('src',htmlBase+'/require.min.js') script.set('data-main',htmlBase+'/'+requireDataMain) head.append(script) html.append(head) body = etree.Element('body') html.append(body) return doc def testPathExists(self,relPath): return True def getLastestMinorVersion(baseIn): import glob from core import CCP4Utils testSplit = baseIn.split('.') globList = glob.glob(os.path.join(CCP4Utils.getCCP4I2Dir(),'docs','report_files','*')) lastMinor = -1 for path in globList: v = os.path.split(path)[1].split('.') if v[0] == testSplit[0] and v[1] == testSplit[1]: minor = int(v[2]) lastMinor = max(lastMinor,minor) if lastMinor>=0: return testSplit[0]+'.'+testSplit[1]+'.'+str(lastMinor) else: return None def toBoolean(text): try: i = int(text) return bool(i) except: return bool(text) def getChildObject(child,xmlnode,jobInfo={},report=None): if child.tag == XRTNS+"table": obj = Table( child, xmlnode ) elif child.tag == XRTNS+"graphgroup": obj = GraphGroup( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"graph": obj = Graph( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"objectgallery": obj = ObjectGallery( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"results": obj = Results( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"fold": obj = Fold( child, xmlnode ) elif child.tag == XRTNS+"text": obj = Text( child, xmlnode ) elif child.tag == XRTNS+"status": obj = Status( child, xmlnode ) elif child.tag == XRTNS+"if": obj = IfContainer( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"ifnot": obj = IfContainer( child, xmlnode,jobInfo, False ) elif child.tag == XRTNS+"loop": obj = Loop( child, xmlnode,jobInfo ) elif child.tag == XRTNS+"copy": obj = Copy( child, xmlnode ) elif child.tag == XRTNS+"inputdata": obj = InputData( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"outputdata": obj = OutputData( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"importedfiles": obj = ImportedFiles( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"title": obj = Title( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"jobdetails": obj = JobDetails( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"picture": obj = Picture( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"launch": obj = Launch( child, xmlnode, jobInfo ) elif child.tag == XRTNS+"drilldown": obj = DrillDown( jobInfo ) elif child.tag == XRTNS+"comment": obj = None else: obj = Generic( child, xmlnode ) return obj def findChildren(obj,cls,id=None): retList = [] if not hasattr(obj,'children'): return retList for child in obj.children: #print 'findChildren',child, isinstance(child,cls),isinstance(child,Container) if isinstance(child,cls): retList.append(child) elif isinstance(child,Container): retList.extend(findChildren(child,cls,id)) return retList def applySelect(xrtnode,xmlnode,jobInfo={}): # Test all nodes in xrtnode for a 'select' attribute # Find the value in xmlnode and copy into xrtnode node.text and remove the select attribute # Currently this used to process the plotting input if xrtnode.get('select') is not None: if xmlnode is not None: values = xmlnode.xpath(xrtnode.get('select')) if len(values)>0: xrtnode.text = str(values[0].text) else: xrtnode.text = 'NO DATA AVAILABLE' del xrtnode.attrib['select'] elif xrtnode.get('database') is not None: pathList = xrtnode.get('database').split('/') while pathList.count('')>0: pathList.remove('') data = jobInfo.get(pathList[0],{}) for path in pathList[1:]: data = data.get(path,{}) if not isinstance(data,dict): if isinstance(data,list): xrtnode.text = str(data[0]) else: xrtnode.text = str(data) del xrtnode.attrib['database'] for child in xrtnode: applySelect(child,xmlnode,jobInfo) return xrtnode def saveToFile(tree,fileName): text = etree.tostring(tree, pretty_print=True, xml_declaration=True) f = open(fileName,'w') f.write(text) f.close() def xpathEval( srcexpr, xmlnode ): """Evaluate a python expression containing xpath elements deliminated by {}. The xpath expressions are evaluated and return strings which are substituted into the expression. The expression is evaluated and the result returned.""" tgtexpr = "" for i in range(srcexpr.count('{')): i0 = srcexpr.find('{') if i0 < 0: break i1 = srcexpr.find('}',i0) if i1 < 0: break tgtexpr += srcexpr[:i0] xp = srcexpr[i0+1:i1] nodes = xmlnode.xpath( xp ) tgtexpr += '"""' for node in nodes: tgtexpr += node.text tgtexpr += '"""' srcexpr = srcexpr[i1+1:] tgtexpr += srcexpr return eval( tgtexpr ) class SearchableElement(etree.ElementBase): def select(self,path): l = self.xpath(path) if len(l)>0: if '@' in path: return l[0] else: return l[0].text else: return '' def ifselect(self,path,default=False): l = self.xpath(path) if len(l)>0: return toBoolean(l[0].text) else: return default def haspath(self,path): l = self.xpath(path) if len(l)>0: return True else: return False def xpath0(self,path): l = self.xpath(path) if len(l)>0: return l[0] else: None def xpath1(self,path): l = self.xpath(path) if len(l)>0: return l[0] else: return PARSER().makeelement("dummy") def PARSER(): if I2XmlParser.insts is None: lookup = etree.ElementDefaultClassLookup(element=SearchableElement) I2XmlParser.insts = etree.XMLParser(remove_blank_text=True) I2XmlParser.insts.set_element_class_lookup(lookup) return I2XmlParser.insts class I2XmlParser: insts = None class ReportClass(object): def __init__(self, *arg, **kw): super(ReportClass,self).__init__() self.id = kw.get('id',None) self.label = kw.get('label',None) self.title = kw.get('title',None) self.class_ = kw.get('class_',None) self.style = kw.get('style',None) self.parent = kw.get('parent',None) self.outputXml = kw.get('outputXml',False) self.internalId = kw.get('internalId',None) if self.internalId is None: report = self.getReport() if report is not None: className = type(self).__name__ instanceCount = len(findChildren(report,type(self))) self.internalId = className+'_'+str(instanceCount) else: className = type(self).__name__ self.internalId = className + '_' + str(Report.elementCount) Report.elementCount += 1 def getReport(self): if hasattr(self,'parent') and self.parent is not None: return self.parent.getReport() return None def data_id(self): return 'data_'+self.internalId def data_url(self): return './tables_as_xml_files/'+self.data_id()+'.xml' # Container class - base class for reports and folds class Container(ReportClass): tag = 'container' ERROR_CODES = { 1 : { 'severity': SEVERITY_WARNING, 'description' : 'Failed to interpret xrt node tag' }, 2 : { 'description' : 'Can not create IfContainer instance without xrtnode argument (it should not be used in Python mode)' }, 3 : { 'description' : 'Can not create Loop instance without xrtnode argument (it should not be used in Python mode)' }, 4 : { 'description' : 'Unable to create RTF file - unable to import PyQt4' } } def __init__( self, xrtnode=None, xmlnode=None, jobInfo = {} , **kw ): super(Container,self).__init__(xrtnode=xrtnode, xmlnode=xmlnode, jobInfo = jobInfo, **kw) if getattr(self,'errReport',None) is None: self.errReport = CException() self.children = [] self.jobInfo = {} self.jobInfo.update(jobInfo) self.xrtnode = xrtnode self.xmlnode= xmlnode self.text = '' self.tail = '' self._scriptErrorReport = None if xrtnode is not None: self.interpretXrt(xrtnode=xrtnode) def interpretXrt(self,xrtnode=None): if xrtnode is not None: if xrtnode.tag in [ XRTNS+'remove', 'remove']: self.tag = XRTNS+'remove' else: self.tag = XHTMLNS+'root' # Initialising 'ifContainer' may skip initialising children if the tag is changed to dummy for child in xrtnode: obj = getChildObject(child,self.xmlnode,self.jobInfo) if obj is None: self.errReport.append(self.__class__,1,str(child.tag)) else: self.children.append( obj ) self.text = xrtnode.text self.tail = xrtnode.tail else: self.text = kw.get('text',None) self.tail = kw.get('tail',None) if self.text is None: self.text = '' if self.tail is None: self.tail = '' def append(self,child): if isinstance(child,str): self.children.append(Generic(xmlnode=self.xmlnode,text=child)) else: self.children.append(child) def insert(self,indx,child): if isinstance(child,str): self.children.insert(indx,Generic(xmlnode=self.xmlnode,text=child)) else: self.children.insert(indx,child) def __len__(self): return len(self.children) def addObjectOfClass(self, classOfObject, xrtnode=None,xmlnode=None,jobInfo=None,**kw): if xrtnode is None: xrtnode=self.xrtnode if xmlnode is None: xmlnode = self.xmlnode if jobInfo is None: jobInfo = self.jobInfo obj = classOfObject(xrtnode=xrtnode, xmlnode = xmlnode, jobInfo = jobInfo, parent=self, **kw) self.children.append(obj) return obj def addText(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Text, xrtnode, xmlnode, jobInfo, **kw) def addPre(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Pre, xrtnode, xmlnode, jobInfo, **kw) def addGraph(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Graph, xrtnode, xmlnode, jobInfo, **kw) def addProgress(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Progress, xrtnode, xmlnode, jobInfo, **kw) def addFlotGraph(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(FlotGraph, xrtnode, xmlnode, jobInfo, **kw) def addGraphGroup(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(GraphGroup, xrtnode, xmlnode, jobInfo, **kw) def addFlotGraphGroup(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(FlotGraphGroup, xrtnode, xmlnode, jobInfo, **kw) def addDrawnDiv(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(DrawnDiv, xrtnode, xmlnode, jobInfo, **kw) def addObjectGallery(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(ObjectGallery, xrtnode, xmlnode, jobInfo, **kw) def addGraphLineChooser(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(GraphLineChooser, xrtnode, xmlnode, jobInfo, **kw) def addPictureGroup(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(PictureGroup, xrtnode, xmlnode, jobInfo, **kw) def addDiv(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Div, xrtnode, xmlnode, jobInfo, **kw) def addTable(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Table, xrtnode, xmlnode, jobInfo, **kw) def addPicture(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Picture, xrtnode, xmlnode, jobInfo, **kw) def addTitle(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Title, xrtnode, xmlnode, jobInfo, **kw) def addLaunch(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Launch, xrtnode, xmlnode, jobInfo, **kw) def addDownload(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Download, xrtnode, xmlnode, jobInfo, **kw) def addResults(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Results, xrtnode, xmlnode, jobInfo, **kw) def addFold(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Fold, xrtnode, xmlnode, jobInfo, **kw) def addCopy(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Copy, xrtnode, xmlnode, jobInfo, **kw) def addHelp(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): return self.addObjectOfClass(Help, xrtnode, xmlnode, jobInfo, **kw) def getPictures(self): rv = [] for child in self.children: if isinstance(child,Picture): rv.append(child.picDefFile.__str__()) elif isinstance(child,(Container,Loop)): rv.extend(child.getPictures()) #print 'Container.getPictures',rv return rv def as_html( self ): s = "" if self.text: s += self.text for child in self.children: s += child.as_html() + "\n" if self.tail: s += self.tail return s def as_etree(self): # Test if marked for removal or tag is not str (probably comment) if self.tag == XRTNS+'remove' or not isinstance(self.tag,str): return None root = etree.Element(self.tag) root.text = self.text root.tail = self.tail if self.id is not None: root.set('id',self.id) if self.class_ is not None: root.set('class',self.class_) if self.style is not None: root.set('style',self.style) for child in self.children: #print 'Container.as_etree',child,type(child) try: tree = child.as_etree() #print 'Container.as_etree',child,tree,tree.tag,len(tree) if tree is not None: if str(tree.tag) in ['root',XHTMLNS+'root']: #print 'Container.as_etree add root',len(root),root. root.extend(tree) elif tree.tag == XRTNS+'dummy': # Dont output tags around this (always Text?) element # Need to put the text content in either self.text or preceeding siblings tail if len(root)>=1: root[-1].tail += child.getText() else: root.text+= child.getText() else: root.append(tree) except: root.append(etree.fromstring(child)) return root def graph_data_as_rtf(self,fileName=None): try: from PyQt4 import QtGui,QtCore except: raise CException(self.__class__,4,fileName) document = QtGui.QTextDocument() graphList = findChildren(self,Graph) for graph in graphList: table = graph.data_as_rtf(document=document) writer = QtGui.QTextDocumentWriter() writer.setFormat(QtCore.QByteArray('ODF')) writer.setFileName(fileName) writer.write(document) def errorReport(self): err = CException() err.extend(self.errReport) for child in self.children: if getattr(child,'errReport',None) is not None: err.extend(child.errorReport()) return err def loadXmlFile(self,fileName): from core import CCP4Utils text = CCP4Utils.readFile(fileName) ele = etree.fromstring(text,PARSER()) return ele def scriptErrorReport(self): from core import CCP4ErrorHandling,CCP4File if self._scriptErrorReport is None: self._scriptErrorReport = CCP4ErrorHandling.CErrorReport() root = self.jobInfo.get('fileroot',None) print 'scriptErrorReport root',root if root is not None: filePath = os.path.join(root,'diagnostic.xml') if os.path.exists(filePath): i2xml = CCP4File.CI2XmlDataFile(filePath) self._scriptErrorReport.setEtree(i2xml.getBodyEtree()) return self._scriptErrorReport # If class - container for conditional content class IfContainer( Container ): def __init__( self, xrtnode=None, xmlnode=None , jobInfo={}, target = True, **kw ): if xrtnode is None: raise CException(self.__class__,2) #print 'ReportParser IfContainer',xmlnode.xpath( xrtnode.get( "select" ) ),type(xmlnode.xpath( xrtnode.get( "select" ) )) if xmlnode is not None and len(xmlnode.xpath( xrtnode.get( "select" ) )) != 1: # Failed to find the 'if' parameter in the output so do not put anything in report Container.__init__ ( self, etree.Element(XRTNS+"remove"), xmlnode, jobInfo, **kw ) return try: value = toBoolean(xmlnode.xpath( xrtnode.get( "select" ) )[0].text) except: Container.__init__ ( self, etree.Element(XRTNS+"remove"), xmlnode, jobInfo , **kw ) return #print 'ReportParser IfContainer from program output:',value,'target:',target if value == target: Container.__init__ ( self, xrtnode, xmlnode, jobInfo ) else: Container.__init__ ( self, etree.Element(XRTNS+"remove"), xmlnode, jobInfo, **kw ) class Loop(ReportClass): def __init__( self, xrtnode=None, xmlnode=None, jobInfo={}, **kw): super(Loop,self).__init__(xrtnode=xrtnode, xmlnode=xmlnode, jobInfo=jobInfo, **kw) if xrtnode is None: raise CException(self.__class__,3) import copy self.children = [] self.text = xrtnode.text self.tail = xrtnode.tail selectStr = xrtnode.get('select') #print 'Loop.init',selectStr if selectStr is not None and xmlnode is not None: selectedNodes = xmlnode.xpath( selectStr ) #print 'Loop.init selectedNodes',selectedNodes for node in selectedNodes: for child in xrtnode: childCopy = copy.deepcopy(child) obj = getChildObject(childCopy,node,jobInfo) if obj is not None: self.children.append( obj ) #self.children[-1].text = xrtnode.text #self.children[-1].tail = xrtnode.tail def as_etree(self): root = etree.Element('root') root.text = self.text root.tail = self.tail if self.id is not None: root.set('id',self.id) if self.class_ is not None: root.set('class',self.class_) for child in self.children: tree = child.as_etree() if str(tree.tag) in ['root',XHTMLNS+'root']: root.extend(tree) elif tree.tag == XRTNS+'dummy': # Dont output tags around this (always Text?) element # Need to put the text content in either self.text or preceeding siblings tail if len(root)>=1: root[-1].tail += child.getText() else: root.text+= child.getText() else: root.append(tree) return root def getPictures(self): rv = [] for child in self.children: if isinstance(child,Picture): rv.append(child.picDefFile.__str__()) elif isinstance(child,(Container,Loop)): rv.extend(child.getPictures()) #print 'Loop.getPictures',rv return rv # Report class - container for ccp4 html report class Report( Container ): TASKNAME = '' TASKVERSION = '0.0.0' RUNNING = False WATCHED_FILE = None FAILED = False USEPROGRAMXML = True SEPARATEDATA=False elementCount = 1 ERROR_CODES = { 0 : { 'severity' : SEVERITY_OK, 'description' : 'OK' }, 101 : {'description' : 'Import xrt file does not exist'}, 102 : {'description' : 'Failed to read import xrt file'}, 103 : {'description' : 'Failed to find insert xrt element in program file'}, 104 : {'description' : 'Failed to find insert element in imported xrt file'}, 105 : {'description' : 'Failed loading job info for jobId'}, 106 : {'description' : 'Failed loading XML file'}, 107 : {'description' : 'Failed creating csv file'}, 108 : {'description' : 'Failed creating xml data file'}, } def __init__(self, xrtnode=None, xmlnode=None, jobInfo = {}, **kw ): Container.__init__(self, xrtnode=xrtnode, xmlnode=xmlnode, jobInfo=jobInfo, **kw) self.tag = 'report' self.pictureQueue = None self.standardise = kw.get('standardise',False) self.jobNumber = kw.get('jobNumber',None) self.jobStatus = kw.get('jobStatus',None) self.cssFile = kw.get('cssFile',None) self.jsFile = kw.get('jsFile',None) self.additionalCssFiles = kw.get('additionalCssFiles',None) self.additionalJsFiles = kw.get('additionalJsFiles',None) self.additionalScript = kw.get('additionalScript',None) self.requireDataMain = kw.get('requireDataMain','mosflmApp') self.referenceList = [] self.htmlBase = kw.get('htmlBase',None) self.cssVersion = kw.get('cssVersion',None) if kw.has_key('jobId'): try: from report import CCP4ReportGenerator jobInfo = CCP4ReportGenerator.getReportJobInfo(kw['jobId']) self.jobInfo.update(jobInfo) except: self.errReport.append(self.__class__,105,kw['jobId']) return if xmlnode is None and kw.has_key('xmlFile'): try: text = open( kw['xmlFile'] ).read() self.xmlnode = etree.fromstring( text, PARSER() ) except Exception as e: self.errReport.append(self.__class__,106, 'Reading file: '+str(kw['xmlFile'])+'\n'+str(e)) return if xrtnode is not None: xrtnode = self.removeComments(xrtnode) if xmlnode is not None: xrtnode = self.makeInserts(xrtnode, xmlnode) if self.standardise and str(xrtnode.tag) == 'report': xrtnode = self.standardiseXrtReport(xrtnode) Container.interpretXrt(self,xrtnode=xrtnode) #self._makeMgPicture = None def removeComments(self,xrtnode): for ele in xrtnode.iterfind('.//'+XRTNS+'comment'): #print 'Removing comment',ele.text ele.getparent().remove(ele) return xrtnode def makeInserts(self,xrtnode, xmlnode): for insertEle in xrtnode.iterfind('.//'+XRTNS+'insertXrt'): ele = None if insertEle.get('filename') is not None: from core import CCP4Utils fileName = insertEle.get('filename') if fileName[0:8] == '$CCP4I2/': fileName = os.path.join(CCP4Utils.getCCP4I2Dir(),fileName[8:]) #print 'Report.makeInserts fileName',fileName if not os.path.exists(fileName): self.errReport.append(self.__class__,101,fileName) else: try: ele = etree.fromstring( open(fileName ).read(), PARSER() ) except: self.errReport.append(self.__class__,102,fileName) else: # Look for sub-element of the inserted file if insertEle.get('select') is not None: path = insertEle.get('select') ele0 = ele.find(path) if ele0 is None: self.errReport.append(self.__class__,104,'file: '+str(fileName)+' xpath: '+str(path)) else: ele = ele0 # This is looking in the program output for xrt - dubious. elif insertEle.get('select') is not None: path = insertEle.get('select') ele = xmlnode.find(path) if ele is None: self.errReport.append(self.__class__,103,path) if ele is not None: for child in ele.getchildren(): insertEle.addnext(child) insertEle.getparent().remove(insertEle) #print etree.tostring(xrtnode,pretty_print=True) return xrtnode def containsPictures(self): #print 'Report.containsPictures',self._makeMgPicture #if self._makeMgPicture is None or len(self._makeMgPicture.pictureQueue)==0: if self.pictureQueue is None: self.pictureQueue = self.getPictures() if len(self.pictureQueue) == 0: return False else: return True def makeMgPicture(self): if self._makeMgPicture is None: import CCP4MakeMgPicture self._makeMgPicture = CCP4MakeMgPicture.CMakeMgPicture(jobInfo=self.jobInfo) return self._makeMgPicture def standardisePythonReport(self): self.children.insert(0,Title(jobInfo = self.jobInfo)) for cls in (InputData,OutputData,JobDetails): add = True for child in self.children: if isinstance(child,cls): add = False break if add: self.children.append(cls(jobInfo=self.jobInfo)) # If there is not list of references try adding the default for the task if len(self.referenceList)==0: self.addTaskReferences() if len(self.referenceList)>0: fold = Fold(label='Bibliographic references',brief='Biblio',jobInfo=self.jobInfo) fold.children.extend(self.referenceList) if isinstance(self.children[-1],JobDetails): self.children.insert(-1,fold) else: self.children.append(fold) def standardiseXrtReport(self,report): #if report.find(XRTNS+'title') is None: # titleEle = etree.Element(XRTNS+'title') # report.insert(0,titleEle) if report.find(XRTNS+'inputdata') is None: inEle = etree.Element(XRTNS+'inputdata') report.append(inEle) if report.find(XRTNS+'outputdata') is None: outEle = etree.Element(XRTNS+'outputdata') report.append(outEle) #if report.find(XRTNS+'drilldown') is None: # jobEle = etree.Element(XRTNS+'drilldown') # report.append(jobEle) if report.find(XRTNS+'jobdetails') is None: jobEle = etree.Element(XRTNS+'jobdetails') report.append(jobEle) return report def as_html_file(self,fileName,pretty_print=True,htmlBase=None,cssVersion=None): from core import CCP4Utils text = self.as_html(htmlBase=htmlBase,cssVersion=cssVersion) if pretty_print: try: from bs4 import BeautifulSoup soup=BeautifulSoup(text) prettyHTML=soup.prettify() #print 'PRINTING BeautifulSoup' CCP4Utils.saveFile(fileName=fileName,text=prettyHTML) except: CCP4Utils.saveFile(fileName=fileName,text=text) else: CCP4Utils.saveFile(fileName=fileName,text=text) def as_html(self, htmlBase=None,cssVersion=None): tree = self.as_etree(htmlBase,cssVersion=cssVersion) text = etree.tostring(tree, pretty_print=True) return text def as_etree(self, htmlBase=None,cssVersion=None): if self.standardise: self.standardisePythonReport() if cssVersion is None: cssVersion = self.cssVersion if htmlBase is not None: doc = htmlDoc(htmlBase=htmlBase,cssFile=self.cssFile,jsFile=self.jsFile,cssVersion=cssVersion,title=self.getTitle(),additionalJsFiles=self.additionalJsFiles, additionalCssFiles=self.additionalCssFiles, requireDataMain=self.requireDataMain,additionalScript=self.additionalScript) elif self.jobNumber is not None: nSub = self.jobNumber.count('.') htmlBase = '../..' for n in range(nSub): htmlBase = htmlBase + '/..' htmlBase = htmlBase + '/report_files' doc = htmlDoc(htmlBase=htmlBase,cssFile=self.cssFile,jsFile=self.jsFile,cssVersion=cssVersion,title=self.getTitle(),additionalJsFiles=self.additionalJsFiles, additionalCssFiles=self.additionalCssFiles, requireDataMain=self.requireDataMain,additionalScript=self.additionalScript) else: doc = htmlDoc(cssFile=self.cssFile,jsFile=self.jsFile,cssVersion=cssVersion,title=self.getTitle(), additionalJsFiles=self.additionalJsFiles, additionalCssFiles=self.additionalCssFiles, requireDataMain=self.requireDataMain, additionalScript=self.additionalScript) body = doc.getroot().xpath('./body')[0] #print 'Report.as_etree',self,etree.tostring(Container.as_etree(self),pretty_print=True) tree = Container.as_etree(self) body.text = tree.text body.tail = tree.tail body.extend(tree) if self.style is not None: body.set('style',self.style) if self.standardise: self.addLinks(body) return doc def addLinks(self,body): #links = etree.Element('p') #links.set('class','links') eleTree = etree.parse(StringIO('')) links = eleTree.getroot() links.set('id','links') links.set('type','CLinksInReport') links.set('style','display:none;') linkList = [ ['inputData','Input data'],['outputData','Output data'] ] folds = findChildren(self,Fold) for item in folds: linkList.append([item.label,item.label]) drillDownList = findChildren(self,DrillDown) if len(drillDownList)>0: linkList.append(['Show Sub-Jobs','Show Sub-Jobs']) linkList.append(['jobDetails','Job details']) #print 'addLinks linkList',linkList for href,label in linkList: anchor = etree.Element('a') anchor.set('href','#'+href) anchor.text = label links.append(anchor) title = body.find("h4") #print 'addLinks title',title if title is None: body.insert(0,links) else: body.insert(2,links) def getTitle(self): if self.jobInfo.has_key('jobnumber') and self.jobInfo.has_key('tasktitle'): title = self.jobInfo['jobnumber']+' '+self.jobInfo['tasktitle'] else: title = 'CCP4 Report' def makeCSVFiles(self,directory=None): from core import CCP4Utils if directory is None: directory = os.getcwd() graphList = findChildren(self,Graph) flotGraphList = findChildren(self,FlotGraph) tableList = findChildren(self,Table) for name,objList in [ ['graph',graphList],['table',tableList],['flotgraph',flotGraphList]]: for obj in objList: if getattr(obj,'outputCsv',True): title = str(obj.id) if obj.title is not None: title = title +'_'+CCP4Utils.safeOneWord(obj.title) fileName = os.path.normpath(os.path.join(directory,title+'.csv')) #print 'Report.makeCSVFiles fileName',fileName self.errReport.extend(obj.data_as_csv(fileName=fileName)) def makeXMLFiles(self,directory=None): from core import CCP4Utils if directory is None: directory = os.getcwd() for ofClass in [Table, FlotGraph, FlotGraphGroup, Progress, Text, Pre]: objList = findChildren(self, ofClass) for obj in objList: if getattr(obj,'outputXml',False): if ofClass == FlotGraphGroup: fileRoot = os.path.normpath(os.path.join(directory,obj.data_url())) self.errReport.extend(obj.data_as_xmls(fileRoot=fileRoot)) else: fileName = os.path.normpath(os.path.join(directory,obj.data_url())) #print 'Report.makeXMLFiles fileName',fileName self.errReport.extend(obj.data_as_xml(fileName=fileName)) def clearXMLFiles(self,directory=None): from core import CCP4Utils if directory is None: directory = os.getcwd() for ofClass in [Table, FlotGraph, Progress, Pre]: objList = findChildren(self, ofClass) for obj in objList: if getattr(obj,'outputXml',False): fileName = os.path.normpath(os.path.join(directory,obj.data_url())) os.remove(fileName) #print 'Report.makeXMLFiles fileName',fileName def addReference(self,xrtnode=None,xmlnode=None,jobInfo=None,**kw): if xmlnode is None: xmlnode = self.xmlnode if jobInfo is None: jobInfo = self.jobInfo if not hasattr(self,'referenceList'): self.referenceList = [ ReferenceGroup() ] obj = Reference(xrtnode=xrtnode, xmlnode = xmlnode, jobInfo = jobInfo, **kw) self.referenceList[-1].append(obj) return obj def addTaskReferences(self,taskName=None,drillDown=True): if taskName is None: taskName = self.TASKNAME if not hasattr(self,'referenceList'): self.referenceList = [ ] from core import CCP4TaskManager helpFileList = CCP4TaskManager.TASKMANAGER().searchReferenceFile(name=taskName,drillDown=drillDown) #print 'Report.addTaskReferences',helpFileList for helpFile in helpFileList: self.referenceList.append(ReferenceGroup()) self.referenceList[-1].loadFromMedLine(fileName=helpFile) def getReport(self): return self def newPageOrNewData(self): # MN This function returns the string "NEWPAGE" if it has generated new # HTML code, or "NEWDATA" if it has generated only new data to be supplied to existing # widgets on the GUI. Code that uses this call will decide whether to force an HTML reload # or simply cause a loaded report to reload its data. if not self.SEPARATEDATA: #print 'Newpage because not SEPARATEDATA' return "NEWPAGE" if not hasattr(self, 'jobStatus'): #print 'Newpage because not has jobStatus' return "NEWPAGE" if not hasattr(self.jobStatus, 'lower'): #print 'Newpage because not lowerable jobStatus' return "NEWPAGE" if not self.jobStatus.lower()=='running': #print 'Newpage because not running' return "NEWPAGE" #Here we look to see if data files for *ALL* report element for which data are separated #already have data files...this would imply that we should return newdata try: flotGraphs = findChildren(self, FlotGraph) #flotGraphGroups = findChildren(self, FlotGraphGroup) tables = findChildren(self, Table) progresses = findChildren(self, Progress) pres = findChildren(self, Pre) #texts = findChildren(self, Text) xmlSeparableItems = progresses+flotGraphs+tables+pres#+texts result="NEWDATA" import os for xmlSeparableItem in xmlSeparableItems: if not xmlSeparableItem.outputXml: #print 'Newpage because ',xmlSeparableItem,'is not outputXML' result="NEWPAGE" continue xmlPath = os.path.normpath(os.path.join(self.jobInfo['fileroot'],xmlSeparableItem.data_url())) if not os.path.isfile(xmlPath): #print 'Newpage because ',xmlPath,'does not exist' result="NEWPAGE" continue return result except: return "NEWPAGE" class Results(Container): def as_etree(self, htmlBase=None): root = etree.Element('root') anchor = etree.Element('a') anchor.set('name','results') root.append(anchor) head = etree.Element('h5') if self.id is not None: head.set('id',self.id) if self.class_ is not None: head.set('class',self.class_) else: head.set('class','section') #Substituted .style for .class_ below....looked like a typo MN #if self.style is not None: head.set('style',self.class_) if self.style is not None: head.set('style',self.style) head.text = 'Results' root.append(head) root.extend(Container.as_etree(self)) return root class DrillDown(ReportClass): def __init__(self,jobInfo,**kw): super(DrillDown,self).__init__(**kw) self.jobInfo = jobInfo #print 'DrillDown jobInfo',jobInfo def as_etree(self): # Check that ther are some sub-directories # Beware fileroot has fragment of file name on end of directory path jobDir = self.jobInfo.get('fileroot',None) if jobDir is not None: jobDir = os.path.split(jobDir)[0] subJobs = self.getSubJobs(jobDir) #print 'DrillDown.as_etree subJobs',subJobs if len(subJobs)==0: return etree.Element('root') # make a folder ''' fold = foldTitleLine('Show Sub-Jobs') if fold.tag == 'root': root.extend(fold) else: root.append(fold) div = root.find('div') ''' div = etree.Element('div') div.set('class','sub-job-list') if self.id is not None: div.set('id',self.id) if self.class_ is not None: div.set('class',self.class_) h4 = etree.Element('h4') h4.text = 'Sub-Jobs' div.append(h4) try: from core import CCP4TaskManager ifi2 = True except: ifi2 = False for job in subJobs: # jobs is list of subJobNumber,jobId,pluginName,reportFile,subJobs text = str(job[0])+': ' if job[1] is not None: if ifi2: text = text + CCP4TaskManager.TASKMANAGER().getTitle(job[2]) else: text = text + job[2] fold = foldLinkLine(text,job[3],'jobId'+str(job[1])) div.extend(fold) ''' # Simple link mode div = root.find('div') a = etree.Element('a') a.set('href',job[3]) a.set('id','jobId'+str(job[1])) a.text= text div.append(a) div.append(etree.Element('br')) ''' ''' # Alternative 'button' mode obj = etree.Element('object') obj.set('class','qt_object_subjob') obj.set('type','x-ccp4-widget/CSubJobButton') #obj.set('id',self.id+'_'+str(job[0])) div.append(obj) for key,value in [['label',text],['jobId',str(self.jobInfo.get('jobid',None))],['subJobNumber',job[0]],['link',job[2]]: p = etree.Element('param') p.set('name',key) p.set('value',value) obj.append(p) ''' return div def getSubJobs(self,jobDir): import glob from core import CCP4File if jobDir is None: return [] globDirs = glob.glob(os.path.join(jobDir,'job_*')) def sortSubJobsKey(inp): return int(inp.split('_')[-1]) sortedDirs = sorted(globDirs,key=sortSubJobsKey) retSubJobs = [] for path in sortedDirs: subJobs = self.getSubJobs(path) parsFile = glob.glob(os.path.join(path,'*.params.xml')) if len(parsFile)>0: # Get taskName from file f = CCP4File.CI2XmlDataFile(fullPath=parsFile[0]) pluginName = str(f.header.get('pluginName')) jobId = int(f.header.get('jobId')) else: pluginName = None jobId = None ''' reportFile = glob.glob(os.path.join(path,'*.report.html')) if len(reportFile) == 0: reportFile = None else: reportFile = reportFile[0] ''' reportFile = parsFile[0][0:-10]+'report.html' retSubJobs.append([os.path.split(path)[-1].split('_')[-1],jobId,pluginName,reportFile,subJobs]) return retSubJobs def foldTitleLine(label, initiallyOpen, brief = None): root = etree.Element('root') anchor = etree.Element('a') anchor.set('name',label) root.append(anchor) span = etree.Element('span') span.set('class','folder') if brief is not None: span.set('title',brief) span.set('onclick',"toggleview(this)") if initiallyOpen: span.text = u"\u25BC"+ " "+label else: span.text = u"\u25B6"+ " "+label root.append(span) div = etree.Element('div') if initiallyOpen: div.set('class','hidesection displayed') else: div.set('class','hidesection hidden') root.append(div) return root def foldLinkLine(label,href,id): ''' root = etree.Element('root') anchor = etree.Element('a') anchor.set('name',label) root.append(anchor) span = etree.Element('span') span.set('class','folder_link') a = etree.Element('a') a.set('href',href) a.set('id',id) a.text = 'Show '+label span.append(a) root.append(span) return root ''' ''' Aiming for.. Show 1: Model building - Buccaneer
''' root = etree.Element('root') span = etree.Element('span') span.set('class','folder') span.set('onclick',"togglesubjob(this)") span.text = 'Show '+label root.append(span) div = etree.Element('div') div.set('id',id) div.set('class','subjob') root.append(div) return root # Fold class - container for a hidden report within a report class Fold( Container ): def __init__( self, xrtnode=None, xmlnode=None, jobInfo = {} , **kw): super(Fold,self).__init__(xrtnode=xrtnode,xmlnode=xmlnode,jobInfo=jobInfo, **kw ) if xrtnode is not None: self.label = xrtnode.get('label','Show details') self.brief = xrtnode.get('brief',None) else: self.label = kw.get('label','Fold') self.brief = kw.get('brief',None) self.initiallyOpen = kw.get('initiallyOpen',False) def as_html( self ): return """Show details
\n{0}
\n""".format(Container.as_html(self)) def as_etree(self): root = foldTitleLine(self.label, self.initiallyOpen, self.brief) root.find('div').extend(Container.as_etree(self)) return root class Text(ReportClass): tag='span' def __init__( self, xrtnode=None, xmlnode=None, jobInfo = {}, **kw ): super(Text,self).__init__(xrtnode=xrtnode, xmlnode=xmlnode, jobInfo=jobInfo, **kw) self.text = "" self.tail = "" #print 'Text.init',xrtnode.get( "if" ),xrtnode.get( "select" ),xrtnode.text,xrtnode.tail if xrtnode is not None and len(xrtnode)>0: if xrtnode.get( "if" ) is not None and (xmlnode is None or not bool(xmlnode.xpath( xrtnode.get("if")))): return if xrtnode.text: self.text += xrtnode.text #print 'Text.init self.text',self.text if xrtnode.tail: self.tail += xrtnode.tail if xrtnode.get( "select" ) and xmlnode is not None: nodes = xmlnode.xpath( xrtnode.get( "select" ) ) for node in nodes: self.text += node.text elif kw.get('text',None) is not None: self.text += kw['text'] #print 'Text.__init__',text elif kw.get('select',None) is not None and xmlnode is not None: nodes = xmlnode.xpath( kw['select'] ) for node in nodes: self.text += node.text def as_html( self ): return self.text def as_etree(self): # Tag as dummy so parent container will strip the tags if self.outputXml: return etree.fromstring('') else: return self.data_as_xml() def data_as_xml(self, fileName=None): # Tag as dummy so parent container will strip the tags root = etree.Element(self.tag) if self.style is not None: root.set('style',self.style) if self.class_ is not None: root.set('class',self.class_) try: if self.text is not None: root.text = self.text except: print 'Failed creating XML for:',self.text try: if self.tail is not None: root.tail = self.tail except: print 'Failed creating XML for:',self.tail #print 'Text.as_etree',root.text,root.tail if fileName is not None: with open(fileName,'w') as outputFile: outputFile.write(etree.tostring(root, pretty_print=True)) return root def getText(self): if len(self.text)==0 or len(self.tail)==0 or self.text[-1]==' ' or self.tail[0]==' ': return self.text + self.tail else: return self.text + ' ' + self.tail class Pre(Text): tag='pre' # Status class class Status(Container): def as_html( self ): return "

"+self.text+"

" def as_etree(self): div = etree.Element('div') if self.id is not None: div.set('id',self.id) if self.class_ is not None: div.set('class',self.class_) #div.set('width','100%') if self.style is not None: div.set('style',self.style) else: div.set('style','background-color:#80FF80;') div.extend(self.text) return div # Copy class class Copy(ReportClass): def __init__( self, xrtnode=None, xmlnode=None, **kw ): super(Copy,self).__init__(xrtnode=xrtnode, xmlnode=xmlnode, **kw) self.text = "" self.root = etree.Element('root') if xmlnode is not None: if xrtnode is not None: self.root.extend(xmlnode.xpath( xrtnode.get( "select" ) )) elif kw.get('select',False): self.root.extend(xmlnode.xpath(kw.get('select',False))) #print 'Copy __init__ root',self.root.tag def as_html( self ): text = '' for node in self.root.iterChildren(): text += etree.tostring( node ) return text def as_etree(self): return self.root class Generic(ReportClass): ERROR_CODES = { 1 : { 'description' : 'Can not interpret text' }, 2 : { 'description' : 'Error substituting values into generic item' } } def __init__(self,xrtnode=None,xmlnode=None,jobInfo={},text=None,defaultTag='p',**kw): self.id = kw.get('id',None) self.class_ = kw.get('class_',None) self.xmltree = None if xrtnode is None and text is not None: try: xrtnode = etree.fromstring(text,PARSER()) except: try: xrtnode = etree.fromstring('<'+defaultTag+'>'+text+'',PARSER()) except: raise CException(self.__class__,1,str(text)) if xrtnode is not None: try: self.xmltree = applySelect(xrtnode,xmlnode,jobInfo) except: if text is not None: self.errReport.append(self.__class__,2,str(text)) def as_etree(self): if self.id is not None: self.xmltree.set('id',self.id) if self.class_ is not None: self.xmltree.set('class',self.class_) return self.xmltree # Table class class BaseTable(ReportClass): tableCount = 0 def __init__( self, xrtnode=None, xmlnode=None, jobInfo={}, **kw ): super(BaseTable,self).__init__(xrtnode=xrtnode, xmlnode=xmlnode, **kw) BaseTable.tableCount += 1 self.id = kw.get('id','table_'+str( BaseTable.tableCount)) self.coldata = [] self.coltitle = [] self.colsubtitle = [] self.colTips = [] self.xmldata = [] self.help = None self.download = None self.outputCsv = kw.get('outputCsv',True) downloadable = kw.get('downloadable',False) if downloadable: if self.title is not None: self.download = Download(jobInfo=jobInfo,dataName=self.id+'_'+self.title) else: self.download = Download(jobInfo=jobInfo,dataName=self.id) if xrtnode is not None: self.excludeIfDataMissing = xrtnode.get('excludeIfDataMissing',False) if xmlnode is not None: self.xmldata = xmlnode.xpath( xrtnode.get( "select" ) ) self.transpose = ( xrtnode.get( "transpose" ) != None ) if xrtnode.get( "help" ) is not None: self.help = Help(ref = xrtnode.get( "help" )) else: self.excludeIfDataMissing = kw.get('excludeIfDataMissing',False) if xmlnode is not None: if kw.get('select',None) is not None: self.xmldata = xmlnode.xpath(kw.get('select')) else: self.xmldata = [ xmlnode ] self.transpose = kw.get('transpose',False) if kw.get('help',None) is not None: self.help = Help(ref = kw['help']) # assemble column data if xrtnode is not None: for col in xrtnode: if col.tag == XRTNS+"data": colttl1 = col.get( "title" ) colttl2 = col.get( "subtitle" ) colexpr = col.get( "expr" ) colsel = col.get( "select" ) self.addData(xmldata=self.xmldata,title=colttl1,subtitle=colttl2,expr=colexpr,select=colsel) def addData(self,xmldata=None,title=None,subtitle=None,expr=None,function=None,select=None,data=[], tip=None): if tip is not None: self.colTips.append(tip) else: self.colTips += [None] colvals = [] if xmldata is not None: if not isinstance(xmldata,list): xmldata = [xmldata ] else: xmldata = self.xmldata if select != None: # select the values from the xml for x in xmldata: for selitem in x.xpath( select ): if selitem.text is None: val = '-' else: val = selitem.text.strip() if expr != None: # allow an expression to be applied to the data try: val = eval( expr, {"x":float(val)} ) except: val = '-' if function is not None: val = function(val) colvals.append(val) else: # allow a list of values to be given colvals.extend(data) if self.excludeIfDataMissing and len(colvals)==0: pass else: self.coldata.append(colvals) maxlen = max( [ len(col) for col in self.coldata ] ) for i in range(len(self.coldata)): while len(self.coldata[i]) < maxlen: self.coldata[i].append(None) self.coltitle.append(title) self.colsubtitle.append(subtitle) def as_html( self ): # check for subheads hassubhead = sum( [ x != None for x in self.colsubtitle ] ) > 0 # deal with normal and transpose tables in turn if not self.transpose: # Normal tables s = "\n" # column headers s += "" for i in range(len(self.coltitle)): if self.coltitle[i] != None: span = 1 while i+span < len(self.coltitle): if self.coltitle[i+span] != None: break span += 1 text = self.coltitle[i] if self.coltitle[i] else "" colTip = "" if i>=0 and i 1: s += "".format(span, colTip, text) else: s += "".format(colTip, text) # column subheaders if hassubhead: s += "\n" for i in range(len(self.colsubtitle)): if self.coltitle[i] != None or self.colsubtitle[i] != None: span = 1 while i+span < len(self.colsubtitle): if self.coltitle[i+span] != None or self.colsubtitle[i+span] != None: break span += 1 text = self.colsubtitle[i] if self.colsubtitle[i] else "" colTip = "" if i>=0 and i 1: s += "".format(span, colTip, text) else: s += "".format(text) s += "\n\n" # column data s += "\n" for i in range(len(self.coldata[0])): s += "" for col in self.coldata: colTip = "" if col>=0 and col=0 and col 0 table = etree.Element('table') if self.id is not None: table.set('id',self.id) if self.class_ is not None: table.set('class',self.class_) if self.style is not None: table.set('style',self.style) # deal with normal and transpose tables in turn if not self.transpose: head = etree.Element('thead') table.append(head) headtr = etree.Element('tr') for i in range(len(self.coltitle)): if self.coltitle[i] != None: span = 1 while i+span < len(self.coltitle): if self.coltitle[i+span] != None: break span += 1 th = etree.Element('th') th.text = self.coltitle[i] if self.coltitle[i] else "" if span > 1: th.set('colspan',str(span)) headtr.append(th) head.append(headtr) tbody = etree.Element('tbody') tbody.set('class','fancy') for i in range(len(self.coldata[0])): tr= etree.Element('tr') for col in self.coldata: td = etree.Element('td') td.text = unicode(col[i]) tr.append(td) tbody.append(tr) table.append(tbody) else: tbody = etree.Element('tbody') tbody.set('class','fancy') for i in range(len(self.coldata)): tr = etree.Element('tr') tbody.append(tr) th = etree.Element('th') if self.coltitle[i] != None: th.text = str(self.coltitle[i]) tr.append(th) if hassubhead: th1 = etree.Element('th') if self.colsubtitle[i] != None: th1.text = self.colsubtitle[i] tr.append(th1) for j in range(len(self.coldata[i])): td = etree.Element('td') td.text = str(self.coldata[i][j]) tr.append(td) table.append(tbody) root = etree.Element('root') if self.help is None and self.download is None: root.append(table) else: #This is not working well div = etree.Element('div') div.set('id',self.id) root.append(div) div.append(table) if self.help is not None: div.append(self.help.as_etree()) if self.download is not None: div.append(self.download.as_etree()) ''' tab = etree.Element('table') tab.append(etree.Element('tr')) tab.append(etree.Element('tr')) tab[0].append(etree.Element('td')) tab[0][0].set('colspan','2') tab[1].append(etree.Element('td')) tab[1].append(etree.Element('td')) tab[0][0].append(table) if self.help is not None: tab[1][0].append(self.help.as_etree()) if self.download is not None: tab[1][1].append(self.download.as_etree()) root.append(tab) ''' return root def data_as_csv(self,fileName=None): import csv if len(self.coldata)==0: return CErrorReport() try: f = open(fileName,'wb') except: return CErrorReport(Report,107,str(fileName)) try: writer = csv.writer(f) if self.transpose: iRow=0 for row in self.coldata: if len(self.coltitle)>0: if iRow < len(self.coltitle): outputRow = [self.coltitle[iRow]] + row else: outputRow = [" "] + row else: outputRow = row writer.writerow(outputRow) iRow += 1 else: if len(self.coltitle)>0: writer.writerow(self.coltitle) nc = len(self.coldata) nr = len(self.coldata[0]) for n in range(nr): row = [] for col in self.coldata: row.append(col[n]) writer.writerow(row) except: return CErrorReport(Report,107,str(fileName)) try: f.close() except: return CErrorReport(Report,107,str(fileName)) return CErrorReport() def data_as_xml(self,fileName=None): import csv if len(self.coldata)==0: return CErrorReport() try: f = open(fileName,'wb') except: return CErrorReport(Report,107,str(fileName)) try: dataAsEtree = self.data_as_etree() #As it comes out here, the data tag is in ccp4 namespace (i.e. ccp4_data:data) from lxml import etree rootNode = etree.Element('CCP4ApplicationOutput') for childTable in dataAsEtree: childTable.tag = 'CCP4Table' rootNode.append(childTable) from lxml import etree dataAsText = etree.tostring(rootNode,pretty_print=True) f.write(dataAsText) except: print 'Failed to select data' return CErrorReport(Report,107,str(fileName)) try: f.close() except: return CErrorReport(Report,107,str(fileName)) return CErrorReport() # JavaScript-Enhances Table class class Table(BaseTable): def __init__( self, xrtnode=None, xmlnode=None, jobInfo={}, **kw ): super(Table,self).__init__(xrtnode=xrtnode, xmlnode=xmlnode, jobInfo=jobInfo, **kw ) #self.internalId = kw.get("internalId", "tabletable_{0}_{1}".format(jobInfo.get('jobid','xxx'),BaseTable.tableCount)) def as_etree(self): # check for subheads hassubhead = sum( [ x != None for x in self.colsubtitle ] ) > 0 root = etree.Element('root') # deal with normal and transpose tables in turn if True: styleDict = {'height':'100%', 'width':'100%','margin':'0px','padding':'0px','display':'inline-block','margin-top':'1px'} styleStr = ';'.join([key + ':'+styleDict[key] for key in styleDict]) + ';' if self.outputXml: drawnDiv = DrawnDiv(style = styleStr, height=styleDict['height'], width=styleDict['width'], data = self.data_url(), data_is_urls=True,renderer='CCP4i2Widgets.CCP4TableRenderer', require='CCP4i2Widgets', initiallyDrawn='True') else: drawnDiv = DrawnDiv(style = styleStr, height=styleDict['height'], width=styleDict['width'], data = 'data_'+self.internalId, data_is_urls=False, renderer='CCP4i2Widgets.CCP4TableRenderer', require='CCP4i2Widgets', initiallyDrawn='True') root.append(self.data_as_etree()) surroundingDiv = etree.SubElement(root,'div') surroundingDiv.append(drawnDiv.as_etree()) surroundingDiv.set('id',self.id) if self.help is None and self.download is None: pass else: #This is not working well (<- *not* written by me SJM 05/12/2014) if self.help is not None: surroundingDiv.append(self.help.as_etree()) if self.download is not None: surroundingDiv.append(self.download.as_etree()) return root def data_as_etree(self,fileName=None): hassubhead = sum( [ x != None for x in self.colsubtitle ] ) > 0 eleTree = etree.parse(StringIO('')) ccp4_data = eleTree.getroot() ccp4_data.set('id','data_'+self.internalId) ccp4_data.set('type','application/xml') table = etree.Element('table') if not self.transpose: head = etree.Element('thead') table.append(head) headtr = etree.Element('tr') for i in range(len(self.coltitle)): if self.coltitle[i] != None: span = 1 while i+span < len(self.coltitle): if self.coltitle[i+span] != None: break span += 1 th = etree.Element('th') if i >=0 and i 1: th.set('colspan',str(span)) headtr.append(th) head.append(headtr) tbody = etree.Element('tbody') for i in range(len(self.coldata[0])): tr= etree.Element('tr') for col in self.coldata: td = etree.Element('td') if i >=0 and i=0 and i=0 and i0: if isinstance(xmlEleList[0],str): self.title = xmlEleList[0] else: self.title = xmlEleList[0].text else: self.title = None else: self.title = xrtnode.find('title').text else: self.title = xrtnode.get('title',None) elif kw.has_key('title'): self.title = kw['title'] if kw.get('launcher',None) is not None: ele = etree.Element('launch') ele.set('label',kw.get('launcher','More graphs')) ele.set('exe','loggraph') self.launch = Launch(ele,jobInfo=jobInfo,ccp4_data_id='data_'+self.internalId) if xrtnode is not None: help = xrtnode.find(XRTNS+'help') else: help = kw.get('help',None) if help is not None: self.help = Help(help,mode='graph') else: self.help = None if xrtnode is not None: if xrtnode.get( "select" ) is not None and xmlnode is not None: # Make list of selectd xml nodes self.xmldata = xmlnode.xpath( xrtnode.get( "select" ) ) elif kw.has_key('select') and xmlnode is not None: self.xmldata = xmlnode.xpath( kw['select'] ) else: # or put current xml node in a list self.xmldata = [] if xmlnode is not None: self.xmldata.append( xmlnode ) # assemble column data if xrtnode is not None: for node in xrtnode: if node.tag == XRTNS+"data": self.addData(xmldata=self.xmldata,title=node.get('title'),select=node.get('select'),expr=node.get('expr')) # Handle table as a block in the xml file elif node.tag == XRTNS+"table": self.addTable(xmldata=self.xmldata,select=node.get('select'),headers=node.find( XRTNS+'headers')) # get plot definitions if xrtnode is not None: for node in xrtnode: if node.tag == XRTNS+"plot": self.addPlot(xrtnode=node,xmlnode=xmlnode,select=node.get('select')) def addPimpleData(self,xmlnode=None,select=None,usePlotly=False): if xmlnode is None: xmlnode = self.xmlnode if select is not None: xmlnode=xmlnode.xpath0(select) self.pimpleData = etree.Element('pimple_data') if usePlotly: self.pimpleData.set('usePlotly','True') from copy import deepcopy for key in ['headers','data','plot']: eleList = xmlnode.xpath(key) for ele in eleList: #print 'addPimpleData',key,ele.get('id') self.pimpleData.append(deepcopy(ele)) for attr in xmlnode.attrib.keys(): #print 'addPimpleData',attr,xmlnode.get(attr) self.pimpleData.set(attr,xmlnode.get(attr)) def addData(self,xmldata=None,title=None,select=None,expr=None,data=[]): colvals = [] if len(data)>0: colvals.extend(data) else: if xmldata is None: xmldata = self.xmldata for x in xmldata: selectedList = x.xpath(select) for selitem in selectedList: if selitem.text is None: val = '-' else: val = selitem.text.strip() if expr is not None: # allow an expression to be applied to the data try: val = eval( expr, {"x":float(val)} ) except: val = '-' colvals.append(val) self.coldata.append(colvals) self.coltitle.append(title) def addTable(self,xmlnode=None,**kw): if xmlnode is None: if len(self.xmldata)>0: xmlnode = self.xmldata[0] else: return if kw.get('select',None) is not None and xmlnode is not None: tableEleList = xmlnode.xpath(kw['select']) if len(tableEleList)>0: self.tableText = tableEleList[0].text if kw.get('headers',None) is not None and xmlnode is not None: headersEleList = xmlnode.xpath(kw['headers']) #print 'Graph.addTable headersEleList',headersEleList if len(headersEleList)>0: self.headerText = headersEleList[0].text self.headerSeparator = headersEleList[0].get('separator',None) def addPlot(self,xrtnode=None,xmlnode=None,**kw): if xmlnode is None: if len(self.xmldata)>0: xmlnode = self.xmldata[0] if xrtnode is None: #try: if kw.get('plotFile',None): from core import CCP4Utils try: text = CCP4Utils.readFile(kw['plotFile']) import re #text = re.sub('0: maxlen = max( [ len(data) for data in self.coldata ] ) for i in range(len(self.coldata)): while len(self.coldata[i]) < maxlen: self.coldata[i].append(None) # Convert to single text block text = '' for i in range(len(self.coldata[0])): for col in self.coldata: if col[i] is None: text += '- ' else: text += str(col[i]) + ' ' text += "\n" self.tableText = text # Headers to single text block for head in self.coltitle: self.headerText += head + ' ' self.coldata = [] self.coltitle = [] def as_html( self ): s = "\n
{2}{1}
{2}{0}