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 | 149 | self.capture_output() |
|
150 | 150 | try: |
|
151 | 151 | # Add line returns here, to make sure that the statement is |
|
152 | # complete. | |
|
153 | is_complete = codeop.compile_command(string.rstrip() + '\n\n', | |
|
152 | # complete (except if '\' was used). | |
|
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 | 158 | "<string>", "exec") |
|
155 | 159 | self.release_output() |
|
156 | 160 | except Exception, e: |
@@ -270,15 +274,15 b' class LineFrontEndBase(FrontEndBase):' | |||
|
270 | 274 | symbols_per_line = max(1, chars_per_line/max_len) |
|
271 | 275 | |
|
272 | 276 | pos = 1 |
|
273 | buf = [] | |
|
277 | completion_string = [] | |
|
274 | 278 | for symbol in possibilities: |
|
275 | 279 | if pos < symbols_per_line: |
|
276 |
|
|
|
280 | completion_string.append(symbol.ljust(max_len)) | |
|
277 | 281 | pos += 1 |
|
278 | 282 | else: |
|
279 |
|
|
|
283 | completion_string.append(symbol.rstrip() + '\n') | |
|
280 | 284 | pos = 1 |
|
281 |
self.write(''.join( |
|
|
285 | self.write(''.join(completion_string)) | |
|
282 | 286 | self.new_prompt(self.input_prompt_template.substitute( |
|
283 | 287 | number=self.last_result['number'] + 1)) |
|
284 | 288 | self.input_buffer = new_line |
@@ -71,6 +71,13 b' class PrefilterFrontEnd(LineFrontEndBase):' | |||
|
71 | 71 | ipython0: an optional ipython0 instance to use for command |
|
72 | 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 | 81 | LineFrontEndBase.__init__(self, *args, **kwargs) |
|
75 | 82 | self.shell.output_trap = RedirectorOutputTrap( |
|
76 | 83 | out_callback=self.write, |
@@ -184,7 +191,6 b' class PrefilterFrontEnd(LineFrontEndBase):' | |||
|
184 | 191 | # FIXME: This should be factored out in the linefrontendbase |
|
185 | 192 | # method. |
|
186 | 193 | word = self._get_completion_text(line) |
|
187 | word = line.split('\n')[-1].split(' ')[-1] | |
|
188 | 194 | print 'Completion', word |
|
189 | 195 | completions = self.ipython0.complete(word) |
|
190 | 196 | # FIXME: The proper sort should be done in the complete method. |
@@ -15,9 +15,27 b' __docformat__ = "restructuredtext en"' | |||
|
15 | 15 | from cStringIO import StringIO |
|
16 | 16 | import string |
|
17 | 17 | |
|
18 | from nose.tools import assert_equal | |
|
19 | ||
|
18 | 20 | from IPython.ipapi import get as get_ipython0 |
|
19 | 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 | 40 | class TestPrefilterFrontEnd(PrefilterFrontEnd): |
|
23 | 41 | |
@@ -26,16 +44,8 b' class TestPrefilterFrontEnd(PrefilterFrontEnd):' | |||
|
26 | 44 | banner = '' |
|
27 | 45 | |
|
28 | 46 | def __init__(self): |
|
29 | ipython0 = get_ipython0().IP | |
|
30 | 47 | self.out = StringIO() |
|
31 |
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) | |
|
48 | PrefilterFrontEnd.__init__(self) | |
|
39 | 49 | # Some more code for isolation (yeah, crazy) |
|
40 | 50 | self._on_enter() |
|
41 | 51 | self.out.flush() |
@@ -52,17 +62,31 b' class TestPrefilterFrontEnd(PrefilterFrontEnd):' | |||
|
52 | 62 | |
|
53 | 63 | def isolate_ipython0(func): |
|
54 | 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( |
|
|
57 |
ip |
|
|
58 | user_ns = deepcopy(ipython0.user_ns) | |
|
59 | global_ns = deepcopy(ipython0.global_ns) | |
|
72 | def my_func(): | |
|
73 | iplib = get_ipython0() | |
|
74 | if iplib is None: | |
|
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 | 79 | try: |
|
61 |
func( |
|
|
80 | out = func() | |
|
62 | 81 | finally: |
|
63 | 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 | 90 | return my_func |
|
67 | 91 | |
|
68 | 92 | |
@@ -74,7 +98,7 b' def test_execution():' | |||
|
74 | 98 | f.input_buffer = 'print 1' |
|
75 | 99 | f._on_enter() |
|
76 | 100 | out_value = f.out.getvalue() |
|
77 |
assert |
|
|
101 | assert_equal(out_value, '1\n') | |
|
78 | 102 | |
|
79 | 103 | |
|
80 | 104 | @isolate_ipython0 |
@@ -87,20 +111,20 b' def test_multiline():' | |||
|
87 | 111 | f.input_buffer += 'print 1' |
|
88 | 112 | f._on_enter() |
|
89 | 113 | out_value = f.out.getvalue() |
|
90 |
assert |
|
|
114 | assert_equal(out_value, '') | |
|
91 | 115 | f._on_enter() |
|
92 | 116 | out_value = f.out.getvalue() |
|
93 |
assert |
|
|
117 | assert_equal(out_value, '1\n') | |
|
94 | 118 | f = TestPrefilterFrontEnd() |
|
95 | 119 | f.input_buffer='(1 +' |
|
96 | 120 | f._on_enter() |
|
97 | 121 | f.input_buffer += '0)' |
|
98 | 122 | f._on_enter() |
|
99 | 123 | out_value = f.out.getvalue() |
|
100 |
assert |
|
|
124 | assert_equal(out_value, '') | |
|
101 | 125 | f._on_enter() |
|
102 | 126 | out_value = f.out.getvalue() |
|
103 |
assert |
|
|
127 | assert_equal(out_value, '1\n') | |
|
104 | 128 | |
|
105 | 129 | |
|
106 | 130 | @isolate_ipython0 |
@@ -113,13 +137,13 b' def test_capture():' | |||
|
113 | 137 | 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()' |
|
114 | 138 | f._on_enter() |
|
115 | 139 | out_value = f.out.getvalue() |
|
116 |
assert |
|
|
140 | assert_equal(out_value, '1') | |
|
117 | 141 | f = TestPrefilterFrontEnd() |
|
118 | 142 | f.input_buffer = \ |
|
119 | 143 | 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()' |
|
120 | 144 | f._on_enter() |
|
121 | 145 | out_value = f.out.getvalue() |
|
122 |
assert |
|
|
146 | assert_equal(out_value, '1') | |
|
123 | 147 | |
|
124 | 148 | |
|
125 | 149 | @isolate_ipython0 |
@@ -132,7 +156,7 b' def test_magic():' | |||
|
132 | 156 | f.input_buffer += '%who' |
|
133 | 157 | f._on_enter() |
|
134 | 158 | out_value = f.out.getvalue() |
|
135 |
assert |
|
|
159 | assert_equal(out_value, 'Interactive namespace is empty.\n') | |
|
136 | 160 | |
|
137 | 161 | |
|
138 | 162 | @isolate_ipython0 |
@@ -156,8 +180,8 b' def test_help():' | |||
|
156 | 180 | |
|
157 | 181 | |
|
158 | 182 | @isolate_ipython0 |
|
159 | def test_completion(): | |
|
160 | """ Test command-line completion. | |
|
183 | def test_completion_simple(): | |
|
184 | """ Test command-line completion on trivial examples. | |
|
161 | 185 | """ |
|
162 | 186 | f = TestPrefilterFrontEnd() |
|
163 | 187 | f.input_buffer = 'zzza = 1' |
@@ -167,8 +191,47 b' def test_completion():' | |||
|
167 | 191 | f.input_buffer = 'zz' |
|
168 | 192 | f.complete_current_input() |
|
169 | 193 | out_value = f.out.getvalue() |
|
170 |
assert |
|
|
171 |
assert |
|
|
194 | assert_equal(out_value, '\nzzza zzzb ') | |
|
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 | 237 | if __name__ == '__main__': |
@@ -177,4 +240,5 b" if __name__ == '__main__':" | |||
|
177 | 240 | test_execution() |
|
178 | 241 | test_multiline() |
|
179 | 242 | test_capture() |
|
180 | test_completion() | |
|
243 | test_completion_simple() | |
|
244 | test_completion_complex() |
@@ -250,11 +250,8 b' class WxController(ConsoleWidget, PrefilterFrontEnd):' | |||
|
250 | 250 | if (self.AutoCompActive() and line and not line[-1] == '.') \ |
|
251 | 251 | or create==True: |
|
252 | 252 | suggestion, completions = self.complete(line) |
|
253 | offset=0 | |
|
254 | 253 | if completions: |
|
255 | complete_sep = re.compile('[\s\{\}\[\]\(\)\= ,:]') | |
|
256 | residual = complete_sep.split(line)[-1] | |
|
257 | offset = len(residual) | |
|
254 | offset = len(self._get_completion_text(line)) | |
|
258 | 255 | self.pop_completion(completions, offset=offset) |
|
259 | 256 | if self.debug: |
|
260 | 257 | print >>sys.__stdout__, completions |
General Comments 0
You need to be logged in to leave comments.
Login now