##// END OF EJS Templates
Revert PR #5388...
Thomas Kluyver -
Show More
@@ -1,286 +1,285 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 Authors:
7 7
8 8 * Fernando Perez
9 9 * Brian Granger
10 10 * Robert Kern
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Copyright (C) 2008-2011 The IPython Development Team
15 15 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-----------------------------------------------------------------------------
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Imports
23 23 #-----------------------------------------------------------------------------
24 24 from __future__ import print_function
25 25
26 26 import sys
27 27
28 28 from IPython.core.formatters import _safe_get_formatter_method
29 from IPython.core import inputsplitter
30 29 from IPython.config.configurable import Configurable
31 30 from IPython.utils import io
32 31 from IPython.utils.py3compat import builtin_mod
33 32 from IPython.utils.traitlets import Instance
34 33 from IPython.utils.warn import warn
35 34
36 35 #-----------------------------------------------------------------------------
37 36 # Main displayhook class
38 37 #-----------------------------------------------------------------------------
39 38
40 39 # TODO: Move the various attributes (cache_size, [others now moved]). Some
41 40 # of these are also attributes of InteractiveShell. They should be on ONE object
42 41 # only and the other objects should ask that one object for their values.
43 42
44 43 class DisplayHook(Configurable):
45 44 """The custom IPython displayhook to replace sys.displayhook.
46 45
47 46 This class does many things, but the basic idea is that it is a callable
48 47 that gets called anytime user code returns a value.
49 48 """
50 49
51 50 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
52 51
53 52 def __init__(self, shell=None, cache_size=1000, **kwargs):
54 53 super(DisplayHook, self).__init__(shell=shell, **kwargs)
55 54
56 55 cache_size_min = 3
57 56 if cache_size <= 0:
58 57 self.do_full_cache = 0
59 58 cache_size = 0
60 59 elif cache_size < cache_size_min:
61 60 self.do_full_cache = 0
62 61 cache_size = 0
63 62 warn('caching was disabled (min value for cache size is %s).' %
64 63 cache_size_min,level=3)
65 64 else:
66 65 self.do_full_cache = 1
67 66
68 67 self.cache_size = cache_size
69 68
70 69 # we need a reference to the user-level namespace
71 70 self.shell = shell
72 71
73 72 self._,self.__,self.___ = '','',''
74 73
75 74 # these are deliberately global:
76 75 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
77 76 self.shell.user_ns.update(to_user_ns)
78 77
79 78 @property
80 79 def prompt_count(self):
81 80 return self.shell.execution_count
82 81
83 82 #-------------------------------------------------------------------------
84 83 # Methods used in __call__. Override these methods to modify the behavior
85 84 # of the displayhook.
86 85 #-------------------------------------------------------------------------
87 86
88 87 def check_for_underscore(self):
89 88 """Check if the user has set the '_' variable by hand."""
90 89 # If something injected a '_' variable in __builtin__, delete
91 90 # ipython's automatic one so we don't clobber that. gettext() in
92 91 # particular uses _, so we need to stay away from it.
93 92 if '_' in builtin_mod.__dict__:
94 93 try:
95 94 del self.shell.user_ns['_']
96 95 except KeyError:
97 96 pass
98 97
99 98 def quiet(self):
100 99 """Should we silence the display hook because of ';'?"""
101 100 # do not print output if input ends in ';'
102 101 try:
103 102 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
104 return inputsplitter.remove_comments(cell).rstrip().endswith(';')
103 return cell.rstrip().endswith(';')
105 104 except IndexError:
106 105 # some uses of ipshellembed may fail here
107 106 return False
108 107
109 108 def start_displayhook(self):
110 109 """Start the displayhook, initializing resources."""
111 110 pass
112 111
113 112 def write_output_prompt(self):
114 113 """Write the output prompt.
115 114
116 115 The default implementation simply writes the prompt to
117 116 ``io.stdout``.
118 117 """
119 118 # Use write, not print which adds an extra space.
120 119 io.stdout.write(self.shell.separate_out)
121 120 outprompt = self.shell.prompt_manager.render('out')
122 121 if self.do_full_cache:
123 122 io.stdout.write(outprompt)
124 123
125 124 def compute_format_data(self, result):
126 125 """Compute format data of the object to be displayed.
127 126
128 127 The format data is a generalization of the :func:`repr` of an object.
129 128 In the default implementation the format data is a :class:`dict` of
130 129 key value pair where the keys are valid MIME types and the values
131 130 are JSON'able data structure containing the raw data for that MIME
132 131 type. It is up to frontends to determine pick a MIME to to use and
133 132 display that data in an appropriate manner.
134 133
135 134 This method only computes the format data for the object and should
136 135 NOT actually print or write that to a stream.
137 136
138 137 Parameters
139 138 ----------
140 139 result : object
141 140 The Python object passed to the display hook, whose format will be
142 141 computed.
143 142
144 143 Returns
145 144 -------
146 145 (format_dict, md_dict) : dict
147 146 format_dict is a :class:`dict` whose keys are valid MIME types and values are
148 147 JSON'able raw data for that MIME type. It is recommended that
149 148 all return values of this should always include the "text/plain"
150 149 MIME type representation of the object.
151 150 md_dict is a :class:`dict` with the same MIME type keys
152 151 of metadata associated with each output.
153 152
154 153 """
155 154 return self.shell.display_formatter.format(result)
156 155
157 156 def write_format_data(self, format_dict, md_dict=None):
158 157 """Write the format data dict to the frontend.
159 158
160 159 This default version of this method simply writes the plain text
161 160 representation of the object to ``io.stdout``. Subclasses should
162 161 override this method to send the entire `format_dict` to the
163 162 frontends.
164 163
165 164 Parameters
166 165 ----------
167 166 format_dict : dict
168 167 The format dict for the object passed to `sys.displayhook`.
169 168 md_dict : dict (optional)
170 169 The metadata dict to be associated with the display data.
171 170 """
172 171 # We want to print because we want to always make sure we have a
173 172 # newline, even if all the prompt separators are ''. This is the
174 173 # standard IPython behavior.
175 174 result_repr = format_dict['text/plain']
176 175 if '\n' in result_repr:
177 176 # So that multi-line strings line up with the left column of
178 177 # the screen, instead of having the output prompt mess up
179 178 # their first line.
180 179 # We use the prompt template instead of the expanded prompt
181 180 # because the expansion may add ANSI escapes that will interfere
182 181 # with our ability to determine whether or not we should add
183 182 # a newline.
184 183 prompt_template = self.shell.prompt_manager.out_template
185 184 if prompt_template and not prompt_template.endswith('\n'):
186 185 # But avoid extraneous empty lines.
187 186 result_repr = '\n' + result_repr
188 187
189 188 print(result_repr, file=io.stdout)
190 189
191 190 def update_user_ns(self, result):
192 191 """Update user_ns with various things like _, __, _1, etc."""
193 192
194 193 # Avoid recursive reference when displaying _oh/Out
195 194 if result is not self.shell.user_ns['_oh']:
196 195 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
197 196 warn('Output cache limit (currently '+
198 197 repr(self.cache_size)+' entries) hit.\n'
199 198 'Flushing cache and resetting history counter...\n'
200 199 'The only history variables available will be _,__,___ and _1\n'
201 200 'with the current result.')
202 201
203 202 self.flush()
204 203 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
205 204 # we cause buggy behavior for things like gettext).
206 205
207 206 if '_' not in builtin_mod.__dict__:
208 207 self.___ = self.__
209 208 self.__ = self._
210 209 self._ = result
211 210 self.shell.push({'_':self._,
212 211 '__':self.__,
213 212 '___':self.___}, interactive=False)
214 213
215 214 # hackish access to top-level namespace to create _1,_2... dynamically
216 215 to_main = {}
217 216 if self.do_full_cache:
218 217 new_result = '_'+repr(self.prompt_count)
219 218 to_main[new_result] = result
220 219 self.shell.push(to_main, interactive=False)
221 220 self.shell.user_ns['_oh'][self.prompt_count] = result
222 221
223 222 def log_output(self, format_dict):
224 223 """Log the output."""
225 224 if self.shell.logger.log_output:
226 225 self.shell.logger.log_write(format_dict['text/plain'], 'output')
227 226 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
228 227 format_dict['text/plain']
229 228
230 229 def finish_displayhook(self):
231 230 """Finish up all displayhook activities."""
232 231 io.stdout.write(self.shell.separate_out2)
233 232 io.stdout.flush()
234 233
235 234 def __call__(self, result=None):
236 235 """Printing with history cache management.
237 236
238 237 This is invoked everytime the interpreter needs to print, and is
239 238 activated by setting the variable sys.displayhook to it.
240 239 """
241 240 self.check_for_underscore()
242 241 if result is not None and not self.quiet():
243 242 # If _ipython_display_ is defined, use that to display this object.
244 243 display_method = _safe_get_formatter_method(result, '_ipython_display_')
245 244 if display_method is not None:
246 245 try:
247 246 return display_method()
248 247 except NotImplementedError:
249 248 pass
250 249
251 250 self.start_displayhook()
252 251 self.write_output_prompt()
253 252 format_dict, md_dict = self.compute_format_data(result)
254 253 self.write_format_data(format_dict, md_dict)
255 254 self.update_user_ns(result)
256 255 self.log_output(format_dict)
257 256 self.finish_displayhook()
258 257
259 258 def flush(self):
260 259 if not self.do_full_cache:
261 260 raise ValueError("You shouldn't have reached the cache flush "
262 261 "if full caching is not enabled!")
263 262 # delete auto-generated vars from global namespace
264 263
265 264 for n in range(1,self.prompt_count + 1):
266 265 key = '_'+repr(n)
267 266 try:
268 267 del self.shell.user_ns[key]
269 268 except: pass
270 269 # In some embedded circumstances, the user_ns doesn't have the
271 270 # '_oh' key set up.
272 271 oh = self.shell.user_ns.get('_oh', None)
273 272 if oh is not None:
274 273 oh.clear()
275 274
276 275 # Release our own references to objects:
277 276 self._, self.__, self.___ = '', '', ''
278 277
279 278 if '_' not in builtin_mod.__dict__:
280 279 self.shell.user_ns.update({'_':None,'__':None, '___':None})
281 280 import gc
282 281 # TODO: Is this really needed?
283 282 # IronPython blocks here forever
284 283 if sys.platform != "cli":
285 284 gc.collect()
286 285
@@ -1,734 +1,734 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the key interactiveshell module.
3 3
4 4 Historically the main classes in interactiveshell have been under-tested. This
5 5 module should grow as many single-method tests as possible to trap many of the
6 6 recurring bugs we seem to encounter with high-level interaction.
7 7
8 8 Authors
9 9 -------
10 10 * Fernando Perez
11 11 """
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22 # stdlib
23 23 import ast
24 24 import os
25 25 import signal
26 26 import shutil
27 27 import sys
28 28 import tempfile
29 29 import unittest
30 30 try:
31 31 from unittest import mock
32 32 except ImportError:
33 33 import mock
34 34 from os.path import join
35 35
36 36 # third-party
37 37 import nose.tools as nt
38 38
39 39 # Our own
40 40 from IPython.core.inputtransformer import InputTransformer
41 41 from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths
42 42 from IPython.testing import tools as tt
43 43 from IPython.utils import io
44 44 from IPython.utils import py3compat
45 45 from IPython.utils.py3compat import unicode_type, PY3
46 46
47 47 if PY3:
48 48 from io import StringIO
49 49 else:
50 50 from StringIO import StringIO
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # Globals
54 54 #-----------------------------------------------------------------------------
55 55 # This is used by every single test, no point repeating it ad nauseam
56 56 ip = get_ipython()
57 57
58 58 #-----------------------------------------------------------------------------
59 59 # Tests
60 60 #-----------------------------------------------------------------------------
61 61
62 62 class InteractiveShellTestCase(unittest.TestCase):
63 63 def test_naked_string_cells(self):
64 64 """Test that cells with only naked strings are fully executed"""
65 65 # First, single-line inputs
66 66 ip.run_cell('"a"\n')
67 67 self.assertEqual(ip.user_ns['_'], 'a')
68 68 # And also multi-line cells
69 69 ip.run_cell('"""a\nb"""\n')
70 70 self.assertEqual(ip.user_ns['_'], 'a\nb')
71 71
72 72 def test_run_empty_cell(self):
73 73 """Just make sure we don't get a horrible error with a blank
74 74 cell of input. Yes, I did overlook that."""
75 75 old_xc = ip.execution_count
76 76 ip.run_cell('')
77 77 self.assertEqual(ip.execution_count, old_xc)
78 78
79 79 def test_run_cell_multiline(self):
80 80 """Multi-block, multi-line cells must execute correctly.
81 81 """
82 82 src = '\n'.join(["x=1",
83 83 "y=2",
84 84 "if 1:",
85 85 " x += 1",
86 86 " y += 1",])
87 87 ip.run_cell(src)
88 88 self.assertEqual(ip.user_ns['x'], 2)
89 89 self.assertEqual(ip.user_ns['y'], 3)
90 90
91 91 def test_multiline_string_cells(self):
92 92 "Code sprinkled with multiline strings should execute (GH-306)"
93 93 ip.run_cell('tmp=0')
94 94 self.assertEqual(ip.user_ns['tmp'], 0)
95 95 ip.run_cell('tmp=1;"""a\nb"""\n')
96 96 self.assertEqual(ip.user_ns['tmp'], 1)
97 97
98 98 def test_dont_cache_with_semicolon(self):
99 99 "Ending a line with semicolon should not cache the returned object (GH-307)"
100 100 oldlen = len(ip.user_ns['Out'])
101 for cell in ['1;', '1; #a', '1;1;']:
101 for cell in ['1;', '1;1;']:
102 102 ip.run_cell(cell, store_history=True)
103 103 newlen = len(ip.user_ns['Out'])
104 104 self.assertEqual(oldlen, newlen)
105 105 i = 0
106 106 #also test the default caching behavior
107 for cell in ['1', '1 #;', '1;1']:
107 for cell in ['1', '1;1']:
108 108 ip.run_cell(cell, store_history=True)
109 109 newlen = len(ip.user_ns['Out'])
110 110 i += 1
111 111 self.assertEqual(oldlen+i, newlen)
112 112
113 113 def test_In_variable(self):
114 114 "Verify that In variable grows with user input (GH-284)"
115 115 oldlen = len(ip.user_ns['In'])
116 116 ip.run_cell('1;', store_history=True)
117 117 newlen = len(ip.user_ns['In'])
118 118 self.assertEqual(oldlen+1, newlen)
119 119 self.assertEqual(ip.user_ns['In'][-1],'1;')
120 120
121 121 def test_magic_names_in_string(self):
122 122 ip.run_cell('a = """\n%exit\n"""')
123 123 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
124 124
125 125 def test_trailing_newline(self):
126 126 """test that running !(command) does not raise a SyntaxError"""
127 127 ip.run_cell('!(true)\n', False)
128 128 ip.run_cell('!(true)\n\n\n', False)
129 129
130 130 def test_gh_597(self):
131 131 """Pretty-printing lists of objects with non-ascii reprs may cause
132 132 problems."""
133 133 class Spam(object):
134 134 def __repr__(self):
135 135 return "\xe9"*50
136 136 import IPython.core.formatters
137 137 f = IPython.core.formatters.PlainTextFormatter()
138 138 f([Spam(),Spam()])
139 139
140 140
141 141 def test_future_flags(self):
142 142 """Check that future flags are used for parsing code (gh-777)"""
143 143 ip.run_cell('from __future__ import print_function')
144 144 try:
145 145 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
146 146 assert 'prfunc_return_val' in ip.user_ns
147 147 finally:
148 148 # Reset compiler flags so we don't mess up other tests.
149 149 ip.compile.reset_compiler_flags()
150 150
151 151 def test_future_unicode(self):
152 152 """Check that unicode_literals is imported from __future__ (gh #786)"""
153 153 try:
154 154 ip.run_cell(u'byte_str = "a"')
155 155 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
156 156 ip.run_cell('from __future__ import unicode_literals')
157 157 ip.run_cell(u'unicode_str = "a"')
158 158 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
159 159 finally:
160 160 # Reset compiler flags so we don't mess up other tests.
161 161 ip.compile.reset_compiler_flags()
162 162
163 163 def test_can_pickle(self):
164 164 "Can we pickle objects defined interactively (GH-29)"
165 165 ip = get_ipython()
166 166 ip.reset()
167 167 ip.run_cell(("class Mylist(list):\n"
168 168 " def __init__(self,x=[]):\n"
169 169 " list.__init__(self,x)"))
170 170 ip.run_cell("w=Mylist([1,2,3])")
171 171
172 172 from pickle import dumps
173 173
174 174 # We need to swap in our main module - this is only necessary
175 175 # inside the test framework, because IPython puts the interactive module
176 176 # in place (but the test framework undoes this).
177 177 _main = sys.modules['__main__']
178 178 sys.modules['__main__'] = ip.user_module
179 179 try:
180 180 res = dumps(ip.user_ns["w"])
181 181 finally:
182 182 sys.modules['__main__'] = _main
183 183 self.assertTrue(isinstance(res, bytes))
184 184
185 185 def test_global_ns(self):
186 186 "Code in functions must be able to access variables outside them."
187 187 ip = get_ipython()
188 188 ip.run_cell("a = 10")
189 189 ip.run_cell(("def f(x):\n"
190 190 " return x + a"))
191 191 ip.run_cell("b = f(12)")
192 192 self.assertEqual(ip.user_ns["b"], 22)
193 193
194 194 def test_bad_custom_tb(self):
195 195 """Check that InteractiveShell is protected from bad custom exception handlers"""
196 196 from IPython.utils import io
197 197 save_stderr = io.stderr
198 198 try:
199 199 # capture stderr
200 200 io.stderr = StringIO()
201 201 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
202 202 self.assertEqual(ip.custom_exceptions, (IOError,))
203 203 ip.run_cell(u'raise IOError("foo")')
204 204 self.assertEqual(ip.custom_exceptions, ())
205 205 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
206 206 finally:
207 207 io.stderr = save_stderr
208 208
209 209 def test_bad_custom_tb_return(self):
210 210 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
211 211 from IPython.utils import io
212 212 save_stderr = io.stderr
213 213 try:
214 214 # capture stderr
215 215 io.stderr = StringIO()
216 216 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
217 217 self.assertEqual(ip.custom_exceptions, (NameError,))
218 218 ip.run_cell(u'a=abracadabra')
219 219 self.assertEqual(ip.custom_exceptions, ())
220 220 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
221 221 finally:
222 222 io.stderr = save_stderr
223 223
224 224 def test_drop_by_id(self):
225 225 myvars = {"a":object(), "b":object(), "c": object()}
226 226 ip.push(myvars, interactive=False)
227 227 for name in myvars:
228 228 assert name in ip.user_ns, name
229 229 assert name in ip.user_ns_hidden, name
230 230 ip.user_ns['b'] = 12
231 231 ip.drop_by_id(myvars)
232 232 for name in ["a", "c"]:
233 233 assert name not in ip.user_ns, name
234 234 assert name not in ip.user_ns_hidden, name
235 235 assert ip.user_ns['b'] == 12
236 236 ip.reset()
237 237
238 238 def test_var_expand(self):
239 239 ip.user_ns['f'] = u'Ca\xf1o'
240 240 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
241 241 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
242 242 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
243 243 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
244 244
245 245 ip.user_ns['f'] = b'Ca\xc3\xb1o'
246 246 # This should not raise any exception:
247 247 ip.var_expand(u'echo $f')
248 248
249 249 def test_var_expand_local(self):
250 250 """Test local variable expansion in !system and %magic calls"""
251 251 # !system
252 252 ip.run_cell('def test():\n'
253 253 ' lvar = "ttt"\n'
254 254 ' ret = !echo {lvar}\n'
255 255 ' return ret[0]\n')
256 256 res = ip.user_ns['test']()
257 257 nt.assert_in('ttt', res)
258 258
259 259 # %magic
260 260 ip.run_cell('def makemacro():\n'
261 261 ' macroname = "macro_var_expand_locals"\n'
262 262 ' %macro {macroname} codestr\n')
263 263 ip.user_ns['codestr'] = "str(12)"
264 264 ip.run_cell('makemacro()')
265 265 nt.assert_in('macro_var_expand_locals', ip.user_ns)
266 266
267 267 def test_var_expand_self(self):
268 268 """Test variable expansion with the name 'self', which was failing.
269 269
270 270 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
271 271 """
272 272 ip.run_cell('class cTest:\n'
273 273 ' classvar="see me"\n'
274 274 ' def test(self):\n'
275 275 ' res = !echo Variable: {self.classvar}\n'
276 276 ' return res[0]\n')
277 277 nt.assert_in('see me', ip.user_ns['cTest']().test())
278 278
279 279 def test_bad_var_expand(self):
280 280 """var_expand on invalid formats shouldn't raise"""
281 281 # SyntaxError
282 282 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
283 283 # NameError
284 284 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
285 285 # ZeroDivisionError
286 286 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
287 287
288 288 def test_silent_postexec(self):
289 289 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
290 290 pre_explicit = mock.Mock()
291 291 pre_always = mock.Mock()
292 292 post_explicit = mock.Mock()
293 293 post_always = mock.Mock()
294 294
295 295 ip.events.register('pre_run_cell', pre_explicit)
296 296 ip.events.register('pre_execute', pre_always)
297 297 ip.events.register('post_run_cell', post_explicit)
298 298 ip.events.register('post_execute', post_always)
299 299
300 300 try:
301 301 ip.run_cell("1", silent=True)
302 302 assert pre_always.called
303 303 assert not pre_explicit.called
304 304 assert post_always.called
305 305 assert not post_explicit.called
306 306 # double-check that non-silent exec did what we expected
307 307 # silent to avoid
308 308 ip.run_cell("1")
309 309 assert pre_explicit.called
310 310 assert post_explicit.called
311 311 finally:
312 312 # remove post-exec
313 313 ip.events.reset_all()
314 314
315 315 def test_silent_noadvance(self):
316 316 """run_cell(silent=True) doesn't advance execution_count"""
317 317 ec = ip.execution_count
318 318 # silent should force store_history=False
319 319 ip.run_cell("1", store_history=True, silent=True)
320 320
321 321 self.assertEqual(ec, ip.execution_count)
322 322 # double-check that non-silent exec did what we expected
323 323 # silent to avoid
324 324 ip.run_cell("1", store_history=True)
325 325 self.assertEqual(ec+1, ip.execution_count)
326 326
327 327 def test_silent_nodisplayhook(self):
328 328 """run_cell(silent=True) doesn't trigger displayhook"""
329 329 d = dict(called=False)
330 330
331 331 trap = ip.display_trap
332 332 save_hook = trap.hook
333 333
334 334 def failing_hook(*args, **kwargs):
335 335 d['called'] = True
336 336
337 337 try:
338 338 trap.hook = failing_hook
339 339 ip.run_cell("1", silent=True)
340 340 self.assertFalse(d['called'])
341 341 # double-check that non-silent exec did what we expected
342 342 # silent to avoid
343 343 ip.run_cell("1")
344 344 self.assertTrue(d['called'])
345 345 finally:
346 346 trap.hook = save_hook
347 347
348 348 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
349 349 def test_print_softspace(self):
350 350 """Verify that softspace is handled correctly when executing multiple
351 351 statements.
352 352
353 353 In [1]: print 1; print 2
354 354 1
355 355 2
356 356
357 357 In [2]: print 1,; print 2
358 358 1 2
359 359 """
360 360
361 361 def test_ofind_line_magic(self):
362 362 from IPython.core.magic import register_line_magic
363 363
364 364 @register_line_magic
365 365 def lmagic(line):
366 366 "A line magic"
367 367
368 368 # Get info on line magic
369 369 lfind = ip._ofind('lmagic')
370 370 info = dict(found=True, isalias=False, ismagic=True,
371 371 namespace = 'IPython internal', obj= lmagic.__wrapped__,
372 372 parent = None)
373 373 nt.assert_equal(lfind, info)
374 374
375 375 def test_ofind_cell_magic(self):
376 376 from IPython.core.magic import register_cell_magic
377 377
378 378 @register_cell_magic
379 379 def cmagic(line, cell):
380 380 "A cell magic"
381 381
382 382 # Get info on cell magic
383 383 find = ip._ofind('cmagic')
384 384 info = dict(found=True, isalias=False, ismagic=True,
385 385 namespace = 'IPython internal', obj= cmagic.__wrapped__,
386 386 parent = None)
387 387 nt.assert_equal(find, info)
388 388
389 389 def test_custom_exception(self):
390 390 called = []
391 391 def my_handler(shell, etype, value, tb, tb_offset=None):
392 392 called.append(etype)
393 393 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
394 394
395 395 ip.set_custom_exc((ValueError,), my_handler)
396 396 try:
397 397 ip.run_cell("raise ValueError('test')")
398 398 # Check that this was called, and only once.
399 399 self.assertEqual(called, [ValueError])
400 400 finally:
401 401 # Reset the custom exception hook
402 402 ip.set_custom_exc((), None)
403 403
404 404 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
405 405 def test_future_environment(self):
406 406 "Can we run code with & without the shell's __future__ imports?"
407 407 ip.run_cell("from __future__ import division")
408 408 ip.run_cell("a = 1/2", shell_futures=True)
409 409 self.assertEqual(ip.user_ns['a'], 0.5)
410 410 ip.run_cell("b = 1/2", shell_futures=False)
411 411 self.assertEqual(ip.user_ns['b'], 0)
412 412
413 413 ip.compile.reset_compiler_flags()
414 414 # This shouldn't leak to the shell's compiler
415 415 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
416 416 self.assertEqual(ip.user_ns['c'], 0.5)
417 417 ip.run_cell("d = 1/2", shell_futures=True)
418 418 self.assertEqual(ip.user_ns['d'], 0)
419 419
420 420
421 421 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
422 422
423 423 @onlyif_unicode_paths
424 424 def setUp(self):
425 425 self.BASETESTDIR = tempfile.mkdtemp()
426 426 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
427 427 os.mkdir(self.TESTDIR)
428 428 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
429 429 sfile.write("pass\n")
430 430 self.oldpath = py3compat.getcwd()
431 431 os.chdir(self.TESTDIR)
432 432 self.fname = u"Γ₯Àâtestscript.py"
433 433
434 434 def tearDown(self):
435 435 os.chdir(self.oldpath)
436 436 shutil.rmtree(self.BASETESTDIR)
437 437
438 438 @onlyif_unicode_paths
439 439 def test_1(self):
440 440 """Test safe_execfile with non-ascii path
441 441 """
442 442 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
443 443
444 444 class ExitCodeChecks(tt.TempFileMixin):
445 445 def test_exit_code_ok(self):
446 446 self.system('exit 0')
447 447 self.assertEqual(ip.user_ns['_exit_code'], 0)
448 448
449 449 def test_exit_code_error(self):
450 450 self.system('exit 1')
451 451 self.assertEqual(ip.user_ns['_exit_code'], 1)
452 452
453 453 @skipif(not hasattr(signal, 'SIGALRM'))
454 454 def test_exit_code_signal(self):
455 455 self.mktmp("import signal, time\n"
456 456 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
457 457 "time.sleep(1)\n")
458 458 self.system("%s %s" % (sys.executable, self.fname))
459 459 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
460 460
461 461 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
462 462 system = ip.system_raw
463 463
464 464 @onlyif_unicode_paths
465 465 def test_1(self):
466 466 """Test system_raw with non-ascii cmd
467 467 """
468 468 cmd = u'''python -c "'Γ₯Àâ'" '''
469 469 ip.system_raw(cmd)
470 470
471 471 # TODO: Exit codes are currently ignored on Windows.
472 472 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
473 473 system = ip.system_piped
474 474
475 475 @skip_win32
476 476 def test_exit_code_ok(self):
477 477 ExitCodeChecks.test_exit_code_ok(self)
478 478
479 479 @skip_win32
480 480 def test_exit_code_error(self):
481 481 ExitCodeChecks.test_exit_code_error(self)
482 482
483 483 @skip_win32
484 484 def test_exit_code_signal(self):
485 485 ExitCodeChecks.test_exit_code_signal(self)
486 486
487 487 class TestModules(unittest.TestCase, tt.TempFileMixin):
488 488 def test_extraneous_loads(self):
489 489 """Test we're not loading modules on startup that we shouldn't.
490 490 """
491 491 self.mktmp("import sys\n"
492 492 "print('numpy' in sys.modules)\n"
493 493 "print('IPython.parallel' in sys.modules)\n"
494 494 "print('IPython.kernel.zmq' in sys.modules)\n"
495 495 )
496 496 out = "False\nFalse\nFalse\n"
497 497 tt.ipexec_validate(self.fname, out)
498 498
499 499 class Negator(ast.NodeTransformer):
500 500 """Negates all number literals in an AST."""
501 501 def visit_Num(self, node):
502 502 node.n = -node.n
503 503 return node
504 504
505 505 class TestAstTransform(unittest.TestCase):
506 506 def setUp(self):
507 507 self.negator = Negator()
508 508 ip.ast_transformers.append(self.negator)
509 509
510 510 def tearDown(self):
511 511 ip.ast_transformers.remove(self.negator)
512 512
513 513 def test_run_cell(self):
514 514 with tt.AssertPrints('-34'):
515 515 ip.run_cell('print (12 + 22)')
516 516
517 517 # A named reference to a number shouldn't be transformed.
518 518 ip.user_ns['n'] = 55
519 519 with tt.AssertNotPrints('-55'):
520 520 ip.run_cell('print (n)')
521 521
522 522 def test_timeit(self):
523 523 called = set()
524 524 def f(x):
525 525 called.add(x)
526 526 ip.push({'f':f})
527 527
528 528 with tt.AssertPrints("best of "):
529 529 ip.run_line_magic("timeit", "-n1 f(1)")
530 530 self.assertEqual(called, set([-1]))
531 531 called.clear()
532 532
533 533 with tt.AssertPrints("best of "):
534 534 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
535 535 self.assertEqual(called, set([-2, -3]))
536 536
537 537 def test_time(self):
538 538 called = []
539 539 def f(x):
540 540 called.append(x)
541 541 ip.push({'f':f})
542 542
543 543 # Test with an expression
544 544 with tt.AssertPrints("Wall time: "):
545 545 ip.run_line_magic("time", "f(5+9)")
546 546 self.assertEqual(called, [-14])
547 547 called[:] = []
548 548
549 549 # Test with a statement (different code path)
550 550 with tt.AssertPrints("Wall time: "):
551 551 ip.run_line_magic("time", "a = f(-3 + -2)")
552 552 self.assertEqual(called, [5])
553 553
554 554 def test_macro(self):
555 555 ip.push({'a':10})
556 556 # The AST transformation makes this do a+=-1
557 557 ip.define_macro("amacro", "a+=1\nprint(a)")
558 558
559 559 with tt.AssertPrints("9"):
560 560 ip.run_cell("amacro")
561 561 with tt.AssertPrints("8"):
562 562 ip.run_cell("amacro")
563 563
564 564 class IntegerWrapper(ast.NodeTransformer):
565 565 """Wraps all integers in a call to Integer()"""
566 566 def visit_Num(self, node):
567 567 if isinstance(node.n, int):
568 568 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
569 569 args=[node], keywords=[])
570 570 return node
571 571
572 572 class TestAstTransform2(unittest.TestCase):
573 573 def setUp(self):
574 574 self.intwrapper = IntegerWrapper()
575 575 ip.ast_transformers.append(self.intwrapper)
576 576
577 577 self.calls = []
578 578 def Integer(*args):
579 579 self.calls.append(args)
580 580 return args
581 581 ip.push({"Integer": Integer})
582 582
583 583 def tearDown(self):
584 584 ip.ast_transformers.remove(self.intwrapper)
585 585 del ip.user_ns['Integer']
586 586
587 587 def test_run_cell(self):
588 588 ip.run_cell("n = 2")
589 589 self.assertEqual(self.calls, [(2,)])
590 590
591 591 # This shouldn't throw an error
592 592 ip.run_cell("o = 2.0")
593 593 self.assertEqual(ip.user_ns['o'], 2.0)
594 594
595 595 def test_timeit(self):
596 596 called = set()
597 597 def f(x):
598 598 called.add(x)
599 599 ip.push({'f':f})
600 600
601 601 with tt.AssertPrints("best of "):
602 602 ip.run_line_magic("timeit", "-n1 f(1)")
603 603 self.assertEqual(called, set([(1,)]))
604 604 called.clear()
605 605
606 606 with tt.AssertPrints("best of "):
607 607 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
608 608 self.assertEqual(called, set([(2,), (3,)]))
609 609
610 610 class ErrorTransformer(ast.NodeTransformer):
611 611 """Throws an error when it sees a number."""
612 612 def visit_Num(self):
613 613 raise ValueError("test")
614 614
615 615 class TestAstTransformError(unittest.TestCase):
616 616 def test_unregistering(self):
617 617 err_transformer = ErrorTransformer()
618 618 ip.ast_transformers.append(err_transformer)
619 619
620 620 with tt.AssertPrints("unregister", channel='stderr'):
621 621 ip.run_cell("1 + 2")
622 622
623 623 # This should have been removed.
624 624 nt.assert_not_in(err_transformer, ip.ast_transformers)
625 625
626 626 def test__IPYTHON__():
627 627 # This shouldn't raise a NameError, that's all
628 628 __IPYTHON__
629 629
630 630
631 631 class DummyRepr(object):
632 632 def __repr__(self):
633 633 return "DummyRepr"
634 634
635 635 def _repr_html_(self):
636 636 return "<b>dummy</b>"
637 637
638 638 def _repr_javascript_(self):
639 639 return "console.log('hi');", {'key': 'value'}
640 640
641 641
642 642 def test_user_variables():
643 643 # enable all formatters
644 644 ip.display_formatter.active_types = ip.display_formatter.format_types
645 645
646 646 ip.user_ns['dummy'] = d = DummyRepr()
647 647 keys = set(['dummy', 'doesnotexist'])
648 648 r = ip.user_variables(keys)
649 649
650 650 nt.assert_equal(keys, set(r.keys()))
651 651 dummy = r['dummy']
652 652 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
653 653 nt.assert_equal(dummy['status'], 'ok')
654 654 data = dummy['data']
655 655 metadata = dummy['metadata']
656 656 nt.assert_equal(data.get('text/html'), d._repr_html_())
657 657 js, jsmd = d._repr_javascript_()
658 658 nt.assert_equal(data.get('application/javascript'), js)
659 659 nt.assert_equal(metadata.get('application/javascript'), jsmd)
660 660
661 661 dne = r['doesnotexist']
662 662 nt.assert_equal(dne['status'], 'error')
663 663 nt.assert_equal(dne['ename'], 'KeyError')
664 664
665 665 # back to text only
666 666 ip.display_formatter.active_types = ['text/plain']
667 667
668 668 def test_user_expression():
669 669 # enable all formatters
670 670 ip.display_formatter.active_types = ip.display_formatter.format_types
671 671 query = {
672 672 'a' : '1 + 2',
673 673 'b' : '1/0',
674 674 }
675 675 r = ip.user_expressions(query)
676 676 import pprint
677 677 pprint.pprint(r)
678 678 nt.assert_equal(set(r.keys()), set(query.keys()))
679 679 a = r['a']
680 680 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
681 681 nt.assert_equal(a['status'], 'ok')
682 682 data = a['data']
683 683 metadata = a['metadata']
684 684 nt.assert_equal(data.get('text/plain'), '3')
685 685
686 686 b = r['b']
687 687 nt.assert_equal(b['status'], 'error')
688 688 nt.assert_equal(b['ename'], 'ZeroDivisionError')
689 689
690 690 # back to text only
691 691 ip.display_formatter.active_types = ['text/plain']
692 692
693 693
694 694
695 695
696 696
697 697 class TestSyntaxErrorTransformer(unittest.TestCase):
698 698 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
699 699
700 700 class SyntaxErrorTransformer(InputTransformer):
701 701
702 702 def push(self, line):
703 703 pos = line.find('syntaxerror')
704 704 if pos >= 0:
705 705 e = SyntaxError('input contains "syntaxerror"')
706 706 e.text = line
707 707 e.offset = pos + 1
708 708 raise e
709 709 return line
710 710
711 711 def reset(self):
712 712 pass
713 713
714 714 def setUp(self):
715 715 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
716 716 ip.input_splitter.python_line_transforms.append(self.transformer)
717 717 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
718 718
719 719 def tearDown(self):
720 720 ip.input_splitter.python_line_transforms.remove(self.transformer)
721 721 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
722 722
723 723 def test_syntaxerror_input_transformer(self):
724 724 with tt.AssertPrints('1234'):
725 725 ip.run_cell('1234')
726 726 with tt.AssertPrints('SyntaxError: invalid syntax'):
727 727 ip.run_cell('1 2 3') # plain python syntax error
728 728 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
729 729 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
730 730 with tt.AssertPrints('3456'):
731 731 ip.run_cell('3456')
732 732
733 733
734 734
General Comments 0
You need to be logged in to leave comments. Login now