##// END OF EJS Templates
_replace_rlhist_multiline: check if remove_history_item is available
Julian Taylor -
Show More
@@ -1,627 +1,631 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Subclass of InteractiveShell for terminal based frontends."""
2 """Subclass of InteractiveShell for terminal based frontends."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2010 The IPython Development Team
7 # Copyright (C) 2008-2010 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import __builtin__
17 import __builtin__
18 import bdb
18 import bdb
19 import os
19 import os
20 import re
20 import re
21 import sys
21 import sys
22
22
23 try:
23 try:
24 from contextlib import nested
24 from contextlib import nested
25 except:
25 except:
26 from IPython.utils.nested_context import nested
26 from IPython.utils.nested_context import nested
27
27
28 from IPython.core.error import TryNext
28 from IPython.core.error import TryNext
29 from IPython.core.usage import interactive_usage, default_banner
29 from IPython.core.usage import interactive_usage, default_banner
30 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
30 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
31 from IPython.lib.inputhook import enable_gui
31 from IPython.lib.inputhook import enable_gui
32 from IPython.lib.pylabtools import pylab_activate
32 from IPython.lib.pylabtools import pylab_activate
33 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.testing.skipdoctest import skip_doctest
34 from IPython.utils import py3compat
34 from IPython.utils import py3compat
35 from IPython.utils.terminal import toggle_set_term_title, set_term_title
35 from IPython.utils.terminal import toggle_set_term_title, set_term_title
36 from IPython.utils.process import abbrev_cwd
36 from IPython.utils.process import abbrev_cwd
37 from IPython.utils.warn import warn
37 from IPython.utils.warn import warn
38 from IPython.utils.text import num_ini_spaces
38 from IPython.utils.text import num_ini_spaces
39 from IPython.utils.traitlets import Int, CBool, Unicode
39 from IPython.utils.traitlets import Int, CBool, Unicode
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Utilities
42 # Utilities
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45 def get_default_editor():
45 def get_default_editor():
46 try:
46 try:
47 ed = os.environ['EDITOR']
47 ed = os.environ['EDITOR']
48 except KeyError:
48 except KeyError:
49 if os.name == 'posix':
49 if os.name == 'posix':
50 ed = 'vi' # the only one guaranteed to be there!
50 ed = 'vi' # the only one guaranteed to be there!
51 else:
51 else:
52 ed = 'notepad' # same in Windows!
52 ed = 'notepad' # same in Windows!
53 return ed
53 return ed
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Main class
56 # Main class
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 class TerminalInteractiveShell(InteractiveShell):
59 class TerminalInteractiveShell(InteractiveShell):
60
60
61 autoedit_syntax = CBool(False, config=True,
61 autoedit_syntax = CBool(False, config=True,
62 help="auto editing of files with syntax errors.")
62 help="auto editing of files with syntax errors.")
63 banner = Unicode('')
63 banner = Unicode('')
64 banner1 = Unicode(default_banner, config=True,
64 banner1 = Unicode(default_banner, config=True,
65 help="""The part of the banner to be printed before the profile"""
65 help="""The part of the banner to be printed before the profile"""
66 )
66 )
67 banner2 = Unicode('', config=True,
67 banner2 = Unicode('', config=True,
68 help="""The part of the banner to be printed after the profile"""
68 help="""The part of the banner to be printed after the profile"""
69 )
69 )
70 confirm_exit = CBool(True, config=True,
70 confirm_exit = CBool(True, config=True,
71 help="""
71 help="""
72 Set to confirm when you try to exit IPython with an EOF (Control-D
72 Set to confirm when you try to exit IPython with an EOF (Control-D
73 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
73 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
74 you can force a direct exit without any confirmation.""",
74 you can force a direct exit without any confirmation.""",
75 )
75 )
76 # This display_banner only controls whether or not self.show_banner()
76 # This display_banner only controls whether or not self.show_banner()
77 # is called when mainloop/interact are called. The default is False
77 # is called when mainloop/interact are called. The default is False
78 # because for the terminal based application, the banner behavior
78 # because for the terminal based application, the banner behavior
79 # is controlled by Global.display_banner, which IPythonApp looks at
79 # is controlled by Global.display_banner, which IPythonApp looks at
80 # to determine if *it* should call show_banner() by hand or not.
80 # to determine if *it* should call show_banner() by hand or not.
81 display_banner = CBool(False) # This isn't configurable!
81 display_banner = CBool(False) # This isn't configurable!
82 embedded = CBool(False)
82 embedded = CBool(False)
83 embedded_active = CBool(False)
83 embedded_active = CBool(False)
84 editor = Unicode(get_default_editor(), config=True,
84 editor = Unicode(get_default_editor(), config=True,
85 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
85 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
86 )
86 )
87 pager = Unicode('less', config=True,
87 pager = Unicode('less', config=True,
88 help="The shell program to be used for paging.")
88 help="The shell program to be used for paging.")
89
89
90 screen_length = Int(0, config=True,
90 screen_length = Int(0, config=True,
91 help=
91 help=
92 """Number of lines of your screen, used to control printing of very
92 """Number of lines of your screen, used to control printing of very
93 long strings. Strings longer than this number of lines will be sent
93 long strings. Strings longer than this number of lines will be sent
94 through a pager instead of directly printed. The default value for
94 through a pager instead of directly printed. The default value for
95 this is 0, which means IPython will auto-detect your screen size every
95 this is 0, which means IPython will auto-detect your screen size every
96 time it needs to print certain potentially long strings (this doesn't
96 time it needs to print certain potentially long strings (this doesn't
97 change the behavior of the 'print' keyword, it's only triggered
97 change the behavior of the 'print' keyword, it's only triggered
98 internally). If for some reason this isn't working well (it needs
98 internally). If for some reason this isn't working well (it needs
99 curses support), specify it yourself. Otherwise don't change the
99 curses support), specify it yourself. Otherwise don't change the
100 default.""",
100 default.""",
101 )
101 )
102 term_title = CBool(False, config=True,
102 term_title = CBool(False, config=True,
103 help="Enable auto setting the terminal title."
103 help="Enable auto setting the terminal title."
104 )
104 )
105
105
106 def __init__(self, config=None, ipython_dir=None, profile_dir=None, user_ns=None,
106 def __init__(self, config=None, ipython_dir=None, profile_dir=None, user_ns=None,
107 user_global_ns=None, custom_exceptions=((),None),
107 user_global_ns=None, custom_exceptions=((),None),
108 usage=None, banner1=None, banner2=None,
108 usage=None, banner1=None, banner2=None,
109 display_banner=None):
109 display_banner=None):
110
110
111 super(TerminalInteractiveShell, self).__init__(
111 super(TerminalInteractiveShell, self).__init__(
112 config=config, profile_dir=profile_dir, user_ns=user_ns,
112 config=config, profile_dir=profile_dir, user_ns=user_ns,
113 user_global_ns=user_global_ns, custom_exceptions=custom_exceptions
113 user_global_ns=user_global_ns, custom_exceptions=custom_exceptions
114 )
114 )
115 # use os.system instead of utils.process.system by default, except on Windows
115 # use os.system instead of utils.process.system by default, except on Windows
116 if os.name == 'nt':
116 if os.name == 'nt':
117 self.system = self.system_piped
117 self.system = self.system_piped
118 else:
118 else:
119 self.system = self.system_raw
119 self.system = self.system_raw
120
120
121 self.init_term_title()
121 self.init_term_title()
122 self.init_usage(usage)
122 self.init_usage(usage)
123 self.init_banner(banner1, banner2, display_banner)
123 self.init_banner(banner1, banner2, display_banner)
124
124
125 #-------------------------------------------------------------------------
125 #-------------------------------------------------------------------------
126 # Things related to the terminal
126 # Things related to the terminal
127 #-------------------------------------------------------------------------
127 #-------------------------------------------------------------------------
128
128
129 @property
129 @property
130 def usable_screen_length(self):
130 def usable_screen_length(self):
131 if self.screen_length == 0:
131 if self.screen_length == 0:
132 return 0
132 return 0
133 else:
133 else:
134 num_lines_bot = self.separate_in.count('\n')+1
134 num_lines_bot = self.separate_in.count('\n')+1
135 return self.screen_length - num_lines_bot
135 return self.screen_length - num_lines_bot
136
136
137 def init_term_title(self):
137 def init_term_title(self):
138 # Enable or disable the terminal title.
138 # Enable or disable the terminal title.
139 if self.term_title:
139 if self.term_title:
140 toggle_set_term_title(True)
140 toggle_set_term_title(True)
141 set_term_title('IPython: ' + abbrev_cwd())
141 set_term_title('IPython: ' + abbrev_cwd())
142 else:
142 else:
143 toggle_set_term_title(False)
143 toggle_set_term_title(False)
144
144
145 #-------------------------------------------------------------------------
145 #-------------------------------------------------------------------------
146 # Things related to aliases
146 # Things related to aliases
147 #-------------------------------------------------------------------------
147 #-------------------------------------------------------------------------
148
148
149 def init_alias(self):
149 def init_alias(self):
150 # The parent class defines aliases that can be safely used with any
150 # The parent class defines aliases that can be safely used with any
151 # frontend.
151 # frontend.
152 super(TerminalInteractiveShell, self).init_alias()
152 super(TerminalInteractiveShell, self).init_alias()
153
153
154 # Now define aliases that only make sense on the terminal, because they
154 # Now define aliases that only make sense on the terminal, because they
155 # need direct access to the console in a way that we can't emulate in
155 # need direct access to the console in a way that we can't emulate in
156 # GUI or web frontend
156 # GUI or web frontend
157 if os.name == 'posix':
157 if os.name == 'posix':
158 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
158 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
159 ('man', 'man')]
159 ('man', 'man')]
160 elif os.name == 'nt':
160 elif os.name == 'nt':
161 aliases = [('cls', 'cls')]
161 aliases = [('cls', 'cls')]
162
162
163
163
164 for name, cmd in aliases:
164 for name, cmd in aliases:
165 self.alias_manager.define_alias(name, cmd)
165 self.alias_manager.define_alias(name, cmd)
166
166
167 #-------------------------------------------------------------------------
167 #-------------------------------------------------------------------------
168 # Things related to the banner and usage
168 # Things related to the banner and usage
169 #-------------------------------------------------------------------------
169 #-------------------------------------------------------------------------
170
170
171 def _banner1_changed(self):
171 def _banner1_changed(self):
172 self.compute_banner()
172 self.compute_banner()
173
173
174 def _banner2_changed(self):
174 def _banner2_changed(self):
175 self.compute_banner()
175 self.compute_banner()
176
176
177 def _term_title_changed(self, name, new_value):
177 def _term_title_changed(self, name, new_value):
178 self.init_term_title()
178 self.init_term_title()
179
179
180 def init_banner(self, banner1, banner2, display_banner):
180 def init_banner(self, banner1, banner2, display_banner):
181 if banner1 is not None:
181 if banner1 is not None:
182 self.banner1 = banner1
182 self.banner1 = banner1
183 if banner2 is not None:
183 if banner2 is not None:
184 self.banner2 = banner2
184 self.banner2 = banner2
185 if display_banner is not None:
185 if display_banner is not None:
186 self.display_banner = display_banner
186 self.display_banner = display_banner
187 self.compute_banner()
187 self.compute_banner()
188
188
189 def show_banner(self, banner=None):
189 def show_banner(self, banner=None):
190 if banner is None:
190 if banner is None:
191 banner = self.banner
191 banner = self.banner
192 self.write(banner)
192 self.write(banner)
193
193
194 def compute_banner(self):
194 def compute_banner(self):
195 self.banner = self.banner1
195 self.banner = self.banner1
196 if self.profile and self.profile != 'default':
196 if self.profile and self.profile != 'default':
197 self.banner += '\nIPython profile: %s\n' % self.profile
197 self.banner += '\nIPython profile: %s\n' % self.profile
198 if self.banner2:
198 if self.banner2:
199 self.banner += '\n' + self.banner2
199 self.banner += '\n' + self.banner2
200
200
201 def init_usage(self, usage=None):
201 def init_usage(self, usage=None):
202 if usage is None:
202 if usage is None:
203 self.usage = interactive_usage
203 self.usage = interactive_usage
204 else:
204 else:
205 self.usage = usage
205 self.usage = usage
206
206
207 #-------------------------------------------------------------------------
207 #-------------------------------------------------------------------------
208 # Mainloop and code execution logic
208 # Mainloop and code execution logic
209 #-------------------------------------------------------------------------
209 #-------------------------------------------------------------------------
210
210
211 def mainloop(self, display_banner=None):
211 def mainloop(self, display_banner=None):
212 """Start the mainloop.
212 """Start the mainloop.
213
213
214 If an optional banner argument is given, it will override the
214 If an optional banner argument is given, it will override the
215 internally created default banner.
215 internally created default banner.
216 """
216 """
217
217
218 with nested(self.builtin_trap, self.display_trap):
218 with nested(self.builtin_trap, self.display_trap):
219
219
220 while 1:
220 while 1:
221 try:
221 try:
222 self.interact(display_banner=display_banner)
222 self.interact(display_banner=display_banner)
223 #self.interact_with_readline()
223 #self.interact_with_readline()
224 # XXX for testing of a readline-decoupled repl loop, call
224 # XXX for testing of a readline-decoupled repl loop, call
225 # interact_with_readline above
225 # interact_with_readline above
226 break
226 break
227 except KeyboardInterrupt:
227 except KeyboardInterrupt:
228 # this should not be necessary, but KeyboardInterrupt
228 # this should not be necessary, but KeyboardInterrupt
229 # handling seems rather unpredictable...
229 # handling seems rather unpredictable...
230 self.write("\nKeyboardInterrupt in interact()\n")
230 self.write("\nKeyboardInterrupt in interact()\n")
231
231
232 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
232 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
233 """Store multiple lines as a single entry in history"""
233 """Store multiple lines as a single entry in history"""
234
234
235 # do nothing without readline or disabled multiline
235 # do nothing without readline or disabled multiline
236 if not self.has_readline or not self.multiline_history:
236 if not self.has_readline or not self.multiline_history:
237 return hlen_before_cell
237 return hlen_before_cell
238
238
239 # windows rl has no remove_history_item
240 if not hasattr(self.readline, "remove_history_item"):
241 return hlen_before_cell
242
239 # skip empty cells
243 # skip empty cells
240 if not source_raw.rstrip():
244 if not source_raw.rstrip():
241 return hlen_before_cell
245 return hlen_before_cell
242
246
243 # nothing changed do nothing, e.g. when rl removes consecutive dups
247 # nothing changed do nothing, e.g. when rl removes consecutive dups
244 hlen = self.readline.get_current_history_length()
248 hlen = self.readline.get_current_history_length()
245 if hlen == hlen_before_cell:
249 if hlen == hlen_before_cell:
246 return hlen_before_cell
250 return hlen_before_cell
247
251
248 for i in range(hlen - hlen_before_cell):
252 for i in range(hlen - hlen_before_cell):
249 self.readline.remove_history_item(hlen - i - 1)
253 self.readline.remove_history_item(hlen - i - 1)
250 stdin_encoding = sys.stdin.encoding or "utf-8"
254 stdin_encoding = sys.stdin.encoding or "utf-8"
251 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
255 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
252 stdin_encoding))
256 stdin_encoding))
253 return self.readline.get_current_history_length()
257 return self.readline.get_current_history_length()
254
258
255 def interact(self, display_banner=None):
259 def interact(self, display_banner=None):
256 """Closely emulate the interactive Python console."""
260 """Closely emulate the interactive Python console."""
257
261
258 # batch run -> do not interact
262 # batch run -> do not interact
259 if self.exit_now:
263 if self.exit_now:
260 return
264 return
261
265
262 if display_banner is None:
266 if display_banner is None:
263 display_banner = self.display_banner
267 display_banner = self.display_banner
264
268
265 if isinstance(display_banner, basestring):
269 if isinstance(display_banner, basestring):
266 self.show_banner(display_banner)
270 self.show_banner(display_banner)
267 elif display_banner:
271 elif display_banner:
268 self.show_banner()
272 self.show_banner()
269
273
270 more = False
274 more = False
271
275
272 # Mark activity in the builtins
276 # Mark activity in the builtins
273 __builtin__.__dict__['__IPYTHON__active'] += 1
277 __builtin__.__dict__['__IPYTHON__active'] += 1
274
278
275 if self.has_readline:
279 if self.has_readline:
276 self.readline_startup_hook(self.pre_readline)
280 self.readline_startup_hook(self.pre_readline)
277 hlen_b4_cell = self.readline.get_current_history_length()
281 hlen_b4_cell = self.readline.get_current_history_length()
278 else:
282 else:
279 hlen_b4_cell = 0
283 hlen_b4_cell = 0
280 # exit_now is set by a call to %Exit or %Quit, through the
284 # exit_now is set by a call to %Exit or %Quit, through the
281 # ask_exit callback.
285 # ask_exit callback.
282
286
283 while not self.exit_now:
287 while not self.exit_now:
284 self.hooks.pre_prompt_hook()
288 self.hooks.pre_prompt_hook()
285 if more:
289 if more:
286 try:
290 try:
287 prompt = self.hooks.generate_prompt(True)
291 prompt = self.hooks.generate_prompt(True)
288 except:
292 except:
289 self.showtraceback()
293 self.showtraceback()
290 if self.autoindent:
294 if self.autoindent:
291 self.rl_do_indent = True
295 self.rl_do_indent = True
292
296
293 else:
297 else:
294 try:
298 try:
295 prompt = self.hooks.generate_prompt(False)
299 prompt = self.hooks.generate_prompt(False)
296 except:
300 except:
297 self.showtraceback()
301 self.showtraceback()
298 try:
302 try:
299 line = self.raw_input(prompt)
303 line = self.raw_input(prompt)
300 if self.exit_now:
304 if self.exit_now:
301 # quick exit on sys.std[in|out] close
305 # quick exit on sys.std[in|out] close
302 break
306 break
303 if self.autoindent:
307 if self.autoindent:
304 self.rl_do_indent = False
308 self.rl_do_indent = False
305
309
306 except KeyboardInterrupt:
310 except KeyboardInterrupt:
307 #double-guard against keyboardinterrupts during kbdint handling
311 #double-guard against keyboardinterrupts during kbdint handling
308 try:
312 try:
309 self.write('\nKeyboardInterrupt\n')
313 self.write('\nKeyboardInterrupt\n')
310 source_raw = self.input_splitter.source_raw_reset()[1]
314 source_raw = self.input_splitter.source_raw_reset()[1]
311 hlen_b4_cell = \
315 hlen_b4_cell = \
312 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
316 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
313 more = False
317 more = False
314 except KeyboardInterrupt:
318 except KeyboardInterrupt:
315 pass
319 pass
316 except EOFError:
320 except EOFError:
317 if self.autoindent:
321 if self.autoindent:
318 self.rl_do_indent = False
322 self.rl_do_indent = False
319 if self.has_readline:
323 if self.has_readline:
320 self.readline_startup_hook(None)
324 self.readline_startup_hook(None)
321 self.write('\n')
325 self.write('\n')
322 self.exit()
326 self.exit()
323 except bdb.BdbQuit:
327 except bdb.BdbQuit:
324 warn('The Python debugger has exited with a BdbQuit exception.\n'
328 warn('The Python debugger has exited with a BdbQuit exception.\n'
325 'Because of how pdb handles the stack, it is impossible\n'
329 'Because of how pdb handles the stack, it is impossible\n'
326 'for IPython to properly format this particular exception.\n'
330 'for IPython to properly format this particular exception.\n'
327 'IPython will resume normal operation.')
331 'IPython will resume normal operation.')
328 except:
332 except:
329 # exceptions here are VERY RARE, but they can be triggered
333 # exceptions here are VERY RARE, but they can be triggered
330 # asynchronously by signal handlers, for example.
334 # asynchronously by signal handlers, for example.
331 self.showtraceback()
335 self.showtraceback()
332 else:
336 else:
333 self.input_splitter.push(line)
337 self.input_splitter.push(line)
334 more = self.input_splitter.push_accepts_more()
338 more = self.input_splitter.push_accepts_more()
335 if (self.SyntaxTB.last_syntax_error and
339 if (self.SyntaxTB.last_syntax_error and
336 self.autoedit_syntax):
340 self.autoedit_syntax):
337 self.edit_syntax_error()
341 self.edit_syntax_error()
338 if not more:
342 if not more:
339 source_raw = self.input_splitter.source_raw_reset()[1]
343 source_raw = self.input_splitter.source_raw_reset()[1]
340 self.run_cell(source_raw, store_history=True)
344 self.run_cell(source_raw, store_history=True)
341 hlen_b4_cell = \
345 hlen_b4_cell = \
342 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
346 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
343
347
344 # We are off again...
348 # We are off again...
345 __builtin__.__dict__['__IPYTHON__active'] -= 1
349 __builtin__.__dict__['__IPYTHON__active'] -= 1
346
350
347 # Turn off the exit flag, so the mainloop can be restarted if desired
351 # Turn off the exit flag, so the mainloop can be restarted if desired
348 self.exit_now = False
352 self.exit_now = False
349
353
350 def raw_input(self, prompt=''):
354 def raw_input(self, prompt=''):
351 """Write a prompt and read a line.
355 """Write a prompt and read a line.
352
356
353 The returned line does not include the trailing newline.
357 The returned line does not include the trailing newline.
354 When the user enters the EOF key sequence, EOFError is raised.
358 When the user enters the EOF key sequence, EOFError is raised.
355
359
356 Optional inputs:
360 Optional inputs:
357
361
358 - prompt(''): a string to be printed to prompt the user.
362 - prompt(''): a string to be printed to prompt the user.
359
363
360 - continue_prompt(False): whether this line is the first one or a
364 - continue_prompt(False): whether this line is the first one or a
361 continuation in a sequence of inputs.
365 continuation in a sequence of inputs.
362 """
366 """
363 # Code run by the user may have modified the readline completer state.
367 # Code run by the user may have modified the readline completer state.
364 # We must ensure that our completer is back in place.
368 # We must ensure that our completer is back in place.
365
369
366 if self.has_readline:
370 if self.has_readline:
367 self.set_readline_completer()
371 self.set_readline_completer()
368
372
369 try:
373 try:
370 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
374 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
371 except ValueError:
375 except ValueError:
372 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
376 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
373 " or sys.stdout.close()!\nExiting IPython!")
377 " or sys.stdout.close()!\nExiting IPython!")
374 self.ask_exit()
378 self.ask_exit()
375 return ""
379 return ""
376
380
377 # Try to be reasonably smart about not re-indenting pasted input more
381 # Try to be reasonably smart about not re-indenting pasted input more
378 # than necessary. We do this by trimming out the auto-indent initial
382 # than necessary. We do this by trimming out the auto-indent initial
379 # spaces, if the user's actual input started itself with whitespace.
383 # spaces, if the user's actual input started itself with whitespace.
380 if self.autoindent:
384 if self.autoindent:
381 if num_ini_spaces(line) > self.indent_current_nsp:
385 if num_ini_spaces(line) > self.indent_current_nsp:
382 line = line[self.indent_current_nsp:]
386 line = line[self.indent_current_nsp:]
383 self.indent_current_nsp = 0
387 self.indent_current_nsp = 0
384
388
385 return line
389 return line
386
390
387 #-------------------------------------------------------------------------
391 #-------------------------------------------------------------------------
388 # Methods to support auto-editing of SyntaxErrors.
392 # Methods to support auto-editing of SyntaxErrors.
389 #-------------------------------------------------------------------------
393 #-------------------------------------------------------------------------
390
394
391 def edit_syntax_error(self):
395 def edit_syntax_error(self):
392 """The bottom half of the syntax error handler called in the main loop.
396 """The bottom half of the syntax error handler called in the main loop.
393
397
394 Loop until syntax error is fixed or user cancels.
398 Loop until syntax error is fixed or user cancels.
395 """
399 """
396
400
397 while self.SyntaxTB.last_syntax_error:
401 while self.SyntaxTB.last_syntax_error:
398 # copy and clear last_syntax_error
402 # copy and clear last_syntax_error
399 err = self.SyntaxTB.clear_err_state()
403 err = self.SyntaxTB.clear_err_state()
400 if not self._should_recompile(err):
404 if not self._should_recompile(err):
401 return
405 return
402 try:
406 try:
403 # may set last_syntax_error again if a SyntaxError is raised
407 # may set last_syntax_error again if a SyntaxError is raised
404 self.safe_execfile(err.filename,self.user_ns)
408 self.safe_execfile(err.filename,self.user_ns)
405 except:
409 except:
406 self.showtraceback()
410 self.showtraceback()
407 else:
411 else:
408 try:
412 try:
409 f = file(err.filename)
413 f = file(err.filename)
410 try:
414 try:
411 # This should be inside a display_trap block and I
415 # This should be inside a display_trap block and I
412 # think it is.
416 # think it is.
413 sys.displayhook(f.read())
417 sys.displayhook(f.read())
414 finally:
418 finally:
415 f.close()
419 f.close()
416 except:
420 except:
417 self.showtraceback()
421 self.showtraceback()
418
422
419 def _should_recompile(self,e):
423 def _should_recompile(self,e):
420 """Utility routine for edit_syntax_error"""
424 """Utility routine for edit_syntax_error"""
421
425
422 if e.filename in ('<ipython console>','<input>','<string>',
426 if e.filename in ('<ipython console>','<input>','<string>',
423 '<console>','<BackgroundJob compilation>',
427 '<console>','<BackgroundJob compilation>',
424 None):
428 None):
425
429
426 return False
430 return False
427 try:
431 try:
428 if (self.autoedit_syntax and
432 if (self.autoedit_syntax and
429 not self.ask_yes_no('Return to editor to correct syntax error? '
433 not self.ask_yes_no('Return to editor to correct syntax error? '
430 '[Y/n] ','y')):
434 '[Y/n] ','y')):
431 return False
435 return False
432 except EOFError:
436 except EOFError:
433 return False
437 return False
434
438
435 def int0(x):
439 def int0(x):
436 try:
440 try:
437 return int(x)
441 return int(x)
438 except TypeError:
442 except TypeError:
439 return 0
443 return 0
440 # always pass integer line and offset values to editor hook
444 # always pass integer line and offset values to editor hook
441 try:
445 try:
442 self.hooks.fix_error_editor(e.filename,
446 self.hooks.fix_error_editor(e.filename,
443 int0(e.lineno),int0(e.offset),e.msg)
447 int0(e.lineno),int0(e.offset),e.msg)
444 except TryNext:
448 except TryNext:
445 warn('Could not open editor')
449 warn('Could not open editor')
446 return False
450 return False
447 return True
451 return True
448
452
449 #-------------------------------------------------------------------------
453 #-------------------------------------------------------------------------
450 # Things related to GUI support and pylab
454 # Things related to GUI support and pylab
451 #-------------------------------------------------------------------------
455 #-------------------------------------------------------------------------
452
456
453 def enable_pylab(self, gui=None, import_all=True):
457 def enable_pylab(self, gui=None, import_all=True):
454 """Activate pylab support at runtime.
458 """Activate pylab support at runtime.
455
459
456 This turns on support for matplotlib, preloads into the interactive
460 This turns on support for matplotlib, preloads into the interactive
457 namespace all of numpy and pylab, and configures IPython to correcdtly
461 namespace all of numpy and pylab, and configures IPython to correcdtly
458 interact with the GUI event loop. The GUI backend to be used can be
462 interact with the GUI event loop. The GUI backend to be used can be
459 optionally selected with the optional :param:`gui` argument.
463 optionally selected with the optional :param:`gui` argument.
460
464
461 Parameters
465 Parameters
462 ----------
466 ----------
463 gui : optional, string
467 gui : optional, string
464
468
465 If given, dictates the choice of matplotlib GUI backend to use
469 If given, dictates the choice of matplotlib GUI backend to use
466 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
470 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
467 'gtk'), otherwise we use the default chosen by matplotlib (as
471 'gtk'), otherwise we use the default chosen by matplotlib (as
468 dictated by the matplotlib build-time options plus the user's
472 dictated by the matplotlib build-time options plus the user's
469 matplotlibrc configuration file).
473 matplotlibrc configuration file).
470 """
474 """
471 # We want to prevent the loading of pylab to pollute the user's
475 # We want to prevent the loading of pylab to pollute the user's
472 # namespace as shown by the %who* magics, so we execute the activation
476 # namespace as shown by the %who* magics, so we execute the activation
473 # code in an empty namespace, and we update *both* user_ns and
477 # code in an empty namespace, and we update *both* user_ns and
474 # user_ns_hidden with this information.
478 # user_ns_hidden with this information.
475 ns = {}
479 ns = {}
476 gui = pylab_activate(ns, gui, import_all)
480 gui = pylab_activate(ns, gui, import_all)
477 self.user_ns.update(ns)
481 self.user_ns.update(ns)
478 self.user_ns_hidden.update(ns)
482 self.user_ns_hidden.update(ns)
479 # Now we must activate the gui pylab wants to use, and fix %run to take
483 # Now we must activate the gui pylab wants to use, and fix %run to take
480 # plot updates into account
484 # plot updates into account
481 enable_gui(gui)
485 enable_gui(gui)
482 self.magic_run = self._pylab_magic_run
486 self.magic_run = self._pylab_magic_run
483
487
484 #-------------------------------------------------------------------------
488 #-------------------------------------------------------------------------
485 # Things related to exiting
489 # Things related to exiting
486 #-------------------------------------------------------------------------
490 #-------------------------------------------------------------------------
487
491
488 def ask_exit(self):
492 def ask_exit(self):
489 """ Ask the shell to exit. Can be overiden and used as a callback. """
493 """ Ask the shell to exit. Can be overiden and used as a callback. """
490 self.exit_now = True
494 self.exit_now = True
491
495
492 def exit(self):
496 def exit(self):
493 """Handle interactive exit.
497 """Handle interactive exit.
494
498
495 This method calls the ask_exit callback."""
499 This method calls the ask_exit callback."""
496 if self.confirm_exit:
500 if self.confirm_exit:
497 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
501 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
498 self.ask_exit()
502 self.ask_exit()
499 else:
503 else:
500 self.ask_exit()
504 self.ask_exit()
501
505
502 #------------------------------------------------------------------------
506 #------------------------------------------------------------------------
503 # Magic overrides
507 # Magic overrides
504 #------------------------------------------------------------------------
508 #------------------------------------------------------------------------
505 # Once the base class stops inheriting from magic, this code needs to be
509 # Once the base class stops inheriting from magic, this code needs to be
506 # moved into a separate machinery as well. For now, at least isolate here
510 # moved into a separate machinery as well. For now, at least isolate here
507 # the magics which this class needs to implement differently from the base
511 # the magics which this class needs to implement differently from the base
508 # class, or that are unique to it.
512 # class, or that are unique to it.
509
513
510 def magic_autoindent(self, parameter_s = ''):
514 def magic_autoindent(self, parameter_s = ''):
511 """Toggle autoindent on/off (if available)."""
515 """Toggle autoindent on/off (if available)."""
512
516
513 self.shell.set_autoindent()
517 self.shell.set_autoindent()
514 print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent]
518 print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent]
515
519
516 @skip_doctest
520 @skip_doctest
517 def magic_cpaste(self, parameter_s=''):
521 def magic_cpaste(self, parameter_s=''):
518 """Paste & execute a pre-formatted code block from clipboard.
522 """Paste & execute a pre-formatted code block from clipboard.
519
523
520 You must terminate the block with '--' (two minus-signs) or Ctrl-D alone on the
524 You must terminate the block with '--' (two minus-signs) or Ctrl-D alone on the
521 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
525 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
522 is the new sentinel for this operation)
526 is the new sentinel for this operation)
523
527
524 The block is dedented prior to execution to enable execution of method
528 The block is dedented prior to execution to enable execution of method
525 definitions. '>' and '+' characters at the beginning of a line are
529 definitions. '>' and '+' characters at the beginning of a line are
526 ignored, to allow pasting directly from e-mails, diff files and
530 ignored, to allow pasting directly from e-mails, diff files and
527 doctests (the '...' continuation prompt is also stripped). The
531 doctests (the '...' continuation prompt is also stripped). The
528 executed block is also assigned to variable named 'pasted_block' for
532 executed block is also assigned to variable named 'pasted_block' for
529 later editing with '%edit pasted_block'.
533 later editing with '%edit pasted_block'.
530
534
531 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
535 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
532 This assigns the pasted block to variable 'foo' as string, without
536 This assigns the pasted block to variable 'foo' as string, without
533 dedenting or executing it (preceding >>> and + is still stripped)
537 dedenting or executing it (preceding >>> and + is still stripped)
534
538
535 '%cpaste -r' re-executes the block previously entered by cpaste.
539 '%cpaste -r' re-executes the block previously entered by cpaste.
536
540
537 Do not be alarmed by garbled output on Windows (it's a readline bug).
541 Do not be alarmed by garbled output on Windows (it's a readline bug).
538 Just press enter and type -- (and press enter again) and the block
542 Just press enter and type -- (and press enter again) and the block
539 will be what was just pasted.
543 will be what was just pasted.
540
544
541 IPython statements (magics, shell escapes) are not supported (yet).
545 IPython statements (magics, shell escapes) are not supported (yet).
542
546
543 See also
547 See also
544 --------
548 --------
545 paste: automatically pull code from clipboard.
549 paste: automatically pull code from clipboard.
546
550
547 Examples
551 Examples
548 --------
552 --------
549 ::
553 ::
550
554
551 In [8]: %cpaste
555 In [8]: %cpaste
552 Pasting code; enter '--' alone on the line to stop.
556 Pasting code; enter '--' alone on the line to stop.
553 :>>> a = ["world!", "Hello"]
557 :>>> a = ["world!", "Hello"]
554 :>>> print " ".join(sorted(a))
558 :>>> print " ".join(sorted(a))
555 :--
559 :--
556 Hello world!
560 Hello world!
557 """
561 """
558
562
559 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
563 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
560 par = args.strip()
564 par = args.strip()
561 if opts.has_key('r'):
565 if opts.has_key('r'):
562 self._rerun_pasted()
566 self._rerun_pasted()
563 return
567 return
564
568
565 sentinel = opts.get('s','--')
569 sentinel = opts.get('s','--')
566
570
567 block = self._strip_pasted_lines_for_code(
571 block = self._strip_pasted_lines_for_code(
568 self._get_pasted_lines(sentinel))
572 self._get_pasted_lines(sentinel))
569
573
570 self._execute_block(block, par)
574 self._execute_block(block, par)
571
575
572 def magic_paste(self, parameter_s=''):
576 def magic_paste(self, parameter_s=''):
573 """Paste & execute a pre-formatted code block from clipboard.
577 """Paste & execute a pre-formatted code block from clipboard.
574
578
575 The text is pulled directly from the clipboard without user
579 The text is pulled directly from the clipboard without user
576 intervention and printed back on the screen before execution (unless
580 intervention and printed back on the screen before execution (unless
577 the -q flag is given to force quiet mode).
581 the -q flag is given to force quiet mode).
578
582
579 The block is dedented prior to execution to enable execution of method
583 The block is dedented prior to execution to enable execution of method
580 definitions. '>' and '+' characters at the beginning of a line are
584 definitions. '>' and '+' characters at the beginning of a line are
581 ignored, to allow pasting directly from e-mails, diff files and
585 ignored, to allow pasting directly from e-mails, diff files and
582 doctests (the '...' continuation prompt is also stripped). The
586 doctests (the '...' continuation prompt is also stripped). The
583 executed block is also assigned to variable named 'pasted_block' for
587 executed block is also assigned to variable named 'pasted_block' for
584 later editing with '%edit pasted_block'.
588 later editing with '%edit pasted_block'.
585
589
586 You can also pass a variable name as an argument, e.g. '%paste foo'.
590 You can also pass a variable name as an argument, e.g. '%paste foo'.
587 This assigns the pasted block to variable 'foo' as string, without
591 This assigns the pasted block to variable 'foo' as string, without
588 dedenting or executing it (preceding >>> and + is still stripped)
592 dedenting or executing it (preceding >>> and + is still stripped)
589
593
590 Options
594 Options
591 -------
595 -------
592
596
593 -r: re-executes the block previously entered by cpaste.
597 -r: re-executes the block previously entered by cpaste.
594
598
595 -q: quiet mode: do not echo the pasted text back to the terminal.
599 -q: quiet mode: do not echo the pasted text back to the terminal.
596
600
597 IPython statements (magics, shell escapes) are not supported (yet).
601 IPython statements (magics, shell escapes) are not supported (yet).
598
602
599 See also
603 See also
600 --------
604 --------
601 cpaste: manually paste code into terminal until you mark its end.
605 cpaste: manually paste code into terminal until you mark its end.
602 """
606 """
603 opts,args = self.parse_options(parameter_s,'rq',mode='string')
607 opts,args = self.parse_options(parameter_s,'rq',mode='string')
604 par = args.strip()
608 par = args.strip()
605 if opts.has_key('r'):
609 if opts.has_key('r'):
606 self._rerun_pasted()
610 self._rerun_pasted()
607 return
611 return
608
612
609 text = self.shell.hooks.clipboard_get()
613 text = self.shell.hooks.clipboard_get()
610 block = self._strip_pasted_lines_for_code(text.splitlines())
614 block = self._strip_pasted_lines_for_code(text.splitlines())
611
615
612 # By default, echo back to terminal unless quiet mode is requested
616 # By default, echo back to terminal unless quiet mode is requested
613 if not opts.has_key('q'):
617 if not opts.has_key('q'):
614 write = self.shell.write
618 write = self.shell.write
615 write(self.shell.pycolorize(block))
619 write(self.shell.pycolorize(block))
616 if not block.endswith('\n'):
620 if not block.endswith('\n'):
617 write('\n')
621 write('\n')
618 write("## -- End pasted text --\n")
622 write("## -- End pasted text --\n")
619
623
620 self._execute_block(block, par)
624 self._execute_block(block, par)
621
625
622 def showindentationerror(self):
626 def showindentationerror(self):
623 super(TerminalInteractiveShell, self).showindentationerror()
627 super(TerminalInteractiveShell, self).showindentationerror()
624 print("If you want to paste code into IPython, try the %paste magic function.")
628 print("If you want to paste code into IPython, try the %paste magic function.")
625
629
626
630
627 InteractiveShellABC.register(TerminalInteractiveShell)
631 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -1,142 +1,150 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Authors
4 Authors
5 -------
5 -------
6 * Julian Taylor
6 * Julian Taylor
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # stdlib
18 # stdlib
19 import unittest
19 import unittest
20
20
21 from IPython.testing.decorators import skipif
21 from IPython.testing.decorators import skipif
22
22
23 class InteractiveShellTestCase(unittest.TestCase):
23 class InteractiveShellTestCase(unittest.TestCase):
24 def rl_hist_entries(self, rl, n):
24 def rl_hist_entries(self, rl, n):
25 """Get last n readline history entries as a list"""
25 """Get last n readline history entries as a list"""
26 return [rl.get_history_item(rl.get_current_history_length() - x)
26 return [rl.get_history_item(rl.get_current_history_length() - x)
27 for x in range(n - 1, -1, -1)]
27 for x in range(n - 1, -1, -1)]
28
28
29 def test_runs_without_rl(self):
29 def test_runs_without_rl(self):
30 """Test that function does not throw without readline"""
30 """Test that function does not throw without readline"""
31 ip = get_ipython()
31 ip = get_ipython()
32 ip.has_readline = False
32 ip.has_readline = False
33 ip.readline = None
33 ip.readline = None
34 ip._replace_rlhist_multiline(u'source', 0)
34 ip._replace_rlhist_multiline(u'source', 0)
35
35
36 @skipif(not get_ipython().has_readline, 'no readline')
36 @skipif(not get_ipython().has_readline, 'no readline')
37 def test_runs_without_remove_history_item(self):
38 """Test that function does not throw on windows without
39 remove_history_item"""
40 ip = get_ipython()
41 del ip.readline.remove_history_item
42 ip._replace_rlhist_multiline(u'source', 0)
43
44 @skipif(not get_ipython().has_readline, 'no readline')
37 def test_replace_multiline_hist_disabled(self):
45 def test_replace_multiline_hist_disabled(self):
38 """Test that multiline replace does nothing if disabled"""
46 """Test that multiline replace does nothing if disabled"""
39 ip = get_ipython()
47 ip = get_ipython()
40 ip.multiline_history = False
48 ip.multiline_history = False
41
49
42 ghist = [u'line1', u'line2']
50 ghist = [u'line1', u'line2']
43 for h in ghist:
51 for h in ghist:
44 ip.readline.add_history(h)
52 ip.readline.add_history(h)
45 hlen_b4_cell = ip.readline.get_current_history_length()
53 hlen_b4_cell = ip.readline.get_current_history_length()
46 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2',
54 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2',
47 hlen_b4_cell)
55 hlen_b4_cell)
48
56
49 self.assertEquals(ip.readline.get_current_history_length(),
57 self.assertEquals(ip.readline.get_current_history_length(),
50 hlen_b4_cell)
58 hlen_b4_cell)
51 hist = self.rl_hist_entries(ip.readline, 2)
59 hist = self.rl_hist_entries(ip.readline, 2)
52 self.assertEquals(hist, ghist)
60 self.assertEquals(hist, ghist)
53
61
54 @skipif(not get_ipython().has_readline, 'no readline')
62 @skipif(not get_ipython().has_readline, 'no readline')
55 def test_replace_multiline_hist_adds(self):
63 def test_replace_multiline_hist_adds(self):
56 """Test that multiline replace function adds history"""
64 """Test that multiline replace function adds history"""
57 ip = get_ipython()
65 ip = get_ipython()
58
66
59 hlen_b4_cell = ip.readline.get_current_history_length()
67 hlen_b4_cell = ip.readline.get_current_history_length()
60 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€', hlen_b4_cell)
68 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€', hlen_b4_cell)
61
69
62 self.assertEquals(hlen_b4_cell,
70 self.assertEquals(hlen_b4_cell,
63 ip.readline.get_current_history_length())
71 ip.readline.get_current_history_length())
64
72
65 @skipif(not get_ipython().has_readline, 'no readline')
73 @skipif(not get_ipython().has_readline, 'no readline')
66 def test_replace_multiline_hist_keeps_history(self):
74 def test_replace_multiline_hist_keeps_history(self):
67 """Test that multiline replace does not delete history"""
75 """Test that multiline replace does not delete history"""
68 ip = get_ipython()
76 ip = get_ipython()
69 ip.multiline_history = True
77 ip.multiline_history = True
70
78
71 ghist = [u'line1', u'line2']
79 ghist = [u'line1', u'line2']
72 for h in ghist:
80 for h in ghist:
73 ip.readline.add_history(h)
81 ip.readline.add_history(h)
74
82
75 #start cell
83 #start cell
76 hlen_b4_cell = ip.readline.get_current_history_length()
84 hlen_b4_cell = ip.readline.get_current_history_length()
77 # nothing added to rl history, should do nothing
85 # nothing added to rl history, should do nothing
78 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2',
86 hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2',
79 hlen_b4_cell)
87 hlen_b4_cell)
80
88
81 self.assertEquals(ip.readline.get_current_history_length(),
89 self.assertEquals(ip.readline.get_current_history_length(),
82 hlen_b4_cell)
90 hlen_b4_cell)
83 hist = self.rl_hist_entries(ip.readline, 2)
91 hist = self.rl_hist_entries(ip.readline, 2)
84 self.assertEquals(hist, ghist)
92 self.assertEquals(hist, ghist)
85
93
86
94
87 @skipif(not get_ipython().has_readline, 'no readline')
95 @skipif(not get_ipython().has_readline, 'no readline')
88 def test_replace_multiline_hist_replaces_twice(self):
96 def test_replace_multiline_hist_replaces_twice(self):
89 """Test that multiline entries are replaced twice"""
97 """Test that multiline entries are replaced twice"""
90 ip = get_ipython()
98 ip = get_ipython()
91 ip.multiline_history = True
99 ip.multiline_history = True
92
100
93 ip.readline.add_history(u'line0')
101 ip.readline.add_history(u'line0')
94 #start cell
102 #start cell
95 hlen_b4_cell = ip.readline.get_current_history_length()
103 hlen_b4_cell = ip.readline.get_current_history_length()
96 ip.readline.add_history('l€ne1')
104 ip.readline.add_history('l€ne1')
97 ip.readline.add_history('line2')
105 ip.readline.add_history('line2')
98 #replace cell with single line
106 #replace cell with single line
99 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2',
107 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2',
100 hlen_b4_cell)
108 hlen_b4_cell)
101 ip.readline.add_history('l€ne3')
109 ip.readline.add_history('l€ne3')
102 ip.readline.add_history('line4')
110 ip.readline.add_history('line4')
103 #replace cell with single line
111 #replace cell with single line
104 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3\nline4',
112 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3\nline4',
105 hlen_b4_cell)
113 hlen_b4_cell)
106
114
107 self.assertEquals(ip.readline.get_current_history_length(),
115 self.assertEquals(ip.readline.get_current_history_length(),
108 hlen_b4_cell)
116 hlen_b4_cell)
109 hist = self.rl_hist_entries(ip.readline, 3)
117 hist = self.rl_hist_entries(ip.readline, 3)
110 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3\nline4'])
118 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3\nline4'])
111
119
112
120
113 @skipif(not get_ipython().has_readline, 'no readline')
121 @skipif(not get_ipython().has_readline, 'no readline')
114 def test_replace_multiline_hist_replaces_empty_line(self):
122 def test_replace_multiline_hist_replaces_empty_line(self):
115 """Test that multiline history skips empty line cells"""
123 """Test that multiline history skips empty line cells"""
116 ip = get_ipython()
124 ip = get_ipython()
117 ip.multiline_history = True
125 ip.multiline_history = True
118
126
119 ip.readline.add_history(u'line0')
127 ip.readline.add_history(u'line0')
120 #start cell
128 #start cell
121 hlen_b4_cell = ip.readline.get_current_history_length()
129 hlen_b4_cell = ip.readline.get_current_history_length()
122 ip.readline.add_history('l€ne1')
130 ip.readline.add_history('l€ne1')
123 ip.readline.add_history('line2')
131 ip.readline.add_history('line2')
124 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2',
132 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2',
125 hlen_b4_cell)
133 hlen_b4_cell)
126 ip.readline.add_history('')
134 ip.readline.add_history('')
127 hlen_b4_cell = ip._replace_rlhist_multiline(u'', hlen_b4_cell)
135 hlen_b4_cell = ip._replace_rlhist_multiline(u'', hlen_b4_cell)
128 ip.readline.add_history('l€ne3')
136 ip.readline.add_history('l€ne3')
129 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3', hlen_b4_cell)
137 hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3', hlen_b4_cell)
130 ip.readline.add_history(' ')
138 ip.readline.add_history(' ')
131 hlen_b4_cell = ip._replace_rlhist_multiline(' ', hlen_b4_cell)
139 hlen_b4_cell = ip._replace_rlhist_multiline(' ', hlen_b4_cell)
132 ip.readline.add_history('\t')
140 ip.readline.add_history('\t')
133 ip.readline.add_history('\t ')
141 ip.readline.add_history('\t ')
134 hlen_b4_cell = ip._replace_rlhist_multiline('\t', hlen_b4_cell)
142 hlen_b4_cell = ip._replace_rlhist_multiline('\t', hlen_b4_cell)
135 ip.readline.add_history('line4')
143 ip.readline.add_history('line4')
136 hlen_b4_cell = ip._replace_rlhist_multiline(u'line4', hlen_b4_cell)
144 hlen_b4_cell = ip._replace_rlhist_multiline(u'line4', hlen_b4_cell)
137
145
138 self.assertEquals(ip.readline.get_current_history_length(),
146 self.assertEquals(ip.readline.get_current_history_length(),
139 hlen_b4_cell)
147 hlen_b4_cell)
140 hist = self.rl_hist_entries(ip.readline, 4)
148 hist = self.rl_hist_entries(ip.readline, 4)
141 # expect no empty cells in history
149 # expect no empty cells in history
142 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3', 'line4'])
150 self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3', 'line4'])
General Comments 0
You need to be logged in to leave comments. Login now