##// END OF EJS Templates
json_clean zmqshell replies...
MinRK -
Show More
@@ -1,441 +1,442 b''
1 1 """A ZMQ-based subclass of InteractiveShell.
2 2
3 3 This code is meant to ease the refactoring of the base InteractiveShell into
4 4 something with a cleaner architecture for 2-process use, without actually
5 5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 6 we subclass and override what we want to fix. Once this is working well, we
7 7 can go back to the base class and refactor the code for a cleaner inheritance
8 8 implementation that doesn't rely on so much monkeypatching.
9 9
10 10 But this lets us maintain a fully working IPython as we develop the new
11 11 machinery. This should thus be thought of as scaffolding.
12 12 """
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib
19 19 import inspect
20 20 import os
21 21
22 22 # Our own
23 23 from IPython.core.interactiveshell import (
24 24 InteractiveShell, InteractiveShellABC
25 25 )
26 26 from IPython.core import page
27 27 from IPython.core.autocall import ZMQExitAutocall
28 28 from IPython.core.displaypub import DisplayPublisher
29 29 from IPython.core.macro import Macro
30 30 from IPython.core.magic import MacroToEdit
31 31 from IPython.core.payloadpage import install_payload_page
32 32 from IPython.utils import io
33 from IPython.utils.jsonutil import json_clean
33 34 from IPython.utils.path import get_py_filename
34 35 from IPython.utils.traitlets import Instance, Type, Dict, CBool
35 36 from IPython.utils.warn import warn
36 37 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
37 38 from IPython.zmq.session import extract_header
38 39 from session import Session
39 40
40 41 #-----------------------------------------------------------------------------
41 42 # Globals and side-effects
42 43 #-----------------------------------------------------------------------------
43 44
44 45 # Install the payload version of page.
45 46 install_payload_page()
46 47
47 48 #-----------------------------------------------------------------------------
48 49 # Functions and classes
49 50 #-----------------------------------------------------------------------------
50 51
51 52 class ZMQDisplayPublisher(DisplayPublisher):
52 53 """A display publisher that publishes data using a ZeroMQ PUB socket."""
53 54
54 55 session = Instance(Session)
55 56 pub_socket = Instance('zmq.Socket')
56 57 parent_header = Dict({})
57 58
58 59 def set_parent(self, parent):
59 60 """Set the parent for outbound messages."""
60 61 self.parent_header = extract_header(parent)
61 62
62 63 def publish(self, source, data, metadata=None):
63 64 if metadata is None:
64 65 metadata = {}
65 66 self._validate_data(source, data, metadata)
66 67 content = {}
67 68 content['source'] = source
68 69 _encode_binary(data)
69 70 content['data'] = data
70 71 content['metadata'] = metadata
71 72 self.session.send(
72 self.pub_socket, u'display_data', content,
73 self.pub_socket, u'display_data', json_clean(content),
73 74 parent=self.parent_header
74 75 )
75 76
76 77
77 78 class ZMQInteractiveShell(InteractiveShell):
78 79 """A subclass of InteractiveShell for ZMQ."""
79 80
80 81 displayhook_class = Type(ZMQShellDisplayHook)
81 82 display_pub_class = Type(ZMQDisplayPublisher)
82 83
83 84 # Override the traitlet in the parent class, because there's no point using
84 85 # readline for the kernel. Can be removed when the readline code is moved
85 86 # to the terminal frontend.
86 87
87 88 # FIXME. This is disabled for now, even though it may cause problems under
88 89 # Windows, because it breaks %run in the Qt console. See gh-617 for more
89 90 # details. Re-enable once we've fully tested that %run works in the Qt
90 91 # console with syntax highlighting in tracebacks.
91 92 # readline_use = CBool(False)
92 93 # /FIXME
93 94
94 95 exiter = Instance(ZMQExitAutocall)
95 96 def _exiter_default(self):
96 97 return ZMQExitAutocall(self)
97 98
98 99 keepkernel_on_exit = None
99 100
100 101 def init_environment(self):
101 102 """Configure the user's environment.
102 103
103 104 """
104 105 env = os.environ
105 106 # These two ensure 'ls' produces nice coloring on BSD-derived systems
106 107 env['TERM'] = 'xterm-color'
107 108 env['CLICOLOR'] = '1'
108 109 # Since normal pagers don't work at all (over pexpect we don't have
109 110 # single-key control of the subprocess), try to disable paging in
110 111 # subprocesses as much as possible.
111 112 env['PAGER'] = 'cat'
112 113 env['GIT_PAGER'] = 'cat'
113 114
114 115 def auto_rewrite_input(self, cmd):
115 116 """Called to show the auto-rewritten input for autocall and friends.
116 117
117 118 FIXME: this payload is currently not correctly processed by the
118 119 frontend.
119 120 """
120 121 new = self.displayhook.prompt1.auto_rewrite() + cmd
121 122 payload = dict(
122 123 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
123 124 transformed_input=new,
124 125 )
125 126 self.payload_manager.write_payload(payload)
126 127
127 128 def ask_exit(self):
128 129 """Engage the exit actions."""
129 130 payload = dict(
130 131 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
131 132 exit=True,
132 133 keepkernel=self.keepkernel_on_exit,
133 134 )
134 135 self.payload_manager.write_payload(payload)
135 136
136 137 def _showtraceback(self, etype, evalue, stb):
137 138
138 139 exc_content = {
139 140 u'traceback' : stb,
140 141 u'ename' : unicode(etype.__name__),
141 142 u'evalue' : unicode(evalue)
142 143 }
143 144
144 145 dh = self.displayhook
145 146 # Send exception info over pub socket for other clients than the caller
146 147 # to pick up
147 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', exc_content, dh.parent_header)
148 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header)
148 149
149 150 # FIXME - Hack: store exception info in shell object. Right now, the
150 151 # caller is reading this info after the fact, we need to fix this logic
151 152 # to remove this hack. Even uglier, we need to store the error status
152 153 # here, because in the main loop, the logic that sets it is being
153 154 # skipped because runlines swallows the exceptions.
154 155 exc_content[u'status'] = u'error'
155 156 self._reply_content = exc_content
156 157 # /FIXME
157 158
158 159 return exc_content
159 160
160 161 #------------------------------------------------------------------------
161 162 # Magic overrides
162 163 #------------------------------------------------------------------------
163 164 # Once the base class stops inheriting from magic, this code needs to be
164 165 # moved into a separate machinery as well. For now, at least isolate here
165 166 # the magics which this class needs to implement differently from the base
166 167 # class, or that are unique to it.
167 168
168 169 def magic_doctest_mode(self,parameter_s=''):
169 170 """Toggle doctest mode on and off.
170 171
171 172 This mode is intended to make IPython behave as much as possible like a
172 173 plain Python shell, from the perspective of how its prompts, exceptions
173 174 and output look. This makes it easy to copy and paste parts of a
174 175 session into doctests. It does so by:
175 176
176 177 - Changing the prompts to the classic ``>>>`` ones.
177 178 - Changing the exception reporting mode to 'Plain'.
178 179 - Disabling pretty-printing of output.
179 180
180 181 Note that IPython also supports the pasting of code snippets that have
181 182 leading '>>>' and '...' prompts in them. This means that you can paste
182 183 doctests from files or docstrings (even if they have leading
183 184 whitespace), and the code will execute correctly. You can then use
184 185 '%history -t' to see the translated history; this will give you the
185 186 input after removal of all the leading prompts and whitespace, which
186 187 can be pasted back into an editor.
187 188
188 189 With these features, you can switch into this mode easily whenever you
189 190 need to do testing and changes to doctests, without having to leave
190 191 your existing IPython session.
191 192 """
192 193
193 194 from IPython.utils.ipstruct import Struct
194 195
195 196 # Shorthands
196 197 shell = self.shell
197 198 disp_formatter = self.shell.display_formatter
198 199 ptformatter = disp_formatter.formatters['text/plain']
199 200 # dstore is a data store kept in the instance metadata bag to track any
200 201 # changes we make, so we can undo them later.
201 202 dstore = shell.meta.setdefault('doctest_mode', Struct())
202 203 save_dstore = dstore.setdefault
203 204
204 205 # save a few values we'll need to recover later
205 206 mode = save_dstore('mode', False)
206 207 save_dstore('rc_pprint', ptformatter.pprint)
207 208 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
208 209 save_dstore('xmode', shell.InteractiveTB.mode)
209 210
210 211 if mode == False:
211 212 # turn on
212 213 ptformatter.pprint = False
213 214 disp_formatter.plain_text_only = True
214 215 shell.magic_xmode('Plain')
215 216 else:
216 217 # turn off
217 218 ptformatter.pprint = dstore.rc_pprint
218 219 disp_formatter.plain_text_only = dstore.rc_plain_text_only
219 220 shell.magic_xmode(dstore.xmode)
220 221
221 222 # Store new mode and inform on console
222 223 dstore.mode = bool(1-int(mode))
223 224 mode_label = ['OFF','ON'][dstore.mode]
224 225 print('Doctest mode is:', mode_label)
225 226
226 227 # Send the payload back so that clients can modify their prompt display
227 228 payload = dict(
228 229 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
229 230 mode=dstore.mode)
230 231 self.payload_manager.write_payload(payload)
231 232
232 233 def magic_edit(self,parameter_s='',last_call=['','']):
233 234 """Bring up an editor and execute the resulting code.
234 235
235 236 Usage:
236 237 %edit [options] [args]
237 238
238 239 %edit runs an external text editor. You will need to set the command for
239 240 this editor via the ``TerminalInteractiveShell.editor`` option in your
240 241 configuration file before it will work.
241 242
242 243 This command allows you to conveniently edit multi-line code right in
243 244 your IPython session.
244 245
245 246 If called without arguments, %edit opens up an empty editor with a
246 247 temporary file and will execute the contents of this file when you
247 248 close it (don't forget to save it!).
248 249
249 250
250 251 Options:
251 252
252 253 -n <number>: open the editor at a specified line number. By default,
253 254 the IPython editor hook uses the unix syntax 'editor +N filename', but
254 255 you can configure this by providing your own modified hook if your
255 256 favorite editor supports line-number specifications with a different
256 257 syntax.
257 258
258 259 -p: this will call the editor with the same data as the previous time
259 260 it was used, regardless of how long ago (in your current session) it
260 261 was.
261 262
262 263 -r: use 'raw' input. This option only applies to input taken from the
263 264 user's history. By default, the 'processed' history is used, so that
264 265 magics are loaded in their transformed version to valid Python. If
265 266 this option is given, the raw input as typed as the command line is
266 267 used instead. When you exit the editor, it will be executed by
267 268 IPython's own processor.
268 269
269 270 -x: do not execute the edited code immediately upon exit. This is
270 271 mainly useful if you are editing programs which need to be called with
271 272 command line arguments, which you can then do using %run.
272 273
273 274
274 275 Arguments:
275 276
276 277 If arguments are given, the following possibilites exist:
277 278
278 279 - The arguments are numbers or pairs of colon-separated numbers (like
279 280 1 4:8 9). These are interpreted as lines of previous input to be
280 281 loaded into the editor. The syntax is the same of the %macro command.
281 282
282 283 - If the argument doesn't start with a number, it is evaluated as a
283 284 variable and its contents loaded into the editor. You can thus edit
284 285 any string which contains python code (including the result of
285 286 previous edits).
286 287
287 288 - If the argument is the name of an object (other than a string),
288 289 IPython will try to locate the file where it was defined and open the
289 290 editor at the point where it is defined. You can use `%edit function`
290 291 to load an editor exactly at the point where 'function' is defined,
291 292 edit it and have the file be executed automatically.
292 293
293 294 If the object is a macro (see %macro for details), this opens up your
294 295 specified editor with a temporary file containing the macro's data.
295 296 Upon exit, the macro is reloaded with the contents of the file.
296 297
297 298 Note: opening at an exact line is only supported under Unix, and some
298 299 editors (like kedit and gedit up to Gnome 2.8) do not understand the
299 300 '+NUMBER' parameter necessary for this feature. Good editors like
300 301 (X)Emacs, vi, jed, pico and joe all do.
301 302
302 303 - If the argument is not found as a variable, IPython will look for a
303 304 file with that name (adding .py if necessary) and load it into the
304 305 editor. It will execute its contents with execfile() when you exit,
305 306 loading any code in the file into your interactive namespace.
306 307
307 308 After executing your code, %edit will return as output the code you
308 309 typed in the editor (except when it was an existing file). This way
309 310 you can reload the code in further invocations of %edit as a variable,
310 311 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
311 312 the output.
312 313
313 314 Note that %edit is also available through the alias %ed.
314 315
315 316 This is an example of creating a simple function inside the editor and
316 317 then modifying it. First, start up the editor:
317 318
318 319 In [1]: ed
319 320 Editing... done. Executing edited code...
320 321 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
321 322
322 323 We can then call the function foo():
323 324
324 325 In [2]: foo()
325 326 foo() was defined in an editing session
326 327
327 328 Now we edit foo. IPython automatically loads the editor with the
328 329 (temporary) file where foo() was previously defined:
329 330
330 331 In [3]: ed foo
331 332 Editing... done. Executing edited code...
332 333
333 334 And if we call foo() again we get the modified version:
334 335
335 336 In [4]: foo()
336 337 foo() has now been changed!
337 338
338 339 Here is an example of how to edit a code snippet successive
339 340 times. First we call the editor:
340 341
341 342 In [5]: ed
342 343 Editing... done. Executing edited code...
343 344 hello
344 345 Out[5]: "print 'hello'n"
345 346
346 347 Now we call it again with the previous output (stored in _):
347 348
348 349 In [6]: ed _
349 350 Editing... done. Executing edited code...
350 351 hello world
351 352 Out[6]: "print 'hello world'n"
352 353
353 354 Now we call it with the output #8 (stored in _8, also as Out[8]):
354 355
355 356 In [7]: ed _8
356 357 Editing... done. Executing edited code...
357 358 hello again
358 359 Out[7]: "print 'hello again'n"
359 360 """
360 361
361 362 opts,args = self.parse_options(parameter_s,'prn:')
362 363
363 364 try:
364 365 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
365 366 except MacroToEdit as e:
366 367 # TODO: Implement macro editing over 2 processes.
367 368 print("Macro editing not yet implemented in 2-process model.")
368 369 return
369 370
370 371 # Make sure we send to the client an absolute path, in case the working
371 372 # directory of client and kernel don't match
372 373 filename = os.path.abspath(filename)
373 374
374 375 payload = {
375 376 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
376 377 'filename' : filename,
377 378 'line_number' : lineno
378 379 }
379 380 self.payload_manager.write_payload(payload)
380 381
381 382 def magic_gui(self, *args, **kwargs):
382 383 raise NotImplementedError(
383 384 'Kernel GUI support is not implemented yet, except for --pylab.')
384 385
385 386 def magic_pylab(self, *args, **kwargs):
386 387 raise NotImplementedError(
387 388 'pylab support must be enabled in command line options.')
388 389
389 390 # A few magics that are adapted to the specifics of using pexpect and a
390 391 # remote terminal
391 392
392 393 def magic_clear(self, arg_s):
393 394 """Clear the terminal."""
394 395 if os.name == 'posix':
395 396 self.shell.system("clear")
396 397 else:
397 398 self.shell.system("cls")
398 399
399 400 if os.name == 'nt':
400 401 # This is the usual name in windows
401 402 magic_cls = magic_clear
402 403
403 404 # Terminal pagers won't work over pexpect, but we do have our own pager
404 405
405 406 def magic_less(self, arg_s):
406 407 """Show a file through the pager.
407 408
408 409 Files ending in .py are syntax-highlighted."""
409 410 cont = open(arg_s).read()
410 411 if arg_s.endswith('.py'):
411 412 cont = self.shell.pycolorize(cont)
412 413 page.page(cont)
413 414
414 415 magic_more = magic_less
415 416
416 417 # Man calls a pager, so we also need to redefine it
417 418 if os.name == 'posix':
418 419 def magic_man(self, arg_s):
419 420 """Find the man page for the given command and display in pager."""
420 421 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
421 422 split=False))
422 423
423 424 # FIXME: this is specific to the GUI, so we should let the gui app load
424 425 # magics at startup that are only for the gui. Once the gui app has proper
425 426 # profile and configuration management, we can have it initialize a kernel
426 427 # with a special config file that provides these.
427 428 def magic_guiref(self, arg_s):
428 429 """Show a basic reference about the GUI console."""
429 430 from IPython.core.usage import gui_reference
430 431 page.page(gui_reference, auto_html=True)
431 432
432 433 def set_next_input(self, text):
433 434 """Send the specified text to the frontend to be presented at the next
434 435 input cell."""
435 436 payload = dict(
436 437 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
437 438 text=text
438 439 )
439 440 self.payload_manager.write_payload(payload)
440 441
441 442 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now