##// END OF EJS Templates
Fix for 'man' formatting (mostly on OSX, but the fix is OK on linux)
Fernando Perez -
Show More
@@ -1,545 +1,546 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 import re
22 22
23 23 # Our own
24 24 from IPython.core.interactiveshell import (
25 25 InteractiveShell, InteractiveShellABC
26 26 )
27 27 from IPython.core import page
28 28 from IPython.core.displayhook import DisplayHook
29 29 from IPython.core.macro import Macro
30 30 from IPython.core.payloadpage import install_payload_page
31 31 from IPython.utils import io
32 32 from IPython.utils.path import get_py_filename
33 33 from IPython.utils.text import StringTypes
34 34 from IPython.utils.traitlets import Instance, Type, Dict
35 35 from IPython.utils.warn import warn
36 36 from IPython.zmq.session import extract_header
37 37 from session import Session
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # Globals and side-effects
41 41 #-----------------------------------------------------------------------------
42 42
43 43 # Install the payload version of page.
44 44 install_payload_page()
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Functions and classes
48 48 #-----------------------------------------------------------------------------
49 49
50 50 class ZMQDisplayHook(DisplayHook):
51 51
52 52 session = Instance(Session)
53 53 pub_socket = Instance('zmq.Socket')
54 54 parent_header = Dict({})
55 55
56 56 def set_parent(self, parent):
57 57 """Set the parent for outbound messages."""
58 58 self.parent_header = extract_header(parent)
59 59
60 60 def start_displayhook(self):
61 61 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
62 62
63 63 def write_output_prompt(self):
64 64 """Write the output prompt."""
65 65 if self.do_full_cache:
66 66 self.msg['content']['execution_count'] = self.prompt_count
67 67
68 68 def write_result_repr(self, result_repr):
69 69 self.msg['content']['data'] = result_repr
70 70
71 71 def finish_displayhook(self):
72 72 """Finish up all displayhook activities."""
73 73 self.pub_socket.send_json(self.msg)
74 74 self.msg = None
75 75
76 76
77 77 class ZMQInteractiveShell(InteractiveShell):
78 78 """A subclass of InteractiveShell for ZMQ."""
79 79
80 80 displayhook_class = Type(ZMQDisplayHook)
81 81
82 82 def init_environment(self):
83 83 """Configure the user's environment.
84 84
85 85 """
86 86 env = os.environ
87 87 # These two ensure 'ls' produces nice coloring on BSD-derived systems
88 88 env['TERM'] = 'xterm-color'
89 89 env['CLICOLOR'] = '1'
90 90 # Since normal pagers don't work at all (over pexpect we don't have
91 91 # single-key control of the subprocess), try to disable paging in
92 92 # subprocesses as much as possible.
93 93 env['PAGER'] = 'cat'
94 94 env['GIT_PAGER'] = 'cat'
95 95
96 96 def auto_rewrite_input(self, cmd):
97 97 """Called to show the auto-rewritten input for autocall and friends.
98 98
99 99 FIXME: this payload is currently not correctly processed by the
100 100 frontend.
101 101 """
102 102 new = self.displayhook.prompt1.auto_rewrite() + cmd
103 103 payload = dict(
104 104 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
105 105 transformed_input=new,
106 106 )
107 107 self.payload_manager.write_payload(payload)
108 108
109 109 def ask_exit(self):
110 110 """Engage the exit actions."""
111 111 payload = dict(
112 112 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
113 113 exit=True,
114 114 )
115 115 self.payload_manager.write_payload(payload)
116 116
117 117 def _showtraceback(self, etype, evalue, stb):
118 118
119 119 exc_content = {
120 120 u'traceback' : stb,
121 121 u'ename' : unicode(etype.__name__),
122 122 u'evalue' : unicode(evalue)
123 123 }
124 124
125 125 dh = self.displayhook
126 126 exc_msg = dh.session.msg(u'pyerr', exc_content, dh.parent_header)
127 127 # Send exception info over pub socket for other clients than the caller
128 128 # to pick up
129 129 dh.pub_socket.send_json(exc_msg)
130 130
131 131 # FIXME - Hack: store exception info in shell object. Right now, the
132 132 # caller is reading this info after the fact, we need to fix this logic
133 133 # to remove this hack. Even uglier, we need to store the error status
134 134 # here, because in the main loop, the logic that sets it is being
135 135 # skipped because runlines swallows the exceptions.
136 136 exc_content[u'status'] = u'error'
137 137 self._reply_content = exc_content
138 138 # /FIXME
139 139
140 140 return exc_content
141 141
142 142 #------------------------------------------------------------------------
143 143 # Magic overrides
144 144 #------------------------------------------------------------------------
145 145 # Once the base class stops inheriting from magic, this code needs to be
146 146 # moved into a separate machinery as well. For now, at least isolate here
147 147 # the magics which this class needs to implement differently from the base
148 148 # class, or that are unique to it.
149 149
150 150 def magic_doctest_mode(self,parameter_s=''):
151 151 """Toggle doctest mode on and off.
152 152
153 153 This mode is intended to make IPython behave as much as possible like a
154 154 plain Python shell, from the perspective of how its prompts, exceptions
155 155 and output look. This makes it easy to copy and paste parts of a
156 156 session into doctests. It does so by:
157 157
158 158 - Changing the prompts to the classic ``>>>`` ones.
159 159 - Changing the exception reporting mode to 'Plain'.
160 160 - Disabling pretty-printing of output.
161 161
162 162 Note that IPython also supports the pasting of code snippets that have
163 163 leading '>>>' and '...' prompts in them. This means that you can paste
164 164 doctests from files or docstrings (even if they have leading
165 165 whitespace), and the code will execute correctly. You can then use
166 166 '%history -t' to see the translated history; this will give you the
167 167 input after removal of all the leading prompts and whitespace, which
168 168 can be pasted back into an editor.
169 169
170 170 With these features, you can switch into this mode easily whenever you
171 171 need to do testing and changes to doctests, without having to leave
172 172 your existing IPython session.
173 173 """
174 174
175 175 from IPython.utils.ipstruct import Struct
176 176
177 177 # Shorthands
178 178 shell = self.shell
179 179 # dstore is a data store kept in the instance metadata bag to track any
180 180 # changes we make, so we can undo them later.
181 181 dstore = shell.meta.setdefault('doctest_mode', Struct())
182 182 save_dstore = dstore.setdefault
183 183
184 184 # save a few values we'll need to recover later
185 185 mode = save_dstore('mode', False)
186 186 save_dstore('rc_pprint', shell.pprint)
187 187 save_dstore('xmode', shell.InteractiveTB.mode)
188 188
189 189 if mode == False:
190 190 # turn on
191 191 shell.pprint = False
192 192 shell.magic_xmode('Plain')
193 193 else:
194 194 # turn off
195 195 shell.pprint = dstore.rc_pprint
196 196 shell.magic_xmode(dstore.xmode)
197 197
198 198 # Store new mode and inform on console
199 199 dstore.mode = bool(1-int(mode))
200 200 mode_label = ['OFF','ON'][dstore.mode]
201 201 print('Doctest mode is:', mode_label)
202 202
203 203 # Send the payload back so that clients can modify their prompt display
204 204 payload = dict(
205 205 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
206 206 mode=dstore.mode)
207 207 self.payload_manager.write_payload(payload)
208 208
209 209 def magic_edit(self,parameter_s='',last_call=['','']):
210 210 """Bring up an editor and execute the resulting code.
211 211
212 212 Usage:
213 213 %edit [options] [args]
214 214
215 215 %edit runs IPython's editor hook. The default version of this hook is
216 216 set to call the __IPYTHON__.rc.editor command. This is read from your
217 217 environment variable $EDITOR. If this isn't found, it will default to
218 218 vi under Linux/Unix and to notepad under Windows. See the end of this
219 219 docstring for how to change the editor hook.
220 220
221 221 You can also set the value of this editor via the command line option
222 222 '-editor' or in your ipythonrc file. This is useful if you wish to use
223 223 specifically for IPython an editor different from your typical default
224 224 (and for Windows users who typically don't set environment variables).
225 225
226 226 This command allows you to conveniently edit multi-line code right in
227 227 your IPython session.
228 228
229 229 If called without arguments, %edit opens up an empty editor with a
230 230 temporary file and will execute the contents of this file when you
231 231 close it (don't forget to save it!).
232 232
233 233
234 234 Options:
235 235
236 236 -n <number>: open the editor at a specified line number. By default,
237 237 the IPython editor hook uses the unix syntax 'editor +N filename', but
238 238 you can configure this by providing your own modified hook if your
239 239 favorite editor supports line-number specifications with a different
240 240 syntax.
241 241
242 242 -p: this will call the editor with the same data as the previous time
243 243 it was used, regardless of how long ago (in your current session) it
244 244 was.
245 245
246 246 -r: use 'raw' input. This option only applies to input taken from the
247 247 user's history. By default, the 'processed' history is used, so that
248 248 magics are loaded in their transformed version to valid Python. If
249 249 this option is given, the raw input as typed as the command line is
250 250 used instead. When you exit the editor, it will be executed by
251 251 IPython's own processor.
252 252
253 253 -x: do not execute the edited code immediately upon exit. This is
254 254 mainly useful if you are editing programs which need to be called with
255 255 command line arguments, which you can then do using %run.
256 256
257 257
258 258 Arguments:
259 259
260 260 If arguments are given, the following possibilites exist:
261 261
262 262 - The arguments are numbers or pairs of colon-separated numbers (like
263 263 1 4:8 9). These are interpreted as lines of previous input to be
264 264 loaded into the editor. The syntax is the same of the %macro command.
265 265
266 266 - If the argument doesn't start with a number, it is evaluated as a
267 267 variable and its contents loaded into the editor. You can thus edit
268 268 any string which contains python code (including the result of
269 269 previous edits).
270 270
271 271 - If the argument is the name of an object (other than a string),
272 272 IPython will try to locate the file where it was defined and open the
273 273 editor at the point where it is defined. You can use `%edit function`
274 274 to load an editor exactly at the point where 'function' is defined,
275 275 edit it and have the file be executed automatically.
276 276
277 277 If the object is a macro (see %macro for details), this opens up your
278 278 specified editor with a temporary file containing the macro's data.
279 279 Upon exit, the macro is reloaded with the contents of the file.
280 280
281 281 Note: opening at an exact line is only supported under Unix, and some
282 282 editors (like kedit and gedit up to Gnome 2.8) do not understand the
283 283 '+NUMBER' parameter necessary for this feature. Good editors like
284 284 (X)Emacs, vi, jed, pico and joe all do.
285 285
286 286 - If the argument is not found as a variable, IPython will look for a
287 287 file with that name (adding .py if necessary) and load it into the
288 288 editor. It will execute its contents with execfile() when you exit,
289 289 loading any code in the file into your interactive namespace.
290 290
291 291 After executing your code, %edit will return as output the code you
292 292 typed in the editor (except when it was an existing file). This way
293 293 you can reload the code in further invocations of %edit as a variable,
294 294 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
295 295 the output.
296 296
297 297 Note that %edit is also available through the alias %ed.
298 298
299 299 This is an example of creating a simple function inside the editor and
300 300 then modifying it. First, start up the editor:
301 301
302 302 In [1]: ed
303 303 Editing... done. Executing edited code...
304 304 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
305 305
306 306 We can then call the function foo():
307 307
308 308 In [2]: foo()
309 309 foo() was defined in an editing session
310 310
311 311 Now we edit foo. IPython automatically loads the editor with the
312 312 (temporary) file where foo() was previously defined:
313 313
314 314 In [3]: ed foo
315 315 Editing... done. Executing edited code...
316 316
317 317 And if we call foo() again we get the modified version:
318 318
319 319 In [4]: foo()
320 320 foo() has now been changed!
321 321
322 322 Here is an example of how to edit a code snippet successive
323 323 times. First we call the editor:
324 324
325 325 In [5]: ed
326 326 Editing... done. Executing edited code...
327 327 hello
328 328 Out[5]: "print 'hello'n"
329 329
330 330 Now we call it again with the previous output (stored in _):
331 331
332 332 In [6]: ed _
333 333 Editing... done. Executing edited code...
334 334 hello world
335 335 Out[6]: "print 'hello world'n"
336 336
337 337 Now we call it with the output #8 (stored in _8, also as Out[8]):
338 338
339 339 In [7]: ed _8
340 340 Editing... done. Executing edited code...
341 341 hello again
342 342 Out[7]: "print 'hello again'n"
343 343
344 344
345 345 Changing the default editor hook:
346 346
347 347 If you wish to write your own editor hook, you can put it in a
348 348 configuration file which you load at startup time. The default hook
349 349 is defined in the IPython.core.hooks module, and you can use that as a
350 350 starting example for further modifications. That file also has
351 351 general instructions on how to set a new hook for use once you've
352 352 defined it."""
353 353
354 354 # FIXME: This function has become a convoluted mess. It needs a
355 355 # ground-up rewrite with clean, simple logic.
356 356
357 357 def make_filename(arg):
358 358 "Make a filename from the given args"
359 359 try:
360 360 filename = get_py_filename(arg)
361 361 except IOError:
362 362 if args.endswith('.py'):
363 363 filename = arg
364 364 else:
365 365 filename = None
366 366 return filename
367 367
368 368 # custom exceptions
369 369 class DataIsObject(Exception): pass
370 370
371 371 opts,args = self.parse_options(parameter_s,'prn:')
372 372 # Set a few locals from the options for convenience:
373 373 opts_p = opts.has_key('p')
374 374 opts_r = opts.has_key('r')
375 375
376 376 # Default line number value
377 377 lineno = opts.get('n',None)
378 378 if lineno is not None:
379 379 try:
380 380 lineno = int(lineno)
381 381 except:
382 382 warn("The -n argument must be an integer.")
383 383 return
384 384
385 385 if opts_p:
386 386 args = '_%s' % last_call[0]
387 387 if not self.shell.user_ns.has_key(args):
388 388 args = last_call[1]
389 389
390 390 # use last_call to remember the state of the previous call, but don't
391 391 # let it be clobbered by successive '-p' calls.
392 392 try:
393 393 last_call[0] = self.shell.displayhook.prompt_count
394 394 if not opts_p:
395 395 last_call[1] = parameter_s
396 396 except:
397 397 pass
398 398
399 399 # by default this is done with temp files, except when the given
400 400 # arg is a filename
401 401 use_temp = 1
402 402
403 403 if re.match(r'\d',args):
404 404 # Mode where user specifies ranges of lines, like in %macro.
405 405 # This means that you can't edit files whose names begin with
406 406 # numbers this way. Tough.
407 407 ranges = args.split()
408 408 data = ''.join(self.extract_input_slices(ranges,opts_r))
409 409 elif args.endswith('.py'):
410 410 filename = make_filename(args)
411 411 data = ''
412 412 use_temp = 0
413 413 elif args:
414 414 try:
415 415 # Load the parameter given as a variable. If not a string,
416 416 # process it as an object instead (below)
417 417
418 418 #print '*** args',args,'type',type(args) # dbg
419 419 data = eval(args,self.shell.user_ns)
420 420 if not type(data) in StringTypes:
421 421 raise DataIsObject
422 422
423 423 except (NameError,SyntaxError):
424 424 # given argument is not a variable, try as a filename
425 425 filename = make_filename(args)
426 426 if filename is None:
427 427 warn("Argument given (%s) can't be found as a variable "
428 428 "or as a filename." % args)
429 429 return
430 430
431 431 data = ''
432 432 use_temp = 0
433 433 except DataIsObject:
434 434
435 435 # macros have a special edit function
436 436 if isinstance(data,Macro):
437 437 self._edit_macro(args,data)
438 438 return
439 439
440 440 # For objects, try to edit the file where they are defined
441 441 try:
442 442 filename = inspect.getabsfile(data)
443 443 if 'fakemodule' in filename.lower() and inspect.isclass(data):
444 444 # class created by %edit? Try to find source
445 445 # by looking for method definitions instead, the
446 446 # __module__ in those classes is FakeModule.
447 447 attrs = [getattr(data, aname) for aname in dir(data)]
448 448 for attr in attrs:
449 449 if not inspect.ismethod(attr):
450 450 continue
451 451 filename = inspect.getabsfile(attr)
452 452 if filename and 'fakemodule' not in filename.lower():
453 453 # change the attribute to be the edit target instead
454 454 data = attr
455 455 break
456 456
457 457 datafile = 1
458 458 except TypeError:
459 459 filename = make_filename(args)
460 460 datafile = 1
461 461 warn('Could not find file where `%s` is defined.\n'
462 462 'Opening a file named `%s`' % (args,filename))
463 463 # Now, make sure we can actually read the source (if it was in
464 464 # a temp file it's gone by now).
465 465 if datafile:
466 466 try:
467 467 if lineno is None:
468 468 lineno = inspect.getsourcelines(data)[1]
469 469 except IOError:
470 470 filename = make_filename(args)
471 471 if filename is None:
472 472 warn('The file `%s` where `%s` was defined cannot '
473 473 'be read.' % (filename,data))
474 474 return
475 475 use_temp = 0
476 476 else:
477 477 data = ''
478 478
479 479 if use_temp:
480 480 filename = self.shell.mktempfile(data)
481 481 print('IPython will make a temporary file named:', filename)
482 482
483 483 # Make sure we send to the client an absolute path, in case the working
484 484 # directory of client and kernel don't match
485 485 filename = os.path.abspath(filename)
486 486
487 487 payload = {
488 488 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
489 489 'filename' : filename,
490 490 'line_number' : lineno
491 491 }
492 492 self.payload_manager.write_payload(payload)
493 493
494 494 def magic_gui(self, *args, **kwargs):
495 495 raise NotImplementedError(
496 496 'GUI support must be enabled in command line options.')
497 497
498 498 def magic_pylab(self, *args, **kwargs):
499 499 raise NotImplementedError(
500 500 'pylab support must be enabled in command line options.')
501 501
502 502 # A few magics that are adapted to the specifics of using pexpect and a
503 503 # remote terminal
504 504
505 505 def magic_clear(self, arg_s):
506 506 """Clear the terminal."""
507 507 if os.name == 'posix':
508 508 self.shell.system("clear")
509 509 else:
510 510 self.shell.system("cls")
511 511
512 512 if os.name == 'nt':
513 513 # This is the usual name in windows
514 514 magic_cls = magic_clear
515 515
516 516 # Terminal pagers won't work over pexpect, but we do have our own pager
517 517
518 518 def magic_less(self, arg_s):
519 519 """Show a file through the pager.
520 520
521 521 Files ending in .py are syntax-highlighted."""
522 522 cont = open(arg_s).read()
523 523 if arg_s.endswith('.py'):
524 524 cont = self.shell.pycolorize(cont)
525 525 page.page(cont)
526 526
527 527 magic_more = magic_less
528 528
529 529 # Man calls a pager, so we also need to redefine it
530 530 if os.name == 'posix':
531 531 def magic_man(self, arg_s):
532 532 """Find the man page for the given command and display in pager."""
533 page.page(self.shell.getoutput('man %s' % arg_s, split=False))
533 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
534 split=False))
534 535
535 536 # FIXME: this is specific to the GUI, so we should let the gui app load
536 537 # magics at startup that are only for the gui. Once the gui app has proper
537 538 # profile and configuration management, we can have it initialize a kernel
538 539 # with a special config file that provides these.
539 540 def magic_guiref(self, arg_s):
540 541 """Show a basic reference about the GUI console."""
541 542 from IPython.core.usage import gui_reference
542 543 page.page(gui_reference, auto_html=True)
543 544
544 545
545 546 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now