modules/pymol/setting.py (529 lines of code) (raw):

#A* ------------------------------------------------------------------- #B* This file contains source code for the PyMOL computer program #C* Copyright (c) Schrodinger, LLC. #D* ------------------------------------------------------------------- #E* It is unlawful to modify or remove this copyright notice. #F* ------------------------------------------------------------------- #G* Please see the accompanying LICENSE file for further information. #H* ------------------------------------------------------------------- #I* Additional authors of this source file include: #-* #-* #-* #Z* ------------------------------------------------------------------- from __future__ import print_function if __name__=='pymol.setting': import traceback import string import types from . import selector from .shortcut import Shortcut cmd = __import__("sys").modules["pymol.cmd"] from .cmd import _cmd,lock,lock_attempt,unlock,QuietException, \ is_string, \ _feedback,fb_module,fb_mask, \ DEFAULT_ERROR, DEFAULT_SUCCESS, _raising, is_ok, is_error import re boolean_type = 1 int_type = 2 float_type = 3 float3_type = 4 self = cmd # name -> index mapping index_dict = _cmd.get_setting_indices() # index -> name mapping name_dict = dict((v,k) for (k,v) in index_dict.items()) name_list = list(index_dict.keys()) setting_sc = Shortcut(name_list) # legacy index_dict['ray_shadows'] = index_dict['ray_shadow'] # legacy, in case someone used that in a script class SettingIndex: def __getattr__(self, name): return index_dict[name] boolean_dict = { "true" : 1, "false": 0, "on" : 1, "off" : 0, "1" : 1, "0" : 0, "1.0" : 1, "0.0" : 0, } boolean_sc = Shortcut(boolean_dict.keys()) def _get_index(name): '''Get setting index for given name. `name` may be abbreviated. Raises QuietException for unknown names or ambiguous abbreviations.''' if isinstance(name, int) or name.isdigit(): return int(name) if name not in index_dict: name = setting_sc.auto_err(name, 'Setting') return index_dict[name] def _get_name(index): # legacy, in case someone used that in a script return name_dict.get(index, "") def get_index_list(): # legacy, in case someone used that in a script (e.g. grepset) return list(name_dict.keys()) def get_name_list(): return name_list def _validate_value(type, value): if type==1: # boolean (also support non-zero float for truth) try: # number, non-zero, then interpret as TRUE return 1 if float(value) else 0 except: pass return boolean_dict[boolean_sc.auto_err(str(value), "boolean")] if type < 4: if is_string(value) and boolean_sc.has_key(value): value = boolean_dict[boolean_sc.auto_err(str(value), "boolean")] if type == 2: return int(value) return float(value) if type==4: # float3 - some legacy handling req. if not is_string(value): v = value elif ',' in value: v = eval(value) else: v = value.split() return (float(v[0]), float(v[1]), float(v[2])) if type==5: # color return str(value) if type==6: # string v = str(value) # strip outermost quotes (cheesy approach) if len(v) > 1 and v[0] == v[-1] and v[0] in ('"', "'"): v = v[1:-1] return v raise Exception ###### API functions def set_bond(name, value, selection1, selection2=None, state=0, updates=1, log=0, quiet=1, _self=cmd): ''' DESCRIPTION "set_bond" changes per-bond settings for all bonds which exist between two selections of atoms. USAGE set_bond name, value, selection1 [, selection2 ] ARGUMENTS name = string: name of the setting value = string: new value to use selection1 = string: first set of atoms selection2 = string: seconds set of atoms {default: (selection1)} EXAMPLE set_bond stick_transparency, 0.7, */n+c+ca+o NOTES The following per-bond settings are currently implemented. Others may seem to be recognized but will currently have no effect when set at the per-bond level. * valence * line_width * line_color * stick_radius * stick_color * stick_transparency Note that if you attempt to use the "set" command with a per-bond setting over a selection of atoms, the setting change will appear to take, but no change will be observed. PYMOL API cmd.set_bond ( string name, string value, string selection1, string selection2, int state, int updates, log=0, quiet=1) ''' r = DEFAULT_ERROR selection1 = selector.process(selection1) selection2 = selector.process(selection2) if selection2 else selection1 index = _get_index(str(name)) if log: name = name_dict.get(index, name) _self.log('', "cmd.set_bond('%s',%s,%s,%s,%s)\n" % (name, repr(value), repr(selection1), repr(selection2), state)) if True: try: _self.lock(_self) type = _cmd.get_setting_type(index) if type < 0: print("Error: unable to get setting type.") raise QuietException try: v = (type, _validate_value(type, value)) r = _cmd.set_bond(_self._COb,int(index),v, "("+selection1+")","("+selection2+")", int(state)-1,int(quiet), int(updates)) except QuietException: pass except: if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): traceback.print_exc() raise _self.pymol.CmdException("invalid value: %s" % repr(value)) finally: _self.unlock(r,_self) if _self._raising(r,_self): raise QuietException return r def set(name, value=1, selection='', state=0, updates=1, log=0, quiet=1,_self=cmd): ''' DESCRIPTION "set" changes global, object, object-state, or per-atom settings. USAGE set name [,value [,selection [,state ]]] ARGUMENTS name = string: setting name value = string: a setting value {default: 1} selection = string: name-pattern or selection-expression {default:'' (global)} state = a state number {default: 0 (per-object setting)} EXAMPLES set orthoscopic set line_width, 3 set surface_color, white, 1hpv set sphere_scale, 0.5, elem C NOTES The default behavior (with a blank selection) is global. If the selection is "all", then the setting entry in each individual object will be changed. Likewise, for a given object, if state is zero, then the object setting will be modified. Otherwise, the setting for the indicated state within the object will be modified. If a selection is provided as opposed to an object name, then the atomic setting entries are modified. The following per-atom settings are currently implemented. Others may seem to be recognized but will have no effect when set on a per-atom basis. * sphere_color * surface_color * mesh_color * label_color * dot_color * cartoon_color * ribbon_color * transparency (for surfaces) * sphere_transparency Note that if you attempt to use the "set" command with a per-bond setting over a selection of atoms, the setting change will appear to take, but no change will be observed. Please use the "set_bond" command for per-bond settings. PYMOL API cmd.set(string name, string value, string selection, int state, int updates, int quiet) SEE ALSO get, set_bond ''' r = DEFAULT_ERROR selection = selector.process(selection) index = _get_index(name) if log: name = name_dict.get(index, name) _self.log('', "cmd.set('%s',%s,%s,%s)\n" % (name, repr(value), repr(selection), state)) if True: try: _self.lock(_self) type = _cmd.get_setting_type(index) if type < 0: print("Error: unable to get setting type.") raise QuietException try: v = (type, _validate_value(type, value)) r = _cmd.set(_self._COb,int(index),v, selection, int(state)-1,int(quiet), int(updates)) except QuietException: pass except: if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): traceback.print_exc() raise _self.pymol.CmdException("invalid value: %s" % repr(value)) finally: _self.unlock(r,_self) if _self._raising(r,_self): raise QuietException return r def unset(name, selection='', state=0, updates=1, log=0, quiet=1, _self=cmd): ''' DESCRIPTION "unset" clear non-global settings and zeros out global settings. USAGE unset name [,selection [,state ]] EXAMPLE unset orthoscopic unset surface_color, 1hpv unset sphere_scale, elem C NOTES If selection is not provided, unset changes the named global setting to a zero or off value. If a selection is provided, then "unset" undefines per-object, per-state, or per-atom settings. PYMOL API cmd.unset(string name, string selection, int state, int updates, int log) SEE ALSO set, set_bond ''' r = DEFAULT_ERROR selection = selector.process(selection) index = _get_index(str(name)) if log: name = name_dict.get(index, name) _self.log('', "cmd.unset('%s',%s,%s)\n" % (name, repr(selection), state)) if True: try: _self.lock(_self) try: r = _cmd.unset(_self._COb,int(index),selection, int(state)-1,int(quiet), int(updates)) except: if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): traceback.print_exc() raise QuietException print("Error: unable to unset setting value.") finally: _self.unlock(r,_self) return r def unset_bond(name,selection1,selection2=None,state=0,updates=1,log=0,quiet=1,_self=cmd): ''' DESCRIPTION "unset_bond" removes a per-bond setting for a given set of bonds. USAGE unset name [,selection [, selection [,state ]]] ''' r = DEFAULT_ERROR selection1 = selector.process(selection1) selection2 = selector.process(selection2) if selection2 else selection1 index = _get_index(str(name)) if log: name = name_dict.get(index, name) _self.log('', "cmd.unset_bond('%s',%s,%s,%s)\n" % (name, repr(selection1), repr(selection2), state)) if True: try: _self.lock(_self) try: r = _cmd.unset_bond(_self._COb,int(index),selection1,selection2, int(state)-1,int(quiet), int(updates)) except: if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): traceback.print_exc() raise QuietException print("Error: unable to unset setting value.") finally: _self.unlock(r,_self) if _self._raising(r,_self): raise QuietException return r def get_setting(name,object='',state=0,_self=cmd): # INTERNAL r = DEFAULT_ERROR i = _get_index(name) try: _self.lock(_self) r = _cmd.get_setting_tuple(_self._COb,i,str(object),int(state)-1) typ = r[0] if typ<3: # boolean, int value = int(r[1][0]) elif typ<4: # float value = r[1][0] elif typ<5: # vector value = r[1] else: value = r[1] # color or string finally: _self.unlock(r,_self) if is_ok(r): return value elif _self._raising(r,_self): raise QuietException return r def get(name, selection='', state=0, quiet=1, _self=cmd): ''' DESCRIPTION "get" prints out the current value of a setting. USAGE get name [, selection [, state ]] EXAMPLE get line_width ARGUMENTS name = string: setting name selection = string: object name (selections not yet supported) state = integer: state number NOTES "get" currently only works with global, per-object, and per-state settings. Atom level settings get be queried with "iterate" (e.g. iterate all, print s.line_width) PYMOL API cmd.get(string name, string object, int state, int quiet) SEE ALSO set, set_bond, get_bond ''' r = DEFAULT_ERROR state = int(state) i = _get_index(name) try: _self.lock(_self) r = _cmd.get_setting_text(_self._COb,i,str(selection),state-1) finally: _self.unlock(r,_self) if is_ok(r) and (r!=None): if not int(quiet): name = name_dict.get(i, name) r_str = str(r) if len(r_str) > 200: r_str = r_str[:185] + '... (truncated)' if(selection==''): print(" get: %s = %s"%(name,r_str)) elif state<=0: print(" get: %s = %s in object %s"%(name,r_str,selection)) else: print(" get: %s = %s in object %s state %d"%(name,r_str,selection,state)) if _self._raising(r,_self): raise QuietException return r def get_setting_tuple_new(name,object='',state=0,_self=cmd): # INTERNAL r = DEFAULT_ERROR i = _get_index(name) try: _self.lock(_self) r = _cmd.get_setting_tuple(_self._COb,i,str(object),int(state)-1) finally: _self.unlock(r,_self) if _self._raising(r,_self): raise QuietException return r def get_setting_tuple(name,object='',state=0,_self=cmd): # INTERNAL r = get_setting_tuple_new(name, object, state, _self) if r[0] != 4: # legacy API r = (r[0], (r[1],)) return r def get_setting_boolean(name,object='',state=0,_self=cmd): # INTERNAL r = DEFAULT_ERROR i = _get_index(name) try: _self.lock(_self) r = _cmd.get_setting_of_type(_self._COb,i,str(object),int(state)-1,1) finally: _self.unlock(r,_self) if _self._raising(r,_self): raise QuietException return r def get_setting_int(name,object='',state=0,_self=cmd): # INTERNAL r = DEFAULT_ERROR i = _get_index(name) try: _self.lock(_self) r = _cmd.get_setting_of_type(_self._COb,i,str(object),int(state)-1,2) finally: _self.unlock(r,_self) return r def get_setting_float(name,object='',state=0,_self=cmd): # INTERNAL r = DEFAULT_ERROR i = _get_index(name) try: _self.lock(_self) r = _cmd.get_setting_of_type(_self._COb,i,str(object),int(state)-1,3) finally: _self.unlock(r,_self) if _self._raising(r,_self): raise QuietException return r def get_setting_text(name,object='',state=0,_self=cmd): # INTERNAL r = DEFAULT_ERROR i = _get_index(name) try: _self.lock(_self) r = _cmd.get_setting_text(_self._COb,i,str(object),int(state)-1) finally: _self.unlock(r,_self) if _self._raising(r,_self): raise QuietException return r def get_setting_updates(object='', state=0, _self=cmd): # INTERNAL r = [] if lock_attempt(_self): try: r = _cmd.get_setting_updates(_self._COb, object, state-1) finally: _self.unlock(r,_self) return r def get_bond(name, selection1, selection2=None, state=0, updates=1, quiet=1, _self=cmd): ''' DESCRIPTION "get_bond" gets per-bond settings for all bonds which exist between two selections of atoms. USAGE get_bond name, selection1 [, selection2 ] ARGUMENTS name = string: name of the setting selection1 = string: first set of atoms selection2 = string: seconds set of atoms {default: (selection1)} EXAMPLE get_bond stick_transparency, */n+c+ca+o NOTES The following per-bond settings are currently implemented. Others may seem to be recognized but will currently have no effect when set at the per-bond level. * valence * line_width * line_color * stick_radius * stick_color * stick_transparency PYMOL API cmd.get_bond ( string name, string selection1, string selection2, int state, int updates, quiet=1) ''' state, quiet = int(state), int(quiet) r = DEFAULT_ERROR selection1 = selector.process(selection1) selection2 = selector.process(selection2) if selection2 else selection1 index = _get_index(str(name)) if True: try: _self.lock(_self) try: r = _cmd.get_bond(_self._COb,int(index), "("+selection1+")","("+selection2+")", int(state)-1,int(quiet), int(updates)) except: traceback.print_exc() if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): traceback.print_exc() print("Error: unable to get_bond info.") raise QuietException finally: _self.unlock(r,_self) if _self._raising(r,_self): raise QuietException if not quiet: name = name_dict.get(index, name) suffix = ' state %d' % state if state > 0 else '' for model, vlist in r: print(' %s = %s for object %s' % (name, _self.get(name, model), model)) for idx1, idx2, value in vlist: if value is None: continue print(' %s = %s between (%s`%d)-(%s`%d%s)' % (name, value, model, idx1, model, idx2, suffix)) return r def unset_deep(settings='', object='*', updates=1, quiet=1, _self=cmd): ''' DESCRIPTION Unset all object, object-state, atom, and bond level settings. Note: Does currently NOT unset atom-state level settings. Check for atom-state level settings with: PyMOL> iterate_state 1, *, print list(s) Unset e.g. atom-state level "label_screen_point" (index 728) with: PyMOL> alter_state 1, *, del s[728] ARGUMENTS settings = str: space separated list of setting names or empty string for all settings {default: } object = str: name of one object or * for all objects {default: *} ''' quiet = int(quiet) kwargs = {'quiet': quiet, 'updates': 0, '_self': _self} if not settings: settings = iter(name_dict) # index iterator elif _self.is_string(settings): settings = settings.split() if object in ['all', '*']: object = '*' selection = '(*)' else: selection = None try: if _self.get_type(object) in ( 'object:group', 'object:molecule'): selection = '(' + object + ')' except: pass # 0 (object-level) and 1-N (object-state-level) states = range(_self.count_states(object) + 1) for setting in settings: try: for state in states: unset(setting, object, state=state, **kwargs) if selection: unset(setting, selection, **kwargs) except: if not quiet: print(' Setting: %s unset failed' % setting) if int(updates): _self.rebuild(object)