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