代码语言:javascript复制
"""
###################################################################################
launch Python programs with command lines and reusable launcher scheme classes;
auto inserts "python" and/or path to Python executable at front of command line;
some of this module may assume 'python' is on your system path (see Launcher.py);
subprocess module would work too, but os.popen() uses it internally, and the goal
is to start a program running independently here, not to connect to its streams;
multiprocessing module also is an option, but this is command-lines, not functions:
doesn't make sense to start a process which would just do one of the options here;
new in this edition: runs script filename path through normpath() to change any
/ to for Windows tools where required; fix is inherited by PyEdit and others;
on Windows, / is generally allowed for file opens, but not by all launcher tools;
###################################################################################
"""
import sys, os
pyfile = (sys.platform[:3] == 'win' and 'python.exe') or 'python'
pypath = sys.executable # use sys in newer pys
def fixWindowsPath(cmdline):
"""
change all / to in script filename path at front of cmdline;
used only by classes which run tools that require this on Windows;
on other platforms, this does not hurt (e.g., os.system on Unix);
"""
splitline = cmdline.lstrip().split(' ') # split on spaces
fixedpath = os.path.normpath(splitline[0]) # fix forward slashes
return ' '.join([fixedpath] splitline[1:]) # put it back together
class LaunchMode:
"""
on call to instance, announce label and run command;
subclasses format command lines as required in run();
command should begin with name of the Python script
file to run, and not with "python" or its full path;
"""
def init(self, label, command):
self.what = label
self.where = command
def call(self): # on call, ex: button press callback
self.announce(self.what)
self.run(self.where) # subclasses must define run()
def announce(self, text): # subclasses may redefine announce()
print(text) # methods instead of if/elif logic
def run(self, cmdline):
assert False, 'run must be defined'
class System(LaunchMode):
"""
run Python script named in shell command line
caveat: may block caller, unless & added on Unix
"""
def run(self, cmdline):
cmdline = fixWindowsPath(cmdline)
os.system('%s %s' % (pypath, cmdline))
class Popen(LaunchMode):
"""
run shell command line in a new process
caveat: may block caller, since pipe closed too soon
"""
def run(self, cmdline):
cmdline = fixWindowsPath(cmdline)
os.popen(pypath ' ' cmdline) # assume nothing to be read
class Fork(LaunchMode):
"""
run command in explicitly created new process
for Unix-like systems only, including cygwin
"""
def run(self, cmdline):
assert hasattr(os, 'fork')
cmdline = cmdline.split() # convert string to list
if os.fork() == 0: # start new child process
os.execvp(pypath, [pyfile] cmdline) # run new program in child
class Start(LaunchMode):
"""
run command independent of caller
for Windows only: uses filename associations
"""
def run(self, cmdline):
assert sys.platform[:3] == 'win'
cmdline = fixWindowsPath(cmdline)
os.startfile(cmdline)
class StartArgs(LaunchMode):
"""
for Windows only: args may require real start
forward slashes are okay here
"""
def run(self, cmdline):
assert sys.platform[:3] == 'win'
os.system('start ' cmdline) # may create pop-up window
class Spawn(LaunchMode):
"""
run python in new process independent of caller
for Windows or Unix; use P_NOWAIT for dos box;
forward slashes are okay here
"""
def run(self, cmdline):
os.spawnv(os.P_DETACH, pypath, (pyfile, cmdline))
class Top_level(LaunchMode):
"""
run in new window, same process
tbd: requires GUI class info too
"""
def run(self, cmdline):
assert False, 'Sorry - mode not yet implemented'
pick a "best" launcher for this platform
may need to specialize the choice elsewhere
if sys.platform[:3] == 'win':
PortableLauncher = Spawn
else:
PortableLauncher = Fork
class QuietPortableLauncher(PortableLauncher):
def announce(self, text):
pass
def selftest():
file = 'echo.py'
input('default mode...')
launcher = PortableLauncher(file, file)
launcher() # no block
input('system mode...')
System(file, file)() # blocks
if sys.platform[:3] == 'win':
input('DOS start mode...') # no block
StartArgs(file, file)()
if name == 'main': selftest()