-
Notifications
You must be signed in to change notification settings - Fork 8
/
wxPopen.py
154 lines (122 loc) · 4.16 KB
/
wxPopen.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import time
from cStringIO import StringIO
import wx
class ProcessRunnerMix:
def __init__(self, input, handler=None):
if handler is None:
handler = self
self.handler = handler
handler.Bind(wx.EVT_IDLE, self.OnIdle)
handler.Bind(wx.EVT_END_PROCESS, self.OnProcessEnded)
input.reverse() # so we can pop
self.input = input
self.reset()
def reset(self):
self.process = None
self.pid = -1
self.output = []
self.errors = []
self.inputStream = None
self.errorStream = None
self.outputStream = None
self.outputFunc = None
self.errorsFunc = None
self.finishedFunc = None
self.finished = False
self.responded = False
def execute(self, cmd):
self.process = wx.Process(self.handler)
self.process.Redirect()
self.pid = wx.Execute(cmd, wx.EXEC_NOHIDE, self.process)
self.inputStream = self.process.GetOutputStream()
self.errorStream = self.process.GetErrorStream()
self.outputStream = self.process.GetInputStream()
#self.OnIdle()
wx.WakeUpIdle()
def setCallbacks(self, output, errors, finished):
self.outputFunc = output
self.errorsFunc = errors
self.finishedFunc = finished
def detach(self):
if self.process is not None:
self.process.CloseOutput()
self.process.Detach()
self.process = None
def kill(self):
if self.process is not None:
self.process.CloseOutput()
if wx.Process.Kill(self.pid, wx.SIGTERM) != wx.KILL_OK:
wx.Process.Kill(self.pid, wx.SIGKILL)
self.process = None
def updateStream(self, stream, data):
if stream and stream.CanRead():
if not self.responded:
self.responded = True
text = stream.read()
data.append(text)
return text
else:
return None
def updateInpStream(self, stream, input):
if stream and input:
line = input.pop()
stream.write(line)
def updateErrStream(self, stream, data):
return self.updateStream(stream, data)
def updateOutStream(self, stream, data):
return self.updateStream(stream, data)
def OnIdle(self, event=None):
if self.process is not None:
self.updateInpStream(self.inputStream, self.input)
e = self.updateErrStream(self.errorStream, self.errors)
if e is not None and self.errorsFunc is not None:
wx.CallAfter(self.errorsFunc, e)
o = self.updateOutStream(self.outputStream, self.output)
if o is not None and self.outputFunc is not None:
wx.CallAfter(self.outputFunc, o)
#wxWakeUpIdle()
#time.sleep(0.001)
def OnProcessEnded(self, event):
self.OnIdle()
if self.process:
self.process.Destroy()
self.process = None
self.finished = True
# XXX doesn't work ???
#self.handler.Disconnect(-1, wxEVT_IDLE)
if self.finishedFunc:
wx.CallAfter(self.finishedFunc)
class ProcessRunner(wx.EvtHandler, ProcessRunnerMix):
def __init__(self, input):
wx.EvtHandler.__init__(self)
ProcessRunnerMix.__init__(self, input)
def wxPopen3(cmd, input, output, errors, finish, handler=None):
p = ProcessRunnerMix(input, handler)
p.setCallbacks(output, errors, finish)
p.execute(cmd)
return p
def _test():
app = wx.PySimpleApp()
f = wx.Frame(None, -1, 'asd')#, style=0)
f.Show()
def output(v):
print 'OUTPUT:', v
def errors(v):
print 'ERRORS:', v
def fin():
p = locals().get('p')
if p: p.Close()
f.Close()
print 'FINISHED'
def spin(p):
while not p.finished:
wx.Yield()
time.sleep(0.01)
def evt(self, event):
input = []
p = wxPopen3('''c:\\python23\\python.exe -c "print '*'*5000"''',
input, output, errors, fin, f)
print p.pid
app.MainLoop()
if __name__ == '__main__':
_test()