|
@@
-1,282
+1,282
b''
|
|
1
|
1
|
# -*- coding: utf-8 -*-
|
|
2
|
2
|
"""Frontend of ipython working with python-zmq
|
|
3
|
3
|
|
|
4
|
4
|
Ipython's frontend, is a ipython interface that send request to kernel and proccess the kernel's outputs.
|
|
5
|
5
|
|
|
6
|
6
|
For more details, see the ipython-zmq design
|
|
7
|
7
|
"""
|
|
8
|
8
|
#-----------------------------------------------------------------------------
|
|
9
|
9
|
# Copyright (C) 2010 The IPython Development Team
|
|
10
|
10
|
#
|
|
11
|
11
|
# Distributed under the terms of the BSD License. The full license is in
|
|
12
|
12
|
# the file COPYING, distributed as part of this software.
|
|
13
|
13
|
#-----------------------------------------------------------------------------
|
|
14
|
14
|
|
|
15
|
15
|
#-----------------------------------------------------------------------------
|
|
16
|
16
|
# Imports
|
|
17
|
17
|
#-----------------------------------------------------------------------------
|
|
18
|
18
|
|
|
19
|
19
|
import __builtin__
|
|
20
|
20
|
from contextlib import nested
|
|
21
|
21
|
import time
|
|
22
|
22
|
import sys
|
|
23
|
23
|
import os
|
|
24
|
24
|
import signal
|
|
25
|
25
|
import uuid
|
|
26
|
26
|
import cPickle as pickle
|
|
27
|
27
|
import code
|
|
28
|
28
|
import zmq
|
|
29
|
29
|
import readline
|
|
30
|
30
|
import rlcompleter
|
|
31
|
31
|
import time
|
|
32
|
32
|
|
|
33
|
33
|
#-----------------------------------------------------------------------------
|
|
34
|
34
|
# Imports from ipython
|
|
35
|
35
|
#-----------------------------------------------------------------------------
|
|
36
|
36
|
from IPython.external.argparse import ArgumentParser
|
|
37
|
37
|
from IPython.utils.traitlets import (
|
|
38
|
38
|
Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode
|
|
39
|
39
|
)
|
|
40
|
40
|
from IPython.core.interactiveshell import get_default_colors
|
|
41
|
41
|
from IPython.core.excolors import exception_colors
|
|
42
|
42
|
from IPython.utils import PyColorize
|
|
43
|
43
|
from IPython.core.inputsplitter import InputSplitter
|
|
44
|
|
from IPython.frontend.terminal.kernelmanager import KernelManager2p as KernelManager
|
|
|
44
|
from IPython.frontend.zmqterminal.kernelmanager import KernelManager2p as KernelManager
|
|
45
|
45
|
from IPython.zmq.session import Session
|
|
46
|
|
from IPython.frontend.terminal.completer import ClientCompleter2p
|
|
|
46
|
from IPython.frontend.zmqterminal.completer import ClientCompleter2p
|
|
47
|
47
|
|
|
48
|
48
|
#-----------------------------------------------------------------------------
|
|
49
|
49
|
# Network Constants
|
|
50
|
50
|
#-----------------------------------------------------------------------------
|
|
51
|
51
|
|
|
52
|
52
|
from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
|
|
53
|
53
|
class Frontend(object):
|
|
54
|
54
|
""" this class is a simple frontend to ipython-zmq
|
|
55
|
55
|
|
|
56
|
56
|
NOTE: this class use kernelmanager to manipulate sockets
|
|
57
|
57
|
|
|
58
|
58
|
Parameters:
|
|
59
|
59
|
-----------
|
|
60
|
60
|
kernelmanager : object
|
|
61
|
61
|
instantiated object from class KernelManager in module kernelmanager
|
|
62
|
62
|
|
|
63
|
63
|
"""
|
|
64
|
64
|
|
|
65
|
65
|
def __init__(self,kernelmanager):
|
|
66
|
66
|
self.km = kernelmanager
|
|
67
|
67
|
self.session = kernelmanager.session
|
|
68
|
68
|
self.request_socket = self.km.xreq_channel.socket
|
|
69
|
69
|
self.sub_socket = self.km.sub_channel.socket
|
|
70
|
70
|
self.reply_socket = self.km.rep_channel.socket
|
|
71
|
71
|
self.msg_header = self.km.session.msg_header()
|
|
72
|
72
|
self.completer = ClientCompleter2p(self,self.km)
|
|
73
|
73
|
readline.parse_and_bind("tab: complete")
|
|
74
|
74
|
readline.parse_and_bind('set show-all-if-ambiguous on')
|
|
75
|
75
|
readline.set_completer(self.completer.complete)
|
|
76
|
76
|
|
|
77
|
77
|
history_path = os.path.expanduser('~/.ipython/history')
|
|
78
|
78
|
if os.path.isfile(history_path):
|
|
79
|
79
|
rlcompleter.readline.read_history_file(history_path)
|
|
80
|
80
|
else:
|
|
81
|
81
|
print("history file can not be readed.")
|
|
82
|
82
|
|
|
83
|
83
|
self.messages = {}
|
|
84
|
84
|
|
|
85
|
85
|
self._splitter = InputSplitter()
|
|
86
|
86
|
self.code = ""
|
|
87
|
87
|
|
|
88
|
88
|
self.prompt_count = 0
|
|
89
|
89
|
self._get_initail_promt()
|
|
90
|
90
|
|
|
91
|
91
|
def _get_initail_promt(self):
|
|
92
|
92
|
self._execute('', hidden=True)
|
|
93
|
93
|
|
|
94
|
94
|
def interact(self):
|
|
95
|
95
|
""" let you get input from console using inputsplitter, then
|
|
96
|
96
|
while you enter code it can indent and set index id to any input
|
|
97
|
97
|
|
|
98
|
98
|
"""
|
|
99
|
99
|
|
|
100
|
100
|
try:
|
|
101
|
101
|
self._splitter.push(raw_input('In[%i]:'%self.prompt_count+self.code))
|
|
102
|
102
|
while self._splitter.push_accepts_more():
|
|
103
|
103
|
self.code = raw_input('.....:'+' '*self._splitter.indent_spaces)
|
|
104
|
104
|
self._splitter.push(' '*self._splitter.indent_spaces+self.code)
|
|
105
|
105
|
self._execute(self._splitter.source,False)
|
|
106
|
106
|
self._splitter.reset()
|
|
107
|
107
|
except KeyboardInterrupt:
|
|
108
|
108
|
print('\nKeyboardInterrupt\n')
|
|
109
|
109
|
pass
|
|
110
|
110
|
|
|
111
|
111
|
|
|
112
|
112
|
def start(self):
|
|
113
|
113
|
""" init a bucle that call interact method to get code.
|
|
114
|
114
|
|
|
115
|
115
|
"""
|
|
116
|
116
|
while True:
|
|
117
|
117
|
try:
|
|
118
|
118
|
self.interact()
|
|
119
|
119
|
except KeyboardInterrupt:
|
|
120
|
120
|
print('\nKeyboardInterrupt\n')
|
|
121
|
121
|
pass
|
|
122
|
122
|
except EOFError:
|
|
123
|
123
|
answer = ''
|
|
124
|
124
|
while True:
|
|
125
|
125
|
answer = raw_input('\nDo you really want to exit ([y]/n)?')
|
|
126
|
126
|
if answer == 'y' or answer == '' :
|
|
127
|
127
|
self.km.shutdown_kernel()
|
|
128
|
128
|
sys.exit()
|
|
129
|
129
|
elif answer == 'n':
|
|
130
|
130
|
break
|
|
131
|
131
|
|
|
132
|
132
|
def _execute(self, source, hidden = True):
|
|
133
|
133
|
""" Execute 'source'. If 'hidden', do not show any output.
|
|
134
|
134
|
|
|
135
|
135
|
See parent class :meth:`execute` docstring for full details.
|
|
136
|
136
|
"""
|
|
137
|
137
|
self.km.xreq_channel.execute(source, hidden)
|
|
138
|
138
|
self.handle_xreq_channel()
|
|
139
|
139
|
self.handle_rep_channel()
|
|
140
|
140
|
|
|
141
|
141
|
def handle_xreq_channel(self):
|
|
142
|
142
|
# Give the kernel up to 0.5s to respond
|
|
143
|
143
|
for i in range(5):
|
|
144
|
144
|
if self.km.xreq_channel.was_called():
|
|
145
|
145
|
self.msg_xreq = self.km.xreq_channel.get_msg()
|
|
146
|
146
|
if self.msg_header["session"] == self.msg_xreq["parent_header"]["session"] :
|
|
147
|
147
|
if self.msg_xreq["content"]["status"] == 'ok' :
|
|
148
|
148
|
if self.msg_xreq["msg_type"] == "execute_reply" :
|
|
149
|
149
|
self.handle_sub_channel()
|
|
150
|
150
|
self.prompt_count = self.msg_xreq["content"]["execution_count"]+1
|
|
151
|
151
|
|
|
152
|
152
|
else:
|
|
153
|
153
|
etb = self.msg_xreq["content"]["traceback"]
|
|
154
|
154
|
print >> sys.stderr, etb[0]
|
|
155
|
155
|
print >> sys.stderr, etb[1]
|
|
156
|
156
|
print >> sys.stderr, etb[2]
|
|
157
|
157
|
self.prompt_count = self.msg_xreq["content"]["execution_count"]+1
|
|
158
|
158
|
break
|
|
159
|
159
|
time.sleep(0.1)
|
|
160
|
160
|
|
|
161
|
161
|
|
|
162
|
162
|
def handle_sub_channel(self):
|
|
163
|
163
|
""" Method to procces subscribe channel's messages
|
|
164
|
164
|
|
|
165
|
165
|
this method read a message and procces the content
|
|
166
|
166
|
in differents outputs like stdout, stderr, pyout
|
|
167
|
167
|
and status
|
|
168
|
168
|
|
|
169
|
169
|
Arguments:
|
|
170
|
170
|
sub_msg: message receive from kernel in the sub socket channel
|
|
171
|
171
|
capture by kernel manager.
|
|
172
|
172
|
|
|
173
|
173
|
"""
|
|
174
|
174
|
while self.km.sub_channel.was_called():
|
|
175
|
175
|
sub_msg = self.km.sub_channel.get_msg()
|
|
176
|
176
|
if self.msg_header["username"] == sub_msg['parent_header']['username'] and self.km.session.session == sub_msg['parent_header']['session']:
|
|
177
|
177
|
if sub_msg['msg_type'] == 'status' :
|
|
178
|
178
|
if sub_msg["content"]["execution_state"] == "busy" :
|
|
179
|
179
|
pass
|
|
180
|
180
|
|
|
181
|
181
|
if sub_msg['msg_type'] == 'stream' :
|
|
182
|
182
|
if sub_msg["content"]["name"] == "stdout":
|
|
183
|
183
|
print >> sys.stdout,sub_msg["content"]["data"]
|
|
184
|
184
|
sys.stdout.flush()
|
|
185
|
185
|
if sub_msg["content"]["name"] == "stderr" :
|
|
186
|
186
|
print >> sys.stderr,sub_msg["content"]["data"]
|
|
187
|
187
|
sys.stderr.flush()
|
|
188
|
188
|
|
|
189
|
189
|
if sub_msg['msg_type'] == 'pyout' :
|
|
190
|
190
|
print >> sys.stdout,"Out[%i]:"%sub_msg["content"]["execution_count"], sub_msg["content"]["data"]["text/plain"]
|
|
191
|
191
|
sys.stdout.flush()
|
|
192
|
192
|
|
|
193
|
193
|
def handle_rep_channel(self):
|
|
194
|
194
|
""" Method to capture raw_input
|
|
195
|
195
|
"""
|
|
196
|
196
|
if self.km.rep_channel.was_called() :
|
|
197
|
197
|
self.msg_rep = self.km.rep_channel.get_msg()
|
|
198
|
198
|
if self.msg_header["session"] == self.msg_rep["parent_header"]["session"] :
|
|
199
|
199
|
raw_data = raw_input(self.msg_rep["content"]["prompt"])
|
|
200
|
200
|
self.km.rep_channel.input(raw_data)
|
|
201
|
201
|
|
|
202
|
202
|
|
|
203
|
203
|
|
|
204
|
204
|
|
|
205
|
205
|
def start_frontend():
|
|
206
|
206
|
""" Entry point for application.
|
|
207
|
207
|
|
|
208
|
208
|
"""
|
|
209
|
209
|
# Parse command line arguments.
|
|
210
|
210
|
parser = ArgumentParser()
|
|
211
|
211
|
kgroup = parser.add_argument_group('kernel options')
|
|
212
|
212
|
kgroup.add_argument('-e', '--existing', action='store_true',
|
|
213
|
213
|
help='connect to an existing kernel')
|
|
214
|
214
|
kgroup.add_argument('--ip', type=str, default=LOCALHOST,
|
|
215
|
215
|
help=\
|
|
216
|
216
|
"set the kernel\'s IP address [default localhost].\
|
|
217
|
217
|
If the IP address is something other than localhost, then \
|
|
218
|
218
|
Consoles on other machines will be able to connect\
|
|
219
|
219
|
to the Kernel, so be careful!")
|
|
220
|
220
|
kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
|
|
221
|
221
|
help='set the XREQ channel port [default random]')
|
|
222
|
222
|
kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
|
|
223
|
223
|
help='set the SUB channel port [default random]')
|
|
224
|
224
|
kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
|
|
225
|
225
|
help='set the REP channel port [default random]')
|
|
226
|
226
|
kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
|
|
227
|
227
|
help='set the heartbeat port [default random]')
|
|
228
|
228
|
|
|
229
|
229
|
egroup = kgroup.add_mutually_exclusive_group()
|
|
230
|
230
|
egroup.add_argument('--pure', action='store_true', help = \
|
|
231
|
231
|
'use a pure Python kernel instead of an IPython kernel')
|
|
232
|
232
|
egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
|
|
233
|
233
|
const='auto', help = \
|
|
234
|
234
|
"Pre-load matplotlib and numpy for interactive use. If GUI is not \
|
|
235
|
235
|
given, the GUI backend is matplotlib's, otherwise use one of: \
|
|
236
|
236
|
['tk', 'gtk', 'qt', 'wx', 'inline'].")
|
|
237
|
237
|
egroup.add_argument('--colors', type=str,
|
|
238
|
238
|
help="Set the color scheme (LightBG,Linux,NoColor). This is guessed\
|
|
239
|
239
|
based on the pygments style if not set.")
|
|
240
|
240
|
|
|
241
|
241
|
args = parser.parse_args()
|
|
242
|
242
|
|
|
243
|
243
|
# parse the colors arg down to current known labels
|
|
244
|
244
|
if args.colors:
|
|
245
|
245
|
colors=args.colors.lower()
|
|
246
|
246
|
if colors in ('lightbg', 'light'):
|
|
247
|
247
|
colors='lightbg'
|
|
248
|
248
|
elif colors in ('dark', 'linux'):
|
|
249
|
249
|
colors='linux'
|
|
250
|
250
|
else:
|
|
251
|
251
|
colors='nocolor'
|
|
252
|
252
|
else:
|
|
253
|
253
|
colors=None
|
|
254
|
254
|
|
|
255
|
255
|
# Create a KernelManager and start a kernel.
|
|
256
|
256
|
kernel_manager = KernelManager(xreq_address=(args.ip, args.xreq),
|
|
257
|
257
|
sub_address=(args.ip, args.sub),
|
|
258
|
258
|
rep_address=(args.ip, args.rep),
|
|
259
|
259
|
hb_address=(args.ip, args.hb))
|
|
260
|
260
|
if not args.existing:
|
|
261
|
261
|
# if not args.ip in LOCAL_IPS+ALL_ALIAS:
|
|
262
|
262
|
# raise ValueError("Must bind a local ip, such as: %s"%LOCAL_IPS)
|
|
263
|
263
|
|
|
264
|
264
|
kwargs = dict(ip=args.ip)
|
|
265
|
265
|
if args.pure:
|
|
266
|
266
|
kwargs['ipython']=False
|
|
267
|
267
|
else:
|
|
268
|
268
|
kwargs['colors']=colors
|
|
269
|
269
|
if args.pylab:
|
|
270
|
270
|
kwargs['pylab']=args.pylab
|
|
271
|
271
|
kernel_manager.start_kernel(**kwargs)
|
|
272
|
272
|
|
|
273
|
273
|
|
|
274
|
274
|
kernel_manager.start_channels()
|
|
275
|
275
|
time.sleep(4)
|
|
276
|
276
|
|
|
277
|
277
|
frontend=Frontend(kernel_manager)
|
|
278
|
278
|
return frontend
|
|
279
|
279
|
|
|
280
|
280
|
if __name__ == "__main__" :
|
|
281
|
281
|
frontend=start_frontend()
|
|
282
|
282
|
frontend.start()
|