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