##// 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 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 58 print 'This feature is only available if numbered prompts are in use.'
59 59 return
60 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 44 import os, bisect
45 45 import sys
46 46
47 from pprint import PrettyPrinter
48
47 from IPython.core.error import TryNext
49 48 import IPython.utils.io
50 49 from IPython.utils.process import shell
51 50
52 from IPython.core.error import TryNext
53
54 51 # List here all the default hooks. For now it's just the editor functions
55 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 55 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
59 'generate_prompt', 'generate_output_prompt','shell_hook',
56 'generate_prompt','shell_hook',
60 57 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook',
61 58 'clipboard_get']
62 59
63 pformat = PrettyPrinter().pformat
64
65 60 def editor(self,filename, linenum=None):
66 61 """Open the default editor at the given filename and linenumber.
67 62
@@ -221,12 +216,8 b' def late_startup_hook(self):'
221 216 def generate_prompt(self, is_continuation):
222 217 """ calculate and return a string with the prompt to display """
223 218 if is_continuation:
224 return str(self.outputcache.prompt2)
225 return str(self.outputcache.prompt1)
226
227
228 def generate_output_prompt(self):
229 return str(self.outputcache.prompt_out)
219 return str(self.displayhook.prompt2)
220 return str(self.displayhook.prompt1)
230 221
231 222
232 223 def shell_hook(self,cmd):
@@ -46,7 +46,7 b' from IPython.core.logger import Logger'
46 46 from IPython.core.magic import Magic
47 47 from IPython.core.plugin import PluginManager
48 48 from IPython.core.prefilter import PrefilterManager
49 from IPython.core.prompts import CachedOutput
49 from IPython.core.displayhook import DisplayHook
50 50 import IPython.core.hooks
51 51 from IPython.external.Itpl import ItplNS
52 52 from IPython.utils import PyColorize
@@ -206,8 +206,8 b' class InteractiveShell(Configurable, Magic):'
206 206 # TODO: this part of prompt management should be moved to the frontends.
207 207 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
208 208 separate_in = SeparateStr('\n', config=True)
209 separate_out = SeparateStr('', config=True)
210 separate_out2 = SeparateStr('', config=True)
209 separate_out = SeparateStr('\n', config=True)
210 separate_out2 = SeparateStr('\n', config=True)
211 211 system_header = Str('IPython system call: ', config=True)
212 212 system_verbose = CBool(False, config=True)
213 213 wildcards_case_sensitive = CBool(True, config=True)
@@ -428,10 +428,15 b' class InteractiveShell(Configurable, Magic):'
428 428 IPython.utils.io.Term = Term
429 429
430 430 def init_prompts(self):
431 # Initialize cache, set in/out prompts and printing system
432 self.outputcache = CachedOutput(self,
433 self.cache_size,
434 self.pprint,
431 # TODO: This is a pass for now because the prompts are managed inside
432 # the DisplayHook. Once there is a separate prompt manager, this
433 # will initialize that object and all prompt related information.
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 440 input_sep = self.separate_in,
436 441 output_sep = self.separate_out,
437 442 output_sep2 = self.separate_out2,
@@ -439,15 +444,9 b' class InteractiveShell(Configurable, Magic):'
439 444 ps2 = self.prompt_in2,
440 445 ps_out = self.prompt_out,
441 446 pad_left = self.prompts_pad_left)
442
443 # user may have over-ridden the default print hook:
444 try:
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)
447 # This is a context manager that installs/revmoes the displayhook at
448 # the appropriate time.
449 self.display_trap = DisplayTrap(hook=self.displayhook)
451 450
452 451 def init_reload_doctest(self):
453 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 1483 def init_magics(self):
1485 # Set user colors (don't do it in the constructor above so that it
1486 # doesn't crash if colors option is invalid)
1484 # FIXME: Move the color initialization to the DisplayHook, which
1485 # should be split into a prompt manager and displayhook. We probably
1486 # even need a centralize colors management object.
1487 1487 self.magic_colors(self.colors)
1488 1488 # History was moved to a separate module
1489 1489 from . import history
@@ -182,14 +182,14 b' which already exists. But you must first start the logging process with'
182 182
183 183 # update the auto _i tables
184 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 186 try:
187 187 input_hist = self.shell.user_ns['_ih']
188 188 except:
189 189 #print 'userns:',self.shell.user_ns.keys() # dbg
190 190 return
191 191
192 out_cache = self.shell.outputcache
192 out_cache = self.shell.displayhook
193 193
194 194 # add blank lines if the input cache fell out of sync.
195 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 209 # hackish access to top-level namespace to create _i1,_i2... dynamically
210 210 to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
211 if self.shell.outputcache.do_full_cache:
212 in_num = self.shell.outputcache.prompt_count
211 if self.shell.displayhook.do_full_cache:
212 in_num = self.shell.displayhook.prompt_count
213 213
214 214 # but if the opposite is true (a macro can produce multiple inputs
215 215 # with no output display called), then bring the output counter in
216 216 # sync:
217 217 last_num = len(input_hist)-1
218 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 220 new_i = '_i%s' % in_num
221 221 if continuation:
222 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 2378 # use last_call to remember the state of the previous call, but don't
2379 2379 # let it be clobbered by successive '-p' calls.
2380 2380 try:
2381 last_call[0] = self.shell.outputcache.prompt_count
2381 last_call[0] = self.shell.displayhook.prompt_count
2382 2382 if not opts_p:
2383 2383 last_call[1] = parameter_s
2384 2384 except:
@@ -2566,12 +2566,12 b' Defaulting color scheme to \'NoColor\'"""'
2566 2566
2567 2567 # Set prompt colors
2568 2568 try:
2569 shell.outputcache.set_colors(new_scheme)
2569 shell.displayhook.set_colors(new_scheme)
2570 2570 except:
2571 2571 color_switch_err('prompt')
2572 2572 else:
2573 2573 shell.colors = \
2574 shell.outputcache.color_table.active_scheme_name
2574 shell.displayhook.color_table.active_scheme_name
2575 2575 # Set exception colors
2576 2576 try:
2577 2577 shell.InteractiveTB.set_colors(scheme = new_scheme)
@@ -2889,7 +2889,7 b' Defaulting color scheme to \'NoColor\'"""'
2889 2889 if ps:
2890 2890 try:
2891 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 2893 set_term_title('IPython: ' + abbrev_cwd())
2894 2894 except OSError:
2895 2895 print sys.exc_info()[1]
@@ -2902,7 +2902,7 b' Defaulting color scheme to \'NoColor\'"""'
2902 2902
2903 2903 else:
2904 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 2906 set_term_title('IPython: ' + '~')
2907 2907 cwd = os.getcwd()
2908 2908 dhist = self.shell.user_ns['_dh']
@@ -3439,7 +3439,7 b' Defaulting color scheme to \'NoColor\'"""'
3439 3439
3440 3440 # Shorthands
3441 3441 shell = self.shell
3442 oc = shell.outputcache
3442 oc = shell.displayhook
3443 3443 meta = shell.meta
3444 3444 # dstore is a data store kept in the instance metadata bag to track any
3445 3445 # changes we make, so we can undo them later.
@@ -405,7 +405,7 b' class PrefilterManager(Configurable):'
405 405 normal_handler = self.get_handler_by_name('normal')
406 406 if not stripped:
407 407 if not continue_prompt:
408 self.shell.outputcache.prompt_count -= 1
408 self.shell.displayhook.prompt_count -= 1
409 409
410 410 return normal_handler.handle(line_info)
411 411
@@ -916,7 +916,7 b' class AutoHandler(PrefilterHandler):'
916 916 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
917 917
918 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 921 try:
922 922 # plain ascii works better w/ pyreadline, on some machines, so
@@ -1,19 +1,24 b''
1 1 # -*- coding: utf-8 -*-
2 """
3 Classes for handling input/output prompts.
2 """Classes for handling input/output prompts.
3
4 Authors:
5
6 * Fernando Perez
7 * Brian Granger
4 8 """
5 9
6 #*****************************************************************************
7 # Copyright (C) 2008-2009 The IPython Development Team
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2010 The IPython Development Team
8 12 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
9 13 #
10 14 # Distributed under the terms of the BSD License. The full license is in
11 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 22 import os
18 23 import re
19 24 import socket
@@ -21,14 +26,11 b' import sys'
21 26
22 27 from IPython.core import release
23 28 from IPython.external.Itpl import ItplNS
24 from IPython.core.error import TryNext
25 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 #Color schemes for Prompts.
31 #-----------------------------------------------------------------------------
32 # Color schemes for prompts
33 #-----------------------------------------------------------------------------
32 34
33 35 PromptColors = coloransi.ColorSchemeTable()
34 36 InputColors = coloransi.InputTermColors # just a shorthand
@@ -76,6 +78,9 b' PromptColors.add_scheme(__PColLightBG)'
76 78 del Colors,InputColors
77 79
78 80 #-----------------------------------------------------------------------------
81 # Utilities
82 #-----------------------------------------------------------------------------
83
79 84 def multiple_replace(dict, text):
80 85 """ Replace in 'text' all occurences of any key in the given
81 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 97 # Special characters that can be used in prompt templates, mainly bash-like
98 #-----------------------------------------------------------------------------
93 99
94 100 # If $HOME isn't defined (Windows), make it an absurd string so that it can
95 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 207 prompt_specials = prompt_specials_nocolor
202 208
203 209 #-----------------------------------------------------------------------------
210 # More utilities
211 #-----------------------------------------------------------------------------
212
204 213 def str_safe(arg):
205 214 """Convert to a string, without ever raising an exception.
206 215
@@ -221,6 +230,10 b' def str_safe(arg):'
221 230 #raise # dbg
222 231 return out
223 232
233 #-----------------------------------------------------------------------------
234 # Prompt classes
235 #-----------------------------------------------------------------------------
236
224 237 class BasePrompt(object):
225 238 """Interactive prompt similar to Mathematica's."""
226 239
@@ -234,7 +247,7 b' class BasePrompt(object):'
234 247 p_template = property(_get_p_template,_set_p_template,
235 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 252 # Hack: we access information about the primary prompt through the
240 253 # cache argument. We need this, because we want the secondary prompt
@@ -267,17 +280,17 b' class BasePrompt(object):'
267 280 self.p_str = ItplNS('%s%s%s' %
268 281 ('${self.sep}${self.col_p}',
269 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 285 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
273 286 self.p_template),
274 self.cache.user_ns,loc)
287 self.cache.shell.user_ns,loc)
275 288 except:
276 289 print "Illegal prompt template (check $ usage!):",self.p_template
277 290 self.p_str = self.p_template
278 291 self.p_str_nocolor = self.p_template
279 292
280 def write(self,msg): # dbg
293 def write(self, msg):
281 294 sys.stdout.write(msg)
282 295 return ''
283 296
@@ -301,7 +314,7 b' class BasePrompt(object):'
301 314
302 315 # these path filters are put in as methods so that we can control the
303 316 # namespace where the prompt strings get evaluated
304 def cwd_filt(self,depth):
317 def cwd_filt(self, depth):
305 318 """Return the last depth elements of the current working directory.
306 319
307 320 $HOME is always replaced with '~'.
@@ -314,7 +327,7 b' class BasePrompt(object):'
314 327 else:
315 328 return os.sep
316 329
317 def cwd_filt2(self,depth):
330 def cwd_filt2(self, depth):
318 331 """Return the last depth elements of the current working directory.
319 332
320 333 $HOME is always replaced with '~'.
@@ -341,11 +354,12 b' class BasePrompt(object):'
341 354
342 355 return bool(self.p_template)
343 356
357
344 358 class Prompt1(BasePrompt):
345 359 """Input interactive prompt similar to Mathematica's."""
346 360
347 def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
348 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
361 def __init__(self, cache, sep='\n', prompt='In [\\#]: ', pad_left=True):
362 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
349 363
350 364 def set_colors(self):
351 365 self.set_p_str()
@@ -373,11 +387,12 b' class Prompt1(BasePrompt):'
373 387 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
374 388 ' '*nrspaces,self.col_norm_ni)
375 389
390
376 391 class PromptOut(BasePrompt):
377 392 """Output interactive prompt similar to Mathematica's."""
378 393
379 def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
380 BasePrompt.__init__(self,cache,sep,prompt,pad_left)
394 def __init__(self, cache, sep='', prompt='Out[\\#]: ', pad_left=True):
395 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
381 396 if not self.p_template:
382 397 self.__str__ = lambda: ''
383 398
@@ -388,10 +403,11 b' class PromptOut(BasePrompt):'
388 403 self.col_num = Colors.out_number
389 404 self.col_norm = Colors.normal
390 405
406
391 407 class Prompt2(BasePrompt):
392 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 411 self.cache = cache
396 412 self.p_template = prompt
397 413 self.pad_left = pad_left
@@ -404,10 +420,10 b' class Prompt2(BasePrompt):'
404 420 ('${self.col_p2}',
405 421 multiple_replace(prompt_specials, self.p_template),
406 422 '$self.col_norm'),
407 self.cache.user_ns,loc)
423 self.cache.shell.user_ns,loc)
408 424 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
409 425 self.p_template),
410 self.cache.user_ns,loc)
426 self.cache.shell.user_ns,loc)
411 427
412 428 def set_colors(self):
413 429 self.set_p_str()
@@ -419,221 +435,3 b' class Prompt2(BasePrompt):'
419 435 self.col_p = Colors.out_prompt
420 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 122 """Test that prompts correctly generate after %run"""
123 123 self.run_tmpfile()
124 124 _ip = get_ipython()
125 p2 = str(_ip.outputcache.prompt2).strip()
125 p2 = str(_ip.displayhook.prompt2).strip()
126 126 nt.assert_equals(p2[:3], '...')
127 127
128 128
@@ -236,7 +236,7 b' class TerminalInteractiveShell(InteractiveShell):'
236 236 self.write('\nKeyboardInterrupt\n')
237 237 self.resetbuffer()
238 238 # keep cache in sync with the prompt counter:
239 self.outputcache.prompt_count -= 1
239 self.displayhook.prompt_count -= 1
240 240
241 241 if self.autoindent:
242 242 self.indent_current_nsp = 0
@@ -250,7 +250,7 b' class IPTester(object):'
250 250 return os.system(' '.join(self.call_args))
251 251 else:
252 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 254 subp = subprocess.Popen(self.call_args)
255 255 self.pids.append(subp.pid)
256 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 35 @generic
36 def result_display(result):
37 """Print the result of computation."""
38 raise TryNext
39
40
41 @generic
42 36 def inspect_object(obj):
43 37 """Called when you do obj?"""
44 38 raise TryNext
@@ -23,7 +23,6 b' import types'
23 23
24 24 from IPython.external.path import path
25 25
26 from IPython.utils.generics import result_display
27 26 from IPython.utils.io import nlprint
28 27 from IPython.utils.data import flatten
29 28
@@ -94,14 +93,17 b' class LSString(str):'
94 93
95 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):
99 """ Prettier (non-repr-like) and more informative printer for LSString """
100 print "LSString (.p, .n, .l, .s available). Value:"
101 print arg
102
103
104 print_lsstring = result_display.when_type(LSString)(print_lsstring)
100 # def print_lsstring(arg):
101 # """ Prettier (non-repr-like) and more informative printer for LSString """
102 # print "LSString (.p, .n, .l, .s available). Value:"
103 # print arg
104 #
105 #
106 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
105 107
106 108
107 109 class SList(list):
@@ -248,17 +250,20 b' class SList(list):'
248 250 return SList([t[1] for t in dsu])
249 251
250 252
251 def print_slist(arg):
252 """ Prettier (non-repr-like) and more informative printer for SList """
253 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
254 if hasattr(arg, 'hideonce') and arg.hideonce:
255 arg.hideonce = False
256 return
257
258 nlprint(arg)
259
260
261 print_slist = result_display.when_type(SList)(print_slist)
253 # FIXME: We need to reimplement type specific displayhook and then add this
254 # back as a custom printer. This should also be moved outside utils into the
255 # core.
256
257 # def print_slist(arg):
258 # """ Prettier (non-repr-like) and more informative printer for SList """
259 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
260 # if hasattr(arg, 'hideonce') and arg.hideonce:
261 # arg.hideonce = False
262 # return
263 #
264 # nlprint(arg)
265 #
266 # print_slist = result_display.when_type(SList)(print_slist)
262 267
263 268
264 269 def esc_quotes(strng):
@@ -17,7 +17,7 b' class ZMQInteractiveShell(InteractiveShell):'
17 17 for line in p.stderr.read().split('\n'):
18 18 if len(line) > 0:
19 19 print line
20 return p.wait()
20 p.wait()
21 21
22 22 def init_io(self):
23 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