##// END OF EJS Templates
Update displayhook.py...
thethomask -
Show More
@@ -1,290 +1,294 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Displayhook for IPython.
3 3
4 4 This defines a callable class that IPython uses for `sys.displayhook`.
5 5 """
6 6
7 7 # Copyright (c) IPython Development Team.
8 8 # Distributed under the terms of the Modified BSD License.
9 9
10 10 from __future__ import print_function
11 11
12 12 import sys
13 13 import io, tokenize
14 14
15 15 from IPython.core.formatters import _safe_get_formatter_method
16 16 from traitlets.config.configurable import Configurable
17 17 from IPython.utils import io
18 18 from IPython.utils.py3compat import builtin_mod
19 19 from traitlets import Instance, Float
20 20 from IPython.utils.warn import warn
21 21
22 22 # TODO: Move the various attributes (cache_size, [others now moved]). Some
23 23 # of these are also attributes of InteractiveShell. They should be on ONE object
24 24 # only and the other objects should ask that one object for their values.
25 25
26 26 class DisplayHook(Configurable):
27 27 """The custom IPython displayhook to replace sys.displayhook.
28 28
29 29 This class does many things, but the basic idea is that it is a callable
30 30 that gets called anytime user code returns a value.
31 31 """
32 32
33 33 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
34 34 allow_none=True)
35 35 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
36 36 allow_none=True)
37 37 cull_fraction = Float(0.2)
38 38
39 39 def __init__(self, shell=None, cache_size=1000, **kwargs):
40 40 super(DisplayHook, self).__init__(shell=shell, **kwargs)
41 41 cache_size_min = 3
42 42 if cache_size <= 0:
43 43 self.do_full_cache = 0
44 44 cache_size = 0
45 45 elif cache_size < cache_size_min:
46 46 self.do_full_cache = 0
47 47 cache_size = 0
48 48 warn('caching was disabled (min value for cache size is %s).' %
49 49 cache_size_min,level=3)
50 50 else:
51 51 self.do_full_cache = 1
52 52
53 53 self.cache_size = cache_size
54 54
55 55 # we need a reference to the user-level namespace
56 56 self.shell = shell
57 57
58 58 self._,self.__,self.___ = '','',''
59 59
60 60 # these are deliberately global:
61 61 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
62 62 self.shell.user_ns.update(to_user_ns)
63 63
64 64 @property
65 65 def prompt_count(self):
66 66 return self.shell.execution_count
67 67
68 68 #-------------------------------------------------------------------------
69 69 # Methods used in __call__. Override these methods to modify the behavior
70 70 # of the displayhook.
71 71 #-------------------------------------------------------------------------
72 72
73 73 def check_for_underscore(self):
74 74 """Check if the user has set the '_' variable by hand."""
75 75 # If something injected a '_' variable in __builtin__, delete
76 76 # ipython's automatic one so we don't clobber that. gettext() in
77 77 # particular uses _, so we need to stay away from it.
78 78 if '_' in builtin_mod.__dict__:
79 79 try:
80 80 del self.shell.user_ns['_']
81 81 except KeyError:
82 82 pass
83 83
84 84 def quiet(self):
85 85 """Should we silence the display hook because of ';'?"""
86 86 # do not print output if input ends in ';'
87
87
88 88 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
89 89 sio = io.StringIO(cell)
90 90 tokens = list(tokenize.generate_tokens(sio.readline))
91
92 for token in reversed(tokens):
93 if token.type in (tokenize.ENDMARKER, tokenize.COMMENT):
94 continue
95 if (token.type == tokenize.OP) and (token.string == ';'):
96 return True
97 else:
98 return False
91
92 try:
93 for token in reversed(tokens):
94 if token.type in (tokenize.ENDMARKER, tokenize.COMMENT):
95 continue
96 if (token.type == tokenize.OP) and (token.string == ';'):
97 return True
98 else:
99 return False
100 except IndexError:
101 # some uses of ipshellembed may fail here
102 return False
99 103
100 104 def start_displayhook(self):
101 105 """Start the displayhook, initializing resources."""
102 106 pass
103 107
104 108 def write_output_prompt(self):
105 109 """Write the output prompt.
106 110
107 111 The default implementation simply writes the prompt to
108 112 ``io.stdout``.
109 113 """
110 114 # Use write, not print which adds an extra space.
111 115 io.stdout.write(self.shell.separate_out)
112 116 outprompt = self.shell.prompt_manager.render('out')
113 117 if self.do_full_cache:
114 118 io.stdout.write(outprompt)
115 119
116 120 def compute_format_data(self, result):
117 121 """Compute format data of the object to be displayed.
118 122
119 123 The format data is a generalization of the :func:`repr` of an object.
120 124 In the default implementation the format data is a :class:`dict` of
121 125 key value pair where the keys are valid MIME types and the values
122 126 are JSON'able data structure containing the raw data for that MIME
123 127 type. It is up to frontends to determine pick a MIME to to use and
124 128 display that data in an appropriate manner.
125 129
126 130 This method only computes the format data for the object and should
127 131 NOT actually print or write that to a stream.
128 132
129 133 Parameters
130 134 ----------
131 135 result : object
132 136 The Python object passed to the display hook, whose format will be
133 137 computed.
134 138
135 139 Returns
136 140 -------
137 141 (format_dict, md_dict) : dict
138 142 format_dict is a :class:`dict` whose keys are valid MIME types and values are
139 143 JSON'able raw data for that MIME type. It is recommended that
140 144 all return values of this should always include the "text/plain"
141 145 MIME type representation of the object.
142 146 md_dict is a :class:`dict` with the same MIME type keys
143 147 of metadata associated with each output.
144 148
145 149 """
146 150 return self.shell.display_formatter.format(result)
147 151
148 152 def write_format_data(self, format_dict, md_dict=None):
149 153 """Write the format data dict to the frontend.
150 154
151 155 This default version of this method simply writes the plain text
152 156 representation of the object to ``io.stdout``. Subclasses should
153 157 override this method to send the entire `format_dict` to the
154 158 frontends.
155 159
156 160 Parameters
157 161 ----------
158 162 format_dict : dict
159 163 The format dict for the object passed to `sys.displayhook`.
160 164 md_dict : dict (optional)
161 165 The metadata dict to be associated with the display data.
162 166 """
163 167 if 'text/plain' not in format_dict:
164 168 # nothing to do
165 169 return
166 170 # We want to print because we want to always make sure we have a
167 171 # newline, even if all the prompt separators are ''. This is the
168 172 # standard IPython behavior.
169 173 result_repr = format_dict['text/plain']
170 174 if '\n' in result_repr:
171 175 # So that multi-line strings line up with the left column of
172 176 # the screen, instead of having the output prompt mess up
173 177 # their first line.
174 178 # We use the prompt template instead of the expanded prompt
175 179 # because the expansion may add ANSI escapes that will interfere
176 180 # with our ability to determine whether or not we should add
177 181 # a newline.
178 182 prompt_template = self.shell.prompt_manager.out_template
179 183 if prompt_template and not prompt_template.endswith('\n'):
180 184 # But avoid extraneous empty lines.
181 185 result_repr = '\n' + result_repr
182 186
183 187 print(result_repr, file=io.stdout)
184 188
185 189 def update_user_ns(self, result):
186 190 """Update user_ns with various things like _, __, _1, etc."""
187 191
188 192 # Avoid recursive reference when displaying _oh/Out
189 193 if result is not self.shell.user_ns['_oh']:
190 194 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
191 195 self.cull_cache()
192 196 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
193 197 # we cause buggy behavior for things like gettext).
194 198
195 199 if '_' not in builtin_mod.__dict__:
196 200 self.___ = self.__
197 201 self.__ = self._
198 202 self._ = result
199 203 self.shell.push({'_':self._,
200 204 '__':self.__,
201 205 '___':self.___}, interactive=False)
202 206
203 207 # hackish access to top-level namespace to create _1,_2... dynamically
204 208 to_main = {}
205 209 if self.do_full_cache:
206 210 new_result = '_'+repr(self.prompt_count)
207 211 to_main[new_result] = result
208 212 self.shell.push(to_main, interactive=False)
209 213 self.shell.user_ns['_oh'][self.prompt_count] = result
210 214
211 215 def fill_exec_result(self, result):
212 216 if self.exec_result is not None:
213 217 self.exec_result.result = result
214 218
215 219 def log_output(self, format_dict):
216 220 """Log the output."""
217 221 if 'text/plain' not in format_dict:
218 222 # nothing to do
219 223 return
220 224 if self.shell.logger.log_output:
221 225 self.shell.logger.log_write(format_dict['text/plain'], 'output')
222 226 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
223 227 format_dict['text/plain']
224 228
225 229 def finish_displayhook(self):
226 230 """Finish up all displayhook activities."""
227 231 io.stdout.write(self.shell.separate_out2)
228 232 io.stdout.flush()
229 233
230 234 def __call__(self, result=None):
231 235 """Printing with history cache management.
232 236
233 237 This is invoked everytime the interpreter needs to print, and is
234 238 activated by setting the variable sys.displayhook to it.
235 239 """
236 240 self.check_for_underscore()
237 241 if result is not None and not self.quiet():
238 242 self.start_displayhook()
239 243 self.write_output_prompt()
240 244 format_dict, md_dict = self.compute_format_data(result)
241 245 self.update_user_ns(result)
242 246 self.fill_exec_result(result)
243 247 if format_dict:
244 248 self.write_format_data(format_dict, md_dict)
245 249 self.log_output(format_dict)
246 250 self.finish_displayhook()
247 251
248 252 def cull_cache(self):
249 253 """Output cache is full, cull the oldest entries"""
250 254 oh = self.shell.user_ns.get('_oh', {})
251 255 sz = len(oh)
252 256 cull_count = max(int(sz * self.cull_fraction), 2)
253 257 warn('Output cache limit (currently {sz} entries) hit.\n'
254 258 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
255 259
256 260 for i, n in enumerate(sorted(oh)):
257 261 if i >= cull_count:
258 262 break
259 263 self.shell.user_ns.pop('_%i' % n, None)
260 264 oh.pop(n, None)
261 265
262 266
263 267 def flush(self):
264 268 if not self.do_full_cache:
265 269 raise ValueError("You shouldn't have reached the cache flush "
266 270 "if full caching is not enabled!")
267 271 # delete auto-generated vars from global namespace
268 272
269 273 for n in range(1,self.prompt_count + 1):
270 274 key = '_'+repr(n)
271 275 try:
272 276 del self.shell.user_ns[key]
273 277 except: pass
274 278 # In some embedded circumstances, the user_ns doesn't have the
275 279 # '_oh' key set up.
276 280 oh = self.shell.user_ns.get('_oh', None)
277 281 if oh is not None:
278 282 oh.clear()
279 283
280 284 # Release our own references to objects:
281 285 self._, self.__, self.___ = '', '', ''
282 286
283 287 if '_' not in builtin_mod.__dict__:
284 288 self.shell.user_ns.update({'_':None,'__':None, '___':None})
285 289 import gc
286 290 # TODO: Is this really needed?
287 291 # IronPython blocks here forever
288 292 if sys.platform != "cli":
289 293 gc.collect()
290 294
General Comments 0
You need to be logged in to leave comments. Login now