##// END OF EJS Templates
Fix problems with side effects and python 2.6....
Fernando Perez -
Show More
@@ -1,252 +1,266 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Test process execution and IO redirection.
3 Test process execution and IO redirection.
4 """
4 """
5
5
6 __docformat__ = "restructuredtext en"
6 __docformat__ = "restructuredtext en"
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is
11 # Distributed under the terms of the BSD License. The full license is
12 # in the file COPYING, distributed as part of this software.
12 # in the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 from copy import copy, deepcopy
15 from copy import copy, deepcopy
16 from cStringIO import StringIO
16 from cStringIO import StringIO
17 import string
17 import string
18 import sys
18
19
19 from nose.tools import assert_equal
20 from nose.tools import assert_equal
20
21
21 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
22 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
22 from IPython.ipapi import get as get_ipython0
23 from IPython.ipapi import get as get_ipython0
23 from IPython.testing.plugin.ipdoctest import default_argv
24 from IPython.testing.plugin.ipdoctest import default_argv
24
25
25
26
26 def safe_deepcopy(d):
27 """ Deep copy every key of the given dict, when possible. Elsewhere
28 do a copy.
29 """
30 copied_d = dict()
31 for key, value in d.iteritems():
32 try:
33 copied_d[key] = deepcopy(value)
34 except:
35 try:
36 copied_d[key] = copy(value)
37 except:
38 copied_d[key] = value
39 return copied_d
40
41
42 class TestPrefilterFrontEnd(PrefilterFrontEnd):
27 class TestPrefilterFrontEnd(PrefilterFrontEnd):
43
28
44 input_prompt_template = string.Template('')
29 input_prompt_template = string.Template('')
45 output_prompt_template = string.Template('')
30 output_prompt_template = string.Template('')
46 banner = ''
31 banner = ''
47
32
48 def __init__(self):
33 def __init__(self):
49 self.out = StringIO()
34 self.out = StringIO()
50 PrefilterFrontEnd.__init__(self,argv=default_argv())
35 PrefilterFrontEnd.__init__(self,argv=default_argv())
51 # Some more code for isolation (yeah, crazy)
36 # Some more code for isolation (yeah, crazy)
52 self._on_enter()
37 self._on_enter()
53 self.out.flush()
38 self.out.flush()
54 self.out.reset()
39 self.out.reset()
55 self.out.truncate()
40 self.out.truncate()
56
41
57 def write(self, string, *args, **kwargs):
42 def write(self, string, *args, **kwargs):
58 self.out.write(string)
43 self.out.write(string)
59
44
60 def _on_enter(self):
45 def _on_enter(self):
61 self.input_buffer += '\n'
46 self.input_buffer += '\n'
62 PrefilterFrontEnd._on_enter(self)
47 PrefilterFrontEnd._on_enter(self)
63
48
64
49
65 def isolate_ipython0(func):
50 def isolate_ipython0(func):
66 """ Decorator to isolate execution that involves an iptyhon0.
51 """ Decorator to isolate execution that involves an iptyhon0.
67
52
68 Notes
53 Notes
69 -----
54 -----
70
55
71 Apply only to functions with no arguments. Nose skips functions
56 Apply only to functions with no arguments. Nose skips functions
72 with arguments.
57 with arguments.
73 """
58 """
74 def my_func():
59 def my_func():
75 iplib = get_ipython0()
60 ip0 = get_ipython0()
76 if iplib is None:
61 if ip0 is None:
77 return func()
62 return func()
78 ipython0 = iplib.IP
63 # We have a real ipython running...
79 global_ns = safe_deepcopy(ipython0.user_global_ns)
64 user_ns = ip0.IP.user_ns
80 user_ns = safe_deepcopy(ipython0.user_ns)
65 user_global_ns = ip0.IP.user_global_ns
66
67 # Previously the isolation was attempted with a deep copy of the user
68 # dicts, but we found cases where this didn't work correctly. I'm not
69 # quite sure why, but basically it did damage the user namespace, such
70 # that later tests stopped working correctly. Instead we use a simpler
71 # approach, just computing the list of added keys to the namespace and
72 # eliminating those afterwards. Existing keys that may have been
73 # modified remain modified. So far this has proven to be robust.
74
75 # Compute set of old local/global keys
76 old_locals = set(user_ns.keys())
77 old_globals = set(user_global_ns.keys())
81 try:
78 try:
82 out = func()
79 out = func()
83 finally:
80 finally:
84 ipython0.user_ns = user_ns
81 # Find new keys, and if any, remove them
85 ipython0.user_global_ns = global_ns
82 new_locals = set(user_ns.keys()) - old_locals
83 new_globals = set(user_global_ns.keys()) - old_globals
84 for k in new_locals:
85 del user_ns[k]
86 for k in new_globals:
87 del user_global_ns[k]
86 # Undo the hack at creation of PrefilterFrontEnd
88 # Undo the hack at creation of PrefilterFrontEnd
87 from IPython import iplib
89 from IPython import iplib
88 iplib.InteractiveShell.isthreaded = False
90 iplib.InteractiveShell.isthreaded = False
89 return out
91 return out
90
92
91 my_func.__name__ = func.__name__
93 my_func.__name__ = func.__name__
92 return my_func
94 return my_func
93
95
94
96
95 @isolate_ipython0
97 @isolate_ipython0
96 def test_execution():
98 def test_execution():
97 """ Test execution of a command.
99 """ Test execution of a command.
98 """
100 """
99 f = TestPrefilterFrontEnd()
101 f = TestPrefilterFrontEnd()
100 f.input_buffer = 'print 1'
102 f.input_buffer = 'print(1)'
101 f._on_enter()
103 f._on_enter()
102 out_value = f.out.getvalue()
104 out_value = f.out.getvalue()
103 assert_equal(out_value, '1\n')
105 assert_equal(out_value, '1\n')
104
106
105
107
106 @isolate_ipython0
108 @isolate_ipython0
107 def test_multiline():
109 def test_multiline():
108 """ Test execution of a multiline command.
110 """ Test execution of a multiline command.
109 """
111 """
110 f = TestPrefilterFrontEnd()
112 f = TestPrefilterFrontEnd()
111 f.input_buffer = 'if True:'
113 f.input_buffer = 'if True:'
112 f._on_enter()
114 f._on_enter()
113 f.input_buffer += 'print 1'
115 f.input_buffer += 'print 1'
114 f._on_enter()
116 f._on_enter()
115 out_value = f.out.getvalue()
117 out_value = f.out.getvalue()
116 yield assert_equal, out_value, ''
118 yield assert_equal, out_value, ''
117 f._on_enter()
119 f._on_enter()
118 out_value = f.out.getvalue()
120 out_value = f.out.getvalue()
119 yield assert_equal, out_value, '1\n'
121 yield assert_equal, out_value, '1\n'
120 f = TestPrefilterFrontEnd()
122 f = TestPrefilterFrontEnd()
121 f.input_buffer='(1 +'
123 f.input_buffer='(1 +'
122 f._on_enter()
124 f._on_enter()
123 f.input_buffer += '0)'
125 f.input_buffer += '0)'
124 f._on_enter()
126 f._on_enter()
125 out_value = f.out.getvalue()
127 out_value = f.out.getvalue()
126 yield assert_equal, out_value, ''
128 yield assert_equal, out_value, ''
127 f._on_enter()
129 f._on_enter()
128 out_value = f.out.getvalue()
130 out_value = f.out.getvalue()
129 yield assert_equal, out_value, '1\n'
131 yield assert_equal, out_value, '1\n'
130
132
131
133
132 @isolate_ipython0
134 @isolate_ipython0
133 def test_capture():
135 def test_capture():
134 """ Test the capture of output in different channels.
136 """ Test the capture of output in different channels.
135 """
137 """
136 # Test on the OS-level stdout, stderr.
138 # Test on the OS-level stdout, stderr.
137 f = TestPrefilterFrontEnd()
139 f = TestPrefilterFrontEnd()
138 f.input_buffer = \
140 f.input_buffer = \
139 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
141 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
140 f._on_enter()
142 f._on_enter()
141 out_value = f.out.getvalue()
143 out_value = f.out.getvalue()
142 yield assert_equal, out_value, '1'
144 yield assert_equal, out_value, '1'
143 f = TestPrefilterFrontEnd()
145 f = TestPrefilterFrontEnd()
144 f.input_buffer = \
146 f.input_buffer = \
145 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
147 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
146 f._on_enter()
148 f._on_enter()
147 out_value = f.out.getvalue()
149 out_value = f.out.getvalue()
148 yield assert_equal, out_value, '1'
150 yield assert_equal, out_value, '1'
149
151
150
152
151 @isolate_ipython0
153 @isolate_ipython0
152 def test_magic():
154 def test_magic():
153 """ Test the magic expansion and history.
155 """ Test the magic expansion and history.
154
156
155 This test is fairly fragile and will break when magics change.
157 This test is fairly fragile and will break when magics change.
156 """
158 """
157 f = TestPrefilterFrontEnd()
159 f = TestPrefilterFrontEnd()
158 # Before checking the interactive namespace, make sure it's clear (it can
160 # Before checking the interactive namespace, make sure it's clear (it can
159 # otherwise pick up things stored in the user's local db)
161 # otherwise pick up things stored in the user's local db)
160 f.input_buffer += '%reset -f'
162 f.input_buffer += '%reset -f'
161 f._on_enter()
163 f._on_enter()
162 f.complete_current_input()
164 f.complete_current_input()
163 # Now, run the %who magic and check output
165 # Now, run the %who magic and check output
164 f.input_buffer += '%who'
166 f.input_buffer += '%who'
165 f._on_enter()
167 f._on_enter()
166 out_value = f.out.getvalue()
168 out_value = f.out.getvalue()
167 assert_equal(out_value, 'Interactive namespace is empty.\n')
169 assert_equal(out_value, 'Interactive namespace is empty.\n')
168
170
169
171
170 @isolate_ipython0
172 @isolate_ipython0
171 def test_help():
173 def test_help():
172 """ Test object inspection.
174 """ Test object inspection.
173 """
175 """
174 f = TestPrefilterFrontEnd()
176 f = TestPrefilterFrontEnd()
175 f.input_buffer += "def f():"
177 f.input_buffer += "def f():"
176 f._on_enter()
178 f._on_enter()
177 f.input_buffer += "'foobar'"
179 f.input_buffer += "'foobar'"
178 f._on_enter()
180 f._on_enter()
179 f.input_buffer += "pass"
181 f.input_buffer += "pass"
180 f._on_enter()
182 f._on_enter()
181 f._on_enter()
183 f._on_enter()
182 f.input_buffer += "f?"
184 f.input_buffer += "f?"
183 f._on_enter()
185 f._on_enter()
184 assert 'traceback' not in f.last_result
186 assert 'traceback' not in f.last_result
185 ## XXX: ipython doctest magic breaks this. I have no clue why
187 ## XXX: ipython doctest magic breaks this. I have no clue why
186 #out_value = f.out.getvalue()
188 #out_value = f.out.getvalue()
187 #assert out_value.split()[-1] == 'foobar'
189 #assert out_value.split()[-1] == 'foobar'
188
190
189
191
190 @isolate_ipython0
192 @isolate_ipython0
191 def test_completion_simple():
193 def test_completion_simple():
192 """ Test command-line completion on trivial examples.
194 """ Test command-line completion on trivial examples.
193 """
195 """
194 f = TestPrefilterFrontEnd()
196 f = TestPrefilterFrontEnd()
195 f.input_buffer = 'zzza = 1'
197 f.input_buffer = 'zzza = 1'
196 f._on_enter()
198 f._on_enter()
197 f.input_buffer = 'zzzb = 2'
199 f.input_buffer = 'zzzb = 2'
198 f._on_enter()
200 f._on_enter()
199 f.input_buffer = 'zz'
201 f.input_buffer = 'zz'
200 f.complete_current_input()
202 f.complete_current_input()
201 out_value = f.out.getvalue()
203 out_value = f.out.getvalue()
202 yield assert_equal, out_value, '\nzzza zzzb '
204 yield assert_equal, out_value, '\nzzza zzzb '
203 yield assert_equal, f.input_buffer, 'zzz'
205 yield assert_equal, f.input_buffer, 'zzz'
204
206
205
207
206 @isolate_ipython0
208 @isolate_ipython0
207 def test_completion_parenthesis():
209 def test_completion_parenthesis():
208 """ Test command-line completion when a parenthesis is open.
210 """ Test command-line completion when a parenthesis is open.
209 """
211 """
210 f = TestPrefilterFrontEnd()
212 f = TestPrefilterFrontEnd()
211 f.input_buffer = 'zzza = 1'
213 f.input_buffer = 'zzza = 1'
212 f._on_enter()
214 f._on_enter()
213 f.input_buffer = 'zzzb = 2'
215 f.input_buffer = 'zzzb = 2'
214 f._on_enter()
216 f._on_enter()
215 f.input_buffer = 'map(zz'
217 f.input_buffer = 'map(zz'
216 f.complete_current_input()
218 f.complete_current_input()
217 out_value = f.out.getvalue()
219 out_value = f.out.getvalue()
218 yield assert_equal, out_value, '\nzzza zzzb '
220 yield assert_equal, out_value, '\nzzza zzzb '
219 yield assert_equal, f.input_buffer, 'map(zzz'
221 yield assert_equal, f.input_buffer, 'map(zzz'
220
222
221
223
222 @isolate_ipython0
224 @isolate_ipython0
223 def test_completion_indexing():
225 def test_completion_indexing():
224 """ Test command-line completion when indexing on objects.
226 """ Test command-line completion when indexing on objects.
225 """
227 """
226 f = TestPrefilterFrontEnd()
228 f = TestPrefilterFrontEnd()
227 f.input_buffer = 'a = [0]'
229 f.input_buffer = 'a = [0]'
228 f._on_enter()
230 f._on_enter()
229 f.input_buffer = 'a[0].'
231 f.input_buffer = 'a[0].'
230 f.complete_current_input()
232 f.complete_current_input()
231 assert_equal(f.input_buffer, 'a[0].__')
233
234 if sys.version_info[:2] >= (2,6):
235 # In Python 2.6, ints picked up a few non __ methods, so now there are
236 # no completions.
237 assert_equal(f.input_buffer, 'a[0].')
238 else:
239 # Right answer for 2.4/2.5
240 assert_equal(f.input_buffer, 'a[0].__')
232
241
233
242
234 @isolate_ipython0
243 @isolate_ipython0
235 def test_completion_equal():
244 def test_completion_equal():
236 """ Test command-line completion when the delimiter is "=", not " ".
245 """ Test command-line completion when the delimiter is "=", not " ".
237 """
246 """
238 f = TestPrefilterFrontEnd()
247 f = TestPrefilterFrontEnd()
239 f.input_buffer = 'a=1.'
248 f.input_buffer = 'a=1.'
240 f.complete_current_input()
249 f.complete_current_input()
241 assert_equal(f.input_buffer, 'a=1.__')
250 if sys.version_info[:2] >= (2,6):
242
251 # In Python 2.6, ints picked up a few non __ methods, so now there are
252 # no completions.
253 assert_equal(f.input_buffer, 'a=1.')
254 else:
255 # Right answer for 2.4/2.5
256 assert_equal(f.input_buffer, 'a=1.__')
243
257
244
258
245 if __name__ == '__main__':
259 if __name__ == '__main__':
246 test_magic()
260 test_magic()
247 test_help()
261 test_help()
248 test_execution()
262 test_execution()
249 test_multiline()
263 test_multiline()
250 test_capture()
264 test_capture()
251 test_completion_simple()
265 test_completion_simple()
252 test_completion_complex()
266 test_completion_complex()
General Comments 0
You need to be logged in to leave comments. Login now