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