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