##// END OF EJS Templates
Remove the readline shell machinery...
Thomas Kluyver -
Show More
@@ -0,0 +1,207 b''
1 """Extra magics for terminal use."""
2
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
5
6 from __future__ import print_function
7
8 from logging import error
9 import os
10 import sys
11
12 from IPython.core.error import TryNext, UsageError
13 from IPython.core.inputsplitter import IPythonInputSplitter
14 from IPython.core.magic import Magics, magics_class, line_magic
15 from IPython.lib.clipboard import ClipboardEmpty
16 from IPython.utils.text import SList, strip_email_quotes
17 from IPython.utils import py3compat
18
19 def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
20 """ Yield pasted lines until the user enters the given sentinel value.
21 """
22 if not quiet:
23 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
24 % sentinel)
25 prompt = ":"
26 else:
27 prompt = ""
28 while True:
29 try:
30 l = py3compat.str_to_unicode(l_input(prompt))
31 if l == sentinel:
32 return
33 else:
34 yield l
35 except EOFError:
36 print('<EOF>')
37 return
38
39
40 @magics_class
41 class TerminalMagics(Magics):
42 def __init__(self, shell):
43 super(TerminalMagics, self).__init__(shell)
44 self.input_splitter = IPythonInputSplitter()
45
46 def store_or_execute(self, block, name):
47 """ Execute a block, or store it in a variable, per the user's request.
48 """
49 if name:
50 # If storing it for further editing
51 self.shell.user_ns[name] = SList(block.splitlines())
52 print("Block assigned to '%s'" % name)
53 else:
54 b = self.preclean_input(block)
55 self.shell.user_ns['pasted_block'] = b
56 self.shell.using_paste_magics = True
57 try:
58 self.shell.run_cell(b)
59 finally:
60 self.shell.using_paste_magics = False
61
62 def preclean_input(self, block):
63 lines = block.splitlines()
64 while lines and not lines[0].strip():
65 lines = lines[1:]
66 return strip_email_quotes('\n'.join(lines))
67
68 def rerun_pasted(self, name='pasted_block'):
69 """ Rerun a previously pasted command.
70 """
71 b = self.shell.user_ns.get(name)
72
73 # Sanity checks
74 if b is None:
75 raise UsageError('No previous pasted block available')
76 if not isinstance(b, py3compat.string_types):
77 raise UsageError(
78 "Variable 'pasted_block' is not a string, can't execute")
79
80 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
81 self.shell.run_cell(b)
82
83 @line_magic
84 def autoindent(self, parameter_s = ''):
85 """Toggle autoindent on/off (if available)."""
86
87 self.shell.set_autoindent()
88 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
89
90 @line_magic
91 def cpaste(self, parameter_s=''):
92 """Paste & execute a pre-formatted code block from clipboard.
93
94 You must terminate the block with '--' (two minus-signs) or Ctrl-D
95 alone on the line. You can also provide your own sentinel with '%paste
96 -s %%' ('%%' is the new sentinel for this operation).
97
98 The block is dedented prior to execution to enable execution of method
99 definitions. '>' and '+' characters at the beginning of a line are
100 ignored, to allow pasting directly from e-mails, diff files and
101 doctests (the '...' continuation prompt is also stripped). The
102 executed block is also assigned to variable named 'pasted_block' for
103 later editing with '%edit pasted_block'.
104
105 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
106 This assigns the pasted block to variable 'foo' as string, without
107 dedenting or executing it (preceding >>> and + is still stripped)
108
109 '%cpaste -r' re-executes the block previously entered by cpaste.
110 '%cpaste -q' suppresses any additional output messages.
111
112 Do not be alarmed by garbled output on Windows (it's a readline bug).
113 Just press enter and type -- (and press enter again) and the block
114 will be what was just pasted.
115
116 IPython statements (magics, shell escapes) are not supported (yet).
117
118 See also
119 --------
120 paste: automatically pull code from clipboard.
121
122 Examples
123 --------
124 ::
125
126 In [8]: %cpaste
127 Pasting code; enter '--' alone on the line to stop.
128 :>>> a = ["world!", "Hello"]
129 :>>> print " ".join(sorted(a))
130 :--
131 Hello world!
132 """
133 opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
134 if 'r' in opts:
135 self.rerun_pasted()
136 return
137
138 quiet = ('q' in opts)
139
140 sentinel = opts.get('s', u'--')
141 block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
142 self.store_or_execute(block, name)
143
144 @line_magic
145 def paste(self, parameter_s=''):
146 """Paste & execute a pre-formatted code block from clipboard.
147
148 The text is pulled directly from the clipboard without user
149 intervention and printed back on the screen before execution (unless
150 the -q flag is given to force quiet mode).
151
152 The block is dedented prior to execution to enable execution of method
153 definitions. '>' and '+' characters at the beginning of a line are
154 ignored, to allow pasting directly from e-mails, diff files and
155 doctests (the '...' continuation prompt is also stripped). The
156 executed block is also assigned to variable named 'pasted_block' for
157 later editing with '%edit pasted_block'.
158
159 You can also pass a variable name as an argument, e.g. '%paste foo'.
160 This assigns the pasted block to variable 'foo' as string, without
161 executing it (preceding >>> and + is still stripped).
162
163 Options:
164
165 -r: re-executes the block previously entered by cpaste.
166
167 -q: quiet mode: do not echo the pasted text back to the terminal.
168
169 IPython statements (magics, shell escapes) are not supported (yet).
170
171 See also
172 --------
173 cpaste: manually paste code into terminal until you mark its end.
174 """
175 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
176 if 'r' in opts:
177 self.rerun_pasted()
178 return
179 try:
180 block = self.shell.hooks.clipboard_get()
181 except TryNext as clipboard_exc:
182 message = getattr(clipboard_exc, 'args')
183 if message:
184 error(message[0])
185 else:
186 error('Could not get text from the clipboard.')
187 return
188 except ClipboardEmpty:
189 raise UsageError("The clipboard appears to be empty")
190
191 # By default, echo back to terminal unless quiet mode is requested
192 if 'q' not in opts:
193 write = self.shell.write
194 write(self.shell.pycolorize(block))
195 if not block.endswith('\n'):
196 write('\n')
197 write("## -- End pasted text --\n")
198
199 self.store_or_execute(block, name)
200
201 # Class-level: add a '%cls' magic only on Windows
202 if sys.platform == 'win32':
203 @line_magic
204 def cls(self, s):
205 """Clear screen.
206 """
207 os.system("cls")
This diff has been collapsed as it changes many lines, (810 lines changed) Show them Hide them
@@ -1,810 +1,18 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Subclass of InteractiveShell for terminal based frontends."""
2 """DEPRECATED: old import location of TerminalInteractiveShell"""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from __future__ import print_function
8
9 import bdb
10 import os
11 import sys
12
13 from IPython.core.error import TryNext, UsageError
14 from IPython.core.usage import interactive_usage
15 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC
16 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
17 from IPython.core.magic import Magics, magics_class, line_magic
18 from IPython.lib.clipboard import ClipboardEmpty
19 from IPython.utils.contexts import NoOpContext
20 from IPython.utils.decorators import undoc
21 from IPython.utils.encoding import get_stream_enc
22 from IPython.utils import py3compat
23 from IPython.utils.terminal import toggle_set_term_title, set_term_title
24 from IPython.utils.process import abbrev_cwd
25 from warnings import warn
7 from warnings import warn
26 from logging import error
27 from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes
28 from traitlets import Integer, CBool, Unicode
29
30
31 def get_default_editor():
32 try:
33 ed = os.environ['EDITOR']
34 if not py3compat.PY3:
35 ed = ed.decode()
36 return ed
37 except KeyError:
38 pass
39 except UnicodeError:
40 warn("$EDITOR environment variable is not pure ASCII. Using platform "
41 "default editor.")
42
8
43 if os.name == 'posix':
9 from IPython.utils.decorators import undoc
44 return 'vi' # the only one guaranteed to be there!
10 from .ptshell import TerminalInteractiveShell as PromptToolkitShell
45 else:
46 return 'notepad' # same in Windows!
47
48 def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
49 """ Yield pasted lines until the user enters the given sentinel value.
50 """
51 if not quiet:
52 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
53 % sentinel)
54 prompt = ":"
55 else:
56 prompt = ""
57 while True:
58 try:
59 l = py3compat.str_to_unicode(l_input(prompt))
60 if l == sentinel:
61 return
62 else:
63 yield l
64 except EOFError:
65 print('<EOF>')
66 return
67
11
68 @undoc
12 @undoc
69 def no_op(*a, **kw): pass
13 class TerminalInteractiveShell(PromptToolkitShell):
70
14 def __init__(self, *args, **kwargs):
71
15 warn("This is a deprecated alias for IPython.terminal.ptshell.TerminalInteractiveShell. "
72 class ReadlineNoRecord(object):
16 "The terminal interface of this class now uses prompt_toolkit instead of readline.",
73 """Context manager to execute some code, then reload readline history
17 DeprecationWarning, stacklevel=2)
74 so that interactive input to the code doesn't appear when pressing up."""
18 PromptToolkitShell.__init__(self, *args, **kwargs)
75 def __init__(self, shell):
76 self.shell = shell
77 self._nested_level = 0
78
79 def __enter__(self):
80 if self._nested_level == 0:
81 try:
82 self.orig_length = self.current_length()
83 self.readline_tail = self.get_readline_tail()
84 except (AttributeError, IndexError): # Can fail with pyreadline
85 self.orig_length, self.readline_tail = 999999, []
86 self._nested_level += 1
87
88 def __exit__(self, type, value, traceback):
89 self._nested_level -= 1
90 if self._nested_level == 0:
91 # Try clipping the end if it's got longer
92 try:
93 e = self.current_length() - self.orig_length
94 if e > 0:
95 for _ in range(e):
96 self.shell.readline.remove_history_item(self.orig_length)
97
98 # If it still doesn't match, just reload readline history.
99 if self.current_length() != self.orig_length \
100 or self.get_readline_tail() != self.readline_tail:
101 self.shell.refill_readline_hist()
102 except (AttributeError, IndexError):
103 pass
104 # Returning False will cause exceptions to propagate
105 return False
106
107 def current_length(self):
108 return self.shell.readline.get_current_history_length()
109
110 def get_readline_tail(self, n=10):
111 """Get the last n items in readline history."""
112 end = self.shell.readline.get_current_history_length() + 1
113 start = max(end-n, 1)
114 ghi = self.shell.readline.get_history_item
115 return [ghi(x) for x in range(start, end)]
116
117
118 @magics_class
119 class TerminalMagics(Magics):
120 def __init__(self, shell):
121 super(TerminalMagics, self).__init__(shell)
122 self.input_splitter = IPythonInputSplitter()
123
124 def store_or_execute(self, block, name):
125 """ Execute a block, or store it in a variable, per the user's request.
126 """
127 if name:
128 # If storing it for further editing
129 self.shell.user_ns[name] = SList(block.splitlines())
130 print("Block assigned to '%s'" % name)
131 else:
132 b = self.preclean_input(block)
133 self.shell.user_ns['pasted_block'] = b
134 self.shell.using_paste_magics = True
135 try:
136 self.shell.run_cell(b)
137 finally:
138 self.shell.using_paste_magics = False
139
140 def preclean_input(self, block):
141 lines = block.splitlines()
142 while lines and not lines[0].strip():
143 lines = lines[1:]
144 return strip_email_quotes('\n'.join(lines))
145
146 def rerun_pasted(self, name='pasted_block'):
147 """ Rerun a previously pasted command.
148 """
149 b = self.shell.user_ns.get(name)
150
151 # Sanity checks
152 if b is None:
153 raise UsageError('No previous pasted block available')
154 if not isinstance(b, py3compat.string_types):
155 raise UsageError(
156 "Variable 'pasted_block' is not a string, can't execute")
157
158 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
159 self.shell.run_cell(b)
160
161 @line_magic
162 def autoindent(self, parameter_s = ''):
163 """Toggle autoindent on/off (if available)."""
164
165 self.shell.set_autoindent()
166 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
167
168 @line_magic
169 def cpaste(self, parameter_s=''):
170 """Paste & execute a pre-formatted code block from clipboard.
171
172 You must terminate the block with '--' (two minus-signs) or Ctrl-D
173 alone on the line. You can also provide your own sentinel with '%paste
174 -s %%' ('%%' is the new sentinel for this operation).
175
176 The block is dedented prior to execution to enable execution of method
177 definitions. '>' and '+' characters at the beginning of a line are
178 ignored, to allow pasting directly from e-mails, diff files and
179 doctests (the '...' continuation prompt is also stripped). The
180 executed block is also assigned to variable named 'pasted_block' for
181 later editing with '%edit pasted_block'.
182
183 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
184 This assigns the pasted block to variable 'foo' as string, without
185 dedenting or executing it (preceding >>> and + is still stripped)
186
187 '%cpaste -r' re-executes the block previously entered by cpaste.
188 '%cpaste -q' suppresses any additional output messages.
189
190 Do not be alarmed by garbled output on Windows (it's a readline bug).
191 Just press enter and type -- (and press enter again) and the block
192 will be what was just pasted.
193
194 IPython statements (magics, shell escapes) are not supported (yet).
195
196 See also
197 --------
198 paste: automatically pull code from clipboard.
199
200 Examples
201 --------
202 ::
203
204 In [8]: %cpaste
205 Pasting code; enter '--' alone on the line to stop.
206 :>>> a = ["world!", "Hello"]
207 :>>> print " ".join(sorted(a))
208 :--
209 Hello world!
210 """
211 opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
212 if 'r' in opts:
213 self.rerun_pasted()
214 return
215
216 quiet = ('q' in opts)
217
218 sentinel = opts.get('s', u'--')
219 block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
220 self.store_or_execute(block, name)
221
222 @line_magic
223 def paste(self, parameter_s=''):
224 """Paste & execute a pre-formatted code block from clipboard.
225
226 The text is pulled directly from the clipboard without user
227 intervention and printed back on the screen before execution (unless
228 the -q flag is given to force quiet mode).
229
230 The block is dedented prior to execution to enable execution of method
231 definitions. '>' and '+' characters at the beginning of a line are
232 ignored, to allow pasting directly from e-mails, diff files and
233 doctests (the '...' continuation prompt is also stripped). The
234 executed block is also assigned to variable named 'pasted_block' for
235 later editing with '%edit pasted_block'.
236
237 You can also pass a variable name as an argument, e.g. '%paste foo'.
238 This assigns the pasted block to variable 'foo' as string, without
239 executing it (preceding >>> and + is still stripped).
240
241 Options:
242
243 -r: re-executes the block previously entered by cpaste.
244
245 -q: quiet mode: do not echo the pasted text back to the terminal.
246
247 IPython statements (magics, shell escapes) are not supported (yet).
248
249 See also
250 --------
251 cpaste: manually paste code into terminal until you mark its end.
252 """
253 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
254 if 'r' in opts:
255 self.rerun_pasted()
256 return
257 try:
258 block = self.shell.hooks.clipboard_get()
259 except TryNext as clipboard_exc:
260 message = getattr(clipboard_exc, 'args')
261 if message:
262 error(message[0])
263 else:
264 error('Could not get text from the clipboard.')
265 return
266 except ClipboardEmpty:
267 raise UsageError("The clipboard appears to be empty")
268
269 # By default, echo back to terminal unless quiet mode is requested
270 if 'q' not in opts:
271 write = self.shell.write
272 write(self.shell.pycolorize(block))
273 if not block.endswith('\n'):
274 write('\n')
275 write("## -- End pasted text --\n")
276
277 self.store_or_execute(block, name)
278
279 # Class-level: add a '%cls' magic only on Windows
280 if sys.platform == 'win32':
281 @line_magic
282 def cls(self, s):
283 """Clear screen.
284 """
285 os.system("cls")
286
287
288 class TerminalInteractiveShell(InteractiveShell):
289
290 autoedit_syntax = CBool(False, config=True,
291 help="auto editing of files with syntax errors.")
292 confirm_exit = CBool(True, config=True,
293 help="""
294 Set to confirm when you try to exit IPython with an EOF (Control-D
295 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
296 you can force a direct exit without any confirmation.""",
297 )
298 # This display_banner only controls whether or not self.show_banner()
299 # is called when mainloop/interact are called. The default is False
300 # because for the terminal based application, the banner behavior
301 # is controlled by the application.
302 display_banner = CBool(False) # This isn't configurable!
303 embedded = CBool(False)
304 embedded_active = CBool(False)
305 editor = Unicode(get_default_editor(), config=True,
306 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
307 )
308 pager = Unicode('less', config=True,
309 help="The shell program to be used for paging.")
310
311 screen_length = Integer(0, config=True,
312 help=
313 """Number of lines of your screen, used to control printing of very
314 long strings. Strings longer than this number of lines will be sent
315 through a pager instead of directly printed. The default value for
316 this is 0, which means IPython will auto-detect your screen size every
317 time it needs to print certain potentially long strings (this doesn't
318 change the behavior of the 'print' keyword, it's only triggered
319 internally). If for some reason this isn't working well (it needs
320 curses support), specify it yourself. Otherwise don't change the
321 default.""",
322 )
323 term_title = CBool(False, config=True,
324 help="Enable auto setting the terminal title."
325 )
326 usage = Unicode(interactive_usage)
327
328 # This `using_paste_magics` is used to detect whether the code is being
329 # executed via paste magics functions
330 using_paste_magics = CBool(False)
331
332 # In the terminal, GUI control is done via PyOS_InputHook
333 @staticmethod
334 def enable_gui(gui=None, app=None):
335 """Switch amongst GUI input hooks by name.
336 """
337 # Deferred import
338 from IPython.lib.inputhook import enable_gui as real_enable_gui
339 try:
340 return real_enable_gui(gui, app)
341 except ValueError as e:
342 raise UsageError("%s" % e)
343
344 system = InteractiveShell.system_raw
345
346 #-------------------------------------------------------------------------
347 # Overrides of init stages
348 #-------------------------------------------------------------------------
349
350 def init_display_formatter(self):
351 super(TerminalInteractiveShell, self).init_display_formatter()
352 # terminal only supports plaintext
353 self.display_formatter.active_types = ['text/plain']
354
355 #-------------------------------------------------------------------------
356 # Things related to readline
357 #-------------------------------------------------------------------------
358
359 def init_readline(self):
360 """Command history completion/saving/reloading."""
361
362 if self.readline_use:
363 import IPython.utils.rlineimpl as readline
364
365 self.rl_next_input = None
366 self.rl_do_indent = False
367
368 if not self.readline_use or not readline.have_readline:
369 self.readline = None
370 # Set a number of methods that depend on readline to be no-op
371 self.readline_no_record = NoOpContext()
372 self.set_readline_completer = no_op
373 self.set_custom_completer = no_op
374 if self.readline_use:
375 warn('Readline services not available or not loaded.')
376 else:
377 self.has_readline = True
378 self.readline = readline
379 sys.modules['readline'] = readline
380
381 # Platform-specific configuration
382 if os.name == 'nt':
383 # FIXME - check with Frederick to see if we can harmonize
384 # naming conventions with pyreadline to avoid this
385 # platform-dependent check
386 self.readline_startup_hook = readline.set_pre_input_hook
387 else:
388 self.readline_startup_hook = readline.set_startup_hook
389
390 # Readline config order:
391 # - IPython config (default value)
392 # - custom inputrc
393 # - IPython config (user customized)
394
395 # load IPython config before inputrc if default
396 # skip if libedit because parse_and_bind syntax is different
397 if not self._custom_readline_config and not readline.uses_libedit:
398 for rlcommand in self.readline_parse_and_bind:
399 readline.parse_and_bind(rlcommand)
400
401 # Load user's initrc file (readline config)
402 # Or if libedit is used, load editrc.
403 inputrc_name = os.environ.get('INPUTRC')
404 if inputrc_name is None:
405 inputrc_name = '.inputrc'
406 if readline.uses_libedit:
407 inputrc_name = '.editrc'
408 inputrc_name = os.path.join(self.home_dir, inputrc_name)
409 if os.path.isfile(inputrc_name):
410 try:
411 readline.read_init_file(inputrc_name)
412 except:
413 warn('Problems reading readline initialization file <%s>'
414 % inputrc_name)
415
416 # load IPython config after inputrc if user has customized
417 if self._custom_readline_config:
418 for rlcommand in self.readline_parse_and_bind:
419 readline.parse_and_bind(rlcommand)
420
421 # Remove some chars from the delimiters list. If we encounter
422 # unicode chars, discard them.
423 delims = readline.get_completer_delims()
424 if not py3compat.PY3:
425 delims = delims.encode("ascii", "ignore")
426 for d in self.readline_remove_delims:
427 delims = delims.replace(d, "")
428 delims = delims.replace(ESC_MAGIC, '')
429 readline.set_completer_delims(delims)
430 # Store these so we can restore them if something like rpy2 modifies
431 # them.
432 self.readline_delims = delims
433 # otherwise we end up with a monster history after a while:
434 readline.set_history_length(self.history_length)
435
436 self.refill_readline_hist()
437 self.readline_no_record = ReadlineNoRecord(self)
438
439 # Configure auto-indent for all platforms
440 self.set_autoindent(self.autoindent)
441
442 def init_completer(self):
443 super(TerminalInteractiveShell, self).init_completer()
444
445 # Only configure readline if we truly are using readline.
446 if self.has_readline:
447 self.set_readline_completer()
448
449 def set_readline_completer(self):
450 """Reset readline's completer to be our own."""
451 self.readline.set_completer(self.Completer.rlcomplete)
452
453
454 def pre_readline(self):
455 """readline hook to be used at the start of each line.
456
457 It handles auto-indent and text from set_next_input."""
458
459 if self.rl_do_indent:
460 self.readline.insert_text(self._indent_current_str())
461 if self.rl_next_input is not None:
462 self.readline.insert_text(self.rl_next_input)
463 self.rl_next_input = None
464
465 def refill_readline_hist(self):
466 # Load the last 1000 lines from history
467 self.readline.clear_history()
468 stdin_encoding = sys.stdin.encoding or "utf-8"
469 last_cell = u""
470 for _, _, cell in self.history_manager.get_tail(self.history_load_length,
471 include_latest=True):
472 # Ignore blank lines and consecutive duplicates
473 cell = cell.rstrip()
474 if cell and (cell != last_cell):
475 try:
476 if self.multiline_history:
477 self.readline.add_history(py3compat.unicode_to_str(cell,
478 stdin_encoding))
479 else:
480 for line in cell.splitlines():
481 self.readline.add_history(py3compat.unicode_to_str(line,
482 stdin_encoding))
483 last_cell = cell
484
485 except (TypeError, ValueError) as e:
486 # The history DB can get corrupted so it returns strings
487 # containing null bytes, which readline objects to.
488 warn(("Failed to add string to readline history.\n"
489 "Error: {}\n"
490 "Cell: {!r}").format(e, cell))
491
492 #-------------------------------------------------------------------------
493 # Things related to the terminal
494 #-------------------------------------------------------------------------
495
496 @property
497 def usable_screen_length(self):
498 if self.screen_length == 0:
499 return 0
500 else:
501 num_lines_bot = self.separate_in.count('\n')+1
502 return self.screen_length - num_lines_bot
503
504 def _term_title_changed(self, name, new_value):
505 self.init_term_title()
506
507 def init_term_title(self):
508 # Enable or disable the terminal title.
509 if self.term_title:
510 toggle_set_term_title(True)
511 set_term_title('IPython: ' + abbrev_cwd())
512 else:
513 toggle_set_term_title(False)
514
515 #-------------------------------------------------------------------------
516 # Things related to aliases
517 #-------------------------------------------------------------------------
518
519 def init_alias(self):
520 # The parent class defines aliases that can be safely used with any
521 # frontend.
522 super(TerminalInteractiveShell, self).init_alias()
523
524 # Now define aliases that only make sense on the terminal, because they
525 # need direct access to the console in a way that we can't emulate in
526 # GUI or web frontend
527 if os.name == 'posix':
528 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
529 ('man', 'man')]
530 else :
531 aliases = []
532
533 for name, cmd in aliases:
534 self.alias_manager.soft_define_alias(name, cmd)
535
536 #-------------------------------------------------------------------------
537 # Mainloop and code execution logic
538 #-------------------------------------------------------------------------
539
540 def mainloop(self, display_banner=None):
541 """Start the mainloop.
542
543 If an optional banner argument is given, it will override the
544 internally created default banner.
545 """
546
547 with self.builtin_trap, self.display_trap:
548
549 while 1:
550 try:
551 self.interact(display_banner=display_banner)
552 #self.interact_with_readline()
553 # XXX for testing of a readline-decoupled repl loop, call
554 # interact_with_readline above
555 break
556 except KeyboardInterrupt:
557 # this should not be necessary, but KeyboardInterrupt
558 # handling seems rather unpredictable...
559 self.write("\nKeyboardInterrupt in interact()\n")
560
561 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
562 """Store multiple lines as a single entry in history"""
563
564 # do nothing without readline or disabled multiline
565 if not self.has_readline or not self.multiline_history:
566 return hlen_before_cell
567
568 # windows rl has no remove_history_item
569 if not hasattr(self.readline, "remove_history_item"):
570 return hlen_before_cell
571
572 # skip empty cells
573 if not source_raw.rstrip():
574 return hlen_before_cell
575
576 # nothing changed do nothing, e.g. when rl removes consecutive dups
577 hlen = self.readline.get_current_history_length()
578 if hlen == hlen_before_cell:
579 return hlen_before_cell
580
581 for i in range(hlen - hlen_before_cell):
582 self.readline.remove_history_item(hlen - i - 1)
583 stdin_encoding = get_stream_enc(sys.stdin, 'utf-8')
584 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
585 stdin_encoding))
586 return self.readline.get_current_history_length()
587
588 def interact(self, display_banner=None):
589 """Closely emulate the interactive Python console."""
590
591 # batch run -> do not interact
592 if self.exit_now:
593 return
594
595 if display_banner is None:
596 display_banner = self.display_banner
597
598 if isinstance(display_banner, py3compat.string_types):
599 self.show_banner(display_banner)
600 elif display_banner:
601 self.show_banner()
602
603 more = False
604
605 if self.has_readline:
606 self.readline_startup_hook(self.pre_readline)
607 hlen_b4_cell = self.readline.get_current_history_length()
608 else:
609 hlen_b4_cell = 0
610 # exit_now is set by a call to %Exit or %Quit, through the
611 # ask_exit callback.
612
613 while not self.exit_now:
614 self.hooks.pre_prompt_hook()
615 if more:
616 try:
617 prompt = ' ...: '
618 except:
619 self.showtraceback()
620 if self.autoindent:
621 self.rl_do_indent = True
622
623 else:
624 try:
625 prompt = self.separate_in + 'In [{}]: '.format(self.execution_count)
626 except:
627 self.showtraceback()
628 try:
629 line = self.raw_input(prompt)
630 if self.exit_now:
631 # quick exit on sys.std[in|out] close
632 break
633 if self.autoindent:
634 self.rl_do_indent = False
635
636 except KeyboardInterrupt:
637 #double-guard against keyboardinterrupts during kbdint handling
638 try:
639 self.write('\n' + self.get_exception_only())
640 source_raw = self.input_splitter.raw_reset()
641 hlen_b4_cell = \
642 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
643 more = False
644 except KeyboardInterrupt:
645 pass
646 except EOFError:
647 if self.autoindent:
648 self.rl_do_indent = False
649 if self.has_readline:
650 self.readline_startup_hook(None)
651 self.write('\n')
652 self.exit()
653 except bdb.BdbQuit:
654 warn('The Python debugger has exited with a BdbQuit exception.\n'
655 'Because of how pdb handles the stack, it is impossible\n'
656 'for IPython to properly format this particular exception.\n'
657 'IPython will resume normal operation.')
658 except:
659 # exceptions here are VERY RARE, but they can be triggered
660 # asynchronously by signal handlers, for example.
661 self.showtraceback()
662 else:
663 try:
664 self.input_splitter.push(line)
665 more = self.input_splitter.push_accepts_more()
666 except SyntaxError:
667 # Run the code directly - run_cell takes care of displaying
668 # the exception.
669 more = False
670 if (self.SyntaxTB.last_syntax_error and
671 self.autoedit_syntax):
672 self.edit_syntax_error()
673 if not more:
674 source_raw = self.input_splitter.raw_reset()
675 self.run_cell(source_raw, store_history=True)
676 hlen_b4_cell = \
677 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
678
679 # Turn off the exit flag, so the mainloop can be restarted if desired
680 self.exit_now = False
681
682 def raw_input(self, prompt=''):
683 """Write a prompt and read a line.
684
685 The returned line does not include the trailing newline.
686 When the user enters the EOF key sequence, EOFError is raised.
687
688 Parameters
689 ----------
690
691 prompt : str, optional
692 A string to be printed to prompt the user.
693 """
694 # raw_input expects str, but we pass it unicode sometimes
695 prompt = py3compat.cast_bytes_py2(prompt)
696
697 try:
698 line = py3compat.cast_unicode_py2(self.raw_input_original(prompt))
699 except ValueError:
700 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
701 " or sys.stdout.close()!\nExiting IPython!\n")
702 self.ask_exit()
703 return ""
704
705 # Try to be reasonably smart about not re-indenting pasted input more
706 # than necessary. We do this by trimming out the auto-indent initial
707 # spaces, if the user's actual input started itself with whitespace.
708 if self.autoindent:
709 if num_ini_spaces(line) > self.indent_current_nsp:
710 line = line[self.indent_current_nsp:]
711 self.indent_current_nsp = 0
712
713 return line
714
715 #-------------------------------------------------------------------------
716 # Methods to support auto-editing of SyntaxErrors.
717 #-------------------------------------------------------------------------
718
719 def edit_syntax_error(self):
720 """The bottom half of the syntax error handler called in the main loop.
721
722 Loop until syntax error is fixed or user cancels.
723 """
724
725 while self.SyntaxTB.last_syntax_error:
726 # copy and clear last_syntax_error
727 err = self.SyntaxTB.clear_err_state()
728 if not self._should_recompile(err):
729 return
730 try:
731 # may set last_syntax_error again if a SyntaxError is raised
732 self.safe_execfile(err.filename,self.user_ns)
733 except:
734 self.showtraceback()
735 else:
736 try:
737 f = open(err.filename)
738 try:
739 # This should be inside a display_trap block and I
740 # think it is.
741 sys.displayhook(f.read())
742 finally:
743 f.close()
744 except:
745 self.showtraceback()
746
747 def _should_recompile(self,e):
748 """Utility routine for edit_syntax_error"""
749
750 if e.filename in ('<ipython console>','<input>','<string>',
751 '<console>','<BackgroundJob compilation>',
752 None):
753
754 return False
755 try:
756 if (self.autoedit_syntax and
757 not self.ask_yes_no('Return to editor to correct syntax error? '
758 '[Y/n] ','y')):
759 return False
760 except EOFError:
761 return False
762
763 def int0(x):
764 try:
765 return int(x)
766 except TypeError:
767 return 0
768 # always pass integer line and offset values to editor hook
769 try:
770 self.hooks.fix_error_editor(e.filename,
771 int0(e.lineno),int0(e.offset),e.msg)
772 except TryNext:
773 warn('Could not open editor')
774 return False
775 return True
776
777 #-------------------------------------------------------------------------
778 # Things related to exiting
779 #-------------------------------------------------------------------------
780
781 def ask_exit(self):
782 """ Ask the shell to exit. Can be overiden and used as a callback. """
783 self.exit_now = True
784
785 def exit(self):
786 """Handle interactive exit.
787
788 This method calls the ask_exit callback."""
789 if self.confirm_exit:
790 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
791 self.ask_exit()
792 else:
793 self.ask_exit()
794
795 #-------------------------------------------------------------------------
796 # Things related to magics
797 #-------------------------------------------------------------------------
798
799 def init_magics(self):
800 super(TerminalInteractiveShell, self).init_magics()
801 self.register_magics(TerminalMagics)
802
803 def showindentationerror(self):
804 super(TerminalInteractiveShell, self).showindentationerror()
805 if not self.using_paste_magics:
806 print("If you want to paste code into IPython, try the "
807 "%paste and %cpaste magic functions.")
808
809
810 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -7,8 +7,8 b' import signal'
7 from warnings import warn
7 from warnings import warn
8
8
9 from IPython.core.error import TryNext
9 from IPython.core.error import TryNext
10 from IPython.core.interactiveshell import InteractiveShell
10 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
11 from IPython.utils.py3compat import cast_unicode_py2, input
11 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
13 from IPython.utils.process import abbrev_cwd
13 from IPython.utils.process import abbrev_cwd
14 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance
14 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance
@@ -27,11 +27,29 b' from pygments.styles import get_style_by_name, get_all_styles'
27 from pygments.token import Token
27 from pygments.token import Token
28
28
29 from .debugger import TerminalPdb, Pdb
29 from .debugger import TerminalPdb, Pdb
30 from .magics import TerminalMagics
30 from .pt_inputhooks import get_inputhook_func
31 from .pt_inputhooks import get_inputhook_func
31 from .interactiveshell import get_default_editor, TerminalMagics
32 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
32 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
33 from .ptutils import IPythonPTCompleter, IPythonPTLexer
33 from .ptutils import IPythonPTCompleter, IPythonPTLexer
34
34
35
36 def get_default_editor():
37 try:
38 ed = os.environ['EDITOR']
39 if not PY3:
40 ed = ed.decode()
41 return ed
42 except KeyError:
43 pass
44 except UnicodeError:
45 warn("$EDITOR environment variable is not pure ASCII. Using platform "
46 "default editor.")
47
48 if os.name == 'posix':
49 return 'vi' # the only one guaranteed to be there!
50 else:
51 return 'notepad' # same in Windows!
52
35 _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty()
53 _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty()
36
54
37 class TerminalInteractiveShell(InteractiveShell):
55 class TerminalInteractiveShell(InteractiveShell):
@@ -466,5 +484,7 b' class TerminalInteractiveShell(InteractiveShell):'
466 self._prompts_before = None
484 self._prompts_before = None
467
485
468
486
487 InteractiveShellABC.register(TerminalInteractiveShell)
488
469 if __name__ == '__main__':
489 if __name__ == '__main__':
470 TerminalInteractiveShell.instance().interact()
490 TerminalInteractiveShell.instance().interact()
@@ -1,10 +1,5 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the TerminalInteractiveShell and related pieces."""
3
4 Authors
5 -------
6 * Julian Taylor
7 """
8 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
4 # Copyright (C) 2011 The IPython Development Team
10 #
5 #
@@ -12,17 +7,10 b' Authors'
12 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
14
9
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18 # stdlib
19 import sys
10 import sys
20 import types
21 import unittest
11 import unittest
22
12
23 from IPython.core.inputtransformer import InputTransformer
13 from IPython.core.inputtransformer import InputTransformer
24 from IPython.testing.decorators import skipif
25 from IPython.utils import py3compat
26 from IPython.testing import tools as tt
14 from IPython.testing import tools as tt
27
15
28 # Decorator for interaction loop tests -----------------------------------------
16 # Decorator for interaction loop tests -----------------------------------------
@@ -38,22 +26,22 b' class mock_input_helper(object):'
38 self.ip = get_ipython()
26 self.ip = get_ipython()
39
27
40 def __enter__(self):
28 def __enter__(self):
41 self.orig_raw_input = self.ip.raw_input
29 self.orig_prompt_for_code = self.ip.prompt_for_code
42 self.ip.raw_input = self.fake_input
30 self.ip.prompt_for_code = self.fake_input
43 return self
31 return self
44
32
45 def __exit__(self, etype, value, tb):
33 def __exit__(self, etype, value, tb):
46 self.ip.raw_input = self.orig_raw_input
34 self.ip.prompt_for_code = self.orig_prompt_for_code
47
35
48 def fake_input(self, prompt):
36 def fake_input(self):
49 try:
37 try:
50 return next(self.testgen)
38 return next(self.testgen)
51 except StopIteration:
39 except StopIteration:
52 self.ip.exit_now = True
40 self.ip.keep_running = False
53 return u''
41 return u''
54 except:
42 except:
55 self.exception = sys.exc_info()
43 self.exception = sys.exc_info()
56 self.ip.exit_now = True
44 self.ip.keep_running = False
57 return u''
45 return u''
58
46
59 def mock_input(testfunc):
47 def mock_input(testfunc):
@@ -65,7 +53,7 b' def mock_input(testfunc):'
65 def test_method(self):
53 def test_method(self):
66 testgen = testfunc(self)
54 testgen = testfunc(self)
67 with mock_input_helper(testgen) as mih:
55 with mock_input_helper(testgen) as mih:
68 mih.ip.interact(display_banner=False)
56 mih.ip.interact()
69
57
70 if mih.exception is not None:
58 if mih.exception is not None:
71 # Re-raise captured exception
59 # Re-raise captured exception
@@ -85,148 +73,6 b' class InteractiveShellTestCase(unittest.TestCase):'
85 return [rl.get_history_item(rl.get_current_history_length() - x)
73 return [rl.get_history_item(rl.get_current_history_length() - x)
86 for x in range(n - 1, -1, -1)]
74 for x in range(n - 1, -1, -1)]
87
75
88 def test_runs_without_rl(self):
89 """Test that function does not throw without readline"""
90 ip = get_ipython()
91 ip.has_readline = False
92 ip.readline = None
93 ip._replace_rlhist_multiline(u'source', 0)
94
95 @skipif(not get_ipython().has_readline, 'no readline')
96 def test_runs_without_remove_history_item(self):
97 """Test that function does not throw on windows without
98 remove_history_item"""
99 ip = get_ipython()
100 if hasattr(ip.readline, 'remove_history_item'):
101 del ip.readline.remove_history_item
102 ip._replace_rlhist_multiline(u'source', 0)
103
104 @skipif(not get_ipython().has_readline, 'no readline')
105 @skipif(not hasattr(get_ipython().readline, 'remove_history_item'),
106 'no remove_history_item')
107 def test_replace_multiline_hist_disabled(self):
108 """Test that multiline replace does nothing if disabled"""
109 ip = get_ipython()
110 ip.multiline_history = False
111
112 ghist = [u'line1', u'line2']
113 for h in ghist:
114 ip.readline.add_history(h)
115 hlen_b4_cell = ip.readline.get_current_history_length()
116 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2',
117 hlen_b4_cell)
118
119 self.assertEqual(ip.readline.get_current_history_length(),
120 hlen_b4_cell)
121 hist = self.rl_hist_entries(ip.readline, 2)
122 self.assertEqual(hist, ghist)
123
124 @skipif(not get_ipython().has_readline, 'no readline')
125 @skipif(not hasattr(get_ipython().readline, 'remove_history_item'),
126 'no remove_history_item')
127 def test_replace_multiline_hist_adds(self):
128 """Test that multiline replace function adds history"""
129 ip = get_ipython()
130
131 hlen_b4_cell = ip.readline.get_current_history_length()
132 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€', hlen_b4_cell)
133
134 self.assertEqual(hlen_b4_cell,
135 ip.readline.get_current_history_length())
136
137 @skipif(not get_ipython().has_readline, 'no readline')
138 @skipif(not hasattr(get_ipython().readline, 'remove_history_item'),
139 'no remove_history_item')
140 def test_replace_multiline_hist_keeps_history(self):
141 """Test that multiline replace does not delete history"""
142 ip = get_ipython()
143 ip.multiline_history = True
144
145 ghist = [u'line1', u'line2']
146 for h in ghist:
147 ip.readline.add_history(h)
148
149 #start cell
150 hlen_b4_cell = ip.readline.get_current_history_length()
151 # nothing added to rl history, should do nothing
152 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2',
153 hlen_b4_cell)
154
155 self.assertEqual(ip.readline.get_current_history_length(),
156 hlen_b4_cell)
157 hist = self.rl_hist_entries(ip.readline, 2)
158 self.assertEqual(hist, ghist)
159
160
161 @skipif(not get_ipython().has_readline, 'no readline')
162 @skipif(not hasattr(get_ipython().readline, 'remove_history_item'),
163 'no remove_history_item')
164 def test_replace_multiline_hist_replaces_twice(self):
165 """Test that multiline entries are replaced twice"""
166 ip = get_ipython()
167 ip.multiline_history = True
168
169 ip.readline.add_history(u'line0')
170 #start cell
171 hlen_b4_cell = ip.readline.get_current_history_length()
172 ip.readline.add_history('l€ne1')
173 ip.readline.add_history('line2')
174 #replace cell with single line
175 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2',
176 hlen_b4_cell)
177 ip.readline.add_history('l€ne3')
178 ip.readline.add_history('line4')
179 #replace cell with single line
180 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3\nline4',
181 hlen_b4_cell)
182
183 self.assertEqual(ip.readline.get_current_history_length(),
184 hlen_b4_cell)
185 hist = self.rl_hist_entries(ip.readline, 3)
186 expected = [u'line0', u'l€ne1\nline2', u'l€ne3\nline4']
187 # perform encoding, in case of casting due to ASCII locale
188 enc = sys.stdin.encoding or "utf-8"
189 expected = [ py3compat.unicode_to_str(e, enc) for e in expected ]
190 self.assertEqual(hist, expected)
191
192
193 @skipif(not get_ipython().has_readline, 'no readline')
194 @skipif(not hasattr(get_ipython().readline, 'remove_history_item'),
195 'no remove_history_item')
196 def test_replace_multiline_hist_replaces_empty_line(self):
197 """Test that multiline history skips empty line cells"""
198 ip = get_ipython()
199 ip.multiline_history = True
200
201 ip.readline.add_history(u'line0')
202 #start cell
203 hlen_b4_cell = ip.readline.get_current_history_length()
204 ip.readline.add_history('l€ne1')
205 ip.readline.add_history('line2')
206 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2',
207 hlen_b4_cell)
208 ip.readline.add_history('')
209 hlen_b4_cell = ip._replace_rlhist_multiline(u'', hlen_b4_cell)
210 ip.readline.add_history('l€ne3')
211 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3', hlen_b4_cell)
212 ip.readline.add_history(' ')
213 hlen_b4_cell = ip._replace_rlhist_multiline(' ', hlen_b4_cell)
214 ip.readline.add_history('\t')
215 ip.readline.add_history('\t ')
216 hlen_b4_cell = ip._replace_rlhist_multiline('\t', hlen_b4_cell)
217 ip.readline.add_history('line4')
218 hlen_b4_cell = ip._replace_rlhist_multiline(u'line4', hlen_b4_cell)
219
220 self.assertEqual(ip.readline.get_current_history_length(),
221 hlen_b4_cell)
222 hist = self.rl_hist_entries(ip.readline, 4)
223 # expect no empty cells in history
224 expected = [u'line0', u'l€ne1\nline2', u'l€ne3', u'line4']
225 # perform encoding, in case of casting due to ASCII locale
226 enc = sys.stdin.encoding or "utf-8"
227 expected = [ py3compat.unicode_to_str(e, enc) for e in expected ]
228 self.assertEqual(hist, expected)
229
230 @mock_input
76 @mock_input
231 def test_inputtransformer_syntaxerror(self):
77 def test_inputtransformer_syntaxerror(self):
232 ip = get_ipython()
78 ip = get_ipython()
@@ -264,23 +110,6 b' class SyntaxErrorTransformer(InputTransformer):'
264 pass
110 pass
265
111
266 class TerminalMagicsTestCase(unittest.TestCase):
112 class TerminalMagicsTestCase(unittest.TestCase):
267 def test_paste_magics_message(self):
268 """Test that an IndentationError while using paste magics doesn't
269 trigger a message about paste magics and also the opposite."""
270
271 ip = get_ipython()
272 s = ('for a in range(5):\n'
273 'print(a)')
274
275 tm = ip.magics_manager.registry['TerminalMagics']
276 with tt.AssertPrints("If you want to paste code into IPython, try the "
277 "%paste and %cpaste magic functions."):
278 ip.run_cell(s)
279
280 with tt.AssertNotPrints("If you want to paste code into IPython, try the "
281 "%paste and %cpaste magic functions."):
282 tm.store_or_execute(s, name=None)
283
284 def test_paste_magics_blankline(self):
113 def test_paste_magics_blankline(self):
285 """Test that code with a blank line doesn't get split (gh-3246)."""
114 """Test that code with a blank line doesn't get split (gh-3246)."""
286 ip = get_ipython()
115 ip = get_ipython()
General Comments 0
You need to be logged in to leave comments. Login now