##// END OF EJS Templates
BUG: Integrate bug fixes from Enthought
Gael Varoquaux -
Show More
@@ -0,0 +1,38 b''
1 # encoding: utf-8
2 """
3 Test the LineFrontEnd
4 """
5
6 __docformat__ = "restructuredtext en"
7
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is
12 # in the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
14
15 from IPython.frontend.linefrontendbase import LineFrontEndBase
16 from copy import deepcopy
17
18 class ConcreteLineFrontEnd(LineFrontEndBase):
19 """ A concrete class to test the LineFrontEndBase.
20 """
21 def capture_output(self):
22 pass
23
24 def release_output(self):
25 pass
26
27
28 def test_is_complete():
29 """ Tests line completion heuristic.
30 """
31 frontend = ConcreteLineFrontEnd()
32 assert not frontend.is_complete('for x in \\')
33 assert not frontend.is_complete('for x in (1, ):')
34 assert frontend.is_complete('for x in (1, ):\n pass')
35
36
37 if __name__ == '__main__':
38 test_is_complete()
@@ -149,8 +149,12 b' class LineFrontEndBase(FrontEndBase):'
149 self.capture_output()
149 self.capture_output()
150 try:
150 try:
151 # Add line returns here, to make sure that the statement is
151 # Add line returns here, to make sure that the statement is
152 # complete.
152 # complete (except if '\' was used).
153 is_complete = codeop.compile_command(string.rstrip() + '\n\n',
153 # This should probably be done in a different place (like
154 # maybe 'prefilter_input' method? For now, this works.
155 clean_string = string.rstrip('\n')
156 if not clean_string.endswith('\\'): clean_string +='\n\n'
157 is_complete = codeop.compile_command(clean_string,
154 "<string>", "exec")
158 "<string>", "exec")
155 self.release_output()
159 self.release_output()
156 except Exception, e:
160 except Exception, e:
@@ -270,15 +274,15 b' class LineFrontEndBase(FrontEndBase):'
270 symbols_per_line = max(1, chars_per_line/max_len)
274 symbols_per_line = max(1, chars_per_line/max_len)
271
275
272 pos = 1
276 pos = 1
273 buf = []
277 completion_string = []
274 for symbol in possibilities:
278 for symbol in possibilities:
275 if pos < symbols_per_line:
279 if pos < symbols_per_line:
276 buf.append(symbol.ljust(max_len))
280 completion_string.append(symbol.ljust(max_len))
277 pos += 1
281 pos += 1
278 else:
282 else:
279 buf.append(symbol.rstrip() + '\n')
283 completion_string.append(symbol.rstrip() + '\n')
280 pos = 1
284 pos = 1
281 self.write(''.join(buf))
285 self.write(''.join(completion_string))
282 self.new_prompt(self.input_prompt_template.substitute(
286 self.new_prompt(self.input_prompt_template.substitute(
283 number=self.last_result['number'] + 1))
287 number=self.last_result['number'] + 1))
284 self.input_buffer = new_line
288 self.input_buffer = new_line
@@ -71,6 +71,13 b' class PrefilterFrontEnd(LineFrontEndBase):'
71 ipython0: an optional ipython0 instance to use for command
71 ipython0: an optional ipython0 instance to use for command
72 prefiltering and completion.
72 prefiltering and completion.
73 """
73 """
74 # This is a hack to avoid the IPython exception hook to trigger
75 # on exceptions (https://bugs.launchpad.net/bugs/337105)
76 # XXX: This is horrible: module-leve monkey patching -> side
77 # effects.
78 from IPython import iplib
79 iplib.InteractiveShell.isthreaded = True
80
74 LineFrontEndBase.__init__(self, *args, **kwargs)
81 LineFrontEndBase.__init__(self, *args, **kwargs)
75 self.shell.output_trap = RedirectorOutputTrap(
82 self.shell.output_trap = RedirectorOutputTrap(
76 out_callback=self.write,
83 out_callback=self.write,
@@ -184,7 +191,6 b' class PrefilterFrontEnd(LineFrontEndBase):'
184 # FIXME: This should be factored out in the linefrontendbase
191 # FIXME: This should be factored out in the linefrontendbase
185 # method.
192 # method.
186 word = self._get_completion_text(line)
193 word = self._get_completion_text(line)
187 word = line.split('\n')[-1].split(' ')[-1]
188 print 'Completion', word
194 print 'Completion', word
189 completions = self.ipython0.complete(word)
195 completions = self.ipython0.complete(word)
190 # FIXME: The proper sort should be done in the complete method.
196 # FIXME: The proper sort should be done in the complete method.
@@ -15,9 +15,27 b' __docformat__ = "restructuredtext en"'
15 from cStringIO import StringIO
15 from cStringIO import StringIO
16 import string
16 import string
17
17
18 from nose.tools import assert_equal
19
18 from IPython.ipapi import get as get_ipython0
20 from IPython.ipapi import get as get_ipython0
19 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
21 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
20 from copy import deepcopy
22 from copy import copy, deepcopy
23
24 def safe_deepcopy(d):
25 """ Deep copy every key of the given dict, when possible. Elsewhere
26 do a copy.
27 """
28 copied_d = dict()
29 for key, value in d.iteritems():
30 try:
31 copied_d[key] = deepcopy(value)
32 except:
33 try:
34 copied_d[key] = copy(value)
35 except:
36 copied_d[key] = value
37 return copied_d
38
21
39
22 class TestPrefilterFrontEnd(PrefilterFrontEnd):
40 class TestPrefilterFrontEnd(PrefilterFrontEnd):
23
41
@@ -26,16 +44,8 b' class TestPrefilterFrontEnd(PrefilterFrontEnd):'
26 banner = ''
44 banner = ''
27
45
28 def __init__(self):
46 def __init__(self):
29 ipython0 = get_ipython0().IP
30 self.out = StringIO()
47 self.out = StringIO()
31 PrefilterFrontEnd.__init__(self, ipython0=ipython0)
48 PrefilterFrontEnd.__init__(self)
32 # Clean up the namespace for isolation between tests
33 user_ns = self.ipython0.user_ns
34 # We need to keep references to things so that they don't
35 # get garbage collected (this stinks).
36 self.shadow_ns = dict()
37 for i in self.ipython0.magic_who_ls():
38 self.shadow_ns[i] = user_ns.pop(i)
39 # Some more code for isolation (yeah, crazy)
49 # Some more code for isolation (yeah, crazy)
40 self._on_enter()
50 self._on_enter()
41 self.out.flush()
51 self.out.flush()
@@ -52,17 +62,31 b' class TestPrefilterFrontEnd(PrefilterFrontEnd):'
52
62
53 def isolate_ipython0(func):
63 def isolate_ipython0(func):
54 """ Decorator to isolate execution that involves an iptyhon0.
64 """ Decorator to isolate execution that involves an iptyhon0.
65
66 Notes
67 ------
68
69 Apply only to functions with no arguments. Nose skips functions
70 with arguments.
55 """
71 """
56 def my_func(*args, **kwargs):
72 def my_func():
57 ipython0 = get_ipython0().IP
73 iplib = get_ipython0()
58 user_ns = deepcopy(ipython0.user_ns)
74 if iplib is None:
59 global_ns = deepcopy(ipython0.global_ns)
75 return func()
76 ipython0 = iplib.IP
77 global_ns = safe_deepcopy(ipython0.user_global_ns)
78 user_ns = safe_deepcopy(ipython0.user_ns)
60 try:
79 try:
61 func(*args, **kwargs)
80 out = func()
62 finally:
81 finally:
63 ipython0.user_ns = user_ns
82 ipython0.user_ns = user_ns
64 ipython0.global_ns = global_ns
83 ipython0.user_global_ns = global_ns
84 # Undo the hack at creation of PrefilterFrontEnd
85 from IPython import iplib
86 iplib.InteractiveShell.isthreaded = False
87 return out
65
88
89 my_func.__name__ = func.__name__
66 return my_func
90 return my_func
67
91
68
92
@@ -74,7 +98,7 b' def test_execution():'
74 f.input_buffer = 'print 1'
98 f.input_buffer = 'print 1'
75 f._on_enter()
99 f._on_enter()
76 out_value = f.out.getvalue()
100 out_value = f.out.getvalue()
77 assert out_value == '1\n'
101 assert_equal(out_value, '1\n')
78
102
79
103
80 @isolate_ipython0
104 @isolate_ipython0
@@ -87,20 +111,20 b' def test_multiline():'
87 f.input_buffer += 'print 1'
111 f.input_buffer += 'print 1'
88 f._on_enter()
112 f._on_enter()
89 out_value = f.out.getvalue()
113 out_value = f.out.getvalue()
90 assert out_value == ''
114 assert_equal(out_value, '')
91 f._on_enter()
115 f._on_enter()
92 out_value = f.out.getvalue()
116 out_value = f.out.getvalue()
93 assert out_value == '1\n'
117 assert_equal(out_value, '1\n')
94 f = TestPrefilterFrontEnd()
118 f = TestPrefilterFrontEnd()
95 f.input_buffer='(1 +'
119 f.input_buffer='(1 +'
96 f._on_enter()
120 f._on_enter()
97 f.input_buffer += '0)'
121 f.input_buffer += '0)'
98 f._on_enter()
122 f._on_enter()
99 out_value = f.out.getvalue()
123 out_value = f.out.getvalue()
100 assert out_value == ''
124 assert_equal(out_value, '')
101 f._on_enter()
125 f._on_enter()
102 out_value = f.out.getvalue()
126 out_value = f.out.getvalue()
103 assert out_value == '1\n'
127 assert_equal(out_value, '1\n')
104
128
105
129
106 @isolate_ipython0
130 @isolate_ipython0
@@ -113,13 +137,13 b' def test_capture():'
113 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
137 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
114 f._on_enter()
138 f._on_enter()
115 out_value = f.out.getvalue()
139 out_value = f.out.getvalue()
116 assert out_value == '1'
140 assert_equal(out_value, '1')
117 f = TestPrefilterFrontEnd()
141 f = TestPrefilterFrontEnd()
118 f.input_buffer = \
142 f.input_buffer = \
119 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
143 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
120 f._on_enter()
144 f._on_enter()
121 out_value = f.out.getvalue()
145 out_value = f.out.getvalue()
122 assert out_value == '1'
146 assert_equal(out_value, '1')
123
147
124
148
125 @isolate_ipython0
149 @isolate_ipython0
@@ -132,7 +156,7 b' def test_magic():'
132 f.input_buffer += '%who'
156 f.input_buffer += '%who'
133 f._on_enter()
157 f._on_enter()
134 out_value = f.out.getvalue()
158 out_value = f.out.getvalue()
135 assert out_value == 'Interactive namespace is empty.\n'
159 assert_equal(out_value, 'Interactive namespace is empty.\n')
136
160
137
161
138 @isolate_ipython0
162 @isolate_ipython0
@@ -156,8 +180,8 b' def test_help():'
156
180
157
181
158 @isolate_ipython0
182 @isolate_ipython0
159 def test_completion():
183 def test_completion_simple():
160 """ Test command-line completion.
184 """ Test command-line completion on trivial examples.
161 """
185 """
162 f = TestPrefilterFrontEnd()
186 f = TestPrefilterFrontEnd()
163 f.input_buffer = 'zzza = 1'
187 f.input_buffer = 'zzza = 1'
@@ -167,8 +191,47 b' def test_completion():'
167 f.input_buffer = 'zz'
191 f.input_buffer = 'zz'
168 f.complete_current_input()
192 f.complete_current_input()
169 out_value = f.out.getvalue()
193 out_value = f.out.getvalue()
170 assert out_value == '\nzzza zzzb '
194 assert_equal(out_value, '\nzzza zzzb ')
171 assert f.input_buffer == 'zzz'
195 assert_equal(f.input_buffer, 'zzz')
196
197
198 @isolate_ipython0
199 def test_completion_parenthesis():
200 """ Test command-line completion when a parenthesis is open.
201 """
202 f = TestPrefilterFrontEnd()
203 f.input_buffer = 'zzza = 1'
204 f._on_enter()
205 f.input_buffer = 'zzzb = 2'
206 f._on_enter()
207 f.input_buffer = 'map(zz'
208 f.complete_current_input()
209 out_value = f.out.getvalue()
210 assert_equal(out_value, '\nzzza zzzb ')
211 assert_equal(f.input_buffer, 'map(zzz')
212
213
214 @isolate_ipython0
215 def test_completion_indexing():
216 """ Test command-line completion when indexing on objects.
217 """
218 f = TestPrefilterFrontEnd()
219 f.input_buffer = 'a = [0]'
220 f._on_enter()
221 f.input_buffer = 'a[0].'
222 f.complete_current_input()
223 assert_equal(f.input_buffer, 'a[0].__')
224
225
226 @isolate_ipython0
227 def test_completion_equal():
228 """ Test command-line completion when the delimiter is "=", not " ".
229 """
230 f = TestPrefilterFrontEnd()
231 f.input_buffer = 'a=1.'
232 f.complete_current_input()
233 assert_equal(f.input_buffer, 'a=1.__')
234
172
235
173
236
174 if __name__ == '__main__':
237 if __name__ == '__main__':
@@ -177,4 +240,5 b" if __name__ == '__main__':"
177 test_execution()
240 test_execution()
178 test_multiline()
241 test_multiline()
179 test_capture()
242 test_capture()
180 test_completion()
243 test_completion_simple()
244 test_completion_complex()
@@ -250,11 +250,8 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
250 if (self.AutoCompActive() and line and not line[-1] == '.') \
250 if (self.AutoCompActive() and line and not line[-1] == '.') \
251 or create==True:
251 or create==True:
252 suggestion, completions = self.complete(line)
252 suggestion, completions = self.complete(line)
253 offset=0
254 if completions:
253 if completions:
255 complete_sep = re.compile('[\s\{\}\[\]\(\)\= ,:]')
254 offset = len(self._get_completion_text(line))
256 residual = complete_sep.split(line)[-1]
257 offset = len(residual)
258 self.pop_completion(completions, offset=offset)
255 self.pop_completion(completions, offset=offset)
259 if self.debug:
256 if self.debug:
260 print >>sys.__stdout__, completions
257 print >>sys.__stdout__, completions
General Comments 0
You need to be logged in to leave comments. Login now