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