##// END OF EJS Templates
Refactor of prompts and the displayhook....
Brian Granger -
Show More
@@ -0,0 +1,284 b''
1 # -*- coding: utf-8 -*-
2 """Displayhook for IPython.
3
4 Authors:
5
6 * Fernando Perez
7 * Brian Granger
8 """
9
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2010 The IPython Development Team
12 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
13 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
21
22 import __builtin__
23 from pprint import PrettyPrinter
24 pformat = PrettyPrinter().pformat
25
26 from IPython.config.configurable import Configurable
27 from IPython.core import prompts
28 import IPython.utils.generics
29 import IPython.utils.io
30 from IPython.utils.traitlets import Instance
31 from IPython.utils.warn import warn
32
33 #-----------------------------------------------------------------------------
34 # Main displayhook class
35 #-----------------------------------------------------------------------------
36
37 # TODO: The DisplayHook class should be split into two classes, one that
38 # manages the prompts and their synchronization and another that just does the
39 # displayhook logic and calls into the prompt manager.
40
41 # TODO: Move the various attributes (cache_size, colors, input_sep,
42 # output_sep, output_sep2, ps1, ps2, ps_out, pad_left). Some of these are also
43 # attributes of InteractiveShell. They should be on ONE object only and the
44 # other objects should ask that one object for their values.
45
46 class DisplayHook(Configurable):
47 """The custom IPython displayhook to replace sys.displayhook.
48
49 This class does many things, but the basic idea is that it is a callable
50 that gets called anytime user code returns a value.
51
52 Currently this class does more than just the displayhook logic and that
53 extra logic should eventually be moved out of here.
54 """
55
56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
57
58 def __init__(self, shell=None, cache_size=1000,
59 colors='NoColor', input_sep='\n',
60 output_sep='\n', output_sep2='',
61 ps1 = None, ps2 = None, ps_out = None, pad_left=True,
62 config=None):
63 super(DisplayHook, self).__init__(shell=shell, config=config)
64
65 cache_size_min = 3
66 if cache_size <= 0:
67 self.do_full_cache = 0
68 cache_size = 0
69 elif cache_size < cache_size_min:
70 self.do_full_cache = 0
71 cache_size = 0
72 warn('caching was disabled (min value for cache size is %s).' %
73 cache_size_min,level=3)
74 else:
75 self.do_full_cache = 1
76
77 self.cache_size = cache_size
78 self.input_sep = input_sep
79
80 # we need a reference to the user-level namespace
81 self.shell = shell
82
83 # Set input prompt strings and colors
84 if cache_size == 0:
85 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
86 or ps1.find(r'\N') > -1:
87 ps1 = '>>> '
88 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
89 or ps2.find(r'\N') > -1:
90 ps2 = '... '
91 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
92 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
93 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
94
95 self.color_table = prompts.PromptColors
96 self.prompt1 = prompts.Prompt1(self,sep=input_sep,prompt=self.ps1_str,
97 pad_left=pad_left)
98 self.prompt2 = prompts.Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
99 self.prompt_out = prompts.PromptOut(self,sep='',prompt=self.ps_out_str,
100 pad_left=pad_left)
101 self.set_colors(colors)
102
103 # other more normal stuff
104 # b/c each call to the In[] prompt raises it by 1, even the first.
105 self.prompt_count = 0
106 # Store the last prompt string each time, we need it for aligning
107 # continuation and auto-rewrite prompts
108 self.last_prompt = ''
109 self.output_sep = output_sep
110 self.output_sep2 = output_sep2
111 self._,self.__,self.___ = '','',''
112 self.pprint_types = map(type,[(),[],{}])
113
114 # these are deliberately global:
115 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
116 self.shell.user_ns.update(to_user_ns)
117
118 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
119 if p_str is None:
120 if self.do_full_cache:
121 return cache_def
122 else:
123 return no_cache_def
124 else:
125 return p_str
126
127 def set_colors(self, colors):
128 """Set the active color scheme and configure colors for the three
129 prompt subsystems."""
130
131 # FIXME: This modifying of the global prompts.prompt_specials needs
132 # to be fixed. We need to refactor all of the prompts stuff to use
133 # proper configuration and traits notifications.
134 if colors.lower()=='nocolor':
135 prompts.prompt_specials = prompts.prompt_specials_nocolor
136 else:
137 prompts.prompt_specials = prompts.prompt_specials_color
138
139 self.color_table.set_active_scheme(colors)
140 self.prompt1.set_colors()
141 self.prompt2.set_colors()
142 self.prompt_out.set_colors()
143
144 #-------------------------------------------------------------------------
145 # Methods used in __call__. Override these methods to modify the behavior
146 # of the displayhook.
147 #-------------------------------------------------------------------------
148
149 def check_for_underscore(self):
150 """Check if the user has set the '_' variable by hand."""
151 # If something injected a '_' variable in __builtin__, delete
152 # ipython's automatic one so we don't clobber that. gettext() in
153 # particular uses _, so we need to stay away from it.
154 if '_' in __builtin__.__dict__:
155 try:
156 del self.shell.user_ns['_']
157 except KeyError:
158 pass
159
160 def quite(self):
161 """Should we silence the display hook because of ';'?"""
162 # do not print output if input ends in ';'
163 try:
164 if self.shell.input_hist[self.prompt_count].endswith(';\n'):
165 return True
166 except IndexError:
167 # some uses of ipshellembed may fail here
168 pass
169 return False
170
171 def write_output_prompt(self):
172 """Write the output prompt."""
173 # Use write, not print which adds an extra space.
174 IPython.utils.io.Term.cout.write(self.output_sep)
175 outprompt = str(self.prompt_out)
176 if self.do_full_cache:
177 IPython.utils.io.Term.cout.write(outprompt)
178
179 # TODO: Make this method an extension point. The previous implementation
180 # has both a result_display hook as well as a result_display generic
181 # function to customize the repr on a per class basis. We need to rethink
182 # the hooks mechanism before doing this though.
183 def compute_result_repr(self, result):
184 """Compute and return the repr of the object to be displayed.
185
186 This method only compute the string form of the repr and should NOT
187 actual print or write that to a stream. This method may also transform
188 the result itself, but the default implementation passes the original
189 through.
190 """
191 try:
192 if self.shell.pprint:
193 result_repr = pformat(result)
194 if '\n' in result_repr:
195 # So that multi-line strings line up with the left column of
196 # the screen, instead of having the output prompt mess up
197 # their first line.
198 result_repr = '\n' + result_repr
199 else:
200 result_repr = repr(result)
201 except TypeError:
202 # This happens when result.__repr__ doesn't return a string,
203 # such as when it returns None.
204 result_repr = '\n'
205 return result, result_repr
206
207 def write_result_repr(self, result_repr):
208 # We want to print because we want to always make sure we have a
209 # newline, even if all the prompt separators are ''. This is the
210 # standard IPython behavior.
211 print >>IPython.utils.io.Term.cout, result_repr
212
213 def update_user_ns(self, result):
214 """Update user_ns with various things like _, __, _1, etc."""
215
216 # Avoid recursive reference when displaying _oh/Out
217 if result is not self.shell.user_ns['_oh']:
218 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
219 warn('Output cache limit (currently '+
220 `self.cache_size`+' entries) hit.\n'
221 'Flushing cache and resetting history counter...\n'
222 'The only history variables available will be _,__,___ and _1\n'
223 'with the current result.')
224
225 self.flush()
226 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
227 # we cause buggy behavior for things like gettext).
228 if '_' not in __builtin__.__dict__:
229 self.___ = self.__
230 self.__ = self._
231 self._ = result
232 self.shell.user_ns.update({'_':self._,'__':self.__,'___':self.___})
233
234 # hackish access to top-level namespace to create _1,_2... dynamically
235 to_main = {}
236 if self.do_full_cache:
237 new_result = '_'+`self.prompt_count`
238 to_main[new_result] = result
239 self.shell.user_ns.update(to_main)
240 self.shell.user_ns['_oh'][self.prompt_count] = result
241
242 def log_output(self, result):
243 """Log the output."""
244 if self.shell.logger.log_output:
245 self.shell.logger.log_write(repr(result),'output')
246
247 def finish_displayhook(self):
248 """Finish up all displayhook activities."""
249 IPython.utils.io.Term.cout.write(self.output_sep2)
250 IPython.utils.io.Term.cout.flush()
251
252 def __call__(self, result=None):
253 """Printing with history cache management.
254
255 This is invoked everytime the interpreter needs to print, and is
256 activated by setting the variable sys.displayhook to it.
257 """
258 self.check_for_underscore()
259 if result is not None and not self.quite():
260 self.write_output_prompt()
261 result, result_repr = self.compute_result_repr(result)
262 self.write_result_repr(result_repr)
263 self.update_user_ns(result)
264 self.log_output(result)
265 self.finish_displayhook()
266
267 def flush(self):
268 if not self.do_full_cache:
269 raise ValueError,"You shouldn't have reached the cache flush "\
270 "if full caching is not enabled!"
271 # delete auto-generated vars from global namespace
272
273 for n in range(1,self.prompt_count + 1):
274 key = '_'+`n`
275 try:
276 del self.shell.user_ns[key]
277 except: pass
278 self.shell.user_ns['_oh'].clear()
279
280 if '_' not in __builtin__.__dict__:
281 self.shell.user_ns.update({'_':None,'__':None, '___':None})
282 import gc
283 gc.collect() # xxx needed?
284
@@ -54,7 +54,7 b" def magic_history(self, parameter_s = ''):"
54 confirmation first if it already exists.
54 confirmation first if it already exists.
55 """
55 """
56
56
57 if not self.outputcache.do_full_cache:
57 if not self.displayhook.do_full_cache:
58 print 'This feature is only available if numbered prompts are in use.'
58 print 'This feature is only available if numbered prompts are in use.'
59 return
59 return
60 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
60 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
@@ -44,24 +44,19 b' somewhere in your configuration files or ipython command line.'
44 import os, bisect
44 import os, bisect
45 import sys
45 import sys
46
46
47 from pprint import PrettyPrinter
47 from IPython.core.error import TryNext
48
49 import IPython.utils.io
48 import IPython.utils.io
50 from IPython.utils.process import shell
49 from IPython.utils.process import shell
51
50
52 from IPython.core.error import TryNext
53
54 # List here all the default hooks. For now it's just the editor functions
51 # List here all the default hooks. For now it's just the editor functions
55 # but over time we'll move here all the public API for user-accessible things.
52 # but over time we'll move here all the public API for user-accessible things.
56
53
57 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display',
54 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor',
58 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
55 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
59 'generate_prompt', 'generate_output_prompt','shell_hook',
56 'generate_prompt','shell_hook',
60 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook',
57 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook',
61 'clipboard_get']
58 'clipboard_get']
62
59
63 pformat = PrettyPrinter().pformat
64
65 def editor(self,filename, linenum=None):
60 def editor(self,filename, linenum=None):
66 """Open the default editor at the given filename and linenumber.
61 """Open the default editor at the given filename and linenumber.
67
62
@@ -221,12 +216,8 b' def late_startup_hook(self):'
221 def generate_prompt(self, is_continuation):
216 def generate_prompt(self, is_continuation):
222 """ calculate and return a string with the prompt to display """
217 """ calculate and return a string with the prompt to display """
223 if is_continuation:
218 if is_continuation:
224 return str(self.outputcache.prompt2)
219 return str(self.displayhook.prompt2)
225 return str(self.outputcache.prompt1)
220 return str(self.displayhook.prompt1)
226
227
228 def generate_output_prompt(self):
229 return str(self.outputcache.prompt_out)
230
221
231
222
232 def shell_hook(self,cmd):
223 def shell_hook(self,cmd):
@@ -46,7 +46,7 b' from IPython.core.logger import Logger'
46 from IPython.core.magic import Magic
46 from IPython.core.magic import Magic
47 from IPython.core.plugin import PluginManager
47 from IPython.core.plugin import PluginManager
48 from IPython.core.prefilter import PrefilterManager
48 from IPython.core.prefilter import PrefilterManager
49 from IPython.core.prompts import CachedOutput
49 from IPython.core.displayhook import DisplayHook
50 import IPython.core.hooks
50 import IPython.core.hooks
51 from IPython.external.Itpl import ItplNS
51 from IPython.external.Itpl import ItplNS
52 from IPython.utils import PyColorize
52 from IPython.utils import PyColorize
@@ -206,8 +206,8 b' class InteractiveShell(Configurable, Magic):'
206 # TODO: this part of prompt management should be moved to the frontends.
206 # TODO: this part of prompt management should be moved to the frontends.
207 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
207 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
208 separate_in = SeparateStr('\n', config=True)
208 separate_in = SeparateStr('\n', config=True)
209 separate_out = SeparateStr('', config=True)
209 separate_out = SeparateStr('\n', config=True)
210 separate_out2 = SeparateStr('', config=True)
210 separate_out2 = SeparateStr('\n', config=True)
211 system_header = Str('IPython system call: ', config=True)
211 system_header = Str('IPython system call: ', config=True)
212 system_verbose = CBool(False, config=True)
212 system_verbose = CBool(False, config=True)
213 wildcards_case_sensitive = CBool(True, config=True)
213 wildcards_case_sensitive = CBool(True, config=True)
@@ -428,10 +428,15 b' class InteractiveShell(Configurable, Magic):'
428 IPython.utils.io.Term = Term
428 IPython.utils.io.Term = Term
429
429
430 def init_prompts(self):
430 def init_prompts(self):
431 # Initialize cache, set in/out prompts and printing system
431 # TODO: This is a pass for now because the prompts are managed inside
432 self.outputcache = CachedOutput(self,
432 # the DisplayHook. Once there is a separate prompt manager, this
433 self.cache_size,
433 # will initialize that object and all prompt related information.
434 self.pprint,
434 pass
435
436 def init_displayhook(self):
437 # Initialize displayhook, set in/out prompts and printing system
438 self.displayhook = DisplayHook( shell=self,
439 cache_size=self.cache_size,
435 input_sep = self.separate_in,
440 input_sep = self.separate_in,
436 output_sep = self.separate_out,
441 output_sep = self.separate_out,
437 output_sep2 = self.separate_out2,
442 output_sep2 = self.separate_out2,
@@ -439,15 +444,9 b' class InteractiveShell(Configurable, Magic):'
439 ps2 = self.prompt_in2,
444 ps2 = self.prompt_in2,
440 ps_out = self.prompt_out,
445 ps_out = self.prompt_out,
441 pad_left = self.prompts_pad_left)
446 pad_left = self.prompts_pad_left)
442
447 # This is a context manager that installs/revmoes the displayhook at
443 # user may have over-ridden the default print hook:
448 # the appropriate time.
444 try:
449 self.display_trap = DisplayTrap(hook=self.displayhook)
445 self.outputcache.__class__.display = self.hooks.display
446 except AttributeError:
447 pass
448
449 def init_displayhook(self):
450 self.display_trap = DisplayTrap(hook=self.outputcache)
451
450
452 def init_reload_doctest(self):
451 def init_reload_doctest(self):
453 # Do a proper resetting of doctest, including the necessary displayhook
452 # Do a proper resetting of doctest, including the necessary displayhook
@@ -1482,8 +1481,9 b' class InteractiveShell(Configurable, Magic):'
1482 #-------------------------------------------------------------------------
1481 #-------------------------------------------------------------------------
1483
1482
1484 def init_magics(self):
1483 def init_magics(self):
1485 # Set user colors (don't do it in the constructor above so that it
1484 # FIXME: Move the color initialization to the DisplayHook, which
1486 # doesn't crash if colors option is invalid)
1485 # should be split into a prompt manager and displayhook. We probably
1486 # even need a centralize colors management object.
1487 self.magic_colors(self.colors)
1487 self.magic_colors(self.colors)
1488 # History was moved to a separate module
1488 # History was moved to a separate module
1489 from . import history
1489 from . import history
@@ -182,14 +182,14 b' which already exists. But you must first start the logging process with'
182
182
183 # update the auto _i tables
183 # update the auto _i tables
184 #print '***logging line',line_mod # dbg
184 #print '***logging line',line_mod # dbg
185 #print '***cache_count', self.shell.outputcache.prompt_count # dbg
185 #print '***cache_count', self.shell.displayhook.prompt_count # dbg
186 try:
186 try:
187 input_hist = self.shell.user_ns['_ih']
187 input_hist = self.shell.user_ns['_ih']
188 except:
188 except:
189 #print 'userns:',self.shell.user_ns.keys() # dbg
189 #print 'userns:',self.shell.user_ns.keys() # dbg
190 return
190 return
191
191
192 out_cache = self.shell.outputcache
192 out_cache = self.shell.displayhook
193
193
194 # add blank lines if the input cache fell out of sync.
194 # add blank lines if the input cache fell out of sync.
195 if out_cache.do_full_cache and \
195 if out_cache.do_full_cache and \
@@ -208,15 +208,15 b' which already exists. But you must first start the logging process with'
208
208
209 # hackish access to top-level namespace to create _i1,_i2... dynamically
209 # hackish access to top-level namespace to create _i1,_i2... dynamically
210 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
210 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
211 if self.shell.outputcache.do_full_cache:
211 if self.shell.displayhook.do_full_cache:
212 in_num = self.shell.outputcache.prompt_count
212 in_num = self.shell.displayhook.prompt_count
213
213
214 # but if the opposite is true (a macro can produce multiple inputs
214 # but if the opposite is true (a macro can produce multiple inputs
215 # with no output display called), then bring the output counter in
215 # with no output display called), then bring the output counter in
216 # sync:
216 # sync:
217 last_num = len(input_hist)-1
217 last_num = len(input_hist)-1
218 if in_num != last_num:
218 if in_num != last_num:
219 in_num = self.shell.outputcache.prompt_count = last_num
219 in_num = self.shell.displayhook.prompt_count = last_num
220 new_i = '_i%s' % in_num
220 new_i = '_i%s' % in_num
221 if continuation:
221 if continuation:
222 self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod)
222 self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod)
@@ -2378,7 +2378,7 b' Currently the magic system has the following functions:\\n"""'
2378 # use last_call to remember the state of the previous call, but don't
2378 # use last_call to remember the state of the previous call, but don't
2379 # let it be clobbered by successive '-p' calls.
2379 # let it be clobbered by successive '-p' calls.
2380 try:
2380 try:
2381 last_call[0] = self.shell.outputcache.prompt_count
2381 last_call[0] = self.shell.displayhook.prompt_count
2382 if not opts_p:
2382 if not opts_p:
2383 last_call[1] = parameter_s
2383 last_call[1] = parameter_s
2384 except:
2384 except:
@@ -2566,12 +2566,12 b' Defaulting color scheme to \'NoColor\'"""'
2566
2566
2567 # Set prompt colors
2567 # Set prompt colors
2568 try:
2568 try:
2569 shell.outputcache.set_colors(new_scheme)
2569 shell.displayhook.set_colors(new_scheme)
2570 except:
2570 except:
2571 color_switch_err('prompt')
2571 color_switch_err('prompt')
2572 else:
2572 else:
2573 shell.colors = \
2573 shell.colors = \
2574 shell.outputcache.color_table.active_scheme_name
2574 shell.displayhook.color_table.active_scheme_name
2575 # Set exception colors
2575 # Set exception colors
2576 try:
2576 try:
2577 shell.InteractiveTB.set_colors(scheme = new_scheme)
2577 shell.InteractiveTB.set_colors(scheme = new_scheme)
@@ -2889,7 +2889,7 b' Defaulting color scheme to \'NoColor\'"""'
2889 if ps:
2889 if ps:
2890 try:
2890 try:
2891 os.chdir(os.path.expanduser(ps))
2891 os.chdir(os.path.expanduser(ps))
2892 if self.shell.term_title:
2892 if hasattr(self.shell, 'term_title') and self.shell.term_title:
2893 set_term_title('IPython: ' + abbrev_cwd())
2893 set_term_title('IPython: ' + abbrev_cwd())
2894 except OSError:
2894 except OSError:
2895 print sys.exc_info()[1]
2895 print sys.exc_info()[1]
@@ -2902,7 +2902,7 b' Defaulting color scheme to \'NoColor\'"""'
2902
2902
2903 else:
2903 else:
2904 os.chdir(self.shell.home_dir)
2904 os.chdir(self.shell.home_dir)
2905 if self.shell.term_title:
2905 if hasattr(self.shell, 'term_title') and self.shell.term_title:
2906 set_term_title('IPython: ' + '~')
2906 set_term_title('IPython: ' + '~')
2907 cwd = os.getcwd()
2907 cwd = os.getcwd()
2908 dhist = self.shell.user_ns['_dh']
2908 dhist = self.shell.user_ns['_dh']
@@ -3439,7 +3439,7 b' Defaulting color scheme to \'NoColor\'"""'
3439
3439
3440 # Shorthands
3440 # Shorthands
3441 shell = self.shell
3441 shell = self.shell
3442 oc = shell.outputcache
3442 oc = shell.displayhook
3443 meta = shell.meta
3443 meta = shell.meta
3444 # dstore is a data store kept in the instance metadata bag to track any
3444 # dstore is a data store kept in the instance metadata bag to track any
3445 # changes we make, so we can undo them later.
3445 # changes we make, so we can undo them later.
@@ -405,7 +405,7 b' class PrefilterManager(Configurable):'
405 normal_handler = self.get_handler_by_name('normal')
405 normal_handler = self.get_handler_by_name('normal')
406 if not stripped:
406 if not stripped:
407 if not continue_prompt:
407 if not continue_prompt:
408 self.shell.outputcache.prompt_count -= 1
408 self.shell.displayhook.prompt_count -= 1
409
409
410 return normal_handler.handle(line_info)
410 return normal_handler.handle(line_info)
411
411
@@ -916,7 +916,7 b' class AutoHandler(PrefilterHandler):'
916 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
916 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
917
917
918 if auto_rewrite:
918 if auto_rewrite:
919 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
919 rw = self.shell.displayhook.prompt1.auto_rewrite() + newcmd
920
920
921 try:
921 try:
922 # plain ascii works better w/ pyreadline, on some machines, so
922 # plain ascii works better w/ pyreadline, on some machines, so
@@ -1,19 +1,24 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """Classes for handling input/output prompts.
3 Classes for handling input/output prompts.
3
4 Authors:
5
6 * Fernando Perez
7 * Brian Granger
4 """
8 """
5
9
6 #*****************************************************************************
10 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
11 # Copyright (C) 2008-2010 The IPython Development Team
8 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
12 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
9 #
13 #
10 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
12 #*****************************************************************************
16 #-----------------------------------------------------------------------------
13
17
14 #****************************************************************************
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
15
21
16 import __builtin__
17 import os
22 import os
18 import re
23 import re
19 import socket
24 import socket
@@ -21,14 +26,11 b' import sys'
21
26
22 from IPython.core import release
27 from IPython.core import release
23 from IPython.external.Itpl import ItplNS
28 from IPython.external.Itpl import ItplNS
24 from IPython.core.error import TryNext
25 from IPython.utils import coloransi
29 from IPython.utils import coloransi
26 import IPython.utils.generics
27 from IPython.utils.warn import warn
28 import IPython.utils.io
29
30
30 #****************************************************************************
31 #-----------------------------------------------------------------------------
31 #Color schemes for Prompts.
32 # Color schemes for prompts
33 #-----------------------------------------------------------------------------
32
34
33 PromptColors = coloransi.ColorSchemeTable()
35 PromptColors = coloransi.ColorSchemeTable()
34 InputColors = coloransi.InputTermColors # just a shorthand
36 InputColors = coloransi.InputTermColors # just a shorthand
@@ -76,6 +78,9 b' PromptColors.add_scheme(__PColLightBG)'
76 del Colors,InputColors
78 del Colors,InputColors
77
79
78 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # Utilities
82 #-----------------------------------------------------------------------------
83
79 def multiple_replace(dict, text):
84 def multiple_replace(dict, text):
80 """ Replace in 'text' all occurences of any key in the given
85 """ Replace in 'text' all occurences of any key in the given
81 dictionary by its corresponding value. Returns the new string."""
86 dictionary by its corresponding value. Returns the new string."""
@@ -90,6 +95,7 b' def multiple_replace(dict, text):'
90
95
91 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
92 # Special characters that can be used in prompt templates, mainly bash-like
97 # Special characters that can be used in prompt templates, mainly bash-like
98 #-----------------------------------------------------------------------------
93
99
94 # If $HOME isn't defined (Windows), make it an absurd string so that it can
100 # If $HOME isn't defined (Windows), make it an absurd string so that it can
95 # never be expanded out into '~'. Basically anything which can never be a
101 # never be expanded out into '~'. Basically anything which can never be a
@@ -201,6 +207,9 b' for _color in dir(input_colors):'
201 prompt_specials = prompt_specials_nocolor
207 prompt_specials = prompt_specials_nocolor
202
208
203 #-----------------------------------------------------------------------------
209 #-----------------------------------------------------------------------------
210 # More utilities
211 #-----------------------------------------------------------------------------
212
204 def str_safe(arg):
213 def str_safe(arg):
205 """Convert to a string, without ever raising an exception.
214 """Convert to a string, without ever raising an exception.
206
215
@@ -221,6 +230,10 b' def str_safe(arg):'
221 #raise # dbg
230 #raise # dbg
222 return out
231 return out
223
232
233 #-----------------------------------------------------------------------------
234 # Prompt classes
235 #-----------------------------------------------------------------------------
236
224 class BasePrompt(object):
237 class BasePrompt(object):
225 """Interactive prompt similar to Mathematica's."""
238 """Interactive prompt similar to Mathematica's."""
226
239
@@ -234,7 +247,7 b' class BasePrompt(object):'
234 p_template = property(_get_p_template,_set_p_template,
247 p_template = property(_get_p_template,_set_p_template,
235 doc='Template for prompt string creation')
248 doc='Template for prompt string creation')
236
249
237 def __init__(self,cache,sep,prompt,pad_left=False):
250 def __init__(self, cache, sep, prompt, pad_left=False):
238
251
239 # Hack: we access information about the primary prompt through the
252 # Hack: we access information about the primary prompt through the
240 # cache argument. We need this, because we want the secondary prompt
253 # cache argument. We need this, because we want the secondary prompt
@@ -267,17 +280,17 b' class BasePrompt(object):'
267 self.p_str = ItplNS('%s%s%s' %
280 self.p_str = ItplNS('%s%s%s' %
268 ('${self.sep}${self.col_p}',
281 ('${self.sep}${self.col_p}',
269 multiple_replace(prompt_specials, self.p_template),
282 multiple_replace(prompt_specials, self.p_template),
270 '${self.col_norm}'),self.cache.user_ns,loc)
283 '${self.col_norm}'),self.cache.shell.user_ns,loc)
271
284
272 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
285 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
273 self.p_template),
286 self.p_template),
274 self.cache.user_ns,loc)
287 self.cache.shell.user_ns,loc)
275 except:
288 except:
276 print "Illegal prompt template (check $ usage!):",self.p_template
289 print "Illegal prompt template (check $ usage!):",self.p_template
277 self.p_str = self.p_template
290 self.p_str = self.p_template
278 self.p_str_nocolor = self.p_template
291 self.p_str_nocolor = self.p_template
279
292
280 def write(self,msg): # dbg
293 def write(self, msg):
281 sys.stdout.write(msg)
294 sys.stdout.write(msg)
282 return ''
295 return ''
283
296
@@ -301,7 +314,7 b' class BasePrompt(object):'
301
314
302 # these path filters are put in as methods so that we can control the
315 # these path filters are put in as methods so that we can control the
303 # namespace where the prompt strings get evaluated
316 # namespace where the prompt strings get evaluated
304 def cwd_filt(self,depth):
317 def cwd_filt(self, depth):
305 """Return the last depth elements of the current working directory.
318 """Return the last depth elements of the current working directory.
306
319
307 $HOME is always replaced with '~'.
320 $HOME is always replaced with '~'.
@@ -314,7 +327,7 b' class BasePrompt(object):'
314 else:
327 else:
315 return os.sep
328 return os.sep
316
329
317 def cwd_filt2(self,depth):
330 def cwd_filt2(self, depth):
318 """Return the last depth elements of the current working directory.
331 """Return the last depth elements of the current working directory.
319
332
320 $HOME is always replaced with '~'.
333 $HOME is always replaced with '~'.
@@ -341,11 +354,12 b' class BasePrompt(object):'
341
354
342 return bool(self.p_template)
355 return bool(self.p_template)
343
356
357
344 class Prompt1(BasePrompt):
358 class Prompt1(BasePrompt):
345 """Input interactive prompt similar to Mathematica's."""
359 """Input interactive prompt similar to Mathematica's."""
346
360
347 def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
361 def __init__(self, cache, sep='\n', prompt='In [\\#]: ', pad_left=True):
348 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
362 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
349
363
350 def set_colors(self):
364 def set_colors(self):
351 self.set_p_str()
365 self.set_p_str()
@@ -373,11 +387,12 b' class Prompt1(BasePrompt):'
373 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
387 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
374 ' '*nrspaces,self.col_norm_ni)
388 ' '*nrspaces,self.col_norm_ni)
375
389
390
376 class PromptOut(BasePrompt):
391 class PromptOut(BasePrompt):
377 """Output interactive prompt similar to Mathematica's."""
392 """Output interactive prompt similar to Mathematica's."""
378
393
379 def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
394 def __init__(self, cache, sep='', prompt='Out[\\#]: ', pad_left=True):
380 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
395 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
381 if not self.p_template:
396 if not self.p_template:
382 self.__str__ = lambda: ''
397 self.__str__ = lambda: ''
383
398
@@ -388,10 +403,11 b' class PromptOut(BasePrompt):'
388 self.col_num = Colors.out_number
403 self.col_num = Colors.out_number
389 self.col_norm = Colors.normal
404 self.col_norm = Colors.normal
390
405
406
391 class Prompt2(BasePrompt):
407 class Prompt2(BasePrompt):
392 """Interactive continuation prompt."""
408 """Interactive continuation prompt."""
393
409
394 def __init__(self,cache,prompt=' .\\D.: ',pad_left=True):
410 def __init__(self, cache, prompt=' .\\D.: ', pad_left=True):
395 self.cache = cache
411 self.cache = cache
396 self.p_template = prompt
412 self.p_template = prompt
397 self.pad_left = pad_left
413 self.pad_left = pad_left
@@ -404,10 +420,10 b' class Prompt2(BasePrompt):'
404 ('${self.col_p2}',
420 ('${self.col_p2}',
405 multiple_replace(prompt_specials, self.p_template),
421 multiple_replace(prompt_specials, self.p_template),
406 '$self.col_norm'),
422 '$self.col_norm'),
407 self.cache.user_ns,loc)
423 self.cache.shell.user_ns,loc)
408 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
424 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
409 self.p_template),
425 self.p_template),
410 self.cache.user_ns,loc)
426 self.cache.shell.user_ns,loc)
411
427
412 def set_colors(self):
428 def set_colors(self):
413 self.set_p_str()
429 self.set_p_str()
@@ -419,221 +435,3 b' class Prompt2(BasePrompt):'
419 self.col_p = Colors.out_prompt
435 self.col_p = Colors.out_prompt
420 self.col_num = Colors.out_number
436 self.col_num = Colors.out_number
421
437
422
423 #-----------------------------------------------------------------------------
424 class CachedOutput:
425 """Class for printing output from calculations while keeping a cache of
426 reults. It dynamically creates global variables prefixed with _ which
427 contain these results.
428
429 Meant to be used as a sys.displayhook replacement, providing numbered
430 prompts and cache services.
431
432 Initialize with initial and final values for cache counter (this defines
433 the maximum size of the cache."""
434
435 def __init__(self,shell,cache_size,Pprint,
436 colors='NoColor',input_sep='\n',
437 output_sep='\n',output_sep2='',
438 ps1 = None, ps2 = None,ps_out = None,pad_left=True):
439
440 cache_size_min = 3
441 if cache_size <= 0:
442 self.do_full_cache = 0
443 cache_size = 0
444 elif cache_size < cache_size_min:
445 self.do_full_cache = 0
446 cache_size = 0
447 warn('caching was disabled (min value for cache size is %s).' %
448 cache_size_min,level=3)
449 else:
450 self.do_full_cache = 1
451
452 self.cache_size = cache_size
453 self.input_sep = input_sep
454
455 # we need a reference to the user-level namespace
456 self.shell = shell
457 self.user_ns = shell.user_ns
458 # and to the user's input
459 self.input_hist = shell.input_hist
460 # and to the user's logger, for logging output
461 self.logger = shell.logger
462
463 # Set input prompt strings and colors
464 if cache_size == 0:
465 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
466 or ps1.find(r'\N') > -1:
467 ps1 = '>>> '
468 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
469 or ps2.find(r'\N') > -1:
470 ps2 = '... '
471 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
472 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
473 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
474
475 self.color_table = PromptColors
476 self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str,
477 pad_left=pad_left)
478 self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
479 self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str,
480 pad_left=pad_left)
481 self.set_colors(colors)
482
483 # other more normal stuff
484 # b/c each call to the In[] prompt raises it by 1, even the first.
485 self.prompt_count = 0
486 # Store the last prompt string each time, we need it for aligning
487 # continuation and auto-rewrite prompts
488 self.last_prompt = ''
489 self.Pprint = Pprint
490 self.output_sep = output_sep
491 self.output_sep2 = output_sep2
492 self._,self.__,self.___ = '','',''
493 self.pprint_types = map(type,[(),[],{}])
494
495 # these are deliberately global:
496 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
497 self.user_ns.update(to_user_ns)
498
499 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
500 if p_str is None:
501 if self.do_full_cache:
502 return cache_def
503 else:
504 return no_cache_def
505 else:
506 return p_str
507
508 def set_colors(self,colors):
509 """Set the active color scheme and configure colors for the three
510 prompt subsystems."""
511
512 # FIXME: the prompt_specials global should be gobbled inside this
513 # class instead. Do it when cleaning up the whole 3-prompt system.
514 global prompt_specials
515 if colors.lower()=='nocolor':
516 prompt_specials = prompt_specials_nocolor
517 else:
518 prompt_specials = prompt_specials_color
519
520 self.color_table.set_active_scheme(colors)
521 self.prompt1.set_colors()
522 self.prompt2.set_colors()
523 self.prompt_out.set_colors()
524
525 def __call__(self,arg=None):
526 """Printing with history cache management.
527
528 This is invoked everytime the interpreter needs to print, and is
529 activated by setting the variable sys.displayhook to it."""
530
531 # If something injected a '_' variable in __builtin__, delete
532 # ipython's automatic one so we don't clobber that. gettext() in
533 # particular uses _, so we need to stay away from it.
534 if '_' in __builtin__.__dict__:
535 try:
536 del self.user_ns['_']
537 except KeyError:
538 pass
539 if arg is not None:
540 cout_write = IPython.utils.io.Term.cout.write # fast lookup
541 # first handle the cache and counters
542
543 # do not print output if input ends in ';'
544 try:
545 if self.input_hist[self.prompt_count].endswith(';\n'):
546 return
547 except IndexError:
548 # some uses of ipshellembed may fail here
549 pass
550 # don't use print, puts an extra space
551 cout_write(self.output_sep)
552 outprompt = self.shell.hooks.generate_output_prompt()
553 # print "Got prompt: ", outprompt
554 if self.do_full_cache:
555 cout_write(outprompt)
556
557 # and now call a possibly user-defined print mechanism. Note that
558 # self.display typically prints as a side-effect, we don't do any
559 # printing to stdout here.
560 try:
561 manipulated_val = self.display(arg)
562 except TypeError:
563 # If the user's display hook didn't return a string we can
564 # print, we're done. Happens commonly if they return None
565 cout_write('\n')
566 return
567
568 # user display hooks can change the variable to be stored in
569 # output history
570 if manipulated_val is not None:
571 arg = manipulated_val
572
573 # avoid recursive reference when displaying _oh/Out
574 if arg is not self.user_ns['_oh']:
575 self.update(arg)
576
577 if self.logger.log_output:
578 self.logger.log_write(repr(arg),'output')
579 cout_write(self.output_sep2)
580 IPython.utils.io.Term.cout.flush()
581
582 def _display(self,arg):
583 """Default printer method, uses pprint.
584
585 Do ip.set_hook("result_display", my_displayhook) for custom result
586 display, e.g. when your own objects need special formatting.
587 """
588 try:
589 return IPython.utils.generics.result_display(arg)
590 except TryNext:
591 return self.shell.hooks.result_display(arg)
592
593 # Assign the default display method:
594 display = _display
595
596 def update(self,arg):
597 #print '***cache_count', self.cache_count # dbg
598 if len(self.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
599 warn('Output cache limit (currently '+
600 `self.cache_size`+' entries) hit.\n'
601 'Flushing cache and resetting history counter...\n'
602 'The only history variables available will be _,__,___ and _1\n'
603 'with the current result.')
604
605 self.flush()
606 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
607 # we cause buggy behavior for things like gettext).
608 if '_' not in __builtin__.__dict__:
609 self.___ = self.__
610 self.__ = self._
611 self._ = arg
612 self.user_ns.update({'_':self._,'__':self.__,'___':self.___})
613
614 # hackish access to top-level namespace to create _1,_2... dynamically
615 to_main = {}
616 if self.do_full_cache:
617 new_result = '_'+`self.prompt_count`
618 to_main[new_result] = arg
619 self.user_ns.update(to_main)
620 self.user_ns['_oh'][self.prompt_count] = arg
621
622 def flush(self):
623 if not self.do_full_cache:
624 raise ValueError,"You shouldn't have reached the cache flush "\
625 "if full caching is not enabled!"
626 # delete auto-generated vars from global namespace
627
628 for n in range(1,self.prompt_count + 1):
629 key = '_'+`n`
630 try:
631 del self.user_ns[key]
632 except: pass
633 self.user_ns['_oh'].clear()
634
635 if '_' not in __builtin__.__dict__:
636 self.user_ns.update({'_':None,'__':None, '___':None})
637 import gc
638 gc.collect() # xxx needed?
639
@@ -122,7 +122,7 b' class TestMagicRunPass(tt.TempFileMixin):'
122 """Test that prompts correctly generate after %run"""
122 """Test that prompts correctly generate after %run"""
123 self.run_tmpfile()
123 self.run_tmpfile()
124 _ip = get_ipython()
124 _ip = get_ipython()
125 p2 = str(_ip.outputcache.prompt2).strip()
125 p2 = str(_ip.displayhook.prompt2).strip()
126 nt.assert_equals(p2[:3], '...')
126 nt.assert_equals(p2[:3], '...')
127
127
128
128
@@ -236,7 +236,7 b' class TerminalInteractiveShell(InteractiveShell):'
236 self.write('\nKeyboardInterrupt\n')
236 self.write('\nKeyboardInterrupt\n')
237 self.resetbuffer()
237 self.resetbuffer()
238 # keep cache in sync with the prompt counter:
238 # keep cache in sync with the prompt counter:
239 self.outputcache.prompt_count -= 1
239 self.displayhook.prompt_count -= 1
240
240
241 if self.autoindent:
241 if self.autoindent:
242 self.indent_current_nsp = 0
242 self.indent_current_nsp = 0
@@ -250,7 +250,7 b' class IPTester(object):'
250 return os.system(' '.join(self.call_args))
250 return os.system(' '.join(self.call_args))
251 else:
251 else:
252 def _run_cmd(self):
252 def _run_cmd(self):
253 #print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
253 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
254 subp = subprocess.Popen(self.call_args)
254 subp = subprocess.Popen(self.call_args)
255 self.pids.append(subp.pid)
255 self.pids.append(subp.pid)
256 # If this fails, the pid will be left in self.pids and cleaned up
256 # If this fails, the pid will be left in self.pids and cleaned up
@@ -33,12 +33,6 b' from IPython.external.simplegeneric import generic'
33
33
34
34
35 @generic
35 @generic
36 def result_display(result):
37 """Print the result of computation."""
38 raise TryNext
39
40
41 @generic
42 def inspect_object(obj):
36 def inspect_object(obj):
43 """Called when you do obj?"""
37 """Called when you do obj?"""
44 raise TryNext
38 raise TryNext
@@ -23,7 +23,6 b' import types'
23
23
24 from IPython.external.path import path
24 from IPython.external.path import path
25
25
26 from IPython.utils.generics import result_display
27 from IPython.utils.io import nlprint
26 from IPython.utils.io import nlprint
28 from IPython.utils.data import flatten
27 from IPython.utils.data import flatten
29
28
@@ -94,14 +93,17 b' class LSString(str):'
94
93
95 p = paths = property(get_paths)
94 p = paths = property(get_paths)
96
95
96 # FIXME: We need to reimplement type specific displayhook and then add this
97 # back as a custom printer. This should also be moved outside utils into the
98 # core.
97
99
98 def print_lsstring(arg):
100 # def print_lsstring(arg):
99 """ Prettier (non-repr-like) and more informative printer for LSString """
101 # """ Prettier (non-repr-like) and more informative printer for LSString """
100 print "LSString (.p, .n, .l, .s available). Value:"
102 # print "LSString (.p, .n, .l, .s available). Value:"
101 print arg
103 # print arg
102
104 #
103
105 #
104 print_lsstring = result_display.when_type(LSString)(print_lsstring)
106 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
105
107
106
108
107 class SList(list):
109 class SList(list):
@@ -248,17 +250,20 b' class SList(list):'
248 return SList([t[1] for t in dsu])
250 return SList([t[1] for t in dsu])
249
251
250
252
251 def print_slist(arg):
253 # FIXME: We need to reimplement type specific displayhook and then add this
252 """ Prettier (non-repr-like) and more informative printer for SList """
254 # back as a custom printer. This should also be moved outside utils into the
253 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
255 # core.
254 if hasattr(arg, 'hideonce') and arg.hideonce:
256
255 arg.hideonce = False
257 # def print_slist(arg):
256 return
258 # """ Prettier (non-repr-like) and more informative printer for SList """
257
259 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
258 nlprint(arg)
260 # if hasattr(arg, 'hideonce') and arg.hideonce:
259
261 # arg.hideonce = False
260
262 # return
261 print_slist = result_display.when_type(SList)(print_slist)
263 #
264 # nlprint(arg)
265 #
266 # print_slist = result_display.when_type(SList)(print_slist)
262
267
263
268
264 def esc_quotes(strng):
269 def esc_quotes(strng):
@@ -17,7 +17,7 b' class ZMQInteractiveShell(InteractiveShell):'
17 for line in p.stderr.read().split('\n'):
17 for line in p.stderr.read().split('\n'):
18 if len(line) > 0:
18 if len(line) > 0:
19 print line
19 print line
20 return p.wait()
20 p.wait()
21
21
22 def init_io(self):
22 def init_io(self):
23 # This will just use sys.stdout and sys.stderr. If you want to
23 # This will just use sys.stdout and sys.stderr. If you want to
General Comments 0
You need to be logged in to leave comments. Login now