Dear Xin, Sorry, I was wrong in the last reply, the command line argument problem was just bad result of cut and paste from the email.
However, I have found a couple of issues which are hopefully addressed in the two attached files. 1) A change to ProvideAsuContents.py to work without a database. This should replace the file: /home/programs/ccp4-9/lib/python3.9/site-packages/ccp4i2/wrappers/ProvideAsuContents/script/ProvideAsuContents.py 2) i2run was simply not exiting properly after finishing. The attached CCP4I2Runner.py should fix this. This belongs in: /home/programs/ccp4-9/lib/python3.9/site-packages/ccp4i2/core/CCP4I2Runner.py Please let me know if these do or not fix the problem. Best wishes, Stuart On Fri, 30 Aug 2024 at 08:26, Stuart McNicholas <stuart.mcnicho...@york.ac.uk> wrote: > > Dear Xin, > It appears that the command line arguments are not being parsed > properly. I am looking into this right now. I hope to have a fix for > you very shortly. > > Best wishes, > Stuart > > On Fri, 30 Aug 2024 at 06:30, zx2...@connect.hku.hk > <zx2...@connect.hku.hk> wrote: > > > > Hi all, > > > > I am experiencing some issues with i2run command after updating CCP4 to > > version 9.0. > > > > The command I used is as follows: > > > > $CCP4/lib/python3.9/site-packages/ccp4i2/bin/i2run ProvideAsuContents \ > > --ASU_CONTENT \ > > sequence=${sequence} \ > > nCopies=1 \ > > polymerType=PROTEIN \ > > --noDb > ASU.log > > > > However, I am receiving the following error message: > > > > Traceback (most recent call last): > > File > > "/home/programs/ccp4-9/lib/python3.9/site-packages/ccp4i2/core/CCP4I2Runner.py", > > line 740, in <module> > > threads = app.findChildren(QtCore.QThread) > > AttributeError: 'NoneType' object has no attribute 'findChildren' > > > > I was wondering if you could provide some suggestions on how to solve this > > problem. > > > > Thank you very much for your time and assistance. > > > > Best regards, > > Xin > > > > ________________________________ > > > > To unsubscribe from the CCP4BB list, click the following link: > > https://www.jiscmail.ac.uk/cgi-bin/WA-JISC.exe?SUBED1=CCP4BB&A=1 ######################################################################## To unsubscribe from the CCP4BB list, click the following link: https://www.jiscmail.ac.uk/cgi-bin/WA-JISC.exe?SUBED1=CCP4BB&A=1 This message was issued to members of www.jiscmail.ac.uk/CCP4BB, a mailing list hosted by www.jiscmail.ac.uk, terms & conditions are available at https://www.jiscmail.ac.uk/policyandsecurity/
from core.CCP4PluginScript import CPluginScript from core import CCP4ModelData import os,sys import shutil from lxml import etree class ProvideAsuContents(CPluginScript): TASKNAME = 'ProvideAsuContents' # Task name - should be same as class name RUNEXTERNALPROCESS=False def startProcess(self, command, **kw): asuFileObject = self.container.outputData.ASUCONTENTFILE asuFileObject.fileContent.seqList.set(self.container.inputData.ASU_CONTENT) if self._dbHandler: asuFileObject.saveFile( { 'projectName': self._dbHandler.projectName, 'projectId' : self._dbHandler.projectId, 'jobId' : None, 'jobNumber' : None } ) xmlroot = etree.Element('ASUCONTENTMATTHEWS') totWeight = 0.0 if len(self.container.inputData.ASU_CONTENT) > 0: entries = etree.SubElement(xmlroot,"entries") polymerMode = "" for seqObj in self.container.inputData.ASU_CONTENT: if seqObj.nCopies > 0: if seqObj.polymerType == "PROTEIN": if polymerMode == "D": polymerMode = "C" elif polymerMode == "": polymerMode = "P" if seqObj.polymerType in ["DNA","RNA"]: if polymerMode == "P": polymerMode = "C" elif polymerMode == "": polymerMode = "D" totWeight = totWeight + seqObj.molecularWeight(seqObj.polymerType) entry = etree.SubElement(entries,"entry") nCopies = etree.SubElement(entry,"copies") name = etree.SubElement(entry,"name") weight = etree.SubElement(entry,"weight") sequence = etree.SubElement(entry,"sequence") nCopies.text = str(seqObj.nCopies) name.text = str(seqObj.name) weight.text = "{0:.1f}".format(float(seqObj.molecularWeight(seqObj.polymerType))) sequence.text = str(seqObj.sequence) totalWeightTag = etree.SubElement(xmlroot,"totalWeight") totalWeightTag.text = str(totWeight) if self.container.inputData.HKLIN.isSet() and len(self.container.inputData.ASU_CONTENT) > 0: if totWeight > 1e-6: rv = self.container.inputData.HKLIN.fileContent.matthewsCoeff(molWt=totWeight,polymerMode=polymerMode) vol = rv.get('cell_volume','Unkown') volumeTag = etree.SubElement(xmlroot,"cellVolume") volumeTag.text = str(vol) matthewsComposition = etree.SubElement(xmlroot,"matthewsCompositions") for result in rv.get('results',[]): comp = etree.SubElement(matthewsComposition,"composition") nMolecules = etree.SubElement(comp,"nMolecules") solventPercentage = etree.SubElement(comp,"solventPercentage") matthewsCoeff = etree.SubElement(comp,"matthewsCoeff") matthewsProbability = etree.SubElement(comp,"matthewsProbability") nMolecules.text = str(result.get('nmol_in_asu')) solventPercentage.text = "{0:.2f}".format(float(result.get('percent_solvent'))) matthewsCoeff.text = "{0:.2f}".format(float(result.get('matth_coef'))) matthewsProbability.text = "{0:.2f}".format(float(result.get('prob_matth'))) newXml = etree.tostring(xmlroot,pretty_print=True) with open (self.makeFileName('PROGRAMXML')+'_tmp','w') as programXmlFile: if sys.version_info > (3,0): programXmlFile.write(newXml.decode("utf-8")) else: programXmlFile.write(newXml) shutil.move(self.makeFileName('PROGRAMXML')+'_tmp', self.makeFileName('PROGRAMXML')) return CPluginScript.SUCCEEDED
from __future__ import print_function import argparse import sys import os import traceback import time from xml.etree import ElementTree as ET sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from core import CCP4TaskManager from core import CCP4Config from core import CCP4File from core import CCP4Data from core import CCP4ModelData from core import CCP4XtalData if sys.platform == "win32": import ccp4mg import hklfile else: from ccp4mg import hklfile from core import CCP4Modules #from lxml import etree from xml.etree import ElementTree as ET #import clipper import gemmi import numpy import re from core.CCP4ErrorHandling import CException class CI2Runner(object): def __init__(self, cmdLineArgs, theParser=None): super(CI2Runner, self).__init__() self.defXml = None if not theParser: theParser = argparse.ArgumentParser(description='C2Runner') self.add_arguments(theParser, cmdLineArgs) self.namespace = theParser.parse_args(cmdLineArgs) self.asuFiles = {} def availableNameBasedOn(self, filePath): if not os.path.exists(filePath): return filePath if "." in filePath: #Clumsy thing to deal with double dotted extensions like .scene.xml basePath = filePath.split(".")[0] extension = "."+".".join(filePath.split(".")[1:]) else: basePath = filePath extension = "" counter = 1 while os.path.exists(basePath+"_"+str(counter)+extension): counter += 1 return basePath+"_"+str(counter)+extension def smartSplitMTZ(self, inputFilePath=None, inputColumnPath=None, objectPath=None, intoDirectory=None): if inputFilePath is None: raise Exception("smartSplitMTZ Exception:", "Must provide an input file") if not os.path.isfile(inputFilePath): raise Exception("smartSplitMTZ Exception:", "inputFile must exist"+str(inputFilePath)) if inputColumnPath is None: raise Exception("smartSplitMTZ Exception:", "Must provide an input columnPath e.g. '/*/*/[F,SIGFP]'") if objectPath is not None and intoDirectory is not None: raise Exception("smartSplitMTZ Exception:", "Provide either full output path for file, or name of directory where file should be placed") if objectPath is None and intoDirectory is None: raise Exception("smartSplitMTZ Exception:", "Provide either full output path for file, or name of directory where file should be placed") mtz_file = clipper.CCP4MTZfile() hkl_info = clipper.HKL_info() mtz_file.open_read (inputFilePath) mtz_file.import_hkl_info ( hkl_info ) xtal = clipper.MTZcrystal() mtz_file.import_crystal( xtal, inputColumnPath ) dataset=clipper.MTZdataset() mtz_file.import_dataset( dataset, inputColumnPath ) providedColumnPaths = mtz_file.column_paths() selectedColumnLabelsExp=re.compile(r"^/(?P<XtalName>[A-Za-z0-9_. -+\*,]+)/(?P<DatasetName>[A-Za-z0-9_. -+\*,]+)/\[(?P<Columns>[A-Za-z0-9_. -+\*,]+)\]") columnsMatch=selectedColumnLabelsExp.search(inputColumnPath) selectedColumnLabelExp=re.compile(r"^/(?P<XtalName>[A-Za-z0-9_. -+\*,]+)/(?P<DatasetName>[A-Za-z0-9_. -+\*,]+)/(?P<Column>[A-Za-z0-9_. -+\*,]+)") columnMatch=selectedColumnLabelExp.search(inputColumnPath) if columnsMatch is not None: selectedColumnPaths =["/{}/{}/{}".format(columnsMatch.group("XtalName"),columnsMatch.group("DatasetName"),column) for column in columnsMatch.group("Columns").split(",") ] elif columnMatch is not None: selectedColumnPaths =["/{}/{}/{}".format(columnMatch.group("XtalName"),columnMatch.group("DatasetName"),columnMatch.group("Column"))] typeSignature = "" for selectedColumnPath in selectedColumnPaths: selectedColumnMatch = selectedColumnLabelExp.search(selectedColumnPath) for providedColumnPath in providedColumnPaths: #Generating clipper String and then calling str to deal with #Known unpredictable bug in clipper-python try: columnName, columnType = str(clipper.String(providedColumnPath)).split(" ") except NotImplementedError as err: columnName, columnType = str(providedColumnPath).split(" ") parsedColumnMatch = selectedColumnLabelExp.search(columnName) if ((selectedColumnMatch.group("XtalName") == "*" or selectedColumnMatch.group("XtalName") == parsedColumnMatch.group("XtalName")) and (selectedColumnMatch.group("DatasetName") == "*" or selectedColumnMatch.group("DatasetName") == parsedColumnMatch.group("DatasetName")) and selectedColumnMatch.group("Column") == parsedColumnMatch.group("Column")): typeSignature += columnType break #print("Type signature", typeSignature) if typeSignature == "FQ": extractedData = clipper.HKL_data_F_sigF_float(hkl_info) cls = CCP4XtalData.CObsDataFile contentType = 4 if typeSignature == "JQ": extractedData = clipper.HKL_data_I_sigI_float(hkl_info) cls = CCP4XtalData.CObsDataFile contentType = 3 if typeSignature == "GLGL" or typeSignature == "FQFQ": extractedData = clipper.HKL_data_F_sigF_ano_float(hkl_info) cls = CCP4XtalData.CObsDataFile contentType = 2 if typeSignature == "KMKM" or typeSignature == "JQJQ": extractedData = clipper.HKL_data_I_sigI_ano_float(hkl_info) cls = CCP4XtalData.CObsDataFile contentType = 1 elif typeSignature == "AAAA": extractedData = clipper.HKL_data_ABCD_float(hkl_info) cls = CCP4XtalData.CPhsDataFile contentType = 1 elif typeSignature == "PW": extractedData = clipper.HKL_data_Phi_fom_float(hkl_info) cls = CCP4XtalData.CPhsDataFile contentType = 2 elif typeSignature == "I": extractedData = clipper.HKL_data_Flag(hkl_info) cls = CCP4XtalData.CFreeRDataFile contentType = 1 outputColumnPath = "[{}]".format(','.join(getattr(cls, "CONTENT_SIGNATURE_LIST")[contentType-1])) mtz_file.import_hkl_data( extractedData, inputColumnPath ) mtz_file.close_read() if intoDirectory is not None: firstGuess = os.path.join(intoDirectory,typeSignature+'_ColumnsFrom_'+os.path.split(inputFilePath)[1]) objectPath = availableNameBasedOn(firstGuess) mtzout = clipper.CCP4MTZfile() mtzout.open_write( objectPath ) mtzout.export_hkl_info( hkl_info ) crystalName = clipper.String(xtal.crystal_name()) datasetName = clipper.String(dataset.dataset_name()) outputColumnPath = "/{}/{}/{}".format(str(crystalName), str(datasetName), outputColumnPath ) mtzout.export_crystal( xtal, outputColumnPath ) mtzout.export_dataset( dataset, outputColumnPath ) mtzout.export_hkl_data( extractedData, outputColumnPath ) mtzout.close_write() return objectPath def gemmiSplitMTZ(self, inputFilePath=None, inputColumnPath=None, objectPath=None, intoDirectory=None): if inputFilePath is None: raise Exception("smartSplitMTZ Exception:", "Must provide an input file") if not os.path.isfile(inputFilePath): raise Exception("smartSplitMTZ Exception:", "inputFile must exist"+str(inputFilePath)) if inputColumnPath is None: raise Exception("smartSplitMTZ Exception:", "Must provide an input columnPath e.g. '/*/*/[F,SIGFP]'") if objectPath is not None and intoDirectory is not None: raise Exception("smartSplitMTZ Exception:", "Provide either full output path for file, or name of directory where file should be placed") if objectPath is None and intoDirectory is None: raise Exception("smartSplitMTZ Exception:", "Provide either full output path for file, or name of directory where file should be placed") mtzin = gemmi.read_mtz_file(inputFilePath) providedColumnNames = mtzin.column_labels() if inputColumnPath.startswith('/'): inputColumnPath = inputColumnPath[1:] if len(inputColumnPath.split('/')) not in [1,3]: raise Exception("smartSplitMTZ Exception:", "Invalid input columnPath") selectedColumns = re.sub('[\[\] ]','',inputColumnPath.split('/')[-1]).split(',') outputColumns = [mtzin.column_with_label(label) for label in ['H', 'K', 'L']] typeSignature = '' for columnLabel in selectedColumns: if providedColumnNames.count(columnLabel) == 1: column = mtzin.column_with_label(columnLabel) outputColumns.append(column) typeSignature += column.type else: if len(inputColumnPath.split('/')) != 3: raise Exception("smartSplitMTZ Exception:", "Input file requires full input columnPath e.g. '/crystal/dataset/[F,SIGFP]'") for dataset in mtzin.datasets: if dataset.crystal_name == inputColumnPath.split('/')[-3] and dataset.dataset_name == inputColumnPath.split('/')[-2]: column = mtzin.column_with_label(columnLabel, mtzin.dataset(dataset.id)) outputColumns.append(column) typeSignature += column.type if len(outputColumns[3:]) != len(selectedColumns): raise Exception("smartSplitMTZ Exception:", "Unable to select columns from input file'") if intoDirectory is not None: firstGuess = os.path.join(intoDirectory,typeSignature+'_ColumnsFrom_'+os.path.split(inputFilePath)[1]) objectPath = availableNameBasedOn(firstGuess) mtzout = gemmi.Mtz() mtzout.spacegroup = mtzin.spacegroup mtzout.cell = mtzin.cell mtzout.add_dataset('HKL_base') if len (mtzin.datasets) > 1: dataset = outputColumns[-1].dataset ds = mtzout.add_dataset(dataset.project_name) ds.crystal_name = dataset.crystal_name ds.dataset_name = dataset.dataset_name ds.wavelength = dataset.wavelength outputColumnLabels = ['H', 'K', 'L'] labelsDict = {'FQ':{'cls':CCP4XtalData.CObsDataFile, 'contentType':4}, 'JQ':{'cls':CCP4XtalData.CObsDataFile, 'contentType':3}, 'GLGL':{'cls':CCP4XtalData.CObsDataFile, 'contentType':2}, 'FQFQ':{'cls':CCP4XtalData.CObsDataFile, 'contentType':2}, # surely not 'KMKM':{'cls':CCP4XtalData.CObsDataFile, 'contentType':1}, 'JQJQ':{'cls':CCP4XtalData.CObsDataFile, 'contentType':1}, # surely not 'AAAA':{'cls':CCP4XtalData.CPhsDataFile, 'contentType':1}, 'PW':{'cls':CCP4XtalData.CPhsDataFile, 'contentType':2}, 'I':{'cls':CCP4XtalData.CFreeRDataFile, 'contentType':1} } outputColumnLabels.extend(getattr(labelsDict[typeSignature]['cls'], "CONTENT_SIGNATURE_LIST")[labelsDict[typeSignature]['contentType']-1]) for i, column in enumerate(outputColumns): mtzout.add_column(outputColumnLabels[i], column.type, dataset_id=0) if i < 3 or len(mtzin.datasets) <= 1 else mtzout.add_column(outputColumnLabels[i], column.type, dataset_id=1) data = numpy.stack(outputColumns, axis=1) mtzout.set_data(data) mtzout.history = ['MTZ file created from {} using gemmi.'.format(os.path.basename(inputFilePath))] mtzout.write_to_file(objectPath) return objectPath def recursivelyBuildXML(self, fileName): #print ("In build of ", fileName) taskDefXML = ET.parse(fileName) #print (ET.tostring(taskDefXML.getroot())) #print fileName #print CCP4i2Utils.prettifyXML(ET.tostring(taskDefXML.getroot())) taskBodyNode = taskDefXML.getroot().findall('ccp4i2_body')[0] superclassDefXMLNodes = taskBodyNode.findall('file') for superclassDefXMLNode in superclassDefXMLNodes: #assert(superclassDefXMLNode.findall('project')[0].text == 'CCP4I2_TOP') #Windows fix needed here fullPath = os.path.join(os.path.dirname(__file__),"..", superclassDefXMLNode.findall('CI2XmlDataFile/relPath')[0].text, superclassDefXMLNode.findall('CI2XmlDataFile/baseName')[0].text) superclassXML = self.recursivelyBuildXML(fullPath) superclassBodyNode = superclassXML.getroot().findall('ccp4i2_body')[0] for inputFolderName in ["inputData", "controlParameters", "keywords"]: try: xpath = 'ccp4i2_body/container[@id="{}"]'.format(inputFolderName) classDataNode = taskDefXML.getroot().findall(xpath)[0] except IndexError as err: classDataNode = ET.SubElement(taskBodyNode,"container",id=inputFolderName) try: xpath = 'ccp4i2_body/container[@id="{}"]'.format(inputFolderName) superclassXMLDataNode = superclassXML.getroot().findall(xpath)[0] except IndexError as err: superclassXMLDataNode = ET.SubElement(superclassBodyNode,"container",id=inputFolderName) for contentNode in superclassXMLDataNode.findall('content'): xpathOfContent ='content[@id="{}"]'.format(contentNode.attrib['id']) if len(classDataNode.findall(xpathOfContent)) == 0: classDataNode.append(contentNode) else: print("Not replacing", contentNode) for containerNode in superclassXMLDataNode.findall('container'): xpathOfContent ='container[@id="{}"]'.format(containerNode.attrib['id']) if len(classDataNode.findall(xpathOfContent)) == 0: classDataNode.append(containerNode) else: print("Not replacing", containerNode) taskBodyNode.remove(superclassDefXMLNode) #print ET.tostring(taskDefXML.getroot()) #print "Out build of ", fileName return taskDefXML def defXMLForTaskName(self, taskName): cachedData = {} with open(os.path.join(os.path.split(__file__)[0], "DefXMLCache.json"),"r") as cacheFile: cachedData = json.loads(cacheFile.read()) relPath = cachedData[taskName] fullPath = os.path.join(os.environ['CCP4'], relPath[1:]) return self.recursivelyBuildXML(fullPath) def setEntityValue(self, entityToModify, valueItem): #print("EtoM [{}] [{}]".format(entityToModify, valueItem)) if isinstance(entityToModify,(CCP4File.CDataFile,)) and isinstance(valueItem, (str,)): #Here if setting a CDataFile with a string look to see if using fileUse searchGroup = re.match('(?P<propertyName>[^=]*)\=(?P<propertyValue>.*)', valueItem) if searchGroup is not None: print(searchGroup.group('propertyName'), searchGroup.group('propertyValue')) print('setting CDataFile with string...setting fullpath') entityToModify.setFullPath(os.path.normpath(os.path.expandvars(valueItem))) print('New full path', entityToModify.getFullPath()) return try: entityToModify.set(valueItem) #print("Set {} type {} to value {}".format(entityToModify, type(entityToModify), valueItem)) #print(entityToModify.isSet()) except CException as err: print("Failed to set {} type {} to value {}".format(entityToModify, type(entityToModify), valueItem)) print(err) raise err except ValueError as err: print("Failed setting attribute {} to value {}".format(entityToModify, valueItem)) print(err) raise err def fileUse(self, projectName, propertyValue): jobNumber, jobParamName = propertyValue.split(".") #See if jobParamName includes an array-like index arrayGroup = re.match('(?P<jobParamName>.*)\[(?P<arrayIndexStr>[0-9]+)\]', jobParamName) paramToFind = jobParamName oneToTake = 0 if arrayGroup is not None: paramToFind = arrayGroup.group('jobParamName') oneToTake = int(arrayGroup.group('arrayIndexStr')) #print(jobParamName, paramToFind, jobNumber) try: intJobNumber = int(jobNumber) #print("intJobNumber", intJobNumber) if intJobNumber < 0: allJobs = self.pm.db().getProjectJobListInfo(mode=['jobnumber','taskname'], projectName=projectName, topLevelOnly=True) print("Corresponding job", allJobs[intJobNumber]) #NB intJobNumber + 1 because the current job is last in this list (i.e. python index -1), #the previous job is -2, etc. jobNumber = allJobs[intJobNumber-1]['jobnumber'] print("intJobNumber", intJobNumber) except: print("jobNumber is not int-able", jobNumber) jobId = self.pm.db().getJobInfo(projectName=projectName, jobNumber=jobNumber)['jobid'] try: filesInfo = self.pm.db().getJobFilesInfo(jobId=jobId, jobParamName=paramToFind) return filesInfo[oneToTake]['fileId'] except IndexError as err: filesInfo = self.pm.db().getJobFilesInfo(jobId=jobId, jobParamName=paramToFind, input=True) try: return filesInfo[oneToTake]['fileId'] except IndexError as err: raise Exception('Failed to find a fileUse with param name {} on job with Id {}'.format(paramToFind, jobId)) def addSequenceToASU(self, cAsuDataFile, sequenceToExtract): #print('ASUfile [{}] [{}] [{}]'.format( cAsuDataFile.fullPath, cAsuDataFile.fullPath is None, len(cAsuDataFile.fullPath)==0, sequenceToExtract)) firstSequence = False #print("cAsuDataFile full Path is ", cAsuDataFile.fullPath) if cAsuDataFile.fullPath is None or len(cAsuDataFile.fullPath) == 0: #print("fullPath is None") import tempfile tempASUFile = tempfile.NamedTemporaryFile(delete=True, suffix=".asucontent.xml") tempASUFile.close() xmlFileObject = CCP4File.CI2XmlDataFile(tempASUFile.name) xmlFileObject.header.setCurrent() xmlFileObject.header.function.set('ASUCONTENT') #xmlFileObject.header.projectName.set(projectName) baseRoot=ET.Element("root") sequenceListRoot=ET.SubElement(baseRoot, 'seqList') xmlFileObject.saveFile(baseRoot) cAsuDataFile.setFullPath(tempASUFile.name) firstSequence = True #print('ASUfile [{}] [{}]'.format( cAsuDataFile.fullPath, sequenceToExtract)) cAsuDataFile.loadFile() sequenceFile = CCP4ModelData.CSeqDataFile() sequenceFile.setFullPath(sequenceToExtract) sequenceFile.loadFile() if not firstSequence: cAsuDataFile.fileContent.seqList.append(cAsuDataFile.fileContent.seqList.makeItem()) try: entry = cAsuDataFile.fileContent.seqList[-1] except IndexError as err: #print ("Adding a sequence element to the ASU Data file") cAsuDataFile.fileContent.seqList.append(cAsuDataFile.fileContent.seqList.makeItem()) entry = cAsuDataFile.fileContent.seqList[-1] entry.nCopies = 1 entry.sequence = sequenceFile.fileContent.sequence entry.name = sequenceFile.fileContent.identifier.replace(" ","_").replace("|","_").replace("/","_").replace(":","_") entry.description = sequenceFile.fileContent.description entry.autoSetPolymerType() cAsuDataFile.buildSelection() cAsuDataFile.saveFile() return cAsuDataFile.fullPath def extractColumns(self, inputFile, columnsToExtract, jobDirectory): targetPath = os.path.join(jobDirectory,os.path.basename(inputFile.getFullPath().__str__())) targetPath = self.availableNameBasedOn(targetPath) #print("targetPath", targetPath) self.gemmiSplitMTZ(inputFilePath=inputFile.getFullPath().__str__(), inputColumnPath=columnsToExtract, objectPath=targetPath) inputFile.setFullPath(targetPath) inputFile.setContentFlag(reset=True) def add_arguments(self, parser, cmdLineArgs): taskName = cmdLineArgs[1] #print "taskName",taskName #Add this to swallow the taskname which is mostly used as the first positional argument parser.add_argument(taskName, type=str, nargs='+',) #print "CCP4TaskManager.__file__",CCP4TaskManager.__file__ self.taskManager = CCP4TaskManager.CTaskManager() defXmlPath = self.taskManager.searchDefFile(taskName) if defXmlPath is None: raise Exception('No defXML discovered for task with name {}'.format(taskName)) from core import CCP4File defXml = self.recursivelyBuildXML(defXmlPath) parent_map = dict((c, p) for p in defXml.iter() for c in p) keywords = defXml.findall(".//content") outputKeywords = defXml.findall('.//container[@id="outputData"]/content') parser.add_argument('--projectName', type=str,) parser.add_argument('--projectPath', type=str, default=None) parser.add_argument('--dbFile', default=None) parser.add_argument('--noDb', action='store_true') parser.add_argument('--taskName', type=str, default=taskName) parser.add_argument('--jobDirectory', type=str, default=os.getcwd()) for keyword in keywords: if keyword not in outputKeywords: argumentText = keyword.attrib['id'] #Here handle case that the same "ultimate" content name occurs more than once, #presumably due to having distinct "container" nesting in the .def.xml if len(defXml.findall('.//content[@id="{}"]'.format(keyword.attrib['id']))) > 1: currentNode = keyword #print(parent_map[currentNode].attrib, parent_map[currentNode].attrib['id']) while parent_map[currentNode].tag != "ccp4i2_body": argumentText = parent_map[currentNode].attrib['id']+'.'+argumentText currentNode = parent_map[currentNode] #print(currentNode) commandFlag = '--'+argumentText className = "".join([classNameNode.text for classNameNode in keyword.findall("className")]) helpText = "".join([toolTipNode.text for toolTipNode in keyword.findall("qualifiers/toolTip") if toolTipNode.text is not None]) try: if className in ["CList", "CImportUnmergedList", "CAsuContentSeqList", "CEnsembleList"]: parser.add_argument(commandFlag, type=str, nargs='+', help="{}:{}".format(className, helpText), action="append") else: try: enumerators = keyword.findall('qualifiers/enumerators') parser.add_argument(commandFlag, type=str, help="{}:{}".format(className, helpText), choices=enumerators[0].text.split(","), nargs='+') except: parser.add_argument(commandFlag, type=str, help="{}:{}".format(className, helpText), nargs='+') except argparse.ArgumentError as err: print("Problem handling argument ", err) #print ET.tostring(defXml.getroot()) self.defXml = defXml def configure(self): kwargs = vars(self.namespace) #print("kwargs", kwargs) def etree_iter_path(node, tag=None, path='.'): if tag == "*": tag = None if tag is None or node.tag == tag: yield node, path for child in node: _child_path = '%s/%s' % (path, child.attrib.get('id',None)) for child, child_path in etree_iter_path(child, tag, path=_child_path): yield child, child_path pathMap = {} for elem, path in etree_iter_path(self.defXml.getroot()): pathMap[elem] = path sys.path.append(os.path.dirname(os.path.dirname(__file__))) from core.CCP4TaskManager import CTaskManager theClass = CTaskManager().getPluginScriptClass(kwargs['taskName']) if not os.path.isdir(kwargs['jobDirectory']): print("Job directory {} does not exist".format(kwargs['jobDirectory'])) if kwargs["noDb"]: theWrapper = theClass(workDirectory=kwargs['jobDirectory']) jobDirectory = kwargs['jobDirectory'] else: from core import CCP4ProjectsManager from utils import startup CCP4ProjectsManager.CProjectsManager.insts = None self.pm = startup.startProjectsManager(dbFileName=kwargs.get('dbFile',None)) if kwargs.get('projectPath', None) is not None: try: projectId = self.pm.createProject(projectName=kwargs.get('projectName',None), projectPath=kwargs.get('projectPath',None)) print('Created project [{}] with name [{}] in directory [{}]'.format(projectId, kwargs.get('projectName',None), kwargs.get('projectPath',None))) except CException as err: #print(len(err._reports)) if err._reports[0]['code'] == 117: print("Project with this path already exists") projectData = self.pm.db().getProjectInfo(projectName=kwargs.get('projectName',None), projectId=kwargs.get('projectId',None)) self.pm.db().resetLastJobNumber(projectId=projectData['projectid']) print('projectData', projectData) projectName = projectData['projectname'] projectId = projectData['projectid'] from dbapi import CCP4DbUtils theWrapper = CCP4DbUtils.COpenJob(projectId=projectData['projectid']) theWrapper.createJob(taskName = kwargs['taskName']) jobDirectory = theWrapper.jobDir #print ("kwargs.items", kwargs.items()) #Here a fix, because it may happen that a keyword will match a content id in the "outputData" folder, #since outputData elements may take the same name as an input. Here I collect content nodes taht are #descendents of outputData, to exclude from being set downstream outputDataContainers = self.defXml.findall('.//container[@id="outputData"]') outputDataNodes = [] for outputDataContainer in outputDataContainers: outputDataNodes += outputDataContainer.findall('.//content') ccp4i2BodyNodes = self.defXml.findall('ccp4i2_body') assert len(ccp4i2BodyNodes) == 1 ccp4i2BodyNode = ccp4i2BodyNodes[0] def expandValue(value): if isinstance(value, list): patchedSubkeywordList = [] subKeywordIterator = iter(value) appending = False for nextElement in subKeywordIterator: try: #nextElement = subKeywordIterator.__next__() if isinstance(nextElement, list): nextElement = expandValue(nextElement) patchedSubkeywordList.append(nextElement) elif "=" in nextElement: patchedSubkeywordList.append(nextElement) appending = True elif appending: patchedSubkeywordList[-1] += " {}".format(nextElement) else: patchedSubkeywordList.append(nextElement) except StopIteration: break value = patchedSubkeywordList return value for key, value in kwargs.items(): #Here a truly nasty thing to deal with possibility that value is a list of #subKeyword=subValue entries *one or more of which might have spaces in the subValuefield* if isinstance(value, list): value = expandValue(value) if value is not None: print("Processing command ", key, value) currentNode = ccp4i2BodyNode keyPath = key.split(".") #print('keyPath', keyPath) for i in range(len(keyPath)-1): currentNode = currentNode.findall('container[@id="{}"]'.format(keyPath[i]))[0] valueNodes = currentNode.findall('.//content[@id="'+keyPath[-1]+'"]') #print("nodes", valueNodes) nonOutputValueNodes = [node for node in valueNodes if node not in outputDataNodes] #print("nonOutputValueNodes", nonOutputValueNodes) assert len(nonOutputValueNodes) <= 1 for defXmlNode in nonOutputValueNodes: #defXmlNode = nodes[0] dataPathElements = pathMap[defXmlNode].split('/') theEntity = getattr(theWrapper,"container") for pathElement in dataPathElements[2:]: #print("Moving on to pathElement", pathElement) theEntity = getattr(theEntity, pathElement) parameterName = dataPathElements[-1] #print('Parameter name: [{}] [{}]'.format( parameterName, type(theEntity))) if isinstance(theEntity,(CCP4Data.CList,)) and not isinstance(theEntity,(CCP4Data.CString,)): entityList = theEntity valueLists = value else: entityList = [theEntity] valueLists = [value] #print(parameterName, valueLists) lastDictKey="NullKey" for iValue, valueAsList in enumerate(valueLists): #print("1:", iValue, valueAsList, type(valueAsList), isinstance(valueAsList, CCP4Data.CString)) if isinstance(entityList,(CCP4Data.CList,)): while len(entityList) < iValue+1: entityList.append(entityList.makeItem()) entityToModify = entityList[iValue] for valueItem in valueAsList: #print("\t",valueItem) #First deal with double quoted value. #Assume that the entityToModify will accept a "set" for the quoted value if valueItem.startswith('"') and valueItem.endswith('"'): try: entityToModify.set(valueItem[1:-2]) except CException as err: print("Failed setting attribute {} on {} to value {}".format(parameterName, entityToModify, valueItem[1:-2])) print(err) raise err except ValueError as err: print("Failed setting attribute {} on {} to value {}".format(parameterName, entityToModify, valueItem[1:-2])) print(err) raise err #Now deal with subElement=subValue examples elif "=" in valueItem: valueItemGroup = re.match('(?P<propertyName>[^=]*)\=(?P<propertyValue>.*)', valueItem) propertyName = valueItemGroup.group('propertyName') propertyValue = valueItemGroup.group('propertyValue') propertyPathElements = propertyName.split("/") propertyToModify = entityToModify parentProperty = None for iPathElement, propertyPathElement in enumerate(propertyPathElements): #Look to see if there is an index in the propertyPathELement pathElementGroup = re.match('(?P<arrayName>[^=]*)\[(?P<arrayIndex>.*)\]', propertyPathElement) if pathElementGroup is None: deconvolutedPathElement = propertyPathElement deconvolutedIndex = 0 else: deconvolutedPathElement = pathElementGroup.group('arrayName') deconvolutedIndex = int(pathElementGroup.group('arrayIndex')) #print('Reached {} {} {}'.format(type(propertyToModify), deconvolutedPathElement, propertyValue) ) #Here handle specialisations for various CDataFile types if isinstance(propertyToModify,(CCP4Data.CDict,)): #print("CCP4Data.CDict", deconvolutedPathElement, propertyValue) if deconvolutedPathElement == 'key': lastDictKey = propertyValue continue elif deconvolutedPathElement == 'value': #print("CDict/value", deconvolutedPathElement, deconvolutedIndex, propertyToModify, lastDictKey) propertyToModify[lastDictKey] = propertyValue continue elif isinstance(propertyToModify,(CCP4ModelData.CAtomSelection,)): print(entityToModify) if deconvolutedPathElement == 'text': propertyToModify.text.set(propertyValue) #print("[{}] [{}] [{}]".format(entityToModify, entityToModify.selection, entityToModify.selection.text)) #print(etree.tostring(entityToModify.getEtree())) continue elif isinstance(propertyToModify,(CCP4ModelData.CAsuDataFile,)): if deconvolutedPathElement == 'seqFile': fullPath = self.addSequenceToASU(propertyToModify, os.path.normpath(os.path.expandvars(propertyValue))) propertyToModify.setFullPath(fullPath) #print("CCP4ModelData.CAsuDataFile", deconvolutedPathElement, propertyToModify.fullPath, propertyToModify.baseName) continue elif isinstance(propertyToModify,(CCP4XtalData.CMiniMtzDataFile,)): if deconvolutedPathElement == 'columnLabels': self.extractColumns(propertyToModify, propertyValue, jobDirectory) #print("CCP4XtalData.CMiniMtzDataFile", deconvolutedPathElement) continue #Following applies to all CDataFiledescendents if isinstance(propertyToModify,(CCP4File.CDataFile,)): #print("Evaluating CDataFile ", projectName, deconvolutedPathElement, iPathElement, len(propertyPathElements)) if deconvolutedPathElement == 'fileUse': dbFileId = self.fileUse(projectName, propertyValue) propertyToModify.setDbFileId(dbFileId) continue elif deconvolutedPathElement == 'fullPath': propertyToModify.setFullPath(os.path.normpath(os.path.expandvars(propertyValue))) continue elif deconvolutedPathElement == 'dbFileId': propertyToModify.setDbFileId(propertyValue) continue try: propertyOrArryToModify = getattr(propertyToModify, deconvolutedPathElement) if isinstance(propertyOrArryToModify,(CCP4Data.CList,)): #print("property {} is a CList".format(deconvolutedPathElement)) #Here if the pathElement is a CList...see if index is specified while len(propertyOrArryToModify) < deconvolutedIndex+1: propertyOrArryToModify.append(propertyOrArryToModify.makeItem()) propertyToModify = propertyOrArryToModify[deconvolutedIndex] else: propertyToModify = propertyOrArryToModify #print(type(propertyToModify)) except CException as err: print("Failed to get property {} on {}".format(deconvolutedPathElement, type(propertyToModify))) raise err if iPathElement == len(propertyPathElements)-1: self.setEntityValue(propertyToModify, propertyValue) continue else: self.setEntityValue(entityToModify, valueItem) #print('after setting, the Entity:', theEntity) #print (getattr(theWrapper,"container")) return theWrapper def run(self): kwargs = vars(self.namespace) theWrapper = self.configure() if kwargs['noDb']: self.runNoDb(theWrapper) else: self.runWithDb(theWrapper) def runNoDb(self, theWrapper): theWrapper.doAsync=False theWrapper.process() rv = theWrapper.getErrorReport() print(rv.report(ifStack=True)) def runWithDb(self, cOpenJob): from PySide2 import QtCore rv = cOpenJob.saveParams() cOpenJob.openJob() ifImportFile, errors = self.pm.importFiles(jobId=cOpenJob.jobId, container=cOpenJob.container) #print(ifImportFile, errors) #Record input files in database from dbapi import CCP4DbApi self.pm.db().gleanJobFiles(jobId=cOpenJob.jobId,container=cOpenJob.container, roleList=[CCP4DbApi.FILE_ROLE_IN]) rv = cOpenJob.saveParams() jc=CCP4Modules.JOBCONTROLLER() jc.setDiagnostic(True) jc.setDbFile(self.pm.db()._fileName) lastJobFinishCheckTime = time.time() jc.runTask(cOpenJob.jobId) doContinue = True while doContinue: t = time.time() finishedJobs = self.pm.db().getRecentlyFinishedJobs(after=lastJobFinishCheckTime) print("Any recently finished jobs ...?") print(finishedJobs) lastJobFinishCheckTime = t if len(finishedJobs) > 0: print("... yes ...") for j in finishedJobs: if len(j)>5 and not j[5]: print("... attempting to stop ...") doContinue = False time.sleep(4) print("Attempting to close DB...") self.pm.db().close() print("Returning...") return if __name__ == "__main__": print("##################################################") print("##################################################") print("RUNNING NEW CCP4I2Runner") print("##################################################") print("##################################################") try: theRunner = CI2Runner(sys.argv) theRunner.run() #Quit any web server threads from PySide2 import QtCore app = QtCore.QCoreApplication.instance() if app: threads = app.findChildren(QtCore.QThread) print("##################################################") print("Quitting threads ...") print("##################################################") for t in threads: if hasattr(t,"quitServer"): t.quitServer() print("Waiting for thread",t) timer = QtCore.QDeadlineTimer(1000) t.wait(timer) t.exit() print("##################################################") print("##################################################") print("EXITING FROM NEW CCP4I2Runner") print("##################################################") print("##################################################") sys.exit(0) except Exception as err: print("Failed with exception ", err) traceback.print_exc() sys.exit(1)