1#A* ------------------------------------------------------------------- 2#B* This file contains source code for the PyMOL computer program 3#C* Copyright (c) Schrodinger, LLC. 4#D* ------------------------------------------------------------------- 5#E* It is unlawful to modify or remove this copyright notice. 6#F* ------------------------------------------------------------------- 7#G* Please see the accompanying LICENSE file for further information. 8#H* ------------------------------------------------------------------- 9#I* Additional authors of this source file include: 10#-* 11#-* 12#-* 13#Z* ------------------------------------------------------------------- 14 15from __future__ import print_function 16 17# must match layer1/Setting.h 18cSetting_tuple = -1 19cSetting_blank = 0 20cSetting_boolean = 1 21cSetting_int = 2 22cSetting_float = 3 23cSetting_float3 = 4 24cSetting_color = 5 25cSetting_string = 6 26 27if True: 28 29 import traceback 30 from . import selector 31 from .shortcut import Shortcut 32 cmd = __import__("sys").modules["pymol.cmd"] 33 from .cmd import _cmd,lock,lock_attempt,unlock,QuietException, \ 34 is_string, \ 35 _feedback,fb_module,fb_mask, \ 36 DEFAULT_ERROR, DEFAULT_SUCCESS, _raising, is_ok, is_error 37 38 # name -> index mapping 39 index_dict = _cmd.get_setting_indices() 40 41 # index -> name mapping 42 name_dict = dict((v,k) for (k,v) in index_dict.items()) 43 44 name_list = list(index_dict.keys()) 45 setting_sc = Shortcut(name_list) 46 47 # legacy 48 index_dict['ray_shadows'] = index_dict['ray_shadow'] 49 50 boolean_dict = { 51 "true" : 1, 52 "false": 0, 53 "on" : 1, 54 "off" : 0, 55 "1" : 1, 56 "0" : 0, 57 "1.0" : 1, 58 "0.0" : 0, 59 } 60 61 boolean_sc = Shortcut(boolean_dict.keys()) 62 63 def _get_index(name): 64 '''Get setting index for given name. `name` may be abbreviated. 65 Raises QuietException for unknown names or ambiguous abbreviations.''' 66 if isinstance(name, int) or name.isdigit(): 67 return int(name) 68 if name not in index_dict: 69 name = setting_sc.auto_err(name, 'Setting') 70 return index_dict[name] 71 72 def _get_name(index): 73 # legacy, in case someone used that in a script 74 return name_dict.get(index, "") 75 76 def get_index_list(): 77 # legacy, in case someone used that in a script (e.g. grepset) 78 return list(name_dict.keys()) 79 80 def get_name_list(): 81 return name_list 82 83 def _validate_value(type, value): 84 if type == cSetting_boolean: # (also support non-zero float for truth) 85 try: # number, non-zero, then interpret as TRUE 86 return 1 if float(value) else 0 87 except: 88 pass 89 return boolean_dict[boolean_sc.auto_err(str(value), "boolean")] 90 if type in (cSetting_int, cSetting_float): 91 if is_string(value) and boolean_sc.has_key(value): 92 value = boolean_dict[boolean_sc.auto_err(str(value), "boolean")] 93 if type == cSetting_int: 94 return int(value) 95 return float(value) 96 if type == cSetting_float3: # some legacy handling req. 97 if not is_string(value): 98 v = value 99 elif ',' in value: 100 v = cmd.safe_eval(value) 101 else: 102 v = value.split() 103 return (float(v[0]), float(v[1]), float(v[2])) 104 if type == cSetting_color: 105 return str(value) 106 if type == cSetting_string: 107 v = str(value) 108 # strip outermost quotes (cheesy approach) 109 if len(v) > 1 and v[0] == v[-1] and v[0] in ('"', "'"): 110 v = v[1:-1] 111 return v 112 raise Exception 113 114 ###### API functions 115 116 def set_bond(name, value, selection1, selection2=None, 117 state=0, updates=1, log=0, quiet=1, _self=cmd): 118 ''' 119DESCRIPTION 120 121 "set_bond" changes per-bond settings for all bonds which exist 122 between two selections of atoms. 123 124USAGE 125 126 set_bond name, value, selection1 [, selection2 ] 127 128ARGUMENTS 129 130 name = string: name of the setting 131 132 value = string: new value to use 133 134 selection1 = string: first set of atoms 135 136 selection2 = string: seconds set of atoms {default: (selection1)} 137 138EXAMPLE 139 140 set_bond stick_transparency, 0.7, */n+c+ca+o 141 142 143NOTES 144 145 The following per-bond settings are currently implemented. Others 146 may seem to be recognized but will currently have no effect when 147 set at the per-bond level. 148 149 * valence 150 * line_width 151 * line_color 152 * stick_radius 153 * stick_color 154 * stick_transparency 155 156 Note that if you attempt to use the "set" command with a per-bond 157 setting over a selection of atoms, the setting change will appear 158 to take, but no change will be observed. 159 160PYMOL API 161 162 cmd.set_bond ( string name, string value, 163 string selection1, 164 string selection2, 165 int state, int updates, log=0, quiet=1) 166 167 ''' 168 r = DEFAULT_ERROR 169 selection1 = selector.process(selection1) 170 selection2 = selector.process(selection2) if selection2 else selection1 171 index = _get_index(str(name)) 172 if log: 173 name = name_dict.get(index, name) 174 _self.log('', "cmd.set_bond('%s',%s,%s,%s,%s)\n" % (name, repr(value), 175 repr(selection1), repr(selection2), state)) 176 if True: 177 try: 178 _self.lock(_self) 179 type = _cmd.get_setting_type(index) 180 if type < 0: 181 print("Error: unable to get setting type.") 182 raise QuietException 183 try: 184 v = (type, _validate_value(type, value)) 185 r = _cmd.set_bond(_self._COb,int(index),v, 186 "("+selection1+")","("+selection2+")", 187 int(state)-1,int(quiet), 188 int(updates)) 189 except QuietException: 190 pass 191 except: 192 if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): 193 traceback.print_exc() 194 raise _self.pymol.CmdException("invalid value: %s" % repr(value)) 195 finally: 196 _self.unlock(r,_self) 197 if _self._raising(r,_self): raise QuietException 198 return r 199 200 201 def set(name, value=1, selection='', state=0, updates=1, log=0, 202 quiet=1,_self=cmd): 203 204 ''' 205DESCRIPTION 206 207 "set" changes global, object, object-state, or per-atom settings. 208 209USAGE 210 211 set name [,value [,selection [,state ]]] 212 213ARGUMENTS 214 215 name = string: setting name 216 217 value = string: a setting value {default: 1} 218 219 selection = string: name-pattern or selection-expression 220 {default:'' (global)} 221 222 state = a state number {default: 0 (per-object setting)} 223 224EXAMPLES 225 226 set orthoscopic 227 228 set line_width, 3 229 230 set surface_color, white, 1hpv 231 232 set sphere_scale, 0.5, elem C 233 234NOTES 235 236 The default behavior (with a blank selection) is global. If the 237 selection is "all", then the setting entry in each individual 238 object will be changed. Likewise, for a given object, if state is 239 zero, then the object setting will be modified. Otherwise, the 240 setting for the indicated state within the object will be 241 modified. 242 243 If a selection is provided as opposed to an object name, then the 244 atomic setting entries are modified. 245 246 The following per-atom settings are currently implemented. Others 247 may seem to be recognized but will have no effect when set on a 248 per-atom basis. 249 250 * sphere_color 251 * surface_color 252 * mesh_color 253 * label_color 254 * dot_color 255 * cartoon_color 256 * ribbon_color 257 * transparency (for surfaces) 258 * sphere_transparency 259 260 Note that if you attempt to use the "set" command with a per-bond 261 setting over a selection of atoms, the setting change will appear 262 to take, but no change will be observed. Please use the 263 "set_bond" command for per-bond settings. 264 265 266PYMOL API 267 268 cmd.set(string name, string value, string selection, int state, 269 int updates, int quiet) 270 271SEE ALSO 272 273 get, set_bond 274 275''' 276 r = DEFAULT_ERROR 277 selection = selector.process(selection) 278 index = _get_index(name) 279 if log: 280 name = name_dict.get(index, name) 281 _self.log('', "cmd.set('%s',%s,%s,%s)\n" % (name, repr(value), repr(selection), state)) 282 if True: 283 try: 284 _self.lock(_self) 285 type = _cmd.get_setting_type(index) 286 if type < 0: 287 print("Error: unable to get setting type.") 288 raise QuietException 289 try: 290 v = (type, _validate_value(type, value)) 291 r = _cmd.set(_self._COb,int(index),v, 292 selection, 293 int(state)-1,int(quiet), 294 int(updates)) 295 except QuietException: 296 pass 297 except: 298 if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): 299 traceback.print_exc() 300 raise _self.pymol.CmdException("invalid value: %s" % repr(value)) 301 finally: 302 _self.unlock(r,_self) 303 if _self._raising(r,_self): raise QuietException 304 return r 305 306 def unset(name, selection='', state=0, updates=1, log=0, quiet=1, _self=cmd): 307 ''' 308DESCRIPTION 309 310 "unset" clear non-global settings and zeros out global settings. 311 312USAGE 313 314 unset name [,selection [,state ]] 315 316EXAMPLE 317 318 unset orthoscopic 319 320 unset surface_color, 1hpv 321 322 unset sphere_scale, elem C 323 324NOTES 325 326 If selection is not provided, unset changes the named global 327 setting to a zero or off value. 328 329 If a selection is provided, then "unset" undefines per-object, 330 per-state, or per-atom settings. 331 332PYMOL API 333 334 cmd.unset(string name, string selection, int state, int updates, 335 int log) 336 337SEE ALSO 338 339 set, set_bond 340 341 ''' 342 r = DEFAULT_ERROR 343 selection = selector.process(selection) 344 index = _get_index(str(name)) 345 if log: 346 name = name_dict.get(index, name) 347 _self.log('', "cmd.unset('%s',%s,%s)\n" % (name, repr(selection), state)) 348 if True: 349 try: 350 _self.lock(_self) 351 try: 352 r = _cmd.unset(_self._COb,int(index),selection, 353 int(state)-1,int(quiet), 354 int(updates)) 355 except: 356 if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): 357 traceback.print_exc() 358 raise QuietException 359 print("Error: unable to unset setting value.") 360 finally: 361 _self.unlock(r,_self) 362 return r 363 364 def unset_bond(name,selection1,selection2=None,state=0,updates=1,log=0,quiet=1,_self=cmd): 365 ''' 366DESCRIPTION 367 368 "unset_bond" removes a per-bond setting for a given set of bonds. 369 370USAGE 371 372 unset name [,selection [, selection [,state ]]] 373 374 ''' 375 r = DEFAULT_ERROR 376 selection1 = selector.process(selection1) 377 selection2 = selector.process(selection2) if selection2 else selection1 378 index = _get_index(str(name)) 379 if log: 380 name = name_dict.get(index, name) 381 _self.log('', "cmd.unset_bond('%s',%s,%s,%s)\n" % (name, 382 repr(selection1), repr(selection2), state)) 383 if True: 384 try: 385 _self.lock(_self) 386 try: 387 r = _cmd.unset_bond(_self._COb,int(index),selection1,selection2, 388 int(state)-1,int(quiet), 389 int(updates)) 390 except: 391 if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): 392 traceback.print_exc() 393 raise QuietException 394 print("Error: unable to unset setting value.") 395 finally: 396 _self.unlock(r,_self) 397 if _self._raising(r,_self): raise QuietException 398 return r 399 400 def get_setting(name,object='',state=0,_self=cmd): # INTERNAL 401 return get_setting_tuple_new(name, object, state, _self)[1] 402 403 def get(name, selection='', state=0, quiet=1, _self=cmd): 404 ''' 405DESCRIPTION 406 407 "get" prints out the current value of a setting. 408 409USAGE 410 411 get name [, selection [, state ]] 412 413EXAMPLE 414 415 get line_width 416 417ARGUMENTS 418 419 name = string: setting name 420 421 selection = string: object name (selections not yet supported) 422 423 state = integer: state number 424 425NOTES 426 427 "get" currently only works with global, per-object, and per-state 428 settings. Atom level settings get be queried with "iterate" (e.g. 429 iterate all, print s.line_width) 430 431PYMOL API 432 433 cmd.get(string name, string object, int state, int quiet) 434 435SEE ALSO 436 437 set, set_bond, get_bond 438 439 ''' 440 441 state = int(state) 442 i = _get_index(name) 443 r = get_setting_text(i, str(selection), state, _self) 444 if is_ok(r) and (r is not None): 445 if not int(quiet): 446 name = name_dict.get(i, name) 447 r_str = str(r) 448 if len(r_str) > 200: 449 r_str = r_str[:185] + '... (truncated)' 450 if(selection==''): 451 print(" get: %s = %s"%(name,r_str)) 452 elif state<=0: 453 print(" get: %s = %s in object %s"%(name,r_str,selection)) 454 else: 455 print(" get: %s = %s in object %s state %d"%(name,r_str,selection,state)) 456 return r 457 458 def get_setting_tuple_new(name,object='',state=0,_self=cmd): # INTERNAL 459 i = _get_index(name) 460 with _self.lockcm: 461 return _cmd.get_setting_of_type(_self._COb, i, str(object), int(state) - 1, cSetting_tuple) 462 463 def get_setting_tuple(name,object='',state=0,_self=cmd): # INTERNAL 464 r = get_setting_tuple_new(name, object, state, _self) 465 if r[0] != cSetting_float3: 466 # legacy API 467 r = (r[0], (r[1],)) 468 return r 469 470 def get_setting_boolean(name,object='',state=0,_self=cmd): # INTERNAL 471 i = _get_index(name) 472 with _self.lockcm: 473 return _cmd.get_setting_of_type(_self._COb, i, str(object), int(state) - 1, cSetting_boolean) 474 475 def get_setting_int(name,object='',state=0,_self=cmd): # INTERNAL 476 i = _get_index(name) 477 with _self.lockcm: 478 return _cmd.get_setting_of_type(_self._COb, i, str(object), int(state) - 1, cSetting_int) 479 480 def get_setting_float(name,object='',state=0,_self=cmd): # INTERNAL 481 i = _get_index(name) 482 with _self.lockcm: 483 return _cmd.get_setting_of_type(_self._COb, i, str(object), int(state) - 1, cSetting_float) 484 485 def get_setting_text(name,object='',state=0,_self=cmd): # INTERNAL 486 i = _get_index(name) 487 with _self.lockcm: 488 return _cmd.get_setting_of_type(_self._COb, i, str(object), int(state) - 1, cSetting_string) 489 490 def get_setting_updates(object='', state=0, _self=cmd): # INTERNAL 491 r = [] 492 if lock_attempt(_self): 493 try: 494 r = _cmd.get_setting_updates(_self._COb, object, state-1) 495 finally: 496 _self.unlock(r,_self) 497 return r 498 499 def get_bond(name, selection1, selection2=None, 500 state=0, updates=1, quiet=1, _self=cmd): 501 ''' 502DESCRIPTION 503 504 "get_bond" gets per-bond settings for all bonds which exist 505 between two selections of atoms. 506 507USAGE 508 509 get_bond name, selection1 [, selection2 ] 510 511ARGUMENTS 512 513 name = string: name of the setting 514 515 selection1 = string: first set of atoms 516 517 selection2 = string: seconds set of atoms {default: (selection1)} 518 519EXAMPLE 520 521 get_bond stick_transparency, */n+c+ca+o 522 523 524NOTES 525 526 The following per-bond settings are currently implemented. Others 527 may seem to be recognized but will currently have no effect when 528 set at the per-bond level. 529 530 * valence 531 * line_width 532 * line_color 533 * stick_radius 534 * stick_color 535 * stick_transparency 536 537PYMOL API 538 539 cmd.get_bond ( string name, 540 string selection1, 541 string selection2, 542 int state, int updates, quiet=1) 543 544 ''' 545 state, quiet = int(state), int(quiet) 546 r = DEFAULT_ERROR 547 selection1 = selector.process(selection1) 548 selection2 = selector.process(selection2) if selection2 else selection1 549 550 index = _get_index(str(name)) 551 if True: 552 try: 553 _self.lock(_self) 554 try: 555 r = _cmd.get_bond(_self._COb,int(index), 556 "("+selection1+")","("+selection2+")", 557 int(state)-1,int(quiet), 558 int(updates)) 559 except: 560 traceback.print_exc() 561 if(_feedback(fb_module.cmd,fb_mask.debugging,_self)): 562 traceback.print_exc() 563 print("Error: unable to get_bond info.") 564 raise QuietException 565 finally: 566 _self.unlock(r,_self) 567 if _self._raising(r,_self): raise QuietException 568 if not quiet: 569 name = name_dict.get(index, name) 570 suffix = ' state %d' % state if state > 0 else '' 571 for model, vlist in r: 572 print(' %s = %s for object %s' % (name, _self.get(name, model), model)) 573 for idx1, idx2, value in vlist: 574 if value is None: 575 continue 576 print(' %s = %s between (%s`%d)-(%s`%d%s)' % (name, 577 value, model, idx1, model, idx2, suffix)) 578 return r 579 580 def unset_deep(settings='', object='*', updates=1, quiet=1, _self=cmd): 581 ''' 582DESCRIPTION 583 584 Unset all object, object-state, atom, and bond level settings. 585 586 Note: Does currently NOT unset atom-state level settings. Check for 587 atom-state level settings with: 588 PyMOL> iterate_state 1, *, print(list(s)) 589 Unset e.g. atom-state level "label_screen_point" (index 728) with: 590 PyMOL> alter_state 1, *, del s[728] 591 592ARGUMENTS 593 594 settings = str: space separated list of setting names or empty string 595 for all settings {default: } 596 597 object = str: name of one object or * for all objects {default: *} 598 ''' 599 quiet = int(quiet) 600 kwargs = {'quiet': quiet, 'updates': 0, '_self': _self} 601 602 if not settings: 603 settings = iter(name_dict) # index iterator 604 elif _self.is_string(settings): 605 settings = settings.split() 606 607 if object in ['all', '*']: 608 object = '*' 609 selection = '(*)' 610 else: 611 selection = None 612 try: 613 if _self.get_type(object) in ( 614 'object:group', 'object:molecule'): 615 selection = '(' + object + ')' 616 except: 617 pass 618 619 # 0 (object-level) and 1-N (object-state-level) 620 states = range(_self.count_states(object) + 1) 621 622 for setting in settings: 623 try: 624 for state in states: 625 unset(setting, object, state=state, **kwargs) 626 if selection: 627 unset(setting, selection, **kwargs) 628 except: 629 if not quiet: 630 print(' Setting: %s unset failed' % setting) 631 632 if int(updates): 633 _self.rebuild(object) 634