##// END OF EJS Templates
Simplify handling of messaging in zmqterminal.
Thomas Kluyver -
Show More
@@ -1,42 +1,41 b''
1 1 # -*- coding: utf-8 -*-
2 2 import readline
3 3 from Queue import Empty
4 4
5 5 class ClientCompleter2p(object):
6 6 """Client-side completion machinery.
7 7
8 8 How it works: self.complete will be called multiple times, with
9 9 state=0,1,2,... When state=0 it should compute ALL the completion matches,
10 10 and then return them for each value of state."""
11 11
12 12 def __init__(self,client, km):
13 13 self.km = km
14 14 self.matches = []
15 15 self.client = client
16 16
17 17 def complete_request(self,text):
18 18 line = readline.get_line_buffer()
19 #msg_id = self.km.xreq_channel.complete(text=text,line=line)#this method is not working, the code not continue
20 msg = self.km.session.send(self.km.xreq_channel.socket,
21 'complete_request',
22 dict(text=text, line=line))
19 cursor_pos = readline.get_endidx()
20
23 21 # send completion request to kernel
24 22 # Give the kernel up to 0.5s to respond
23 msg_id = self.km.xreq_channel.complete(text=text, line=line,
24 cursor_pos=cursor_pos)
25
25 26 msg_xreq = self.km.xreq_channel.get_msg(timeout=0.5)
26 if msg["header"]['session'] == msg_xreq["parent_header"]['session'] and \
27 msg_xreq["content"]["status"] == 'ok' and \
28 msg_xreq["msg_type"] == "complete_reply" :
27 if msg_xreq['parent_header']['msg_id'] == msg_id:
29 28 return msg_xreq["content"]["matches"]
30 29 return []
31 30
32 31 def complete(self, text, state):
33 32 if state == 0:
34 33 try:
35 34 self.matches = self.complete_request(text)
36 35 except Empty:
37 36 print('WARNING: Kernel timeout on tab completion.')
38 37
39 38 try:
40 39 return self.matches[state]
41 40 except IndexError:
42 41 return None
@@ -1,266 +1,260 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 import sys
21 21 import os
22 22 from Queue import Empty
23 23 import readline
24 24 import rlcompleter
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Imports from ipython
28 28 #-----------------------------------------------------------------------------
29 29 from IPython.external.argparse import ArgumentParser
30 30 from IPython.core.inputsplitter import IPythonInputSplitter
31 31 from IPython.zmq.blockingkernelmanager import BlockingKernelManager as KernelManager
32 32 from IPython.frontend.zmqterminal.completer import ClientCompleter2p
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Network Constants
36 36 #-----------------------------------------------------------------------------
37 37
38 38 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
39 39 class Frontend(object):
40 40 """This class is a simple frontend to ipython-zmq
41 41
42 42 NOTE: this class uses kernelmanager to manipulate sockets
43 43
44 44 Parameters:
45 45 -----------
46 46 kernelmanager : object
47 47 instantiated object from class KernelManager in module kernelmanager
48 48
49 49 """
50 50
51 51 def __init__(self, kernelmanager):
52 52 self.km = kernelmanager
53 self.session = kernelmanager.session
54 self.request_socket = self.km.xreq_channel.socket
55 self.sub_socket = self.km.sub_channel.socket
56 self.reply_socket = self.km.rep_channel.socket
57 self.msg_header = self.km.session.msg_header()
53 self.session_id = self.km.session.session
58 54 self.completer = ClientCompleter2p(self, self.km)
59 55 readline.parse_and_bind("tab: complete")
60 56 readline.parse_and_bind('set show-all-if-ambiguous on')
61 57 readline.set_completer(self.completer.complete)
62 58
63 59 history_path = os.path.expanduser('~/.ipython/history')
64 60 if os.path.isfile(history_path):
65 61 rlcompleter.readline.read_history_file(history_path)
66 62 else:
67 63 print("history file cannot be read.")
68 64
69 65 self.messages = {}
70 66
71 67 self._splitter = IPythonInputSplitter()
72 68 self.code = ""
73 69
74 70 self.prompt_count = 0
75 71 self._get_initial_prompt()
76 72
77 73 def _get_initial_prompt(self):
78 74 self._execute('', hidden=True)
79 75
80 76 def interact(self):
81 77 """Gets input from console using inputsplitter, then
82 78 while you enter code it can indent and set index id to any input
83 79 """
84 80
85 81 try:
86 82 self._splitter.push(raw_input('In[%i]:'%self.prompt_count+self.code))
87 83 while self._splitter.push_accepts_more():
88 84 self.code = raw_input('.....:'+' '*self._splitter.indent_spaces)
89 85 self._splitter.push(' '*self._splitter.indent_spaces+self.code)
90 86 self._execute(self._splitter.source,False)
91 87 self._splitter.reset()
92 88 except KeyboardInterrupt:
93 89 print('\nKeyboardInterrupt\n')
94 90 pass
95 91
96 92
97 93 def start(self):
98 94 """Start the interaction loop, calling the .interact() method for each
99 95 input cell.
100 96 """
101 97 while True:
102 98 try:
103 99 self.interact()
104 100 except KeyboardInterrupt:
105 101 print('\nKeyboardInterrupt\n')
106 102 pass
107 103 except EOFError:
108 104 answer = ''
109 105 while True:
110 106 answer = raw_input('\nDo you really want to exit ([y]/n)?')
111 107 if answer == 'y' or answer == '' :
112 108 self.km.shutdown_kernel()
113 109 sys.exit()
114 110 elif answer == 'n':
115 111 break
116 112
117 113 def _execute(self, source, hidden = True):
118 114 """ Execute 'source'. If 'hidden', do not show any output.
119 115
120 116 See parent class :meth:`execute` docstring for full details.
121 117 """
122 self.km.xreq_channel.execute(source, hidden)
118 msg_id = self.km.xreq_channel.execute(source, hidden)
123 119 while not self.km.xreq_channel.msg_ready():
124 120 try:
125 121 self.handle_rep_channel(timeout=0.1)
126 122 except Empty:
127 123 pass
128 self.handle_xreq_channel()
124 self.handle_execute_reply(msg_id)
129 125
130 def handle_xreq_channel(self):
131 self.msg_xreq = self.km.xreq_channel.get_msg()
132 if self.msg_header["session"] == self.msg_xreq["parent_header"]["session"]:
133 if self.msg_xreq["content"]["status"] == 'ok' :
134 if self.msg_xreq["msg_type"] == "execute_reply" :
135 self.handle_sub_channel()
136 self.prompt_count = self.msg_xreq["content"]["execution_count"]+1
126 def handle_execute_reply(self, msg_id):
127 msg_xreq = self.km.xreq_channel.get_msg()
128 if msg_xreq["parent_header"]["msg_id"] == msg_id:
129 if msg_xreq["content"]["status"] == 'ok' :
130 self.handle_sub_channel()
131 self.prompt_count = msg_xreq["content"]["execution_count"] + 1
137 132
138 133 else:
139 etb = self.msg_xreq["content"]["traceback"]
134 etb = msg_xreq["content"]["traceback"]
140 135 print >> sys.stderr, etb[0]
141 136 try: # These bits aren't there for a SyntaxError
142 137 print >> sys.stderr, etb[1]
143 138 print >> sys.stderr, etb[2]
144 139 except IndexError:
145 140 pass
146 self.prompt_count = self.msg_xreq["content"]["execution_count"]+1
141 self.prompt_count = msg_xreq["content"]["execution_count"] + 1
147 142
148 143
149 144 def handle_sub_channel(self):
150 145 """ Method to procces subscribe channel's messages
151 146
152 147 This method reads a message and processes the content in different
153 148 outputs like stdout, stderr, pyout and status
154 149
155 150 Arguments:
156 151 sub_msg: message receive from kernel in the sub socket channel
157 152 capture by kernel manager.
158 153 """
159 154 while self.km.sub_channel.msg_ready():
160 155 sub_msg = self.km.sub_channel.get_msg()
161 if self.msg_header["username"] == sub_msg['parent_header']['username'] and \
162 self.km.session.session == sub_msg['parent_header']['session']:
156 if self.session_id == sub_msg['parent_header']['session']:
163 157 if sub_msg['msg_type'] == 'status' :
164 158 if sub_msg["content"]["execution_state"] == "busy" :
165 159 pass
166 160
167 if sub_msg['msg_type'] == 'stream' :
161 elif sub_msg['msg_type'] == 'stream' :
168 162 if sub_msg["content"]["name"] == "stdout":
169 print >> sys.stdout,sub_msg["content"]["data"]
163 print >> sys.stdout, sub_msg["content"]["data"]
170 164 sys.stdout.flush()
171 if sub_msg["content"]["name"] == "stderr" :
172 print >> sys.stderr,sub_msg["content"]["data"]
165 elif sub_msg["content"]["name"] == "stderr" :
166 print >> sys.stderr, sub_msg["content"]["data"]
173 167 sys.stderr.flush()
174 168
175 if sub_msg['msg_type'] == 'pyout' :
169 elif sub_msg['msg_type'] == 'pyout' :
176 170 print >> sys.stdout,"Out[%i]:"%sub_msg["content"]["execution_count"], sub_msg["content"]["data"]["text/plain"]
177 171 sys.stdout.flush()
178 172
179 173 def handle_rep_channel(self, timeout=0.1):
180 174 """ Method to capture raw_input
181 175 """
182 self.msg_rep = self.km.rep_channel.get_msg(timeout=timeout)
183 if self.msg_header["session"] == self.msg_rep["parent_header"]["session"] :
184 raw_data = raw_input(self.msg_rep["content"]["prompt"])
176 msg_rep = self.km.rep_channel.get_msg(timeout=timeout)
177 if self.session_id == msg_rep["parent_header"]["session"] :
178 raw_data = raw_input(msg_rep["content"]["prompt"])
185 179 self.km.rep_channel.input(raw_data)
186 180
187 181
188 182
189 183
190 184 def start_frontend():
191 185 """ Entry point for application.
192 186
193 187 """
194 188 # Parse command line arguments.
195 189 parser = ArgumentParser()
196 190 kgroup = parser.add_argument_group('kernel options')
197 191 kgroup.add_argument('-e', '--existing', action='store_true',
198 192 help='connect to an existing kernel')
199 193 kgroup.add_argument('--ip', type=str, default=LOCALHOST,
200 194 help=\
201 195 "set the kernel\'s IP address [default localhost].\
202 196 If the IP address is something other than localhost, then \
203 197 Consoles on other machines will be able to connect\
204 198 to the Kernel, so be careful!")
205 199 kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
206 200 help='set the XREQ channel port [default random]')
207 201 kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
208 202 help='set the SUB channel port [default random]')
209 203 kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
210 204 help='set the REP channel port [default random]')
211 205 kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
212 206 help='set the heartbeat port [default random]')
213 207
214 208 egroup = kgroup.add_mutually_exclusive_group()
215 209 egroup.add_argument('--pure', action='store_true', help = \
216 210 'use a pure Python kernel instead of an IPython kernel')
217 211 egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
218 212 const='auto', help = \
219 213 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
220 214 given, the GUI backend is matplotlib's, otherwise use one of: \
221 215 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
222 216 egroup.add_argument('--colors', type=str,
223 217 help="Set the color scheme (LightBG,Linux,NoColor). This is guessed\
224 218 based on the pygments style if not set.")
225 219
226 220 args = parser.parse_args()
227 221
228 222 # parse the colors arg down to current known labels
229 223 if args.colors:
230 224 colors=args.colors.lower()
231 225 if colors in ('lightbg', 'light'):
232 226 colors='lightbg'
233 227 elif colors in ('dark', 'linux'):
234 228 colors='linux'
235 229 else:
236 230 colors='nocolor'
237 231 else:
238 232 colors=None
239 233
240 234 # Create a KernelManager and start a kernel.
241 235 kernel_manager = KernelManager(xreq_address=(args.ip, args.xreq),
242 236 sub_address=(args.ip, args.sub),
243 237 rep_address=(args.ip, args.rep),
244 238 hb_address=(args.ip, args.hb))
245 239 if not args.existing:
246 240 # if not args.ip in LOCAL_IPS+ALL_ALIAS:
247 241 # raise ValueError("Must bind a local ip, such as: %s"%LOCAL_IPS)
248 242
249 243 kwargs = dict(ip=args.ip)
250 244 if args.pure:
251 245 kwargs['ipython']=False
252 246 else:
253 247 kwargs['colors']=colors
254 248 if args.pylab:
255 249 kwargs['pylab']=args.pylab
256 250 kernel_manager.start_kernel(**kwargs)
257 251
258 252
259 253 kernel_manager.start_channels()
260 254
261 255 frontend=Frontend(kernel_manager)
262 256 return frontend
263 257
264 258 if __name__ == "__main__" :
265 259 frontend=start_frontend()
266 260 frontend.start()
General Comments 0
You need to be logged in to leave comments. Login now