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