modules/pymol/invocation.py (464 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, absolute_import
# invocation.py
#
# This module unifies argument handling for embedded and modular PyMOL
#
helptext1 = '''Copyright (C) Schrodinger, LLC
Usage: pymol [OPTIONS]... [FILES]... [-- CUSTOM SCRIPT ARGUMENTS]
Options
--help display this help and exit
--version display PyMOL version and exit
--retina use retina resolution (MacPyMOL) and set display_scale_factor=2
--gldebug use glDebugMessageCallback for GL debugging
--testing run pymol testing
-1 config_mouse one_button
-2 config_mouse two_button
-a N alias for -A
-A N application configuration:
-A1 simple viewer window (-qxiF -X 68 -Y 100)
-A3 internal GUI only, no splash (-qx -X 68 -Y 100)
-A4 used by PYMOLVIEWER (-X 68 -Y 100)
-A5 helper application (-QxiICUF -X 68 -Y 100)
-A6 full screen presentation (-qxieICUPF)
-b[N] benchmark wizard
-B (DEPRECATED)
-c launch in command-line only mode for batch processing
-C don't terminate on Ctrl-C
-d cmd execute PyMOL command
-D N defer_builds_mode=N
-e full screen
-E N multisampling (GL_MULTISAMPLE_ARB)
-f N internal_feedback=N
-F internal_feedback=0
-g file save image (png) or movie (mpg)
-G game mode (DEPRECATED)
-h generic helper application (no controls, no feedback)
-H N window height in pixels
-i internal_gui=0
-I auto_reinitialize=1 (Mac only)
-j side-by-side stereo (stereo_mode=4)
-J cd to user's home directory
-k don't load pymolrc or plugins
-K keep alive: when running without a GUI, don't quit after the input
is exhausted
-l file run python script in thread (spawn)
-L file load file after everything else (only if something was loaded before)
-m INTERNAL - do not use (mac external GUI)
-M force mono
-n INTERNAL - do not use (incentive_product=1)
-N name UNSUPPORTED - external gui type (pmg_qt or pmg_tk) (same as -w)
-o disable security protections
-O N sphere_mode=N
-p read commands from STDIN
-P handle scenes as if the session were opened in presentation mode
-q supress startup message
-Q quiet, suppress all text output
-r file run python script
-R launch RPC Server
-s file log to file
-S force stereo
-t N stereo_mode=N
-T name UNSUPPORTED - Tcl/Tk GUI skin
-u file resume log file (execute existing content and append new log output)
-U UNSUPPORTED reuse the helper application
-v UNUSED
-V N external GUI window height in pixels
-w name UNSUPPORTED - external gui type (pmg_qt or pmg_tk) (same as -N)
-W N window width in pixels
-x no external gui
-X N window x position on screen
-y exit on error
-Y N window y position on screen
-z N window_visible=N
-Z N zoom_mode=N
File Extensions
pdb,sdf,... molecular structure files
ccp4,dx,... map files
py,pym,pyc python script
pml PyMOL command script
p5m implies -A5 (PDB File)
psw implies -A6 (PyMOL Show File)
pwg PyMOL web GUI
Active "pymolrc" Files
'''
helptext2 = '''
Mail bug reports to https://lists.sourceforge.net/lists/listinfo/pymol-users
'''
if __name__=='pymol.invocation':
import copy
import re
import os
import glob
import sys
import traceback
pymolrc_pat1 = '.pymolrc*'
pymolrc_pat2 = 'pymolrc*'
ros_pat = 'run_on_startup*'
class generic:
pass
global_options = generic();
options = global_options
options.deferred = []
options.no_gui = 0
options.internal_gui = 1
options.internal_feedback = 1
options.external_gui = 1
options.force_stereo = -1 if sys.platform == 'darwin' else 0
options.game_mode = 0
options.gui = 'pmg_qt'
options.skin = 'normal'
options.show_splash = 1
options.read_stdin = 0
options.win_x = 640
options.win_y = 480
options.win_xy_set = False
options.win_px = 4
options.sigint_handler = 1 # terminate on Ctrl-C?
options.reuse_helper = 0
options.auto_reinitialize = 0
options.keep_thread_alive = 0
options.after_load_script = ""
options.quiet = 0
options.multisample = 0
options.incentive_product = 0
options.window_visible = 1
options.presentation = 0
options.defer_builds_mode = 0
options.full_screen = 0
options.sphere_mode = -1
options.stereo_capable = 0
options.stereo_mode = 0
options.zoom_mode = -1
options.no_quit = 0
options.plugins = 2
options.exit_on_error = 0
options.pymolrc = None
options.retina = 0
options.no_spacenav = 0
options.launch_status = 0
options.gldebug = 0
options.testing = 0
options.win_py = { 'irix':240,
'darwin': 214, # hmm...need to set to 192 for Leopard?...
'linux2': 220,
'win32' : 230}.get(sys.platform,200)
options.ext_y = 168 # external gui height (eg. for Tcl/Tk top bar)
options.blue_line = 0
# Greg Landrum
options.rpcServer = 0
# end
options.security = 1
script_re = re.compile(r"pymolrc$|\.pml$|\.PML$|\.p1m$|\.P1M$")
py_re = re.compile(r"\.py$|\.pym$|\.PY$|\.PYM$")
def get_pwg_options(filename):
for line in open(filename, 'rU'):
a = line.split()
if not a or a[0].startswith('#'):
continue
if a[0].lower() == 'options':
return a[1:]
return []
def get_personal_folder():
if sys.platform.startswith('win'):
try:
try:
import _winreg as winreg
except ImportError:
import winreg
with winreg.OpenKey(winreg.HKEY_CURRENT_USER,
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders') as key:
return winreg.QueryValueEx(key, "Personal")[0]
except:
print(' Warning: failed to query "My Documents" from registry')
return os.path.expanduser('~')
def get_user_config():
for d in [os.getcwd(), '$HOME', '$HOMEDRIVE$HOMEPATH', '$PYMOL_PATH']:
d = os.path.expandvars(d)
for pat in [pymolrc_pat1, pymolrc_pat2]:
lst = glob.glob(d + os.sep + pat)
if lst:
break
if lst:
break
# global run_on_startup script (not overridden by pymolrc files, but is disabled by "-k")
if "PYMOL_PATH" in os.environ:
first = glob.glob(os.environ['PYMOL_PATH']+"/"+ros_pat)
else:
first = []
second = []
for a in lst:
if py_re.search(a):
first.append(a) # preceeding "_ " cloaks
elif script_re.search(a):
second.append(a) # preceeding "_ " cloaks
first.sort()
second.sort()
return first+second
def parse_args(argv, _pymol=None, options=None, restricted=0):
if not restricted:
global _argv
_argv = copy.deepcopy(argv) # pymol.invocation._argv
global global_options
if options == None:
if _pymol==None:
options = global_options
else:
options = _pymol.invocation.options
av = copy.deepcopy(argv)
av = av[1:] # throw out the executable path
av.reverse()
once_dict = {}
options.deferred = []
final_actions = []
loaded_something = 0
python_script = None
# append user settings file as an option
pymolrc = get_user_config()
while 1:
if not len(av):
break
a = av.pop()
a = re.sub(r'''^"|"$|^'|'$''','',a) # strip extra quotes
if a[0:1]=='-':
if (a[1:2]=='-'):
if a in ('--version', '--help'):
import pymol
print(pymol.get_version_message())
if a == '--help':
print(helptext1)
if pymolrc:
for filename in pymolrc:
print(' ' + filename)
else:
print(' (no pymolrc file found)')
print(helptext2)
sys.exit()
elif a == "--retina":
options.retina = 1
elif a == "--nospnav":
print(' Warning: --nospnav not available in Open-Source PyMOL')
elif a == "--gldebug":
options.gldebug = 1
elif a == "--testing":
options.testing = 1
else:
# double hypen signals end of PyMOL arguments
if python_script == None:
python_script = argv[0]
rev_av = copy.deepcopy(av)
rev_av.reverse()
if len(a)>2:
sys.argv = [python_script] + [a] + rev_av
else:
sys.argv = [python_script] + rev_av
break
continue
if ("A" in a) or ("a" in a): # application configuration
new_args = []
# ====== mode 1 - simple viewer window ======
if a[2:3] == "1":
if 'A1' not in once_dict:
once_dict['A1'] = 1
new_args = ["-qxiF",
"-X","68",
"-Y","100",
]
# ====== mode 2 - not available -- clashes with -2 =======
# ====== mode 3 - internal GUI only no splash ======
if a[2:3] == "3":
if 'A3' not in once_dict:
once_dict['A3'] = 1
new_args = ["-qx",
"-X","68",
"-Y","100",
]
# ====== mode 4 - internal GUI only with splash ======
if a[2:3] == "4": # used by PYMOLVIEWER
if 'A4' not in once_dict:
once_dict['A4'] = 1
new_args = [
"-X","68",
"-Y","100",
]
# ====== mode 5 - mode 5 helper application ======
if a[2:3] == "5":
if 'A5' not in once_dict:
once_dict['A5'] = 1
new_args = ["-QxiICUF",
"-X","68",
"-Y","100",
]
# ====== mode 6 - mode 6 presentation (no GUI) ======
if a[2:3] == "6":
if 'A6' not in once_dict:
once_dict['A6'] = 1
new_args = ["-qxieICUPF",
]
# ===============================================
new_args.reverse()
av = av + new_args
if "1" in a[1:2]:
options.deferred.append("_do__ config_mouse one_button")
if "2" in a[1:2]:
options.deferred.append("_do__ config_mouse two_button")
if "q" in a:
options.show_splash = 0
if "i" in a:
options.internal_gui = 0
if "f" in a:
options.internal_feedback = int(av.pop())
if "F" in a:
options.internal_feedback = 0
if "B" in a:
options.blue_line = 1
if "E" in a:
options.multisample = int(av.pop())
if "P" in a:
options.presentation = 1
if "W" in a:
options.win_x = int(av.pop())
options.win_xy_set = True
if "H" in a:
options.win_y = int(av.pop())
options.win_xy_set = True
if "X" in a:
options.win_px = int(av.pop())
if "y" in a:
options.exit_on_error = 1
if "Y" in a:
options.win_py = int(av.pop())
if "D" in a:
options.defer_builds_mode = int(av.pop())
if "V" in a:
options.ext_y = int(av.pop())
if "N" in a: # external gui name...
options.gui = av.pop()
if "x" in a:
options.external_gui = 0
if "n" in a:
options.incentive_product = 1
if "t" in a: # type of stereo to use
options.stereo_mode = int(av.pop())
if "T" in a: # what skin to use?
options.skin = str(av.pop())
if "w" in a: # what gui to use
options.gui = str(av.pop())
if "O" in a:
options.sphere_mode = int(av.pop())
if "z" in a:
options.window_visible = 0
if "Z" in a:
options.zoom_mode = int(av.pop())
if options.zoom_mode==5:
final_actions.append("_do__ zoom")
if not restricted:
if "c" in a:
options.no_gui=1
options.external_gui=0
if "m" in a: # mac external GUI
if options.external_gui == 2:
options.external_gui = 3
if options.win_py == 184: # mac external GUI default
options.win_py = 216
else:
options.external_gui = 2
options.win_py = 184
if "e" in a:
options.full_screen = 1
if "G" in a: # Game mode (reqd for Mac stereo)
options.game_mode = 1
options.win_x = 1024
options.win_y = 768
if "S" in a: # Force stereo context on stereo-capable hardware
options.force_stereo = 1
if options.stereo_mode == 0:
options.stereo_mode = 1 # quadbuffer
if sys.platform=='darwin':
options.deferred.append(
"_do__ set stereo_double_pump_mono,1,quiet=1")
if "M" in a: # Force mono on stereo hardware (all)
options.force_stereo = -1
if "j" in a: # Geowall: two side-by-side images
options.stereo_mode = 4
options.deferred.append("_do__ stereo on")
if ("d" in a):
options.deferred.append(
"_do_" + av.pop().replace('%',' '))
if ("J" in a): # cd to user's home directory on startup (if possible)
path = get_personal_folder()
try:
# immediatly chdir (was: options.deferred.append(...))
os.chdir(path)
# clear PYMOL_WD, which may be set by MacPyMOL
os.environ.pop('PYMOL_WD', None)
except OSError:
print(" Error: could not chdir to", repr(path))
if ("l" in a):
options.deferred.append("_do_spawn %s"%av.pop())
if ("r" in a):
options.deferred.append("_do_run %s,main"%av.pop())
if ("u" in a):
options.deferred.append("_do_resume %s"%av.pop())
if ("s" in a):
options.deferred.append("_do_log_open %s"%av.pop())
if ("o" in a):
options.security = 0
if ("R" in a):
options.rpcServer = 1
if ("g" in a):
filename = av.pop()
if '.png' in filename:
options.deferred.append("_do__ cmd.png('''%s''')"%filename)
elif '.mpg' in filename:
options.deferred.append("_do__ movie.produce('''%s''')"%filename)
if ("C" in a):
options.sigint_handler = 0
if ("L" in a):
options.after_load_script = av.pop()
if ("b" in a): # CPU benchmark
options.deferred.append("_do__ feedback disable,all,everything")
options.deferred.append("_do__ feedback enable,python,output")
options.deferred.append("_do_wizard benchmark")
if a[2:]=='':
options.deferred.append("_do__ cmd.get_wizard().run_cpu()")
if a[2:]=='0':
options.deferred.append("_do__ cmd.get_wizard().ray_trace0()")
if a[2:]=='1':
options.deferred.append("_do__ cmd.get_wizard().ray_trace1()")
if a[2:]=='2':
options.deferred.append("_do__ cmd.get_wizard().ray_trace2()")
if "p" in a:
options.read_stdin = 1
if "K" in a:
options.keep_thread_alive = 1
if "k" in a: # suppress reading of .pymolrc and related files
pymolrc = None
options.plugins = 0
if "U" in a: #
options.reuse_helper = 1
if "Q" in a:
options.quiet = 1
options.show_splash = 0
if "I" in a:
options.auto_reinitialize = 1
if "h" in a: # generic helper application
options.internal_gui = 0
options.external_gui = 0
options.internal_feedback = 0
options.show_splash = 1
elif a in ('+1', '+2', '+3', '+4'):
print('ignoring PyMOLWin.exe argument', a)
elif not restricted:
suffix = a[-4:].lower().split('.')[-1]
if suffix == "p5m":
# mode 5 helper application
av.append("-A5")
elif suffix == "psw":
# presentation mode
av.append("-A6")
elif suffix in [ 'pym' ,'py', 'pyc' ]:
python_script = a
elif suffix in [ 'pwg' ]:
try:
pwg_options = get_pwg_options(a)
if pwg_options:
parse_args(['pymol'] + pwg_options, _pymol, options, 1)
except:
traceback.print_exc()
options.deferred.append(a)
loaded_something = 1
if pymolrc != None:
options.deferred = [('_do__ @' + a) if script_re.search(a) else a
for a in pymolrc] + options.deferred
options.pymolrc = pymolrc
if options.rpcServer:
options.deferred.append('_do__ /import pymol.rpc;pymol.rpc.launch_XMLRPC()')
if options.plugins == 1:
# Load plugins independent of PMGApp (will not add menu items)
options.deferred.append('_do__ /import pymol.plugins;pymol.plugins.initialize(-1)')
if loaded_something and (options.after_load_script!=""):
options.deferred.append(options.after_load_script)
options.deferred.extend(final_actions)
if options.show_splash and not options.no_gui and not restricted:
options.deferred.insert(0,"_do__ cmd.splash(1)")
if options.full_screen:
options.deferred.append("_do__ full_screen on")