##// END OF EJS Templates
Improve io.rprint* interface, unify usage in ipkernel....
Fernando Perez -
Show More
@@ -1,286 +1,294 b''
1 1 # encoding: utf-8
2 2 """
3 3 IO related utilities.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2009 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 from __future__ import print_function
12 13
13 14 #-----------------------------------------------------------------------------
14 15 # Imports
15 16 #-----------------------------------------------------------------------------
16 17 import sys
17 18 import tempfile
18 19
19 20 from IPython.external.Itpl import itpl, printpl
20 21
21 22 #-----------------------------------------------------------------------------
22 23 # Code
23 24 #-----------------------------------------------------------------------------
24 25
25 26
26 27 class IOStream:
27 28
28 29 def __init__(self,stream,fallback):
29 30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
30 31 stream = fallback
31 32 self.stream = stream
32 33 self._swrite = stream.write
33 34 self.flush = stream.flush
34 35
35 36 def write(self,data):
36 37 try:
37 38 self._swrite(data)
38 39 except:
39 40 try:
40 41 # print handles some unicode issues which may trip a plain
41 # write() call. Attempt to emulate write() by using a
42 # trailing comma
43 print >> self.stream, data,
42 # write() call. Emulate write() by using an empty end
43 # argument.
44 print(data, end='', file=self.stream)
44 45 except:
45 46 # if we get here, something is seriously broken.
46 print >> sys.stderr, \
47 'ERROR - failed to write data to stream:', self.stream
47 print('ERROR - failed to write data to stream:', self.stream,
48 file=sys.stderr)
48 49
49 50 # This class used to have a writeln method, but regular files and streams
50 51 # in Python don't have this method. We need to keep this completely
51 52 # compatible so we removed it.
52 53
53 54 def close(self):
54 55 pass
55 56
56 57
57 58 class IOTerm:
58 59 """ Term holds the file or file-like objects for handling I/O operations.
59 60
60 61 These are normally just sys.stdin, sys.stdout and sys.stderr but for
61 62 Windows they can can replaced to allow editing the strings before they are
62 63 displayed."""
63 64
64 65 # In the future, having IPython channel all its I/O operations through
65 66 # this class will make it easier to embed it into other environments which
66 67 # are not a normal terminal (such as a GUI-based shell)
67 68 def __init__(self, cin=None, cout=None, cerr=None):
68 69 self.cin = IOStream(cin, sys.stdin)
69 70 self.cout = IOStream(cout, sys.stdout)
70 71 self.cerr = IOStream(cerr, sys.stderr)
71 72
72 73
73 74 class Tee(object):
74 75 """A class to duplicate an output stream to stdout/err.
75 76
76 77 This works in a manner very similar to the Unix 'tee' command.
77 78
78 79 When the object is closed or deleted, it closes the original file given to
79 80 it for duplication.
80 81 """
81 82 # Inspired by:
82 83 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
83 84
84 85 def __init__(self, file_or_name, mode=None, channel='stdout'):
85 86 """Construct a new Tee object.
86 87
87 88 Parameters
88 89 ----------
89 90 file_or_name : filename or open filehandle (writable)
90 91 File that will be duplicated
91 92
92 93 mode : optional, valid mode for open().
93 94 If a filename was give, open with this mode.
94 95
95 96 channel : str, one of ['stdout', 'stderr']
96 97 """
97 98 if channel not in ['stdout', 'stderr']:
98 99 raise ValueError('Invalid channel spec %s' % channel)
99 100
100 101 if hasattr(file, 'write') and hasattr(file, 'seek'):
101 102 self.file = file_or_name
102 103 else:
103 104 self.file = open(file_or_name, mode)
104 105 self.channel = channel
105 106 self.ostream = getattr(sys, channel)
106 107 setattr(sys, channel, self)
107 108 self._closed = False
108 109
109 110 def close(self):
110 111 """Close the file and restore the channel."""
111 112 self.flush()
112 113 setattr(sys, self.channel, self.ostream)
113 114 self.file.close()
114 115 self._closed = True
115 116
116 117 def write(self, data):
117 118 """Write data to both channels."""
118 119 self.file.write(data)
119 120 self.ostream.write(data)
120 121 self.ostream.flush()
121 122
122 123 def flush(self):
123 124 """Flush both channels."""
124 125 self.file.flush()
125 126 self.ostream.flush()
126 127
127 128 def __del__(self):
128 129 if not self._closed:
129 130 self.close()
130 131
131 132
132 133 def file_read(filename):
133 134 """Read a file and close it. Returns the file source."""
134 135 fobj = open(filename,'r');
135 136 source = fobj.read();
136 137 fobj.close()
137 138 return source
138 139
139 140
140 141 def file_readlines(filename):
141 142 """Read a file and close it. Returns the file source using readlines()."""
142 143 fobj = open(filename,'r');
143 144 lines = fobj.readlines();
144 145 fobj.close()
145 146 return lines
146 147
147 148
148 149 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
149 150 """Take multiple lines of input.
150 151
151 152 A list with each line of input as a separate element is returned when a
152 153 termination string is entered (defaults to a single '.'). Input can also
153 154 terminate via EOF (^D in Unix, ^Z-RET in Windows).
154 155
155 156 Lines of input which end in \\ are joined into single entries (and a
156 157 secondary continuation prompt is issued as long as the user terminates
157 158 lines with \\). This allows entering very long strings which are still
158 159 meant to be treated as single entities.
159 160 """
160 161
161 162 try:
162 163 if header:
163 164 header += '\n'
164 165 lines = [raw_input(header + ps1)]
165 166 except EOFError:
166 167 return []
167 168 terminate = [terminate_str]
168 169 try:
169 170 while lines[-1:] != terminate:
170 171 new_line = raw_input(ps1)
171 172 while new_line.endswith('\\'):
172 173 new_line = new_line[:-1] + raw_input(ps2)
173 174 lines.append(new_line)
174 175
175 176 return lines[:-1] # don't return the termination command
176 177 except EOFError:
177 178 print
178 179 return lines
179 180
180 181
181 182 def raw_input_ext(prompt='', ps2='... '):
182 183 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
183 184
184 185 line = raw_input(prompt)
185 186 while line.endswith('\\'):
186 187 line = line[:-1] + raw_input(ps2)
187 188 return line
188 189
189 190
190 191 def ask_yes_no(prompt,default=None):
191 192 """Asks a question and returns a boolean (y/n) answer.
192 193
193 194 If default is given (one of 'y','n'), it is used if the user input is
194 195 empty. Otherwise the question is repeated until an answer is given.
195 196
196 197 An EOF is treated as the default answer. If there is no default, an
197 198 exception is raised to prevent infinite loops.
198 199
199 200 Valid answers are: y/yes/n/no (match is not case sensitive)."""
200 201
201 202 answers = {'y':True,'n':False,'yes':True,'no':False}
202 203 ans = None
203 204 while ans not in answers.keys():
204 205 try:
205 206 ans = raw_input(prompt+' ').lower()
206 207 if not ans: # response was an empty string
207 208 ans = default
208 209 except KeyboardInterrupt:
209 210 pass
210 211 except EOFError:
211 212 if default in answers.keys():
212 213 ans = default
213 214 print
214 215 else:
215 216 raise
216 217
217 218 return answers[ans]
218 219
219 220
220 221 class NLprinter:
221 222 """Print an arbitrarily nested list, indicating index numbers.
222 223
223 224 An instance of this class called nlprint is available and callable as a
224 225 function.
225 226
226 227 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
227 228 and using 'sep' to separate the index from the value. """
228 229
229 230 def __init__(self):
230 231 self.depth = 0
231 232
232 233 def __call__(self,lst,pos='',**kw):
233 234 """Prints the nested list numbering levels."""
234 235 kw.setdefault('indent',' ')
235 236 kw.setdefault('sep',': ')
236 237 kw.setdefault('start',0)
237 238 kw.setdefault('stop',len(lst))
238 239 # we need to remove start and stop from kw so they don't propagate
239 240 # into a recursive call for a nested list.
240 241 start = kw['start']; del kw['start']
241 242 stop = kw['stop']; del kw['stop']
242 243 if self.depth == 0 and 'header' in kw.keys():
243 print kw['header']
244 print(kw['header'])
244 245
245 246 for idx in range(start,stop):
246 247 elem = lst[idx]
247 248 if type(elem)==type([]):
248 249 self.depth += 1
249 250 self.__call__(elem,itpl('$pos$idx,'),**kw)
250 251 self.depth -= 1
251 252 else:
252 253 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
253 254
254 255 nlprint = NLprinter()
255 256
256 257
257 258 def temp_pyfile(src, ext='.py'):
258 259 """Make a temporary python file, return filename and filehandle.
259 260
260 261 Parameters
261 262 ----------
262 263 src : string or list of strings (no need for ending newlines if list)
263 264 Source code to be written to the file.
264 265
265 266 ext : optional, string
266 267 Extension for the generated file.
267 268
268 269 Returns
269 270 -------
270 271 (filename, open filehandle)
271 272 It is the caller's responsibility to close the open file and unlink it.
272 273 """
273 274 fname = tempfile.mkstemp(ext)[1]
274 275 f = open(fname,'w')
275 276 f.write(src)
276 277 f.flush()
277 278 return fname, f
278 279
279 280
280 def rprint(*info):
281 def rprint(*args, **kw):
282 """Raw print to sys.__stdout__"""
283
284 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
285 file=sys.__stdout__)
286 sys.__stdout__.flush()
287
288
289 def rprinte(*args, **kw):
281 290 """Raw print to sys.__stderr__"""
282 291
283 for item in info:
284 print >> sys.__stderr__, item,
285 print >> sys.__stderr__
292 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
293 file=sys.__stderr__)
286 294 sys.__stderr__.flush()
@@ -1,399 +1,400 b''
1 1 #!/usr/bin/env python
2 2 """A simple interactive kernel that talks to a frontend over 0MQ.
3 3
4 4 Things to do:
5 5
6 6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 7 call set_parent on all the PUB objects with the message about to be executed.
8 8 * Implement random port and security key logic.
9 9 * Implement control messages.
10 10 * Implement event loop and poll version.
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 17
17 18 # Standard library imports.
18 19 import __builtin__
19 20 import sys
20 21 import time
21 22 import traceback
22 23
23 24 # System library imports.
24 25 import zmq
25 26
26 27 # Local imports.
27 28 from IPython.config.configurable import Configurable
29 from IPython.utils import io
28 30 from IPython.utils.traitlets import Instance
29 31 from completer import KernelCompleter
30 32 from entry_point import base_launch_kernel, make_argument_parser, make_kernel, \
31 33 start_kernel
32 34 from iostream import OutStream
33 35 from session import Session, Message
34 36 from zmqshell import ZMQInteractiveShell
35 37
36 38 #-----------------------------------------------------------------------------
37 39 # Main kernel class
38 40 #-----------------------------------------------------------------------------
39 41
40 42 class Kernel(Configurable):
41 43
42 44 #---------------------------------------------------------------------------
43 45 # Kernel interface
44 46 #---------------------------------------------------------------------------
45 47
46 48 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
47 49 session = Instance(Session)
48 50 reply_socket = Instance('zmq.Socket')
49 51 pub_socket = Instance('zmq.Socket')
50 52 req_socket = Instance('zmq.Socket')
51 53
52 54 # Maps user-friendly backend names to matplotlib backend identifiers.
53 55 _pylab_map = { 'tk': 'TkAgg',
54 56 'gtk': 'GTKAgg',
55 57 'wx': 'WXAgg',
56 58 'qt': 'Qt4Agg', # qt3 not supported
57 59 'qt4': 'Qt4Agg',
58 60 'payload-svg' : \
59 61 'module://IPython.zmq.pylab.backend_payload_svg' }
60 62
61 63 def __init__(self, **kwargs):
62 64 super(Kernel, self).__init__(**kwargs)
63 65
64 66 # Initialize the InteractiveShell subclass
65 67 self.shell = ZMQInteractiveShell.instance()
66 68 self.shell.displayhook.session = self.session
67 69 self.shell.displayhook.pub_socket = self.pub_socket
68 70
69 71 # TMP - hack while developing
70 72 self.shell._reply_content = None
71 73
72 74 # Build dict of handlers for message types
73 75 msg_types = [ 'execute_request', 'complete_request',
74 76 'object_info_request', 'prompt_request',
75 77 'history_request' ]
76 78 self.handlers = {}
77 79 for msg_type in msg_types:
78 80 self.handlers[msg_type] = getattr(self, msg_type)
79 81
80 82 def activate_pylab(self, backend=None, import_all=True):
81 83 """ Activates pylab in this kernel's namespace.
82 84
83 85 Parameters:
84 86 -----------
85 87 backend : str, optional
86 88 A valid backend name.
87 89
88 90 import_all : bool, optional
89 91 If true, an 'import *' is done from numpy and pylab.
90 92 """
91 93 # FIXME: This is adapted from IPython.lib.pylabtools.pylab_activate.
92 94 # Common functionality should be refactored.
93 95
94 96 # We must set the desired backend before importing pylab.
95 97 import matplotlib
96 98 if backend:
97 99 backend_id = self._pylab_map[backend]
98 100 if backend_id.startswith('module://'):
99 101 # Work around bug in matplotlib: matplotlib.use converts the
100 102 # backend_id to lowercase even if a module name is specified!
101 103 matplotlib.rcParams['backend'] = backend_id
102 104 else:
103 105 matplotlib.use(backend_id)
104 106
105 107 # Import numpy as np/pyplot as plt are conventions we're trying to
106 108 # somewhat standardize on. Making them available to users by default
107 109 # will greatly help this.
108 110 exec ("import numpy\n"
109 111 "import matplotlib\n"
110 112 "from matplotlib import pylab, mlab, pyplot\n"
111 113 "np = numpy\n"
112 114 "plt = pyplot\n"
113 115 ) in self.shell.user_ns
114 116
115 117 if import_all:
116 118 exec("from matplotlib.pylab import *\n"
117 119 "from numpy import *\n") in self.shell.user_ns
118 120
119 121 matplotlib.interactive(True)
120 122
121 123 def start(self):
122 124 """ Start the kernel main loop.
123 125 """
124 126 while True:
125 127 ident = self.reply_socket.recv()
126 128 assert self.reply_socket.rcvmore(), "Missing message part."
127 129 msg = self.reply_socket.recv_json()
128 130 omsg = Message(msg)
129 print>>sys.__stdout__
130 print>>sys.__stdout__, omsg
131 io.rprint('\n', omsg)
131 132 handler = self.handlers.get(omsg.msg_type, None)
132 133 if handler is None:
133 print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
134 io.rprinte("UNKNOWN MESSAGE TYPE:", omsg)
134 135 else:
135 136 handler(ident, omsg)
136 137
137 138 #---------------------------------------------------------------------------
138 139 # Kernel request handlers
139 140 #---------------------------------------------------------------------------
140 141
141 142 def execute_request(self, ident, parent):
142 143 try:
143 144 code = parent[u'content'][u'code']
144 145 except:
145 print>>sys.__stderr__, "Got bad msg: "
146 print>>sys.__stderr__, Message(parent)
146 io.rprinte("Got bad msg: ")
147 io.rprinte(Message(parent))
147 148 return
148 149 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
149 150 self.pub_socket.send_json(pyin_msg)
150 151
151 152 try:
152 153 # Replace raw_input. Note that is not sufficient to replace
153 154 # raw_input in the user namespace.
154 155 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
155 156 __builtin__.raw_input = raw_input
156 157
157 158 # Set the parent message of the display hook and out streams.
158 159 self.shell.displayhook.set_parent(parent)
159 160 sys.stdout.set_parent(parent)
160 161 sys.stderr.set_parent(parent)
161 162
162 163 # FIXME: runlines calls the exception handler itself. We should
163 164 # clean this up.
164 165 self.shell._reply_content = None
165 166 self.shell.runlines(code)
166 167 except:
167 168 # FIXME: this code right now isn't being used yet by default,
168 169 # because the runlines() call above directly fires off exception
169 170 # reporting. This code, therefore, is only active in the scenario
170 171 # where runlines itself has an unhandled exception. We need to
171 172 # uniformize this, for all exception construction to come from a
172 173 # single location in the codbase.
173 174 etype, evalue, tb = sys.exc_info()
174 175 tb_list = traceback.format_exception(etype, evalue, tb)
175 176 reply_content = self.shell._showtraceback(etype, evalue, tb_list)
176 177 else:
177 178 payload = self.shell.payload_manager.read_payload()
178 179 # Be agressive about clearing the payload because we don't want
179 180 # it to sit in memory until the next execute_request comes in.
180 181 self.shell.payload_manager.clear_payload()
181 182 reply_content = { 'status' : 'ok', 'payload' : payload }
182 183
183 184 # Compute the prompt information
184 185 prompt_number = self.shell.displayhook.prompt_count
185 186 reply_content['prompt_number'] = prompt_number
186 187 prompt_string = self.shell.displayhook.prompt1.peek_next_prompt()
187 188 next_prompt = {'prompt_string' : prompt_string,
188 189 'prompt_number' : prompt_number+1,
189 190 'input_sep' : self.shell.displayhook.input_sep}
190 191 reply_content['next_prompt'] = next_prompt
191 192
192 193 # TMP - fish exception info out of shell, possibly left there by
193 194 # runlines
194 195 if self.shell._reply_content is not None:
195 196 reply_content.update(self.shell._reply_content)
196 197
197 198 # Flush output before sending the reply.
198 199 sys.stderr.flush()
199 200 sys.stdout.flush()
200 201
201 202 # Send the reply.
202 203 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
203 print>>sys.__stdout__, Message(reply_msg)
204 io.rprint(Message(reply_msg))
204 205 self.reply_socket.send(ident, zmq.SNDMORE)
205 206 self.reply_socket.send_json(reply_msg)
206 207 if reply_msg['content']['status'] == u'error':
207 208 self._abort_queue()
208 209
209 210 def complete_request(self, ident, parent):
210 matches = {'matches' : self._complete(parent),
211 txt, matches = self._complete(parent)
212 matches = {'matches' : matches,
213 'matched_text' : txt,
211 214 'status' : 'ok'}
212 215 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
213 216 matches, parent, ident)
214 print >> sys.__stdout__, completion_msg
217 io.rprint(completion_msg)
215 218
216 219 def object_info_request(self, ident, parent):
217 220 context = parent['content']['oname'].split('.')
218 221 object_info = self._object_info(context)
219 222 msg = self.session.send(self.reply_socket, 'object_info_reply',
220 223 object_info, parent, ident)
221 print >> sys.__stdout__, msg
224 io.rprint(msg)
222 225
223 226 def prompt_request(self, ident, parent):
224 227 prompt_number = self.shell.displayhook.prompt_count
225 228 prompt_string = self.shell.displayhook.prompt1.peek_next_prompt()
226 229 content = {'prompt_string' : prompt_string,
227 230 'prompt_number' : prompt_number+1,
228 231 'input_sep' : self.shell.displayhook.input_sep}
229 232 msg = self.session.send(self.reply_socket, 'prompt_reply',
230 233 content, parent, ident)
231 print >> sys.__stdout__, msg
234 io.rprint(msg)
232 235
233 236 def history_request(self, ident, parent):
234 237 output = parent['content']['output']
235 238 index = parent['content']['index']
236 239 raw = parent['content']['raw']
237 240 hist = self.shell.get_history(index=index, raw=raw, output=output)
238 241 content = {'history' : hist}
239 242 msg = self.session.send(self.reply_socket, 'history_reply',
240 243 content, parent, ident)
241 print >> sys.__stdout__, msg
244 io.rprint(msg)
242 245
243 246 #---------------------------------------------------------------------------
244 247 # Protected interface
245 248 #---------------------------------------------------------------------------
246 249
247 250 def _abort_queue(self):
248 251 while True:
249 252 try:
250 253 ident = self.reply_socket.recv(zmq.NOBLOCK)
251 254 except zmq.ZMQError, e:
252 255 if e.errno == zmq.EAGAIN:
253 256 break
254 257 else:
255 258 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
256 259 msg = self.reply_socket.recv_json()
257 print>>sys.__stdout__, "Aborting:"
258 print>>sys.__stdout__, Message(msg)
260 io.rprint("Aborting:\n", Message(msg))
259 261 msg_type = msg['msg_type']
260 262 reply_type = msg_type.split('_')[0] + '_reply'
261 263 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
262 print>>sys.__stdout__, Message(reply_msg)
264 io.rprint(Message(reply_msg))
263 265 self.reply_socket.send(ident,zmq.SNDMORE)
264 266 self.reply_socket.send_json(reply_msg)
265 267 # We need to wait a bit for requests to come in. This can probably
266 268 # be set shorter for true asynchronous clients.
267 269 time.sleep(0.1)
268 270
269 271 def _raw_input(self, prompt, ident, parent):
270 272 # Flush output before making the request.
271 273 sys.stderr.flush()
272 274 sys.stdout.flush()
273 275
274 276 # Send the input request.
275 277 content = dict(prompt=prompt)
276 278 msg = self.session.msg(u'input_request', content, parent)
277 279 self.req_socket.send_json(msg)
278 280
279 281 # Await a response.
280 282 reply = self.req_socket.recv_json()
281 283 try:
282 284 value = reply['content']['value']
283 285 except:
284 print>>sys.__stderr__, "Got bad raw_input reply: "
285 print>>sys.__stderr__, Message(parent)
286 io.rprinte("Got bad raw_input reply: ")
287 io.rprinte(Message(parent))
286 288 value = ''
287 289 return value
288 290
289 291 def _complete(self, msg):
290 #from IPython.utils.io import rprint # dbg
291 #rprint('\n\n**MSG**\n\n', msg) # dbg
292 #import traceback; rprint(''.join(traceback.format_stack())) # dbg
293 292 c = msg['content']
294 293 try:
295 294 cpos = int(c['cursor_pos'])
296 295 except:
297 296 # If we don't get something that we can convert to an integer, at
298 # leasat attempt the completion guessing the cursor is at the end
299 # of the text
297 # least attempt the completion guessing the cursor is at the end of
298 # the text, if there's any, and otherwise of the line
300 299 cpos = len(c['text'])
300 if cpos==0:
301 cpos = len(c['line'])
301 302 return self.shell.complete(c['text'], c['line'], cpos)
302 303
303 304 def _object_info(self, context):
304 305 symbol, leftover = self._symbol_from_context(context)
305 306 if symbol is not None and not leftover:
306 307 doc = getattr(symbol, '__doc__', '')
307 308 else:
308 309 doc = ''
309 310 object_info = dict(docstring = doc)
310 311 return object_info
311 312
312 313 def _symbol_from_context(self, context):
313 314 if not context:
314 315 return None, context
315 316
316 317 base_symbol_string = context[0]
317 318 symbol = self.shell.user_ns.get(base_symbol_string, None)
318 319 if symbol is None:
319 320 symbol = __builtin__.__dict__.get(base_symbol_string, None)
320 321 if symbol is None:
321 322 return None, context
322 323
323 324 context = context[1:]
324 325 for i, name in enumerate(context):
325 326 new_symbol = getattr(symbol, name, None)
326 327 if new_symbol is None:
327 328 return symbol, context[i:]
328 329 else:
329 330 symbol = new_symbol
330 331
331 332 return symbol, []
332 333
333 334 #-----------------------------------------------------------------------------
334 335 # Kernel main and launch functions
335 336 #-----------------------------------------------------------------------------
336 337
337 338 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False,
338 339 pylab=False):
339 340 """ Launches a localhost kernel, binding to the specified ports.
340 341
341 342 Parameters
342 343 ----------
343 344 xrep_port : int, optional
344 345 The port to use for XREP channel.
345 346
346 347 pub_port : int, optional
347 348 The port to use for the SUB channel.
348 349
349 350 req_port : int, optional
350 351 The port to use for the REQ (raw input) channel.
351 352
352 353 independent : bool, optional (default False)
353 354 If set, the kernel process is guaranteed to survive if this process
354 355 dies. If not set, an effort is made to ensure that the kernel is killed
355 356 when this process dies. Note that in this case it is still good practice
356 357 to kill kernels manually before exiting.
357 358
358 359 pylab : bool or string, optional (default False)
359 360 If not False, the kernel will be launched with pylab enabled. If a
360 361 string is passed, matplotlib will use the specified backend. Otherwise,
361 362 matplotlib's default backend will be used.
362 363
363 364 Returns
364 365 -------
365 366 A tuple of form:
366 367 (kernel_process, xrep_port, pub_port, req_port)
367 368 where kernel_process is a Popen object and the ports are integers.
368 369 """
369 370 extra_arguments = []
370 371 if pylab:
371 372 extra_arguments.append('--pylab')
372 373 if isinstance(pylab, basestring):
373 374 extra_arguments.append(pylab)
374 375 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
375 376 xrep_port, pub_port, req_port, independent,
376 377 extra_arguments)
377 378
378 379 def main():
379 380 """ The IPython kernel main entry point.
380 381 """
381 382 parser = make_argument_parser()
382 383 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
383 384 const='auto', help = \
384 385 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
385 386 given, the GUI backend is matplotlib's, otherwise use one of: \
386 387 ['tk', 'gtk', 'qt', 'wx', 'payload-svg'].")
387 388 namespace = parser.parse_args()
388 389
389 390 kernel = make_kernel(namespace, Kernel, OutStream)
390 391 if namespace.pylab:
391 392 if namespace.pylab == 'auto':
392 393 kernel.activate_pylab()
393 394 else:
394 395 kernel.activate_pylab(namespace.pylab)
395 396
396 397 start_kernel(namespace, kernel)
397 398
398 399 if __name__ == '__main__':
399 400 main()
General Comments 0
You need to be logged in to leave comments. Login now