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