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