##// END OF EJS Templates
BUG: For multiline outputs, conditionally prepend a newline if necessary. Move this code to where we actually write the output. Frontends should be able to decide whether to use this or not.
Robert Kern -
Show More
@@ -1,301 +1,304 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Displayhook for IPython.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez
7 7 * Brian Granger
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2008-2010 The IPython Development Team
12 12 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import __builtin__
23 23
24 24 from IPython.config.configurable import Configurable
25 25 from IPython.core import prompts
26 26 import IPython.utils.generics
27 27 import IPython.utils.io
28 28 from IPython.utils.traitlets import Instance, List
29 29 from IPython.utils.warn import warn
30 30 from IPython.core.formatters import DefaultFormatter
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # Main displayhook class
34 34 #-----------------------------------------------------------------------------
35 35
36 36 # TODO: The DisplayHook class should be split into two classes, one that
37 37 # manages the prompts and their synchronization and another that just does the
38 38 # displayhook logic and calls into the prompt manager.
39 39
40 40 # TODO: Move the various attributes (cache_size, colors, input_sep,
41 41 # output_sep, output_sep2, ps1, ps2, ps_out, pad_left). Some of these are also
42 42 # attributes of InteractiveShell. They should be on ONE object only and the
43 43 # other objects should ask that one object for their values.
44 44
45 45 class DisplayHook(Configurable):
46 46 """The custom IPython displayhook to replace sys.displayhook.
47 47
48 48 This class does many things, but the basic idea is that it is a callable
49 49 that gets called anytime user code returns a value.
50 50
51 51 Currently this class does more than just the displayhook logic and that
52 52 extra logic should eventually be moved out of here.
53 53 """
54 54
55 55 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
56 56
57 57 # The default formatter.
58 58 default_formatter = Instance('IPython.core.formatters.FormatterABC')
59 59 def _default_formatter_default(self):
60 60 # FIXME: backwards compatibility for the InteractiveShell.pprint option?
61 61 return DefaultFormatter(config=self.config)
62 62
63 63 # Any additional FormatterABC instances we use.
64 64 # FIXME: currently unused.
65 65 extra_formatters = List(config=True)
66 66
67 67 # Each call to the In[] prompt raises it by 1, even the first.
68 68 #prompt_count = Int(0)
69 69
70 70 def __init__(self, shell=None, cache_size=1000,
71 71 colors='NoColor', input_sep='\n',
72 72 output_sep='\n', output_sep2='',
73 73 ps1 = None, ps2 = None, ps_out = None, pad_left=True,
74 74 config=None):
75 75 super(DisplayHook, self).__init__(shell=shell, config=config)
76 76
77 77 cache_size_min = 3
78 78 if cache_size <= 0:
79 79 self.do_full_cache = 0
80 80 cache_size = 0
81 81 elif cache_size < cache_size_min:
82 82 self.do_full_cache = 0
83 83 cache_size = 0
84 84 warn('caching was disabled (min value for cache size is %s).' %
85 85 cache_size_min,level=3)
86 86 else:
87 87 self.do_full_cache = 1
88 88
89 89 self.cache_size = cache_size
90 90 self.input_sep = input_sep
91 91
92 92 # we need a reference to the user-level namespace
93 93 self.shell = shell
94 94
95 95 # Set input prompt strings and colors
96 96 if cache_size == 0:
97 97 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
98 98 or ps1.find(r'\N') > -1:
99 99 ps1 = '>>> '
100 100 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
101 101 or ps2.find(r'\N') > -1:
102 102 ps2 = '... '
103 103 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
104 104 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
105 105 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
106 106
107 107 self.color_table = prompts.PromptColors
108 108 self.prompt1 = prompts.Prompt1(self,sep=input_sep,prompt=self.ps1_str,
109 109 pad_left=pad_left)
110 110 self.prompt2 = prompts.Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
111 111 self.prompt_out = prompts.PromptOut(self,sep='',prompt=self.ps_out_str,
112 112 pad_left=pad_left)
113 113 self.set_colors(colors)
114 114
115 115 # Store the last prompt string each time, we need it for aligning
116 116 # continuation and auto-rewrite prompts
117 117 self.last_prompt = ''
118 118 self.output_sep = output_sep
119 119 self.output_sep2 = output_sep2
120 120 self._,self.__,self.___ = '','',''
121 121
122 122 # these are deliberately global:
123 123 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
124 124 self.shell.user_ns.update(to_user_ns)
125 125
126 126 @property
127 127 def prompt_count(self):
128 128 return self.shell.execution_count
129 129
130 130 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
131 131 if p_str is None:
132 132 if self.do_full_cache:
133 133 return cache_def
134 134 else:
135 135 return no_cache_def
136 136 else:
137 137 return p_str
138 138
139 139 def set_colors(self, colors):
140 140 """Set the active color scheme and configure colors for the three
141 141 prompt subsystems."""
142 142
143 143 # FIXME: This modifying of the global prompts.prompt_specials needs
144 144 # to be fixed. We need to refactor all of the prompts stuff to use
145 145 # proper configuration and traits notifications.
146 146 if colors.lower()=='nocolor':
147 147 prompts.prompt_specials = prompts.prompt_specials_nocolor
148 148 else:
149 149 prompts.prompt_specials = prompts.prompt_specials_color
150 150
151 151 self.color_table.set_active_scheme(colors)
152 152 self.prompt1.set_colors()
153 153 self.prompt2.set_colors()
154 154 self.prompt_out.set_colors()
155 155
156 156 #-------------------------------------------------------------------------
157 157 # Methods used in __call__. Override these methods to modify the behavior
158 158 # of the displayhook.
159 159 #-------------------------------------------------------------------------
160 160
161 161 def check_for_underscore(self):
162 162 """Check if the user has set the '_' variable by hand."""
163 163 # If something injected a '_' variable in __builtin__, delete
164 164 # ipython's automatic one so we don't clobber that. gettext() in
165 165 # particular uses _, so we need to stay away from it.
166 166 if '_' in __builtin__.__dict__:
167 167 try:
168 168 del self.shell.user_ns['_']
169 169 except KeyError:
170 170 pass
171 171
172 172 def quiet(self):
173 173 """Should we silence the display hook because of ';'?"""
174 174 # do not print output if input ends in ';'
175 175 try:
176 176 if self.shell.input_hist[self.prompt_count].endswith(';\n'):
177 177 return True
178 178 except IndexError:
179 179 # some uses of ipshellembed may fail here
180 180 pass
181 181 return False
182 182
183 183 def start_displayhook(self):
184 184 """Start the displayhook, initializing resources."""
185 185 pass
186 186
187 187 def write_output_prompt(self):
188 188 """Write the output prompt."""
189 189 # Use write, not print which adds an extra space.
190 190 IPython.utils.io.Term.cout.write(self.output_sep)
191 191 outprompt = str(self.prompt_out)
192 192 if self.do_full_cache:
193 193 IPython.utils.io.Term.cout.write(outprompt)
194 194
195 195 def compute_result_repr(self, result):
196 196 """Compute and return the repr of the object to be displayed.
197 197
198 198 This method only compute the string form of the repr and should NOT
199 199 actually print or write that to a stream.
200 200 """
201 201 result_repr = self.default_formatter(result)
202 if '\n' in result_repr:
203 # So that multi-line strings line up with the left column of
204 # the screen, instead of having the output prompt mess up
205 # their first line.
206 outprompt = str(self.prompt_out)
207 if outprompt and not outprompt.endswith('\n'):
208 # But avoid extraneous empty lines.
209 result_repr = '\n' + result_repr
210
211 202 extra_formats = []
212 203 for f in self.extra_formatters:
213 204 try:
214 205 data = f(result)
215 206 except Exception:
216 207 # FIXME: log the exception.
217 208 continue
218 209 if data is not None:
219 210 extra_formats.append((f.id, f.format, data))
220 211
221 212 return result_repr, extra_formats
222 213
223 214 def write_result_repr(self, result_repr, extra_formats):
224 215 # We want to print because we want to always make sure we have a
225 216 # newline, even if all the prompt separators are ''. This is the
226 217 # standard IPython behavior.
218 if '\n' in result_repr:
219 # So that multi-line strings line up with the left column of
220 # the screen, instead of having the output prompt mess up
221 # their first line.
222 # We use the ps_out_str template instead of the expanded prompt
223 # because the expansion may add ANSI escapes that will interfere
224 # with our ability to determine whether or not we should add
225 # a newline.
226 if self.ps_out_str and not self.ps_out_str.endswith('\n'):
227 # But avoid extraneous empty lines.
228 result_repr = '\n' + result_repr
229
227 230 print >>IPython.utils.io.Term.cout, result_repr
228 231
229 232 def update_user_ns(self, result):
230 233 """Update user_ns with various things like _, __, _1, etc."""
231 234
232 235 # Avoid recursive reference when displaying _oh/Out
233 236 if result is not self.shell.user_ns['_oh']:
234 237 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
235 238 warn('Output cache limit (currently '+
236 239 `self.cache_size`+' entries) hit.\n'
237 240 'Flushing cache and resetting history counter...\n'
238 241 'The only history variables available will be _,__,___ and _1\n'
239 242 'with the current result.')
240 243
241 244 self.flush()
242 245 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
243 246 # we cause buggy behavior for things like gettext).
244 247 if '_' not in __builtin__.__dict__:
245 248 self.___ = self.__
246 249 self.__ = self._
247 250 self._ = result
248 251 self.shell.user_ns.update({'_':self._,'__':self.__,'___':self.___})
249 252
250 253 # hackish access to top-level namespace to create _1,_2... dynamically
251 254 to_main = {}
252 255 if self.do_full_cache:
253 256 new_result = '_'+`self.prompt_count`
254 257 to_main[new_result] = result
255 258 self.shell.user_ns.update(to_main)
256 259 self.shell.user_ns['_oh'][self.prompt_count] = result
257 260
258 261 def log_output(self, result):
259 262 """Log the output."""
260 263 if self.shell.logger.log_output:
261 264 self.shell.logger.log_write(repr(result), 'output')
262 265
263 266 def finish_displayhook(self):
264 267 """Finish up all displayhook activities."""
265 268 IPython.utils.io.Term.cout.write(self.output_sep2)
266 269 IPython.utils.io.Term.cout.flush()
267 270
268 271 def __call__(self, result=None):
269 272 """Printing with history cache management.
270 273
271 274 This is invoked everytime the interpreter needs to print, and is
272 275 activated by setting the variable sys.displayhook to it.
273 276 """
274 277 self.check_for_underscore()
275 278 if result is not None and not self.quiet():
276 279 self.start_displayhook()
277 280 self.write_output_prompt()
278 281 result_repr, extra_formats = self.compute_result_repr(result)
279 282 self.write_result_repr(result_repr, extra_formats)
280 283 self.update_user_ns(result)
281 284 self.log_output(result)
282 285 self.finish_displayhook()
283 286
284 287 def flush(self):
285 288 if not self.do_full_cache:
286 289 raise ValueError,"You shouldn't have reached the cache flush "\
287 290 "if full caching is not enabled!"
288 291 # delete auto-generated vars from global namespace
289 292
290 293 for n in range(1,self.prompt_count + 1):
291 294 key = '_'+`n`
292 295 try:
293 296 del self.shell.user_ns[key]
294 297 except: pass
295 298 self.shell.user_ns['_oh'].clear()
296 299
297 300 if '_' not in __builtin__.__dict__:
298 301 self.shell.user_ns.update({'_':None,'__':None, '___':None})
299 302 import gc
300 303 gc.collect() # xxx needed?
301 304
General Comments 0
You need to be logged in to leave comments. Login now