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