##// END OF EJS Templates
Add shell.check_complete() method...
Thomas Kluyver -
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,1171 +1,1170 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Sphinx directive to support embedded IPython code.
4 4
5 5 This directive allows pasting of entire interactive IPython sessions, prompts
6 6 and all, and their code will actually get re-executed at doc build time, with
7 7 all prompts renumbered sequentially. It also allows you to input code as a pure
8 8 python input by giving the argument python to the directive. The output looks
9 9 like an interactive ipython section.
10 10
11 11 To enable this directive, simply list it in your Sphinx ``conf.py`` file
12 12 (making sure the directory where you placed it is visible to sphinx, as is
13 13 needed for all Sphinx directives). For example, to enable syntax highlighting
14 14 and the IPython directive::
15 15
16 16 extensions = ['IPython.sphinxext.ipython_console_highlighting',
17 17 'IPython.sphinxext.ipython_directive']
18 18
19 19 The IPython directive outputs code-blocks with the language 'ipython'. So
20 20 if you do not have the syntax highlighting extension enabled as well, then
21 21 all rendered code-blocks will be uncolored. By default this directive assumes
22 22 that your prompts are unchanged IPython ones, but this can be customized.
23 23 The configurable options that can be placed in conf.py are:
24 24
25 25 ipython_savefig_dir:
26 26 The directory in which to save the figures. This is relative to the
27 27 Sphinx source directory. The default is `html_static_path`.
28 28 ipython_rgxin:
29 29 The compiled regular expression to denote the start of IPython input
30 30 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
31 31 shouldn't need to change this.
32 32 ipython_rgxout:
33 33 The compiled regular expression to denote the start of IPython output
34 34 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
35 35 shouldn't need to change this.
36 36 ipython_promptin:
37 37 The string to represent the IPython input prompt in the generated ReST.
38 38 The default is 'In [%d]:'. This expects that the line numbers are used
39 39 in the prompt.
40 40 ipython_promptout:
41 41 The string to represent the IPython prompt in the generated ReST. The
42 42 default is 'Out [%d]:'. This expects that the line numbers are used
43 43 in the prompt.
44 44 ipython_mplbackend:
45 45 The string which specifies if the embedded Sphinx shell should import
46 46 Matplotlib and set the backend. The value specifies a backend that is
47 47 passed to `matplotlib.use()` before any lines in `ipython_execlines` are
48 48 executed. If not specified in conf.py, then the default value of 'agg' is
49 49 used. To use the IPython directive without matplotlib as a dependency, set
50 50 the value to `None`. It may end up that matplotlib is still imported
51 51 if the user specifies so in `ipython_execlines` or makes use of the
52 52 @savefig pseudo decorator.
53 53 ipython_execlines:
54 54 A list of strings to be exec'd in the embedded Sphinx shell. Typical
55 55 usage is to make certain packages always available. Set this to an empty
56 56 list if you wish to have no imports always available. If specified in
57 57 conf.py as `None`, then it has the effect of making no imports available.
58 58 If omitted from conf.py altogether, then the default value of
59 59 ['import numpy as np', 'import matplotlib.pyplot as plt'] is used.
60 60 ipython_holdcount
61 61 When the @suppress pseudo-decorator is used, the execution count can be
62 62 incremented or not. The default behavior is to hold the execution count,
63 63 corresponding to a value of `True`. Set this to `False` to increment
64 64 the execution count after each suppressed command.
65 65
66 66 As an example, to use the IPython directive when `matplotlib` is not available,
67 67 one sets the backend to `None`::
68 68
69 69 ipython_mplbackend = None
70 70
71 71 An example usage of the directive is:
72 72
73 73 .. code-block:: rst
74 74
75 75 .. ipython::
76 76
77 77 In [1]: x = 1
78 78
79 79 In [2]: y = x**2
80 80
81 81 In [3]: print(y)
82 82
83 83 See http://matplotlib.org/sampledoc/ipython_directive.html for additional
84 84 documentation.
85 85
86 86 Pseudo-Decorators
87 87 =================
88 88
89 89 Note: Only one decorator is supported per input. If more than one decorator
90 90 is specified, then only the last one is used.
91 91
92 92 In addition to the Pseudo-Decorators/options described at the above link,
93 93 several enhancements have been made. The directive will emit a message to the
94 94 console at build-time if code-execution resulted in an exception or warning.
95 95 You can suppress these on a per-block basis by specifying the :okexcept:
96 96 or :okwarning: options:
97 97
98 98 .. code-block:: rst
99 99
100 100 .. ipython::
101 101 :okexcept:
102 102 :okwarning:
103 103
104 104 In [1]: 1/0
105 105 In [2]: # raise warning.
106 106
107 107 To Do
108 108 -----
109 109
110 110 - Turn the ad-hoc test() function into a real test suite.
111 111 - Break up ipython-specific functionality from matplotlib stuff into better
112 112 separated code.
113 113
114 114 Authors
115 115 -------
116 116
117 117 - John D Hunter: original author.
118 118 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
119 119 - VáclavŠmilauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
120 120 - Skipper Seabold, refactoring, cleanups, pure python addition
121 121 """
122 122
123 123 #-----------------------------------------------------------------------------
124 124 # Imports
125 125 #-----------------------------------------------------------------------------
126 126
127 127 # Stdlib
128 128 import atexit
129 129 import errno
130 130 import os
131 131 import re
132 132 import sys
133 133 import tempfile
134 134 import ast
135 135 import warnings
136 136 import shutil
137 137 from io import StringIO
138 138
139 139 # Third-party
140 140 from docutils.parsers.rst import directives
141 141 from docutils.parsers.rst import Directive
142 142
143 143 # Our own
144 144 from traitlets.config import Config
145 145 from IPython import InteractiveShell
146 146 from IPython.core.profiledir import ProfileDir
147 147
148 148 #-----------------------------------------------------------------------------
149 149 # Globals
150 150 #-----------------------------------------------------------------------------
151 151 # for tokenizing blocks
152 152 COMMENT, INPUT, OUTPUT = range(3)
153 153
154 154 #-----------------------------------------------------------------------------
155 155 # Functions and class declarations
156 156 #-----------------------------------------------------------------------------
157 157
158 158 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
159 159 """
160 160 part is a string of ipython text, comprised of at most one
161 161 input, one output, comments, and blank lines. The block parser
162 162 parses the text into a list of::
163 163
164 164 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
165 165
166 166 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
167 167 data is, depending on the type of token::
168 168
169 169 COMMENT : the comment string
170 170
171 171 INPUT: the (DECORATOR, INPUT_LINE, REST) where
172 172 DECORATOR: the input decorator (or None)
173 173 INPUT_LINE: the input as string (possibly multi-line)
174 174 REST : any stdout generated by the input line (not OUTPUT)
175 175
176 176 OUTPUT: the output string, possibly multi-line
177 177
178 178 """
179 179 block = []
180 180 lines = part.split('\n')
181 181 N = len(lines)
182 182 i = 0
183 183 decorator = None
184 184 while 1:
185 185
186 186 if i==N:
187 187 # nothing left to parse -- the last line
188 188 break
189 189
190 190 line = lines[i]
191 191 i += 1
192 192 line_stripped = line.strip()
193 193 if line_stripped.startswith('#'):
194 194 block.append((COMMENT, line))
195 195 continue
196 196
197 197 if line_stripped.startswith('@'):
198 198 # Here is where we assume there is, at most, one decorator.
199 199 # Might need to rethink this.
200 200 decorator = line_stripped
201 201 continue
202 202
203 203 # does this look like an input line?
204 204 matchin = rgxin.match(line)
205 205 if matchin:
206 206 lineno, inputline = int(matchin.group(1)), matchin.group(2)
207 207
208 208 # the ....: continuation string
209 209 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
210 210 Nc = len(continuation)
211 211 # input lines can continue on for more than one line, if
212 212 # we have a '\' line continuation char or a function call
213 213 # echo line 'print'. The input line can only be
214 214 # terminated by the end of the block or an output line, so
215 215 # we parse out the rest of the input line if it is
216 216 # multiline as well as any echo text
217 217
218 218 rest = []
219 219 while i<N:
220 220
221 221 # look ahead; if the next line is blank, or a comment, or
222 222 # an output line, we're done
223 223
224 224 nextline = lines[i]
225 225 matchout = rgxout.match(nextline)
226 226 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
227 227 if matchout or nextline.startswith('#'):
228 228 break
229 229 elif nextline.startswith(continuation):
230 230 # The default ipython_rgx* treat the space following the colon as optional.
231 231 # However, If the space is there we must consume it or code
232 232 # employing the cython_magic extension will fail to execute.
233 233 #
234 234 # This works with the default ipython_rgx* patterns,
235 235 # If you modify them, YMMV.
236 236 nextline = nextline[Nc:]
237 237 if nextline and nextline[0] == ' ':
238 238 nextline = nextline[1:]
239 239
240 240 inputline += '\n' + nextline
241 241 else:
242 242 rest.append(nextline)
243 243 i+= 1
244 244
245 245 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
246 246 continue
247 247
248 248 # if it looks like an output line grab all the text to the end
249 249 # of the block
250 250 matchout = rgxout.match(line)
251 251 if matchout:
252 252 lineno, output = int(matchout.group(1)), matchout.group(2)
253 253 if i<N-1:
254 254 output = '\n'.join([output] + lines[i:])
255 255
256 256 block.append((OUTPUT, output))
257 257 break
258 258
259 259 return block
260 260
261 261
262 262 class EmbeddedSphinxShell(object):
263 263 """An embedded IPython instance to run inside Sphinx"""
264 264
265 265 def __init__(self, exec_lines=None):
266 266
267 267 self.cout = StringIO()
268 268
269 269 if exec_lines is None:
270 270 exec_lines = []
271 271
272 272 # Create config object for IPython
273 273 config = Config()
274 274 config.HistoryManager.hist_file = ':memory:'
275 275 config.InteractiveShell.autocall = False
276 276 config.InteractiveShell.autoindent = False
277 277 config.InteractiveShell.colors = 'NoColor'
278 278
279 279 # create a profile so instance history isn't saved
280 280 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
281 281 profname = 'auto_profile_sphinx_build'
282 282 pdir = os.path.join(tmp_profile_dir,profname)
283 283 profile = ProfileDir.create_profile_dir(pdir)
284 284
285 285 # Create and initialize global ipython, but don't start its mainloop.
286 286 # This will persist across different EmbeddedSphinxShell instances.
287 287 IP = InteractiveShell.instance(config=config, profile_dir=profile)
288 288 atexit.register(self.cleanup)
289 289
290 290 # Store a few parts of IPython we'll need.
291 291 self.IP = IP
292 292 self.user_ns = self.IP.user_ns
293 293 self.user_global_ns = self.IP.user_global_ns
294 self.input_transformer_mgr = self.IP.input_transformer_manager
295 294
296 295 self.lines_waiting = []
297 296 self.input = ''
298 297 self.output = ''
299 298 self.tmp_profile_dir = tmp_profile_dir
300 299
301 300 self.is_verbatim = False
302 301 self.is_doctest = False
303 302 self.is_suppress = False
304 303
305 304 # Optionally, provide more detailed information to shell.
306 305 # this is assigned by the SetUp method of IPythonDirective
307 306 # to point at itself.
308 307 #
309 308 # So, you can access handy things at self.directive.state
310 309 self.directive = None
311 310
312 311 # on the first call to the savefig decorator, we'll import
313 312 # pyplot as plt so we can make a call to the plt.gcf().savefig
314 313 self._pyplot_imported = False
315 314
316 315 # Prepopulate the namespace.
317 316 for line in exec_lines:
318 317 self.process_input_line(line, store_history=False)
319 318
320 319 def cleanup(self):
321 320 shutil.rmtree(self.tmp_profile_dir, ignore_errors=True)
322 321
323 322 def clear_cout(self):
324 323 self.cout.seek(0)
325 324 self.cout.truncate(0)
326 325
327 326 def process_input_line(self, line, store_history=True):
328 327 """process the input, capturing stdout"""
329 328
330 329 stdout = sys.stdout
331 330 try:
332 331 sys.stdout = self.cout
333 332 self.lines_waiting.append(line)
334 if self.input_transformer_mgr.check_complete()[0] != 'incomplete':
333 if self.IP.check_complete()[0] != 'incomplete':
335 334 source_raw = ''.join(self.lines_waiting)
336 335 self.lines_waiting = []
337 336 self.IP.run_cell(source_raw, store_history=store_history)
338 337 finally:
339 338 sys.stdout = stdout
340 339
341 340 def process_image(self, decorator):
342 341 """
343 342 # build out an image directive like
344 343 # .. image:: somefile.png
345 344 # :width 4in
346 345 #
347 346 # from an input like
348 347 # savefig somefile.png width=4in
349 348 """
350 349 savefig_dir = self.savefig_dir
351 350 source_dir = self.source_dir
352 351 saveargs = decorator.split(' ')
353 352 filename = saveargs[1]
354 353 # insert relative path to image file in source (as absolute path for Sphinx)
355 354 outfile = '/' + os.path.relpath(os.path.join(savefig_dir,filename),
356 355 source_dir)
357 356
358 357 imagerows = ['.. image:: %s'%outfile]
359 358
360 359 for kwarg in saveargs[2:]:
361 360 arg, val = kwarg.split('=')
362 361 arg = arg.strip()
363 362 val = val.strip()
364 363 imagerows.append(' :%s: %s'%(arg, val))
365 364
366 365 image_file = os.path.basename(outfile) # only return file name
367 366 image_directive = '\n'.join(imagerows)
368 367 return image_file, image_directive
369 368
370 369 # Callbacks for each type of token
371 370 def process_input(self, data, input_prompt, lineno):
372 371 """
373 372 Process data block for INPUT token.
374 373
375 374 """
376 375 decorator, input, rest = data
377 376 image_file = None
378 377 image_directive = None
379 378
380 379 is_verbatim = decorator=='@verbatim' or self.is_verbatim
381 380 is_doctest = (decorator is not None and \
382 381 decorator.startswith('@doctest')) or self.is_doctest
383 382 is_suppress = decorator=='@suppress' or self.is_suppress
384 383 is_okexcept = decorator=='@okexcept' or self.is_okexcept
385 384 is_okwarning = decorator=='@okwarning' or self.is_okwarning
386 385 is_savefig = decorator is not None and \
387 386 decorator.startswith('@savefig')
388 387
389 388 input_lines = input.split('\n')
390 389 if len(input_lines) > 1:
391 390 if input_lines[-1] != "":
392 391 input_lines.append('') # make sure there's a blank line
393 392 # so splitter buffer gets reset
394 393
395 394 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
396 395
397 396 if is_savefig:
398 397 image_file, image_directive = self.process_image(decorator)
399 398
400 399 ret = []
401 400 is_semicolon = False
402 401
403 402 # Hold the execution count, if requested to do so.
404 403 if is_suppress and self.hold_count:
405 404 store_history = False
406 405 else:
407 406 store_history = True
408 407
409 408 # Note: catch_warnings is not thread safe
410 409 with warnings.catch_warnings(record=True) as ws:
411 410 for i, line in enumerate(input_lines):
412 411 if line.endswith(';'):
413 412 is_semicolon = True
414 413
415 414 if i == 0:
416 415 # process the first input line
417 416 if is_verbatim:
418 417 self.process_input_line('')
419 418 self.IP.execution_count += 1 # increment it anyway
420 419 else:
421 420 # only submit the line in non-verbatim mode
422 421 self.process_input_line(line, store_history=store_history)
423 422 formatted_line = '%s %s'%(input_prompt, line)
424 423 else:
425 424 # process a continuation line
426 425 if not is_verbatim:
427 426 self.process_input_line(line, store_history=store_history)
428 427
429 428 formatted_line = '%s %s'%(continuation, line)
430 429
431 430 if not is_suppress:
432 431 ret.append(formatted_line)
433 432
434 433 if not is_suppress and len(rest.strip()) and is_verbatim:
435 434 # The "rest" is the standard output of the input. This needs to be
436 435 # added when in verbatim mode. If there is no "rest", then we don't
437 436 # add it, as the new line will be added by the processed output.
438 437 ret.append(rest)
439 438
440 439 # Fetch the processed output. (This is not the submitted output.)
441 440 self.cout.seek(0)
442 441 processed_output = self.cout.read()
443 442 if not is_suppress and not is_semicolon:
444 443 #
445 444 # In IPythonDirective.run, the elements of `ret` are eventually
446 445 # combined such that '' entries correspond to newlines. So if
447 446 # `processed_output` is equal to '', then the adding it to `ret`
448 447 # ensures that there is a blank line between consecutive inputs
449 448 # that have no outputs, as in:
450 449 #
451 450 # In [1]: x = 4
452 451 #
453 452 # In [2]: x = 5
454 453 #
455 454 # When there is processed output, it has a '\n' at the tail end. So
456 455 # adding the output to `ret` will provide the necessary spacing
457 456 # between consecutive input/output blocks, as in:
458 457 #
459 458 # In [1]: x
460 459 # Out[1]: 5
461 460 #
462 461 # In [2]: x
463 462 # Out[2]: 5
464 463 #
465 464 # When there is stdout from the input, it also has a '\n' at the
466 465 # tail end, and so this ensures proper spacing as well. E.g.:
467 466 #
468 467 # In [1]: print x
469 468 # 5
470 469 #
471 470 # In [2]: x = 5
472 471 #
473 472 # When in verbatim mode, `processed_output` is empty (because
474 473 # nothing was passed to IP. Sometimes the submitted code block has
475 474 # an Out[] portion and sometimes it does not. When it does not, we
476 475 # need to ensure proper spacing, so we have to add '' to `ret`.
477 476 # However, if there is an Out[] in the submitted code, then we do
478 477 # not want to add a newline as `process_output` has stuff to add.
479 478 # The difficulty is that `process_input` doesn't know if
480 479 # `process_output` will be called---so it doesn't know if there is
481 480 # Out[] in the code block. The requires that we include a hack in
482 481 # `process_block`. See the comments there.
483 482 #
484 483 ret.append(processed_output)
485 484 elif is_semicolon:
486 485 # Make sure there is a newline after the semicolon.
487 486 ret.append('')
488 487
489 488 # context information
490 489 filename = "Unknown"
491 490 lineno = 0
492 491 if self.directive.state:
493 492 filename = self.directive.state.document.current_source
494 493 lineno = self.directive.state.document.current_line
495 494
496 495 # output any exceptions raised during execution to stdout
497 496 # unless :okexcept: has been specified.
498 497 if not is_okexcept and "Traceback" in processed_output:
499 498 s = "\nException in %s at block ending on line %s\n" % (filename, lineno)
500 499 s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n"
501 500 sys.stdout.write('\n\n>>>' + ('-' * 73))
502 501 sys.stdout.write(s)
503 502 sys.stdout.write(processed_output)
504 503 sys.stdout.write('<<<' + ('-' * 73) + '\n\n')
505 504
506 505 # output any warning raised during execution to stdout
507 506 # unless :okwarning: has been specified.
508 507 if not is_okwarning:
509 508 for w in ws:
510 509 s = "\nWarning in %s at block ending on line %s\n" % (filename, lineno)
511 510 s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n"
512 511 sys.stdout.write('\n\n>>>' + ('-' * 73))
513 512 sys.stdout.write(s)
514 513 sys.stdout.write(('-' * 76) + '\n')
515 514 s=warnings.formatwarning(w.message, w.category,
516 515 w.filename, w.lineno, w.line)
517 516 sys.stdout.write(s)
518 517 sys.stdout.write('<<<' + ('-' * 73) + '\n')
519 518
520 519 self.cout.truncate(0)
521 520
522 521 return (ret, input_lines, processed_output,
523 522 is_doctest, decorator, image_file, image_directive)
524 523
525 524
526 525 def process_output(self, data, output_prompt, input_lines, output,
527 526 is_doctest, decorator, image_file):
528 527 """
529 528 Process data block for OUTPUT token.
530 529
531 530 """
532 531 # Recall: `data` is the submitted output, and `output` is the processed
533 532 # output from `input_lines`.
534 533
535 534 TAB = ' ' * 4
536 535
537 536 if is_doctest and output is not None:
538 537
539 538 found = output # This is the processed output
540 539 found = found.strip()
541 540 submitted = data.strip()
542 541
543 542 if self.directive is None:
544 543 source = 'Unavailable'
545 544 content = 'Unavailable'
546 545 else:
547 546 source = self.directive.state.document.current_source
548 547 content = self.directive.content
549 548 # Add tabs and join into a single string.
550 549 content = '\n'.join([TAB + line for line in content])
551 550
552 551 # Make sure the output contains the output prompt.
553 552 ind = found.find(output_prompt)
554 553 if ind < 0:
555 554 e = ('output does not contain output prompt\n\n'
556 555 'Document source: {0}\n\n'
557 556 'Raw content: \n{1}\n\n'
558 557 'Input line(s):\n{TAB}{2}\n\n'
559 558 'Output line(s):\n{TAB}{3}\n\n')
560 559 e = e.format(source, content, '\n'.join(input_lines),
561 560 repr(found), TAB=TAB)
562 561 raise RuntimeError(e)
563 562 found = found[len(output_prompt):].strip()
564 563
565 564 # Handle the actual doctest comparison.
566 565 if decorator.strip() == '@doctest':
567 566 # Standard doctest
568 567 if found != submitted:
569 568 e = ('doctest failure\n\n'
570 569 'Document source: {0}\n\n'
571 570 'Raw content: \n{1}\n\n'
572 571 'On input line(s):\n{TAB}{2}\n\n'
573 572 'we found output:\n{TAB}{3}\n\n'
574 573 'instead of the expected:\n{TAB}{4}\n\n')
575 574 e = e.format(source, content, '\n'.join(input_lines),
576 575 repr(found), repr(submitted), TAB=TAB)
577 576 raise RuntimeError(e)
578 577 else:
579 578 self.custom_doctest(decorator, input_lines, found, submitted)
580 579
581 580 # When in verbatim mode, this holds additional submitted output
582 581 # to be written in the final Sphinx output.
583 582 # https://github.com/ipython/ipython/issues/5776
584 583 out_data = []
585 584
586 585 is_verbatim = decorator=='@verbatim' or self.is_verbatim
587 586 if is_verbatim and data.strip():
588 587 # Note that `ret` in `process_block` has '' as its last element if
589 588 # the code block was in verbatim mode. So if there is no submitted
590 589 # output, then we will have proper spacing only if we do not add
591 590 # an additional '' to `out_data`. This is why we condition on
592 591 # `and data.strip()`.
593 592
594 593 # The submitted output has no output prompt. If we want the
595 594 # prompt and the code to appear, we need to join them now
596 595 # instead of adding them separately---as this would create an
597 596 # undesired newline. How we do this ultimately depends on the
598 597 # format of the output regex. I'll do what works for the default
599 598 # prompt for now, and we might have to adjust if it doesn't work
600 599 # in other cases. Finally, the submitted output does not have
601 600 # a trailing newline, so we must add it manually.
602 601 out_data.append("{0} {1}\n".format(output_prompt, data))
603 602
604 603 return out_data
605 604
606 605 def process_comment(self, data):
607 606 """Process data fPblock for COMMENT token."""
608 607 if not self.is_suppress:
609 608 return [data]
610 609
611 610 def save_image(self, image_file):
612 611 """
613 612 Saves the image file to disk.
614 613 """
615 614 self.ensure_pyplot()
616 615 command = 'plt.gcf().savefig("%s")'%image_file
617 616 #print 'SAVEFIG', command # dbg
618 617 self.process_input_line('bookmark ipy_thisdir', store_history=False)
619 618 self.process_input_line('cd -b ipy_savedir', store_history=False)
620 619 self.process_input_line(command, store_history=False)
621 620 self.process_input_line('cd -b ipy_thisdir', store_history=False)
622 621 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
623 622 self.clear_cout()
624 623
625 624 def process_block(self, block):
626 625 """
627 626 process block from the block_parser and return a list of processed lines
628 627 """
629 628 ret = []
630 629 output = None
631 630 input_lines = None
632 631 lineno = self.IP.execution_count
633 632
634 633 input_prompt = self.promptin % lineno
635 634 output_prompt = self.promptout % lineno
636 635 image_file = None
637 636 image_directive = None
638 637
639 638 found_input = False
640 639 for token, data in block:
641 640 if token == COMMENT:
642 641 out_data = self.process_comment(data)
643 642 elif token == INPUT:
644 643 found_input = True
645 644 (out_data, input_lines, output, is_doctest,
646 645 decorator, image_file, image_directive) = \
647 646 self.process_input(data, input_prompt, lineno)
648 647 elif token == OUTPUT:
649 648 if not found_input:
650 649
651 650 TAB = ' ' * 4
652 651 linenumber = 0
653 652 source = 'Unavailable'
654 653 content = 'Unavailable'
655 654 if self.directive:
656 655 linenumber = self.directive.state.document.current_line
657 656 source = self.directive.state.document.current_source
658 657 content = self.directive.content
659 658 # Add tabs and join into a single string.
660 659 content = '\n'.join([TAB + line for line in content])
661 660
662 661 e = ('\n\nInvalid block: Block contains an output prompt '
663 662 'without an input prompt.\n\n'
664 663 'Document source: {0}\n\n'
665 664 'Content begins at line {1}: \n\n{2}\n\n'
666 665 'Problematic block within content: \n\n{TAB}{3}\n\n')
667 666 e = e.format(source, linenumber, content, block, TAB=TAB)
668 667
669 668 # Write, rather than include in exception, since Sphinx
670 669 # will truncate tracebacks.
671 670 sys.stdout.write(e)
672 671 raise RuntimeError('An invalid block was detected.')
673 672
674 673 out_data = \
675 674 self.process_output(data, output_prompt, input_lines,
676 675 output, is_doctest, decorator,
677 676 image_file)
678 677 if out_data:
679 678 # Then there was user submitted output in verbatim mode.
680 679 # We need to remove the last element of `ret` that was
681 680 # added in `process_input`, as it is '' and would introduce
682 681 # an undesirable newline.
683 682 assert(ret[-1] == '')
684 683 del ret[-1]
685 684
686 685 if out_data:
687 686 ret.extend(out_data)
688 687
689 688 # save the image files
690 689 if image_file is not None:
691 690 self.save_image(image_file)
692 691
693 692 return ret, image_directive
694 693
695 694 def ensure_pyplot(self):
696 695 """
697 696 Ensures that pyplot has been imported into the embedded IPython shell.
698 697
699 698 Also, makes sure to set the backend appropriately if not set already.
700 699
701 700 """
702 701 # We are here if the @figure pseudo decorator was used. Thus, it's
703 702 # possible that we could be here even if python_mplbackend were set to
704 703 # `None`. That's also strange and perhaps worthy of raising an
705 704 # exception, but for now, we just set the backend to 'agg'.
706 705
707 706 if not self._pyplot_imported:
708 707 if 'matplotlib.backends' not in sys.modules:
709 708 # Then ipython_matplotlib was set to None but there was a
710 709 # call to the @figure decorator (and ipython_execlines did
711 710 # not set a backend).
712 711 #raise Exception("No backend was set, but @figure was used!")
713 712 import matplotlib
714 713 matplotlib.use('agg')
715 714
716 715 # Always import pyplot into embedded shell.
717 716 self.process_input_line('import matplotlib.pyplot as plt',
718 717 store_history=False)
719 718 self._pyplot_imported = True
720 719
721 720 def process_pure_python(self, content):
722 721 """
723 722 content is a list of strings. it is unedited directive content
724 723
725 724 This runs it line by line in the InteractiveShell, prepends
726 725 prompts as needed capturing stderr and stdout, then returns
727 726 the content as a list as if it were ipython code
728 727 """
729 728 output = []
730 729 savefig = False # keep up with this to clear figure
731 730 multiline = False # to handle line continuation
732 731 multiline_start = None
733 732 fmtin = self.promptin
734 733
735 734 ct = 0
736 735
737 736 for lineno, line in enumerate(content):
738 737
739 738 line_stripped = line.strip()
740 739 if not len(line):
741 740 output.append(line)
742 741 continue
743 742
744 743 # handle decorators
745 744 if line_stripped.startswith('@'):
746 745 output.extend([line])
747 746 if 'savefig' in line:
748 747 savefig = True # and need to clear figure
749 748 continue
750 749
751 750 # handle comments
752 751 if line_stripped.startswith('#'):
753 752 output.extend([line])
754 753 continue
755 754
756 755 # deal with lines checking for multiline
757 756 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
758 757 if not multiline:
759 758 modified = u"%s %s" % (fmtin % ct, line_stripped)
760 759 output.append(modified)
761 760 ct += 1
762 761 try:
763 762 ast.parse(line_stripped)
764 763 output.append(u'')
765 764 except Exception: # on a multiline
766 765 multiline = True
767 766 multiline_start = lineno
768 767 else: # still on a multiline
769 768 modified = u'%s %s' % (continuation, line)
770 769 output.append(modified)
771 770
772 771 # if the next line is indented, it should be part of multiline
773 772 if len(content) > lineno + 1:
774 773 nextline = content[lineno + 1]
775 774 if len(nextline) - len(nextline.lstrip()) > 3:
776 775 continue
777 776 try:
778 777 mod = ast.parse(
779 778 '\n'.join(content[multiline_start:lineno+1]))
780 779 if isinstance(mod.body[0], ast.FunctionDef):
781 780 # check to see if we have the whole function
782 781 for element in mod.body[0].body:
783 782 if isinstance(element, ast.Return):
784 783 multiline = False
785 784 else:
786 785 output.append(u'')
787 786 multiline = False
788 787 except Exception:
789 788 pass
790 789
791 790 if savefig: # clear figure if plotted
792 791 self.ensure_pyplot()
793 792 self.process_input_line('plt.clf()', store_history=False)
794 793 self.clear_cout()
795 794 savefig = False
796 795
797 796 return output
798 797
799 798 def custom_doctest(self, decorator, input_lines, found, submitted):
800 799 """
801 800 Perform a specialized doctest.
802 801
803 802 """
804 803 from .custom_doctests import doctests
805 804
806 805 args = decorator.split()
807 806 doctest_type = args[1]
808 807 if doctest_type in doctests:
809 808 doctests[doctest_type](self, args, input_lines, found, submitted)
810 809 else:
811 810 e = "Invalid option to @doctest: {0}".format(doctest_type)
812 811 raise Exception(e)
813 812
814 813
815 814 class IPythonDirective(Directive):
816 815
817 816 has_content = True
818 817 required_arguments = 0
819 818 optional_arguments = 4 # python, suppress, verbatim, doctest
820 819 final_argumuent_whitespace = True
821 820 option_spec = { 'python': directives.unchanged,
822 821 'suppress' : directives.flag,
823 822 'verbatim' : directives.flag,
824 823 'doctest' : directives.flag,
825 824 'okexcept': directives.flag,
826 825 'okwarning': directives.flag
827 826 }
828 827
829 828 shell = None
830 829
831 830 seen_docs = set()
832 831
833 832 def get_config_options(self):
834 833 # contains sphinx configuration variables
835 834 config = self.state.document.settings.env.config
836 835
837 836 # get config variables to set figure output directory
838 837 savefig_dir = config.ipython_savefig_dir
839 838 source_dir = self.state.document.settings.env.srcdir
840 839 savefig_dir = os.path.join(source_dir, savefig_dir)
841 840
842 841 # get regex and prompt stuff
843 842 rgxin = config.ipython_rgxin
844 843 rgxout = config.ipython_rgxout
845 844 promptin = config.ipython_promptin
846 845 promptout = config.ipython_promptout
847 846 mplbackend = config.ipython_mplbackend
848 847 exec_lines = config.ipython_execlines
849 848 hold_count = config.ipython_holdcount
850 849
851 850 return (savefig_dir, source_dir, rgxin, rgxout,
852 851 promptin, promptout, mplbackend, exec_lines, hold_count)
853 852
854 853 def setup(self):
855 854 # Get configuration values.
856 855 (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout,
857 856 mplbackend, exec_lines, hold_count) = self.get_config_options()
858 857
859 858 try:
860 859 os.makedirs(savefig_dir)
861 860 except OSError as e:
862 861 if e.errno != errno.EEXIST:
863 862 raise
864 863
865 864 if self.shell is None:
866 865 # We will be here many times. However, when the
867 866 # EmbeddedSphinxShell is created, its interactive shell member
868 867 # is the same for each instance.
869 868
870 869 if mplbackend and 'matplotlib.backends' not in sys.modules:
871 870 import matplotlib
872 871 matplotlib.use(mplbackend)
873 872
874 873 # Must be called after (potentially) importing matplotlib and
875 874 # setting its backend since exec_lines might import pylab.
876 875 self.shell = EmbeddedSphinxShell(exec_lines)
877 876
878 877 # Store IPython directive to enable better error messages
879 878 self.shell.directive = self
880 879
881 880 # reset the execution count if we haven't processed this doc
882 881 #NOTE: this may be borked if there are multiple seen_doc tmp files
883 882 #check time stamp?
884 883 if not self.state.document.current_source in self.seen_docs:
885 884 self.shell.IP.history_manager.reset()
886 885 self.shell.IP.execution_count = 1
887 886 self.seen_docs.add(self.state.document.current_source)
888 887
889 888 # and attach to shell so we don't have to pass them around
890 889 self.shell.rgxin = rgxin
891 890 self.shell.rgxout = rgxout
892 891 self.shell.promptin = promptin
893 892 self.shell.promptout = promptout
894 893 self.shell.savefig_dir = savefig_dir
895 894 self.shell.source_dir = source_dir
896 895 self.shell.hold_count = hold_count
897 896
898 897 # setup bookmark for saving figures directory
899 898 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
900 899 store_history=False)
901 900 self.shell.clear_cout()
902 901
903 902 return rgxin, rgxout, promptin, promptout
904 903
905 904 def teardown(self):
906 905 # delete last bookmark
907 906 self.shell.process_input_line('bookmark -d ipy_savedir',
908 907 store_history=False)
909 908 self.shell.clear_cout()
910 909
911 910 def run(self):
912 911 debug = False
913 912
914 913 #TODO, any reason block_parser can't be a method of embeddable shell
915 914 # then we wouldn't have to carry these around
916 915 rgxin, rgxout, promptin, promptout = self.setup()
917 916
918 917 options = self.options
919 918 self.shell.is_suppress = 'suppress' in options
920 919 self.shell.is_doctest = 'doctest' in options
921 920 self.shell.is_verbatim = 'verbatim' in options
922 921 self.shell.is_okexcept = 'okexcept' in options
923 922 self.shell.is_okwarning = 'okwarning' in options
924 923
925 924 # handle pure python code
926 925 if 'python' in self.arguments:
927 926 content = self.content
928 927 self.content = self.shell.process_pure_python(content)
929 928
930 929 # parts consists of all text within the ipython-block.
931 930 # Each part is an input/output block.
932 931 parts = '\n'.join(self.content).split('\n\n')
933 932
934 933 lines = ['.. code-block:: ipython', '']
935 934 figures = []
936 935
937 936 for part in parts:
938 937 block = block_parser(part, rgxin, rgxout, promptin, promptout)
939 938 if len(block):
940 939 rows, figure = self.shell.process_block(block)
941 940 for row in rows:
942 941 lines.extend([' {0}'.format(line)
943 942 for line in row.split('\n')])
944 943
945 944 if figure is not None:
946 945 figures.append(figure)
947 946
948 947 for figure in figures:
949 948 lines.append('')
950 949 lines.extend(figure.split('\n'))
951 950 lines.append('')
952 951
953 952 if len(lines) > 2:
954 953 if debug:
955 954 print('\n'.join(lines))
956 955 else:
957 956 # This has to do with input, not output. But if we comment
958 957 # these lines out, then no IPython code will appear in the
959 958 # final output.
960 959 self.state_machine.insert_input(
961 960 lines, self.state_machine.input_lines.source(0))
962 961
963 962 # cleanup
964 963 self.teardown()
965 964
966 965 return []
967 966
968 967 # Enable as a proper Sphinx directive
969 968 def setup(app):
970 969 setup.app = app
971 970
972 971 app.add_directive('ipython', IPythonDirective)
973 972 app.add_config_value('ipython_savefig_dir', 'savefig', 'env')
974 973 app.add_config_value('ipython_rgxin',
975 974 re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env')
976 975 app.add_config_value('ipython_rgxout',
977 976 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env')
978 977 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
979 978 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
980 979
981 980 # We could just let matplotlib pick whatever is specified as the default
982 981 # backend in the matplotlibrc file, but this would cause issues if the
983 982 # backend didn't work in headless environments. For this reason, 'agg'
984 983 # is a good default backend choice.
985 984 app.add_config_value('ipython_mplbackend', 'agg', 'env')
986 985
987 986 # If the user sets this config value to `None`, then EmbeddedSphinxShell's
988 987 # __init__ method will treat it as [].
989 988 execlines = ['import numpy as np', 'import matplotlib.pyplot as plt']
990 989 app.add_config_value('ipython_execlines', execlines, 'env')
991 990
992 991 app.add_config_value('ipython_holdcount', True, 'env')
993 992
994 993 metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
995 994 return metadata
996 995
997 996 # Simple smoke test, needs to be converted to a proper automatic test.
998 997 def test():
999 998
1000 999 examples = [
1001 1000 r"""
1002 1001 In [9]: pwd
1003 1002 Out[9]: '/home/jdhunter/py4science/book'
1004 1003
1005 1004 In [10]: cd bookdata/
1006 1005 /home/jdhunter/py4science/book/bookdata
1007 1006
1008 1007 In [2]: from pylab import *
1009 1008
1010 1009 In [2]: ion()
1011 1010
1012 1011 In [3]: im = imread('stinkbug.png')
1013 1012
1014 1013 @savefig mystinkbug.png width=4in
1015 1014 In [4]: imshow(im)
1016 1015 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
1017 1016
1018 1017 """,
1019 1018 r"""
1020 1019
1021 1020 In [1]: x = 'hello world'
1022 1021
1023 1022 # string methods can be
1024 1023 # used to alter the string
1025 1024 @doctest
1026 1025 In [2]: x.upper()
1027 1026 Out[2]: 'HELLO WORLD'
1028 1027
1029 1028 @verbatim
1030 1029 In [3]: x.st<TAB>
1031 1030 x.startswith x.strip
1032 1031 """,
1033 1032 r"""
1034 1033
1035 1034 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
1036 1035 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
1037 1036
1038 1037 In [131]: print url.split('&')
1039 1038 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
1040 1039
1041 1040 In [60]: import urllib
1042 1041
1043 1042 """,
1044 1043 r"""\
1045 1044
1046 1045 In [133]: import numpy.random
1047 1046
1048 1047 @suppress
1049 1048 In [134]: numpy.random.seed(2358)
1050 1049
1051 1050 @doctest
1052 1051 In [135]: numpy.random.rand(10,2)
1053 1052 Out[135]:
1054 1053 array([[ 0.64524308, 0.59943846],
1055 1054 [ 0.47102322, 0.8715456 ],
1056 1055 [ 0.29370834, 0.74776844],
1057 1056 [ 0.99539577, 0.1313423 ],
1058 1057 [ 0.16250302, 0.21103583],
1059 1058 [ 0.81626524, 0.1312433 ],
1060 1059 [ 0.67338089, 0.72302393],
1061 1060 [ 0.7566368 , 0.07033696],
1062 1061 [ 0.22591016, 0.77731835],
1063 1062 [ 0.0072729 , 0.34273127]])
1064 1063
1065 1064 """,
1066 1065
1067 1066 r"""
1068 1067 In [106]: print x
1069 1068 jdh
1070 1069
1071 1070 In [109]: for i in range(10):
1072 1071 .....: print i
1073 1072 .....:
1074 1073 .....:
1075 1074 0
1076 1075 1
1077 1076 2
1078 1077 3
1079 1078 4
1080 1079 5
1081 1080 6
1082 1081 7
1083 1082 8
1084 1083 9
1085 1084 """,
1086 1085
1087 1086 r"""
1088 1087
1089 1088 In [144]: from pylab import *
1090 1089
1091 1090 In [145]: ion()
1092 1091
1093 1092 # use a semicolon to suppress the output
1094 1093 @savefig test_hist.png width=4in
1095 1094 In [151]: hist(np.random.randn(10000), 100);
1096 1095
1097 1096
1098 1097 @savefig test_plot.png width=4in
1099 1098 In [151]: plot(np.random.randn(10000), 'o');
1100 1099 """,
1101 1100
1102 1101 r"""
1103 1102 # use a semicolon to suppress the output
1104 1103 In [151]: plt.clf()
1105 1104
1106 1105 @savefig plot_simple.png width=4in
1107 1106 In [151]: plot([1,2,3])
1108 1107
1109 1108 @savefig hist_simple.png width=4in
1110 1109 In [151]: hist(np.random.randn(10000), 100);
1111 1110
1112 1111 """,
1113 1112 r"""
1114 1113 # update the current fig
1115 1114 In [151]: ylabel('number')
1116 1115
1117 1116 In [152]: title('normal distribution')
1118 1117
1119 1118
1120 1119 @savefig hist_with_text.png
1121 1120 In [153]: grid(True)
1122 1121
1123 1122 @doctest float
1124 1123 In [154]: 0.1 + 0.2
1125 1124 Out[154]: 0.3
1126 1125
1127 1126 @doctest float
1128 1127 In [155]: np.arange(16).reshape(4,4)
1129 1128 Out[155]:
1130 1129 array([[ 0, 1, 2, 3],
1131 1130 [ 4, 5, 6, 7],
1132 1131 [ 8, 9, 10, 11],
1133 1132 [12, 13, 14, 15]])
1134 1133
1135 1134 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
1136 1135
1137 1136 In [2]: x[0,0] = np.inf
1138 1137
1139 1138 In [3]: x[0,1] = np.nan
1140 1139
1141 1140 @doctest float
1142 1141 In [4]: x
1143 1142 Out[4]:
1144 1143 array([[ inf, nan, 2., 3.],
1145 1144 [ 4., 5., 6., 7.],
1146 1145 [ 8., 9., 10., 11.],
1147 1146 [ 12., 13., 14., 15.]])
1148 1147
1149 1148
1150 1149 """,
1151 1150 ]
1152 1151 # skip local-file depending first example:
1153 1152 examples = examples[1:]
1154 1153
1155 1154 #ipython_directive.DEBUG = True # dbg
1156 1155 #options = dict(suppress=True) # dbg
1157 1156 options = {}
1158 1157 for example in examples:
1159 1158 content = example.split('\n')
1160 1159 IPythonDirective('debug', arguments=None, options=options,
1161 1160 content=content, lineno=0,
1162 1161 content_offset=None, block_text=None,
1163 1162 state=None, state_machine=None,
1164 1163 )
1165 1164
1166 1165 # Run test suite as a script
1167 1166 if __name__=='__main__':
1168 1167 if not os.path.isdir('_static'):
1169 1168 os.mkdir('_static')
1170 1169 test()
1171 1170 print('All OK? Check figures in _static/')
@@ -1,541 +1,540 b''
1 1 """IPython terminal interface using prompt_toolkit"""
2 2
3 3 import os
4 4 import sys
5 5 import warnings
6 6 from warnings import warn
7 7
8 8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
9 9 from IPython.utils import io
10 10 from IPython.utils.py3compat import input
11 11 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 12 from IPython.utils.process import abbrev_cwd
13 13 from traitlets import (
14 14 Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union,
15 15 Any,
16 16 )
17 17
18 18 from prompt_toolkit.document import Document
19 19 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
20 20 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
21 21 from prompt_toolkit.history import InMemoryHistory
22 22 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
23 23 from prompt_toolkit.interface import CommandLineInterface
24 24 from prompt_toolkit.key_binding.manager import KeyBindingManager
25 25 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
26 26 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
27 27
28 28 from pygments.styles import get_style_by_name
29 29 from pygments.style import Style
30 30 from pygments.token import Token
31 31
32 32 from .debugger import TerminalPdb, Pdb
33 33 from .magics import TerminalMagics
34 34 from .pt_inputhooks import get_inputhook_name_and_func
35 35 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
36 36 from .ptutils import IPythonPTCompleter, IPythonPTLexer
37 37 from .shortcuts import register_ipython_shortcuts
38 38
39 39 DISPLAY_BANNER_DEPRECATED = object()
40 40
41 41
42 42 class _NoStyle(Style): pass
43 43
44 44
45 45
46 46 _style_overrides_light_bg = {
47 47 Token.Prompt: '#0000ff',
48 48 Token.PromptNum: '#0000ee bold',
49 49 Token.OutPrompt: '#cc0000',
50 50 Token.OutPromptNum: '#bb0000 bold',
51 51 }
52 52
53 53 _style_overrides_linux = {
54 54 Token.Prompt: '#00cc00',
55 55 Token.PromptNum: '#00bb00 bold',
56 56 Token.OutPrompt: '#cc0000',
57 57 Token.OutPromptNum: '#bb0000 bold',
58 58 }
59 59
60 60 def get_default_editor():
61 61 try:
62 62 return os.environ['EDITOR']
63 63 except KeyError:
64 64 pass
65 65 except UnicodeError:
66 66 warn("$EDITOR environment variable is not pure ASCII. Using platform "
67 67 "default editor.")
68 68
69 69 if os.name == 'posix':
70 70 return 'vi' # the only one guaranteed to be there!
71 71 else:
72 72 return 'notepad' # same in Windows!
73 73
74 74 # conservatively check for tty
75 75 # overridden streams can result in things like:
76 76 # - sys.stdin = None
77 77 # - no isatty method
78 78 for _name in ('stdin', 'stdout', 'stderr'):
79 79 _stream = getattr(sys, _name)
80 80 if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
81 81 _is_tty = False
82 82 break
83 83 else:
84 84 _is_tty = True
85 85
86 86
87 87 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
88 88
89 89 class TerminalInteractiveShell(InteractiveShell):
90 90 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
91 91 'to reserve for the completion menu'
92 92 ).tag(config=True)
93 93
94 94 def _space_for_menu_changed(self, old, new):
95 95 self._update_layout()
96 96
97 97 pt_cli = None
98 98 debugger_history = None
99 99 _pt_app = None
100 100
101 101 simple_prompt = Bool(_use_simple_prompt,
102 102 help="""Use `raw_input` for the REPL, without completion and prompt colors.
103 103
104 104 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
105 105 IPython own testing machinery, and emacs inferior-shell integration through elpy.
106 106
107 107 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
108 108 environment variable is set, or the current terminal is not a tty."""
109 109 ).tag(config=True)
110 110
111 111 @property
112 112 def debugger_cls(self):
113 113 return Pdb if self.simple_prompt else TerminalPdb
114 114
115 115 confirm_exit = Bool(True,
116 116 help="""
117 117 Set to confirm when you try to exit IPython with an EOF (Control-D
118 118 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
119 119 you can force a direct exit without any confirmation.""",
120 120 ).tag(config=True)
121 121
122 122 editing_mode = Unicode('emacs',
123 123 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
124 124 ).tag(config=True)
125 125
126 126 mouse_support = Bool(False,
127 127 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
128 128 ).tag(config=True)
129 129
130 130 # We don't load the list of styles for the help string, because loading
131 131 # Pygments plugins takes time and can cause unexpected errors.
132 132 highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
133 133 help="""The name or class of a Pygments style to use for syntax
134 134 highlighting. To see available styles, run `pygmentize -L styles`."""
135 135 ).tag(config=True)
136 136
137 137
138 138 @observe('highlighting_style')
139 139 @observe('colors')
140 140 def _highlighting_style_changed(self, change):
141 141 self.refresh_style()
142 142
143 143 def refresh_style(self):
144 144 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
145 145
146 146
147 147 highlighting_style_overrides = Dict(
148 148 help="Override highlighting format for specific tokens"
149 149 ).tag(config=True)
150 150
151 151 true_color = Bool(False,
152 152 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
153 153 "If your terminal supports true color, the following command "
154 154 "should print 'TRUECOLOR' in orange: "
155 155 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
156 156 ).tag(config=True)
157 157
158 158 editor = Unicode(get_default_editor(),
159 159 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
160 160 ).tag(config=True)
161 161
162 162 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
163 163
164 164 prompts = Instance(Prompts)
165 165
166 166 @default('prompts')
167 167 def _prompts_default(self):
168 168 return self.prompts_class(self)
169 169
170 170 @observe('prompts')
171 171 def _(self, change):
172 172 self._update_layout()
173 173
174 174 @default('displayhook_class')
175 175 def _displayhook_class_default(self):
176 176 return RichPromptDisplayHook
177 177
178 178 term_title = Bool(True,
179 179 help="Automatically set the terminal title"
180 180 ).tag(config=True)
181 181
182 182 term_title_format = Unicode("IPython: {cwd}",
183 183 help="Customize the terminal title format. This is a python format string. " +
184 184 "Available substitutions are: {cwd}."
185 185 ).tag(config=True)
186 186
187 187 display_completions = Enum(('column', 'multicolumn','readlinelike'),
188 188 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
189 189 "'readlinelike'. These options are for `prompt_toolkit`, see "
190 190 "`prompt_toolkit` documentation for more information."
191 191 ),
192 192 default_value='multicolumn').tag(config=True)
193 193
194 194 highlight_matching_brackets = Bool(True,
195 195 help="Highlight matching brackets.",
196 196 ).tag(config=True)
197 197
198 198 extra_open_editor_shortcuts = Bool(False,
199 199 help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
200 200 "This is in addition to the F2 binding, which is always enabled."
201 201 ).tag(config=True)
202 202
203 203 handle_return = Any(None,
204 204 help="Provide an alternative handler to be called when the user presses "
205 205 "Return. This is an advanced option intended for debugging, which "
206 206 "may be changed or removed in later releases."
207 207 ).tag(config=True)
208 208
209 209 enable_history_search = Bool(True,
210 210 help="Allows to enable/disable the prompt toolkit history search"
211 211 ).tag(config=True)
212 212
213 213 @observe('term_title')
214 214 def init_term_title(self, change=None):
215 215 # Enable or disable the terminal title.
216 216 if self.term_title:
217 217 toggle_set_term_title(True)
218 218 set_term_title(self.term_title_format.format(cwd=abbrev_cwd()))
219 219 else:
220 220 toggle_set_term_title(False)
221 221
222 222 def init_display_formatter(self):
223 223 super(TerminalInteractiveShell, self).init_display_formatter()
224 224 # terminal only supports plain text
225 225 self.display_formatter.active_types = ['text/plain']
226 226 # disable `_ipython_display_`
227 227 self.display_formatter.ipython_display_formatter.enabled = False
228 228
229 229 def init_prompt_toolkit_cli(self):
230 230 if self.simple_prompt:
231 231 # Fall back to plain non-interactive output for tests.
232 232 # This is very limited.
233 233 def prompt():
234 itm = self.input_transformer_manager
235 234 prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
236 235 lines = [input(prompt_text)]
237 236 prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
238 while itm.check_complete('\n'.join(lines))[0] == 'incomplete':
237 while self.check_complete('\n'.join(lines))[0] == 'incomplete':
239 238 lines.append( input(prompt_continuation) )
240 239 return '\n'.join(lines)
241 240 self.prompt_for_code = prompt
242 241 return
243 242
244 243 # Set up keyboard shortcuts
245 244 kbmanager = KeyBindingManager.for_prompt(
246 245 enable_open_in_editor=self.extra_open_editor_shortcuts,
247 246 )
248 247 register_ipython_shortcuts(kbmanager.registry, self)
249 248
250 249 # Pre-populate history from IPython's history database
251 250 history = InMemoryHistory()
252 251 last_cell = u""
253 252 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
254 253 include_latest=True):
255 254 # Ignore blank lines and consecutive duplicates
256 255 cell = cell.rstrip()
257 256 if cell and (cell != last_cell):
258 257 history.append(cell)
259 258 last_cell = cell
260 259
261 260 self._style = self._make_style_from_name_or_cls(self.highlighting_style)
262 261 self.style = DynamicStyle(lambda: self._style)
263 262
264 263 editing_mode = getattr(EditingMode, self.editing_mode.upper())
265 264
266 265 def patch_stdout(**kwargs):
267 266 return self.pt_cli.patch_stdout_context(**kwargs)
268 267
269 268 self._pt_app = create_prompt_application(
270 269 editing_mode=editing_mode,
271 270 key_bindings_registry=kbmanager.registry,
272 271 history=history,
273 272 completer=IPythonPTCompleter(shell=self,
274 273 patch_stdout=patch_stdout),
275 274 enable_history_search=self.enable_history_search,
276 275 style=self.style,
277 276 mouse_support=self.mouse_support,
278 277 **self._layout_options()
279 278 )
280 279 self._eventloop = create_eventloop(self.inputhook)
281 280 self.pt_cli = CommandLineInterface(
282 281 self._pt_app, eventloop=self._eventloop,
283 282 output=create_output(true_color=self.true_color))
284 283
285 284 def _make_style_from_name_or_cls(self, name_or_cls):
286 285 """
287 286 Small wrapper that make an IPython compatible style from a style name
288 287
289 288 We need that to add style for prompt ... etc.
290 289 """
291 290 style_overrides = {}
292 291 if name_or_cls == 'legacy':
293 292 legacy = self.colors.lower()
294 293 if legacy == 'linux':
295 294 style_cls = get_style_by_name('monokai')
296 295 style_overrides = _style_overrides_linux
297 296 elif legacy == 'lightbg':
298 297 style_overrides = _style_overrides_light_bg
299 298 style_cls = get_style_by_name('pastie')
300 299 elif legacy == 'neutral':
301 300 # The default theme needs to be visible on both a dark background
302 301 # and a light background, because we can't tell what the terminal
303 302 # looks like. These tweaks to the default theme help with that.
304 303 style_cls = get_style_by_name('default')
305 304 style_overrides.update({
306 305 Token.Number: '#007700',
307 306 Token.Operator: 'noinherit',
308 307 Token.String: '#BB6622',
309 308 Token.Name.Function: '#2080D0',
310 309 Token.Name.Class: 'bold #2080D0',
311 310 Token.Name.Namespace: 'bold #2080D0',
312 311 Token.Prompt: '#009900',
313 312 Token.PromptNum: '#00ff00 bold',
314 313 Token.OutPrompt: '#990000',
315 314 Token.OutPromptNum: '#ff0000 bold',
316 315 })
317 316
318 317 # Hack: Due to limited color support on the Windows console
319 318 # the prompt colors will be wrong without this
320 319 if os.name == 'nt':
321 320 style_overrides.update({
322 321 Token.Prompt: '#ansidarkgreen',
323 322 Token.PromptNum: '#ansigreen bold',
324 323 Token.OutPrompt: '#ansidarkred',
325 324 Token.OutPromptNum: '#ansired bold',
326 325 })
327 326 elif legacy =='nocolor':
328 327 style_cls=_NoStyle
329 328 style_overrides = {}
330 329 else :
331 330 raise ValueError('Got unknown colors: ', legacy)
332 331 else :
333 332 if isinstance(name_or_cls, str):
334 333 style_cls = get_style_by_name(name_or_cls)
335 334 else:
336 335 style_cls = name_or_cls
337 336 style_overrides = {
338 337 Token.Prompt: '#009900',
339 338 Token.PromptNum: '#00ff00 bold',
340 339 Token.OutPrompt: '#990000',
341 340 Token.OutPromptNum: '#ff0000 bold',
342 341 }
343 342 style_overrides.update(self.highlighting_style_overrides)
344 343 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
345 344 style_dict=style_overrides)
346 345
347 346 return style
348 347
349 348 def _layout_options(self):
350 349 """
351 350 Return the current layout option for the current Terminal InteractiveShell
352 351 """
353 352 return {
354 353 'lexer':IPythonPTLexer(),
355 354 'reserve_space_for_menu':self.space_for_menu,
356 355 'get_prompt_tokens':self.prompts.in_prompt_tokens,
357 356 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
358 357 'multiline':True,
359 358 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
360 359
361 360 # Highlight matching brackets, but only when this setting is
362 361 # enabled, and only when the DEFAULT_BUFFER has the focus.
363 362 'extra_input_processors': [ConditionalProcessor(
364 363 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
365 364 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
366 365 Condition(lambda cli: self.highlight_matching_brackets))],
367 366 }
368 367
369 368 def _update_layout(self):
370 369 """
371 370 Ask for a re computation of the application layout, if for example ,
372 371 some configuration options have changed.
373 372 """
374 373 if self._pt_app:
375 374 self._pt_app.layout = create_prompt_layout(**self._layout_options())
376 375
377 376 def prompt_for_code(self):
378 377 with self.pt_cli.patch_stdout_context(raw=True):
379 378 document = self.pt_cli.run(
380 379 pre_run=self.pre_prompt, reset_current_buffer=True)
381 380 return document.text
382 381
383 382 def enable_win_unicode_console(self):
384 383 if sys.version_info >= (3, 6):
385 384 # Since PEP 528, Python uses the unicode APIs for the Windows
386 385 # console by default, so WUC shouldn't be needed.
387 386 return
388 387
389 388 import win_unicode_console
390 389 win_unicode_console.enable()
391 390
392 391 def init_io(self):
393 392 if sys.platform not in {'win32', 'cli'}:
394 393 return
395 394
396 395 self.enable_win_unicode_console()
397 396
398 397 import colorama
399 398 colorama.init()
400 399
401 400 # For some reason we make these wrappers around stdout/stderr.
402 401 # For now, we need to reset them so all output gets coloured.
403 402 # https://github.com/ipython/ipython/issues/8669
404 403 # io.std* are deprecated, but don't show our own deprecation warnings
405 404 # during initialization of the deprecated API.
406 405 with warnings.catch_warnings():
407 406 warnings.simplefilter('ignore', DeprecationWarning)
408 407 io.stdout = io.IOStream(sys.stdout)
409 408 io.stderr = io.IOStream(sys.stderr)
410 409
411 410 def init_magics(self):
412 411 super(TerminalInteractiveShell, self).init_magics()
413 412 self.register_magics(TerminalMagics)
414 413
415 414 def init_alias(self):
416 415 # The parent class defines aliases that can be safely used with any
417 416 # frontend.
418 417 super(TerminalInteractiveShell, self).init_alias()
419 418
420 419 # Now define aliases that only make sense on the terminal, because they
421 420 # need direct access to the console in a way that we can't emulate in
422 421 # GUI or web frontend
423 422 if os.name == 'posix':
424 423 for cmd in ['clear', 'more', 'less', 'man']:
425 424 self.alias_manager.soft_define_alias(cmd, cmd)
426 425
427 426
428 427 def __init__(self, *args, **kwargs):
429 428 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
430 429 self.init_prompt_toolkit_cli()
431 430 self.init_term_title()
432 431 self.keep_running = True
433 432
434 433 self.debugger_history = InMemoryHistory()
435 434
436 435 def ask_exit(self):
437 436 self.keep_running = False
438 437
439 438 rl_next_input = None
440 439
441 440 def pre_prompt(self):
442 441 if self.rl_next_input:
443 442 # We can't set the buffer here, because it will be reset just after
444 443 # this. Adding a callable to pre_run_callables does what we need
445 444 # after the buffer is reset.
446 445 s = self.rl_next_input
447 446 def set_doc():
448 447 self.pt_cli.application.buffer.document = Document(s)
449 448 if hasattr(self.pt_cli, 'pre_run_callables'):
450 449 self.pt_cli.pre_run_callables.append(set_doc)
451 450 else:
452 451 # Older version of prompt_toolkit; it's OK to set the document
453 452 # directly here.
454 453 set_doc()
455 454 self.rl_next_input = None
456 455
457 456 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
458 457
459 458 if display_banner is not DISPLAY_BANNER_DEPRECATED:
460 459 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
461 460
462 461 self.keep_running = True
463 462 while self.keep_running:
464 463 print(self.separate_in, end='')
465 464
466 465 try:
467 466 code = self.prompt_for_code()
468 467 except EOFError:
469 468 if (not self.confirm_exit) \
470 469 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
471 470 self.ask_exit()
472 471
473 472 else:
474 473 if code:
475 474 self.run_cell(code, store_history=True)
476 475
477 476 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
478 477 # An extra layer of protection in case someone mashing Ctrl-C breaks
479 478 # out of our internal code.
480 479 if display_banner is not DISPLAY_BANNER_DEPRECATED:
481 480 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
482 481 while True:
483 482 try:
484 483 self.interact()
485 484 break
486 485 except KeyboardInterrupt as e:
487 486 print("\n%s escaped interact()\n" % type(e).__name__)
488 487 finally:
489 488 # An interrupt during the eventloop will mess up the
490 489 # internal state of the prompt_toolkit library.
491 490 # Stopping the eventloop fixes this, see
492 491 # https://github.com/ipython/ipython/pull/9867
493 492 if hasattr(self, '_eventloop'):
494 493 self._eventloop.stop()
495 494
496 495 _inputhook = None
497 496 def inputhook(self, context):
498 497 if self._inputhook is not None:
499 498 self._inputhook(context)
500 499
501 500 active_eventloop = None
502 501 def enable_gui(self, gui=None):
503 502 if gui:
504 503 self.active_eventloop, self._inputhook =\
505 504 get_inputhook_name_and_func(gui)
506 505 else:
507 506 self.active_eventloop = self._inputhook = None
508 507
509 508 # Run !system commands directly, not through pipes, so terminal programs
510 509 # work correctly.
511 510 system = InteractiveShell.system_raw
512 511
513 512 def auto_rewrite_input(self, cmd):
514 513 """Overridden from the parent class to use fancy rewriting prompt"""
515 514 if not self.show_rewritten_input:
516 515 return
517 516
518 517 tokens = self.prompts.rewrite_prompt_tokens()
519 518 if self.pt_cli:
520 519 self.pt_cli.print_tokens(tokens)
521 520 print(cmd)
522 521 else:
523 522 prompt = ''.join(s for t, s in tokens)
524 523 print(prompt, cmd, sep='')
525 524
526 525 _prompts_before = None
527 526 def switch_doctest_mode(self, mode):
528 527 """Switch prompts to classic for %doctest_mode"""
529 528 if mode:
530 529 self._prompts_before = self.prompts
531 530 self.prompts = ClassicPrompts(self)
532 531 elif self._prompts_before:
533 532 self.prompts = self._prompts_before
534 533 self._prompts_before = None
535 534 self._update_layout()
536 535
537 536
538 537 InteractiveShellABC.register(TerminalInteractiveShell)
539 538
540 539 if __name__ == '__main__':
541 540 TerminalInteractiveShell.instance().interact()
@@ -1,256 +1,256 b''
1 1 """
2 2 Module to define and register Terminal IPython shortcuts with
3 3 :mod:`prompt_toolkit`
4 4 """
5 5
6 6 # Copyright (c) IPython Development Team.
7 7 # Distributed under the terms of the Modified BSD License.
8 8
9 9 import warnings
10 10 import signal
11 11 import sys
12 12 from typing import Callable
13 13
14 14
15 15 from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
16 16 from prompt_toolkit.filters import (HasFocus, HasSelection, Condition,
17 17 ViInsertMode, EmacsInsertMode, HasCompletions)
18 18 from prompt_toolkit.filters.cli import ViMode, ViNavigationMode
19 19 from prompt_toolkit.keys import Keys
20 20 from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
21 21
22 22 from IPython.utils.decorators import undoc
23 23
24 24 @undoc
25 25 @Condition
26 26 def cursor_in_leading_ws(cli):
27 27 before = cli.application.buffer.document.current_line_before_cursor
28 28 return (not before) or before.isspace()
29 29
30 30 def register_ipython_shortcuts(registry, shell):
31 31 """Set up the prompt_toolkit keyboard shortcuts for IPython"""
32 32 insert_mode = ViInsertMode() | EmacsInsertMode()
33 33
34 34 if getattr(shell, 'handle_return', None):
35 35 return_handler = shell.handle_return(shell)
36 36 else:
37 37 return_handler = newline_or_execute_outer(shell)
38 38
39 39 # Ctrl+J == Enter, seemingly
40 40 registry.add_binding(Keys.ControlJ,
41 41 filter=(HasFocus(DEFAULT_BUFFER)
42 42 & ~HasSelection()
43 43 & insert_mode
44 44 ))(return_handler)
45 45
46 46 registry.add_binding(Keys.ControlBackslash)(force_exit)
47 47
48 48 registry.add_binding(Keys.ControlP,
49 49 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
50 50 ))(previous_history_or_previous_completion)
51 51
52 52 registry.add_binding(Keys.ControlN,
53 53 filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
54 54 ))(next_history_or_next_completion)
55 55
56 56 registry.add_binding(Keys.ControlG,
57 57 filter=(HasFocus(DEFAULT_BUFFER) & HasCompletions()
58 58 ))(dismiss_completion)
59 59
60 60 registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)
61 61 )(reset_buffer)
62 62
63 63 registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)
64 64 )(reset_search_buffer)
65 65
66 66 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
67 67 registry.add_binding(Keys.ControlZ, filter=supports_suspend
68 68 )(suspend_to_bg)
69 69
70 70 # Ctrl+I == Tab
71 71 registry.add_binding(Keys.ControlI,
72 72 filter=(HasFocus(DEFAULT_BUFFER)
73 73 & ~HasSelection()
74 74 & insert_mode
75 75 & cursor_in_leading_ws
76 76 ))(indent_buffer)
77 77
78 78 registry.add_binding(Keys.ControlO,
79 79 filter=(HasFocus(DEFAULT_BUFFER)
80 80 & EmacsInsertMode()))(newline_autoindent_outer(shell.input_transformer_manager))
81 81
82 82 registry.add_binding(Keys.F2,
83 83 filter=HasFocus(DEFAULT_BUFFER)
84 84 )(open_input_in_editor)
85 85
86 86 if shell.display_completions == 'readlinelike':
87 87 registry.add_binding(Keys.ControlI,
88 88 filter=(HasFocus(DEFAULT_BUFFER)
89 89 & ~HasSelection()
90 90 & insert_mode
91 91 & ~cursor_in_leading_ws
92 92 ))(display_completions_like_readline)
93 93
94 94 if sys.platform == 'win32':
95 95 registry.add_binding(Keys.ControlV,
96 96 filter=(
97 97 HasFocus(
98 98 DEFAULT_BUFFER) & ~ViMode()
99 99 ))(win_paste)
100 100
101 101
102 102 def newline_or_execute_outer(shell):
103 103 def newline_or_execute(event):
104 104 """When the user presses return, insert a newline or execute the code."""
105 105 b = event.current_buffer
106 106 d = b.document
107 107
108 108 if b.complete_state:
109 109 cc = b.complete_state.current_completion
110 110 if cc:
111 111 b.apply_completion(cc)
112 112 else:
113 113 b.cancel_completion()
114 114 return
115 115
116 116 # If there's only one line, treat it as if the cursor is at the end.
117 117 # See https://github.com/ipython/ipython/issues/10425
118 118 if d.line_count == 1:
119 119 check_text = d.text
120 120 else:
121 121 check_text = d.text[:d.cursor_position]
122 status, indent = shell.input_transformer_manager.check_complete(check_text + '\n')
122 status, indent = shell.check_complete(check_text)
123 123
124 124 if not (d.on_last_line or
125 125 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
126 126 ):
127 b.insert_text('\n' + (' ' * (indent or 0)))
127 b.insert_text('\n' + indent)
128 128 return
129 129
130 130 if (status != 'incomplete') and b.accept_action.is_returnable:
131 131 b.accept_action.validate_and_handle(event.cli, b)
132 132 else:
133 b.insert_text('\n' + (' ' * (indent or 0)))
133 b.insert_text('\n' + indent)
134 134 return newline_or_execute
135 135
136 136
137 137 def previous_history_or_previous_completion(event):
138 138 """
139 139 Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
140 140
141 141 If completer is open this still select previous completion.
142 142 """
143 143 event.current_buffer.auto_up()
144 144
145 145
146 146 def next_history_or_next_completion(event):
147 147 """
148 148 Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
149 149
150 150 If completer is open this still select next completion.
151 151 """
152 152 event.current_buffer.auto_down()
153 153
154 154
155 155 def dismiss_completion(event):
156 156 b = event.current_buffer
157 157 if b.complete_state:
158 158 b.cancel_completion()
159 159
160 160
161 161 def reset_buffer(event):
162 162 b = event.current_buffer
163 163 if b.complete_state:
164 164 b.cancel_completion()
165 165 else:
166 166 b.reset()
167 167
168 168
169 169 def reset_search_buffer(event):
170 170 if event.current_buffer.document.text:
171 171 event.current_buffer.reset()
172 172 else:
173 173 event.cli.push_focus(DEFAULT_BUFFER)
174 174
175 175 def suspend_to_bg(event):
176 176 event.cli.suspend_to_background()
177 177
178 178 def force_exit(event):
179 179 """
180 180 Force exit (with a non-zero return value)
181 181 """
182 182 sys.exit("Quit")
183 183
184 184 def indent_buffer(event):
185 185 event.current_buffer.insert_text(' ' * 4)
186 186
187 187 @undoc
188 188 def newline_with_copy_margin(event):
189 189 """
190 190 DEPRECATED since IPython 6.0
191 191
192 192 See :any:`newline_autoindent_outer` for a replacement.
193 193
194 194 Preserve margin and cursor position when using
195 195 Control-O to insert a newline in EMACS mode
196 196 """
197 197 warnings.warn("`newline_with_copy_margin(event)` is deprecated since IPython 6.0. "
198 198 "see `newline_autoindent_outer(shell)(event)` for a replacement.",
199 199 DeprecationWarning, stacklevel=2)
200 200
201 201 b = event.current_buffer
202 202 cursor_start_pos = b.document.cursor_position_col
203 203 b.newline(copy_margin=True)
204 204 b.cursor_up(count=1)
205 205 cursor_end_pos = b.document.cursor_position_col
206 206 if cursor_start_pos != cursor_end_pos:
207 207 pos_diff = cursor_start_pos - cursor_end_pos
208 208 b.cursor_right(count=pos_diff)
209 209
210 210 def newline_autoindent_outer(inputsplitter) -> Callable[..., None]:
211 211 """
212 212 Return a function suitable for inserting a indented newline after the cursor.
213 213
214 214 Fancier version of deprecated ``newline_with_copy_margin`` which should
215 215 compute the correct indentation of the inserted line. That is to say, indent
216 216 by 4 extra space after a function definition, class definition, context
217 217 manager... And dedent by 4 space after ``pass``, ``return``, ``raise ...``.
218 218 """
219 219
220 220 def newline_autoindent(event):
221 221 """insert a newline after the cursor indented appropriately."""
222 222 b = event.current_buffer
223 223 d = b.document
224 224
225 225 if b.complete_state:
226 226 b.cancel_completion()
227 227 text = d.text[:d.cursor_position] + '\n'
228 228 _, indent = inputsplitter.check_complete(text)
229 229 b.insert_text('\n' + (' ' * (indent or 0)), move_cursor=False)
230 230
231 231 return newline_autoindent
232 232
233 233
234 234 def open_input_in_editor(event):
235 235 event.cli.current_buffer.tempfile_suffix = ".py"
236 236 event.cli.current_buffer.open_in_editor(event.cli)
237 237
238 238
239 239 if sys.platform == 'win32':
240 240 from IPython.core.error import TryNext
241 241 from IPython.lib.clipboard import (ClipboardEmpty,
242 242 win32_clipboard_get,
243 243 tkinter_clipboard_get)
244 244
245 245 @undoc
246 246 def win_paste(event):
247 247 try:
248 248 text = win32_clipboard_get()
249 249 except TryNext:
250 250 try:
251 251 text = tkinter_clipboard_get()
252 252 except (TryNext, ClipboardEmpty):
253 253 return
254 254 except ClipboardEmpty:
255 255 return
256 256 event.current_buffer.insert_text(text.replace('\t', ' ' * 4))
@@ -1,293 +1,293 b''
1 1 =======================
2 2 Specific config details
3 3 =======================
4 4
5 5 .. _custom_prompts:
6 6
7 7 Custom Prompts
8 8 ==============
9 9
10 10 .. versionchanged:: 5.0
11 11
12 12 From IPython 5, prompts are produced as a list of Pygments tokens, which are
13 13 tuples of (token_type, text). You can customise prompts by writing a method
14 14 which generates a list of tokens.
15 15
16 16 There are four kinds of prompt:
17 17
18 18 * The **in** prompt is shown before the first line of input
19 19 (default like ``In [1]:``).
20 20 * The **continuation** prompt is shown before further lines of input
21 21 (default like ``...:``).
22 22 * The **rewrite** prompt is shown to highlight how special syntax has been
23 23 interpreted (default like ``----->``).
24 24 * The **out** prompt is shown before the result from evaluating the input
25 25 (default like ``Out[1]:``).
26 26
27 27 Custom prompts are supplied together as a class. If you want to customise only
28 28 some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`,
29 29 which defines the defaults. The required interface is like this:
30 30
31 31 .. class:: MyPrompts(shell)
32 32
33 33 Prompt style definition. *shell* is a reference to the
34 34 :class:`~.TerminalInteractiveShell` instance.
35 35
36 36 .. method:: in_prompt_tokens(cli=None)
37 37 continuation_prompt_tokens(self, cli=None, width=None)
38 38 rewrite_prompt_tokens()
39 39 out_prompt_tokens()
40 40
41 41 Return the respective prompts as lists of ``(token_type, text)`` tuples.
42 42
43 43 For continuation prompts, *width* is an integer representing the width of
44 44 the prompt area in terminal columns.
45 45
46 46 *cli*, where used, is the prompt_toolkit ``CommandLineInterface`` instance.
47 47 This is mainly for compatibility with the API prompt_toolkit expects.
48 48
49 49 Here is an example Prompt class that will show the current working directory
50 50 in the input prompt:
51 51
52 52 .. code-block:: python
53 53
54 54 from IPython.terminal.prompts import Prompts, Token
55 55 import os
56 56
57 57 class MyPrompt(Prompts):
58 58 def in_prompt_tokens(self, cli=None):
59 59 return [(Token, os.getcwd()),
60 60 (Token.Prompt, ' >>>')]
61 61
62 62 To set the new prompt, assign it to the ``prompts`` attribute of the IPython
63 63 shell:
64 64
65 65 .. code-block:: python
66 66
67 67 In [2]: ip = get_ipython()
68 68 ...: ip.prompts = MyPrompt(ip)
69 69
70 70 /home/bob >>> # it works
71 71
72 72 See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an
73 73 extensions to customise prompts.
74 74
75 75 Inside IPython or in a startup script, you can use a custom prompts class
76 76 by setting ``get_ipython().prompts`` to an *instance* of the class.
77 77 In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to
78 78 either the class object, or a string of its full importable name.
79 79
80 80 To include invisible terminal control sequences in a prompt, use
81 81 ``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored
82 82 when calculating the width.
83 83
84 84 Colours in the prompt are determined by the token types and the highlighting
85 85 style; see below for more details. The tokens used in the default prompts are
86 86 ``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``.
87 87
88 88 .. _termcolour:
89 89
90 90 Terminal Colors
91 91 ===============
92 92
93 93 .. versionchanged:: 5.0
94 94
95 95 There are two main configuration options controlling colours.
96 96
97 97 ``InteractiveShell.colors`` sets the colour of tracebacks and object info (the
98 98 output from e.g. ``zip?``). It may also affect other things if the option below
99 99 is set to ``'legacy'``. It has four case-insensitive values:
100 100 ``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which
101 101 should be legible on either dark or light terminal backgrounds. *linux* is
102 102 optimised for dark backgrounds and *lightbg* for light ones.
103 103
104 104 ``TerminalInteractiveShell.highlighting_style`` determines prompt colours and
105 105 syntax highlighting. It takes the name (as a string) or class (as a subclass of
106 106 ``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'``
107 107 to pick a style in accordance with ``InteractiveShell.colors``.
108 108
109 109 You can see the Pygments styles available on your system by running::
110 110
111 111 import pygments
112 112 list(pygments.styles.get_all_styles())
113 113
114 114 Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override
115 115 specific styles in the highlighting. It should be a dictionary mapping Pygments
116 116 token types to strings defining the style. See `Pygments' documentation
117 117 <http://pygments.org/docs/styles/#creating-own-styles>`__ for the language used
118 118 to define styles.
119 119
120 120 Colors in the pager
121 121 -------------------
122 122
123 123 On some systems, the default pager has problems with ANSI colour codes.
124 124 To configure your default pager to allow these:
125 125
126 126 1. Set the environment PAGER variable to ``less``.
127 127 2. Set the environment LESS variable to ``-r`` (plus any other options
128 128 you always want to pass to less by default). This tells less to
129 129 properly interpret control sequences, which is how color
130 130 information is given to your terminal.
131 131
132 132 .. _editors:
133 133
134 134 Editor configuration
135 135 ====================
136 136
137 137 IPython can integrate with text editors in a number of different ways:
138 138
139 139 * Editors (such as `(X)Emacs`_, vim_ and TextMate_) can
140 140 send code to IPython for execution.
141 141
142 142 * IPython's ``%edit`` magic command can open an editor of choice to edit
143 143 a code block.
144 144
145 145 The %edit command (and its alias %ed) will invoke the editor set in your
146 146 environment as :envvar:`EDITOR`. If this variable is not set, it will default
147 147 to vi under Linux/Unix and to notepad under Windows. You may want to set this
148 148 variable properly and to a lightweight editor which doesn't take too long to
149 149 start (that is, something other than a new instance of Emacs). This way you
150 150 can edit multi-line code quickly and with the power of a real editor right
151 151 inside IPython.
152 152
153 153 You can also control the editor by setting :attr:`TerminalInteractiveShell.editor`
154 154 in :file:`ipython_config.py`.
155 155
156 156 Vim
157 157 ---
158 158
159 159 Paul Ivanov's `vim-ipython <https://github.com/ivanov/vim-ipython>`_ provides
160 160 powerful IPython integration for vim.
161 161
162 162 .. _emacs:
163 163
164 164 (X)Emacs
165 165 --------
166 166
167 167 If you are a dedicated Emacs user, and want to use Emacs when IPython's
168 168 ``%edit`` magic command is called you should set up the Emacs server so that
169 169 new requests are handled by the original process. This means that almost no
170 170 time is spent in handling the request (assuming an Emacs process is already
171 171 running). For this to work, you need to set your EDITOR environment variable
172 172 to 'emacsclient'. The code below, supplied by Francois Pinard, can then be
173 173 used in your :file:`.emacs` file to enable the server:
174 174
175 175 .. code-block:: common-lisp
176 176
177 177 (defvar server-buffer-clients)
178 178 (when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm))
179 179 (server-start)
180 180 (defun fp-kill-server-with-buffer-routine ()
181 181 (and server-buffer-clients (server-done)))
182 182 (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine))
183 183
184 184 Thanks to the work of Alexander Schmolck and Prabhu Ramachandran,
185 185 currently (X)Emacs and IPython get along very well in other ways.
186 186
187 187 With (X)EMacs >= 24, You can enable IPython in python-mode with:
188 188
189 189 .. code-block:: common-lisp
190 190
191 191 (require 'python)
192 192 (setq python-shell-interpreter "ipython")
193 193
194 194 .. _`(X)Emacs`: http://www.gnu.org/software/emacs/
195 195 .. _TextMate: http://macromates.com/
196 196 .. _vim: http://www.vim.org/
197 197
198 198 .. _custom_keyboard_shortcuts:
199 199
200 200 Keyboard Shortcuts
201 201 ==================
202 202
203 203 .. versionchanged:: 5.0
204 204
205 205 You can customise keyboard shortcuts for terminal IPython. Put code like this in
206 206 a :ref:`startup file <startup_files>`::
207 207
208 208 from IPython import get_ipython
209 209 from prompt_toolkit.enums import DEFAULT_BUFFER
210 210 from prompt_toolkit.keys import Keys
211 211 from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode
212 212
213 213 ip = get_ipython()
214 214 insert_mode = ViInsertMode() | EmacsInsertMode()
215 215
216 216 def insert_unexpected(event):
217 217 buf = event.current_buffer
218 218 buf.insert_text('The Spanish Inquisition')
219 219
220 220 # Register the shortcut if IPython is using prompt_toolkit
221 221 if getattr(ip, 'pt_cli'):
222 222 registry = ip.pt_cli.application.key_bindings_registry
223 223 registry.add_binding(Keys.ControlN,
224 224 filter=(HasFocus(DEFAULT_BUFFER)
225 225 & ~HasSelection()
226 226 & insert_mode))(insert_unexpected)
227 227
228 228 For more information on filters and what you can do with the ``event`` object,
229 229 `see the prompt_toolkit docs
230 230 <http://python-prompt-toolkit.readthedocs.io/en/latest/pages/building_prompts.html#adding-custom-key-bindings>`__.
231 231
232 232
233 233 Enter to execute
234 234 ----------------
235 235
236 236 In the Terminal IPython shell – which by default uses the ``prompt_toolkit``
237 237 interface, the semantic meaning of pressing the :kbd:`Enter` key can be
238 238 ambiguous. In some case :kbd:`Enter` should execute code, and in others it
239 239 should add a new line. IPython uses heuristics to decide whether to execute or
240 240 insert a new line at cursor position. For example, if we detect that the current
241 241 code is not valid Python, then the user is likely editing code and the right
242 242 behavior is to likely to insert a new line. If the current code is a simple
243 243 statement like `ord('*')`, then the right behavior is likely to execute. Though
244 244 the exact desired semantics often varies from users to users.
245 245
246 246 As the exact behavior of :kbd:`Enter` is ambiguous, it has been special cased
247 247 to allow users to completely configure the behavior they like. Hence you can
248 248 have enter always execute code. If you prefer fancier behavior, you need to get
249 249 your hands dirty and read the ``prompt_toolkit`` and IPython documentation
250 250 though. See :ghpull:`10500`, set the
251 251 ``c.TerminalInteractiveShell.handle_return`` option and get inspiration from the
252 252 following example that only auto-executes the input if it begins with a bang or
253 253 a modulo character (``!`` or ``%``). To use the following code, add it to your
254 254 IPython configuration::
255 255
256 256 def custom_return(shell):
257 257
258 258 """This function is required by the API. It takes a reference to
259 259 the shell, which is the same thing `get_ipython()` evaluates to.
260 260 This function must return a function that handles each keypress
261 261 event. That function, named `handle` here, references `shell`
262 262 by closure."""
263 263
264 264 def handle(event):
265 265
266 266 """This function is called each time `Enter` is pressed,
267 267 and takes a reference to a Prompt Toolkit event object.
268 268 If the current input starts with a bang or modulo, then
269 269 the input is executed, otherwise a newline is entered,
270 270 followed by any spaces needed to auto-indent."""
271 271
272 272 # set up a few handy references to nested items...
273 273
274 274 buffer = event.current_buffer
275 275 document = buffer.document
276 276 text = document.text
277 277
278 278 if text.startswith('!') or text.startswith('%'): # execute the input...
279 279
280 280 buffer.accept_action.validate_and_handle(event.cli, buffer)
281 281
282 282 else: # insert a newline with auto-indentation...
283 283
284 284 if document.line_count > 1: text = text[:document.cursor_position]
285 indent = shell.input_transformer_manager.check_complete(text)[1] or 0
286 buffer.insert_text('\n' + ' ' * indent)
285 indent = shell.check_complete(text)[1]
286 buffer.insert_text('\n' + indent)
287 287
288 288 # if you just wanted a plain newline without any indentation, you
289 289 # could use `buffer.insert_text('\n')` instead of the lines above
290 290
291 291 return handle
292 292
293 293 c.TerminalInteractiveShell.handle_return = custom_return
General Comments 0
You need to be logged in to leave comments. Login now