""" python/ui/ModelInfo.py: CCP4MG Molecular Graphics Program Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009 University of York This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, modified in accordance with the provisions of the license to address the requirements of UK law. You should have received a copy of the modified GNU Lesser General Public License along with this library. If not, copies may be downloaded from http://www.ccp4.ac.uk/ccp4license.php This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. """ #=================================================================== #=================================================================== #=================================================================== class ModelInfo: #=================================================================== insts = '' monomer_library_elements = [] # list of *_EL.cif files in monomer library #----------------------------------------------------------------- def __init__(self): #----------------------------------------------------------------- import utils import os ModelInfo.insts = self self.ModInfo = {} # list of loaded files self.user_file = {} filename = ['dotCCP4MG','generic.ccp4mg',os.path.join(utils.get_CCP4MG(),'generic.ccp4mg')] self.user_file['generic']=filename # ? this should be in generic self.generic_selection = {} for set,filename in self.user_file.items(): self.restore(set,filename) #------------------------------------------------------------------ def setparams(self,params=''): #------------------------------------------------------------------ ''' Restore data - called from DisplayTableShadow on program initialisation ''' #print "setparams",params for key,value in params.items(): setattr(self,key,value) import types import os for set,filename in self.user_file.items(): if not isinstance(filename,types.ListType): filename = ['FULLPATH',os.path.split(filename)[1],filename] #print "ModelInfo restoring",filename self.user_file[set] = filename self.restore(set=set,filename=filename) #------------------------------------------------------------------ def getparams(self): #------------------------------------------------------------------ ''' Save status - called from DisplayTableShadow Presently saves list of user_defined_files i.e. any loaded .ccp4mg which are not associated with a PDB file ''' params = {} params['user_file'] = self.user_file return params #-------------------------------------------------------------------- def save_user_files(self): #-------------------------------------------------------------------- #print "save_user_files",self.user_file for set,filename in self.user_file.items(): self.save(set=set,filename=filename) #-------------------------------------------------------------------- def save(self,set='',filename=[]): #-------------------------------------------------------------------- ''' Save ModInfo class to .ccp4mg file "set" is the GUI label for the set of data - usually the PDB filename root ''' import os import pickle import sys #print "ModelInfo save",set,filename if not set or not self.ModInfo.has_key(set): return 1 if not filename: if self.user_file.has_key(set): filename = self.user_file[set] else: import global_definitions dobj = global_definitions.data(set) #print 'ModelInfo.save dobj',dobj if dobj: filename = dobj.filename else: return 2 #print "ModelInfo save",filename pickle_file =os.path.splitext(filename[2])[0] + '.ccp4mg' #print "save ModInfo"+pickle_file try: if sys.platform == 'win32': f = open(pickle_file,'w') else: f = open(pickle_file,'wb') except: #print "ERROR opening file",pickle_file return 3 try: pickle.dump(self.ModInfo[set],f) f.close() except: pass return 0 #-------------------------------------------------------------------- def restore(self,set='',filename=[],user_file=0,override=1,create=1): #-------------------------------------------------------------------- ''' Restore ModInfo class from a .ccp4mg file For GUI purposes the data has a name "set" which is uusually the filename root of the PDB file ''' import os import pickle #print "restore self.ModInfo",self.ModInfo,'set',set # override=0 when called as initialising PDB - saves # repeating load if cloned PDBs if set and self.ModInfo.has_key(set) and not override: return [0] if set == 'generic': import utils pickle_file = ['dotCCP4MG','generic.ccp4mg',os.path.join(utils.get_CCP4MG(), \ 'generic.ccp4mg')] elif filename: name = os.path.splitext(filename[1])[0] + '.ccp4mg' pickle_file = [filename[0],name,os.path.splitext(filename[2])[0] + '.ccp4mg'] else: return [1] #print "restore",pickle_file if not os.path.exists(pickle_file[2]): if create: if not set:set=utils.fileRoot(filename[1]) self.ModInfo[set]=ModInfo() self.ModInfo[set].initialise(pdbfile=filename[2]) if user_file: self.user_file[set]=pickle_file #print "creating",set if create>=2: self.save(set=set,filename=filename) return [2] obj = None try: f = open(pickle_file[2],'r') obj = pickle.load(f) #print "restore obj",obj except: # If this file is associated with a PDB file then give # user a waring message return [2,'Error reading file '+pickle_file[2]] if not set: import utils set = utils.fileRoot(filename[1]) #print "ModelInfo restore",set self.ModInfo[set] = obj if user_file:self.user_file[set]=pickle_file return [0] #----------------------------------------------------------------------- def delete(self,pickle_file='',exit='',filename=[],check=0,**keywords): #----------------------------------------------------------------------- #print "delete",exit,pickle_file if exit != 'delete': return import os import GUI if not pickle_file and filename : pickle_file=os.path.splitext(filename[2])[0] + '.ccp4mg' if not pickle_file or not os.path.exists(pickle_file): return 1 try: os.remove(pickle_file) except: GUI.GUI.insts.WarningMessage("Error attempting to delete file "+ \ pickle_file+ \ "\\nPlease remove it or there will be problems handling\\n"+ \ filename) return 2 return 0 #-------------------------------------------------------------------- def close(self,set='',check=1): #-------------------------------------------------------------------- ''' Close the data set ''' if self.ModInfo.has_key(set): del self.ModInfo[set] if self.user_file.has_key(set): del self.user_file[set] #--------------------------------------------------------------------- def list_loaded(self): #--------------------------------------------------------------------- ''' Return a list of the loaded sets of ModInfo ''' menu = self.user_file.keys() if menu.count('generic')>0: menu.remove('generic') return menu #--------------------------------------------------------------------- def interpret_set(self,set=''): #--------------------------------------------------------------------- # Ensure that set is a list - if wildcard then set default to all sets import types # Make sure its a list if not isinstance(set,types.ListType): set = [set] # Replace a '*' or '' with list of currently loaded user_file for i in range(len(set)): if set[i] == '*' or set[i] == '': set.pop(i) for item in self.user_file.keys(): set.insert(i,item) #print " interpret_set",set return set #------------------------------------------------------------------- def get_set(self,set=''): #------------------------------------------------------------------- # get all info relating to one coordinate file if self.ModInfo.has_key(set): #print "get_set",set,self.ModInfo[set] return self.ModInfo[set] else: return {} #--------------------------------------------------------------------- def set_set(self,set='',ModInfo = {}): #--------------------------------------------------------------------- #print "set_set",set,ModInfo self.ModInfo[set] = ModInfo #---------------------------------------------------------------------- def get_info(self,info='',set='',key='',first=0): #---------------------------------------------------------------------- ''' Return a status,dictionary where dictionary is the data of type 'info' (eg user_selection) from the given set(s) - or if set == '' or set=='*' then all sets either return a whole dictionary (key='') or dictionary with the item 'key' if first is true then only return first key that satisfies criteria ''' if not info: return [1,{}] # Ensure that set is a list - if wildcard then set default to all sets set = self.interpret_set(set) #if key == 'edit_secstr': print "get_info info,key,set",info,key,set, output = {} for s in set: #print "has_key", s,self.ModInfo.has_key(s) #if self.ModInfo.has_key(s): print "hasattr", hasattr(self.ModInfo[s],info) if self.ModInfo.has_key(s) and hasattr(self.ModInfo[s],info): data = getattr(self.ModInfo[s],info) #if key == 'edit_secstr': print "get_info data",self.ModInfo[s],data if key: if data.has_key(key): output[key]=data[key] if first: return [0,output] else: for k,v in data.items(): output[k]=v return [0,output] #---------------------------------------------------------------------- def add_info(self,info='',set='',key='',value='',pdbfile='',save=0): #---------------------------------------------------------------------- #print "ModelInfo.add_info",set,info,key,value if not set or not info or not key: return 1 changed = [] if not self.ModInfo.has_key(set): self.ModInfo[set]=ModInfo() self.ModInfo[set].initialise(pdbfile=pdbfile) if hasattr(self.ModInfo[set],info): dic = getattr(self.ModInfo[set],info) else: dic = {} dic[key]=value setattr(self.ModInfo[set],info,dic) changed.append(set) #print "add_info set",hasattr(self.ModInfo[set],info),getattr(self.ModInfo[set],info) if save: #save the edited set(s) for set in changed: self.save(set=set) return 0 #---------------------------------------------------------------------- def delete_info(self,info='',set='',key='',first=0,save=0): #---------------------------------------------------------------------- ''' Delete the data of type 'info' (eg user_selection) with given key optionally from the given set(s) ''' #print "delete_info",set,info,key set=self.interpret_set(set) if len(set)==1 and not self.ModInfo.has_key(set[0]): return 1 if not info or not key: return 2 changed = [] for s in set: if self.ModInfo.has_key(s) and hasattr(self.ModInfo[s],info): if key == '*': try: delattr(self.ModInfo[s],info) changed.append(s) except: pass else: try: dic = getattr(self.ModInfo[s],info) if dic.has_key(key): del dic[key] setattr(self.ModInfo[s],dic) changed.append(s) if first: return 0 except: pass if not changed: return 2 if save: #save the edited set(s) for set in changed: self.save(set=set) return 0 #----------------------------------------------------------------------- def get_protocol_menu(self,type='',set=''): #----------------------------------------------------------------------- ''' Get definitions for menus to select by amino acid/element/etc Precedence of definitions: from the model (from .ccp4mg), from generic or from selection_protocols.py file ''' import selection_protocols groups = getattr(selection_protocols,type+"_groups",{}) names = getattr(selection_protocols,type,{}) order = [] if names.has_key('ORDER'): for item in names['ORDER']:order.append(item) #print "get_protocol_menu first order",order,names status,dic=self.get_info(set=set,info='selection_protocols', \ key=type+'_groups') if not status and dic: for key,value in dic[type+'_groups'].items():groups[key]=value status,dic=self.get_info(set=set,info='selection_protocols', \ key=type) if (not status) and dic: for key,value in dic[type].items(): if key == 'ORDER': for item in value: if not order.count(item):order.append(item) else: names[key]=value #print "names",order,names menu = [] alias = [] if order: for item in order: if names.has_key(item): menu.append(names[item]) alias.append(item) else: menu.append(item) alias.append(item) else: menu = names.values() alias = names.keys() return [menu,alias,groups] #-------------------------------------------------------------------- def add_name(self,key='',set='',new_name=''): #-------------------------------------------------------------------- ''' Get a list of the residue/element types ''' import selection_protocols import types order = [] #print "add_name",key,new_name # BEware shallow copy... changes to order end up in selection_protocols std_sele = getattr(selection_protocols,key,{}) if std_sele.has_key('ORDER'): for item in std_sele['ORDER']: order.append(item) status,sel_prot= self.get_info(set=[set,'generic'], \ info='selection_protocols',key=key,first=1) if not sel_prot.has_key(key): sel_prot[key] = {} if sel_prot[key].has_key('ORDER'): for item in sel_prot[key]['ORDER']: if not order.count(item): order.append(item) if not order.count(new_name): order.append(new_name) #print "order",order sel_prot[key]['ORDER'] = order self.add_info(set=set, \ info='selection_protocols',key=key,value=sel_prot[key]) #-------------------------------------------------------------------- def get_names(self,key='',set=''): #-------------------------------------------------------------------- ''' Get a list of the residue/element types ''' import selection_protocols import types # BEware shallow copy... changes to order end up in selection_protocols order=[] if key == 'conflicts': return self.get_monomer_lib_conflicts() std_sele = getattr(selection_protocols,key,{}) if std_sele.has_key('ORDER'): for item in std_sele['ORDER']: order.append(item) status,sel_prot= self.get_info(set=[set,'generic'], \ info='selection_protocols',key=key,first=1) if not status and sel_prot.has_key(key): #sel_prot[key] can be either a list or a dictionary with an item 'ORDER' if isinstance(sel_prot[key],types.ListType): for item in sel_prot[key]: if not order.count(item):order.append(item) elif sel_prot[key].has_key('ORDER'): for item in sel_prot[key]['ORDER']: order.append(item) #print "get_names order",order return order #------------------------------------------------------------------------- def get_names_string(self,key='',set=''): #------------------------------------------------------------------------ name_list = self.get_names(key=key,set=set) if not name_list: return "" text = name_list[0] if len(name_list) <= 1: return text for item in name_list[1:]: text = text + ',' + item return text #------------------------------------------------------------------------ def get_monomer_lib_conflicts(self): #------------------------------------------------------------------------ import os,utils,glob if not ModelInfo.monomer_library_elements: monlib = os.path.join(utils.get_CCP4MG(),'data','monomer_library') search_path = os.path.join(os.environ["CCP4_MGDATA"],'monomer_library','*','*_EL.cif') element_files = glob.glob(search_path) #print 'ModelInfo.get_elements_from_monomer_lib', search_path, element_files ele_list = [] for item in element_files: ele_list.append(os.path.split(item)[-1][0:-7]) #print 'ModelInfo.get_elements_from_monomer_lib', ele_list ModelInfo.monomer_library_elements = ele_list return ModelInfo.monomer_library_elements #---------------------------------------------------------------------- def expand_selection_alias (self,alias='',set=''): #---------------------------------------------------------------------- ''' Get the expansion of a selection alias Precedence is given to user defined selections ''' expanded = [] # Is it a user defined selection - either associated with # the model itself or from any loaded .ccp4mg if set: set_list=[set,'generic'] else: set_list=['generic'] status,user_selection=self.get_info(set=[set,'generic'], \ info='user_selection',key=alias,first=1) if not status and user_selection: expanded = user_selection[alias] #print "MolData expanded",expanded # Is the alias a generic selection from selection_protocols file if not expanded: import selection_protocols expanded = selection_protocols.generic_selection.get(alias,None) #if expanded[1] == alias: expanded = None #print "initial expanded",expanded if expanded: expanded = self.apply_patches(input=expanded,set=set) #print "from apply_patches",expanded return expanded #------------------------------------------------------------------------ def apply_patches( self,input=[],set='' ): #------------------------------------------------------------------------ ''' Substitute for selection aliases such as 'amino_acid' - can be model specific definition of list of residue types / element types ''' #print "apply_patches",input,"set",set import re if not input: return input if input[0]==None: # Expand any residue/atom type/etc lists defn = input[1] #print "apply_patches defn",defn match = re.search('%([^%]+)%',defn) while match: type = match.groups()[0] names = self.get_names(key=type,set=set) #print "apply_patches type",type,names if not names: defn = re.sub('%'+type+'%','',defn) elif len(names) == 1: defn = re.sub('%'+type+'%',names[0],defn) else: sub = names[0] for item in names[1:]: sub = sub + ',' + item #print "type",type,"sub",sub defn = re.sub('%'+type+'%',sub,defn) match = re.search('%([^%]+)%',defn) #print "final expanded",[None,defn] return [None,defn] elif len(input)==2: return [input[0],self.apply_patches(input[1],set=set) ] elif len(input)>2: return [input[0],self.apply_patches(input[1],set=set), \ self.apply_patches(input[2],set=set)] else: return input #--------------------------------------------------------------- def save_picture_definition(self,pretty_print=None,style='method', set='',info='',keys=[] ): #--------------------------------------------------------------- alias = { 'user_selection' : 'SelectionScheme', 'user_colour_schemes' : 'ColourScheme',} if not alias.has_key(info): return pic_def_class = alias[info] import utils indent = 5 if style == 'method': b_end = ' )\n\n' b_start = alias[info] + ' (' else: b_end = '}' b_start = alias[info] + ' = {' stream = '' status,info_dict = self.get_info(set=set,info=info) #print "info_dict",info_dict if status: return '' if info == 'user_selection': status,info_selparams = self.get_info(set=set,info='user_selparams') import model_selection SP = model_selection.SelectionParser() if info == 'user_selection': for name,defn in info_dict.items(): if not keys or keys.count(name): com = SP.list_to_command(defn) if not com[0]: stream = stream+ b_start + \ utils.picture_defn_item('name',name,pretty_print,style=style) + \ utils.picture_defn_item('selection',com[1],pretty_print,style=style) if set == 'generic': stream = stream+utils.picture_defn_item('context','generic',pretty_print,style=style) if info_selparams.has_key(name): stream = stream+utils.picture_defn_item('selparams',info_selparams[name],pretty_print,style=style) stream = stream[0:-1] + b_end elif info == 'user_colour_schemes': for name,defn in info_dict.items(): if not keys or keys.count(name): output = [] for coldef in defn: com = SP.list_to_command(coldef[1]) if not com[0]: output.append([coldef[0],com[1]]) stream = stream+ b_start + \ utils.picture_defn_item('name',name,pretty_print,style=style) + \ utils.picture_defn_item('colours',output,pretty_print,style=style,indent=10) if set == 'generic': stream = stream+utils.picture_defn_item('context','generic',pretty_print,style=style) stream = stream[0:-1] + b_end return stream #--------------------------------------------------------------- def getColourSchemeNames(self,MolData=''): #--------------------------------------------------------------- scheme_list = [] #Create list of the sets to search sets = [] # NB the set should be the name label if MolData: sets.append(MolData) sets.append('generic') sets.extend(self.list_loaded()) for set in sets: status,user_colour_schemes = self.get_info( \ set=[set],info='user_colour_schemes') if not status: col_list = [] for col in user_colour_schemes.keys(): col_list.append(col) if col_list: scheme_list.append([set,col_list]) #print "getColourSchemes",scheme_list return scheme_list #---------------------------------------------------------------- #---------------------------------------------------------------- #---------------------------------------------------------------- class ModInfo: #---------------------------------------------------------------- #---------------------------------------------------------------- #---------------------------------------------------------------- # class to hold the data associted with coordinate file # saved as .ccp4mg file #--------------------------------------------------------------- def init(self): #--------------------------------------------------------------- pass #--------------------------------------------------------------- def initialise(self,pdbfile=''): #--------------------------------------------------------------- import version import utils self.ccp4mg_version = version.ccp4mg_version if pdbfile: self.pdbfile = pdbfile