##// END OF EJS Templates
run_cell returns an ExecutionResult instance...
Thomas Kluyver -
Show More

The requested changes are too big and content was truncated. Show full diff

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