Problems with wx.Process & wx.Execute
John Jackson
jjackson at pobox.com
Tue Mar 11 12:08:40 PDT 2008
I've been trying to use wx.Process to launch a Django from a wxPython
application with no luck.
What I see in my log are messages such as
11:36:46: Starting server with command:
/Library/Frameworks/Python.framework/Versions/Current/bin/python ~/
Source/Mine/DjangoTest/mysite/manage.py runserver
11:36:46: Debug: wxMacExecute Bad bundle: /Library/Frameworks/
Python.framework/Versions/Current/bin/python
11:36:46: Debug: pid=22933
11:36:46: Debug: Successfully added notification to the runloop
11:36:46: DjangoStarter: serverPID "22933" started.
11:36:46: Debug: Process ended
I'm also sometimes seeing GetOutputStream() returning a stream, and
sometimes not, even when Exists() is False.
Googling "wxMacExecute Bad bundle" returns some hits, but nothing
that helped. There was a request by Robin for a sample, application,
but none seemed to be offered.
So, see below for a sample application. You'll need to have Django
installed, and then either modify the command to point to a site, or
use the "Set Server Command" button to do the same.
I'm going to try this under Windows and see if the same results happen.
#
# djangoStarter.py
# DjangoRunner
#
# Created by John Jackson on 3/10/08.
# version 1.0
import wx
APP_TITLE = "DjangoStarter"
STARTED = {True: "started", False: "stopped"}
START_STOP_TEXT = {False: "Start Django Server",
True: "Stop Django Server"}
SPACING = 5
DOUBLE_SPACING = 2 * SPACING
QUAD_SPACING = 4 * SPACING
# Note: change this command based on your installation...
SERVER_COMMAND = r"/Library/Frameworks/Python.framework/Versions/
Current/bin/python "\
+ "~/Source/Mine/DjangoTest/mysite/manage.py runserver"
class DjangoStarter(wx.Frame):
def __init__(self, parent=None, ID=-1, title=APP_TITLE,
controller=None):
wx.Frame.__init__(self, parent, ID, title, size=(600,400))
self.controller = controller
self.BuildLogView()
self.BuildButtons()
self.BuildSizers()
# These bindings throw you into the debugger...
# self.Bind(wx.EVT_IDLE, self.OnIdle)
# self.Bind(wx.EVT_END_PROCESS, self.OnIdle)
def BuildLogView(self):
# Set up the log window
self.logTextCtrl = wx.TextCtrl(self, -1,
style = wx.TE_MULTILINE|wx.TE_READONLY)
if wx.Platform == "__WXMAC__":
self.logTextCtrl.MacCheckSpelling(False)
wx.Log_SetActiveTarget(wx.LogTextCtrl(self.logTextCtrl))
def BuildButtons(self):
self.setCommandButton = wx.Button(self, label="Set Server
Command")
self.Bind(wx.EVT_BUTTON, self.OnSetPath, self.setCommandButton)
self.startStopButton = wx.Button(self)
self.Bind(wx.EVT_BUTTON, self.OnStartStop,
self.startStopButton)
self.SetStartStopButtonLabel()
def BuildSizers(self):
self.buttonsSizer = wx.BoxSizer(wx.HORIZONTAL)
self.buttonsSizer.Add(self.setCommandButton, 0,
wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, SPACING)
self.buttonsSizer.Add((SPACING, DOUBLE_SPACING), 1, wx.EXPAND)
self.buttonsSizer.Add(self.startStopButton, 0,
wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, SPACING)
self.buttonsSizer.Add((SPACING, DOUBLE_SPACING), 0, wx.EXPAND)
self.contentSizer = wx.BoxSizer(wx.VERTICAL)
self.contentSizer.Add(self.logTextCtrl, 1,
wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM,
DOUBLE_SPACING)
self.contentSizer.Add(self.buttonsSizer, 0,
wx.EXPAND|wx.TOP|wx.BOTTOM, SPACING)
self.contentSizer.Add((SPACING, QUAD_SPACING), 0, wx.EXPAND)
self.SetSizer(self.contentSizer)
self.SetAutoLayout(True)
self.Layout()
def OnSetPath(self, event):
if self.controller.serverCommand:
serverCommand = self.controller.serverCommand
else:
serverCommand = SERVER_COMMAND
dlg = wx.TextEntryDialog(self, "Set Django Server Start
Command",
"Enter a command with a full local
path",
serverCommand, wx.OK|wx.CANCEL)
dlg.CentreOnParent()
if dlg.ShowModal() == wx.ID_OK:
self.controller.serverCommand = dlg.GetValue()
dlg.Destroy()
def OnStartStop(self, event):
self.controller.start_stop_server()
self.SetStartStopButtonLabel()
def OnIdle(self, event):
self.controller.log_server()
def SetStartStopButtonLabel(self):
self.startStopButton.SetLabel(START_STOP_TEXT
[self.controller.serverStarted])
class Controller(object):
def __init__(self):
self.serverStarted = False
self.serverCommand = SERVER_COMMAND
self.serverPID = None
self.serverProcess = None
# Start application
self.app = wx.PySimpleApp()
self.gui = DjangoStarter(controller=self)
self.gui.Show(1)
self.app.MainLoop()
def __del__(self):
if self.serverProcess is not None:
self.serverProcess.Detach()
self.serverProcess.CloseOutput()
self.serverProcess = None
def log(self, message):
# Adds message to the log
wx.LogMessage(message)
# Need to yield here so that scrollbar can move.
wx.Yield()
def start_stop_server(self, window=None, serverCommand=None):
if serverCommand:
self.serverCommand = serverCommand
if not self.serverStarted:
self._start_server(window, self.serverCommand)
else:
self._stop_server()
def log_server(self):
if self.serverProcess:
self._read_stream(self.serverProcess.IsInputAvailable,
self.serverProcess.GetInputStream)
self._read_stream(self.serverProcess.IsErrorAvailable,
self.serverProcess.GetErrorStream)
def _read_stream(self, testStreamFunction, getStreamFunction):
if testStreamFunction():
stream = getStreamFunction()
if stream.CanRead():
text = stream.Read()
else:
text = "Stream cannot be read: %s" % getStreamFunction
else:
text = "Stream not available: %s" % testStreamFunction
self.log(text)
def _start_server(self, window, serverCommand=None):
self.log("Starting server with command:\n%s" %
self.serverCommand)
self.serverCommand = serverCommand
self.serverProcess = wx.Process(window)
self.serverProcess.Redirect();
self.serverPID = wx.Execute(self.serverCommand,
wx.EXEC_ASYNC, self.serverProcess)
self.serverStarted = True
self._log_server()
def _stop_server(self):
self.log('serverPID: %s\n serverStarted: %s\n serverProcess:
%s' % (self.serverPID,
self.serverStarted, self.serverProcess))
if self.serverProcess:
exists = self.serverProcess.Exists(self.serverPID)
self.log('serverProcess.Exists: %s' % exists)
CTRL_C = 3
stream = self.serverProcess.GetOutputStream()
self.log('serverProcess.GetOutputStream: %s' % stream)
if stream and exists:
stream.write(chr(CTRL_C) + '\n')
self.serverProcess.Detach()
self.log('ServerProcess detached')
self.serverProcess.CloseOutput()
self.log('ServerProcess closed output')
self.serverProcess = None
self.serverStarted = False
self._log_server()
self.serverPID = 0
def _log_server(self):
self.log('%s: serverPID "%s" %s.' % (APP_TITLE,
self.serverPID, STARTED[self.serverStarted]))
if __name__ == '__main__':
Controller()
More information about the wxpython-mac
mailing list