##// END OF EJS Templates
Merge: fixes to testing for wx frontend.
Gael Varoquaux -
r1536:c3c75c6c merge
parent child Browse files
Show More
@@ -1,221 +1,223 b''
1 1 """
2 2 Frontend class that uses IPython0 to prefilter the inputs.
3 3
4 4 Using the IPython0 mechanism gives us access to the magics.
5 5
6 6 This is a transitory class, used here to do the transition between
7 7 ipython0 and ipython1. This class is meant to be short-lived as more
8 8 functionnality is abstracted out of ipython0 in reusable functions and
9 9 is added on the interpreter. This class can be a used to guide this
10 10 refactoring.
11 11 """
12 12 __docformat__ = "restructuredtext en"
13 13
14 14 #-------------------------------------------------------------------------------
15 15 # Copyright (C) 2008 The IPython Development Team
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-------------------------------------------------------------------------------
20 20
21 21 #-------------------------------------------------------------------------------
22 22 # Imports
23 23 #-------------------------------------------------------------------------------
24 24 import sys
25 25
26 26 from linefrontendbase import LineFrontEndBase, common_prefix
27 27
28 28 from IPython.ipmaker import make_IPython
29 29 from IPython.ipapi import IPApi
30 30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
31 31
32 32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
33 33
34 34 from IPython.genutils import Term
35 35 import pydoc
36 36 import os
37 37
38 38
39 39 def mk_system_call(system_call_function, command):
40 40 """ given a os.system replacement, and a leading string command,
41 41 returns a function that will execute the command with the given
42 42 argument string.
43 43 """
44 44 def my_system_call(args):
45 45 system_call_function("%s %s" % (command, args))
46 46 return my_system_call
47 47
48 48 #-------------------------------------------------------------------------------
49 49 # Frontend class using ipython0 to do the prefiltering.
50 50 #-------------------------------------------------------------------------------
51 51 class PrefilterFrontEnd(LineFrontEndBase):
52 52 """ Class that uses ipython0 to do prefilter the input, do the
53 53 completion and the magics.
54 54
55 55 The core trick is to use an ipython0 instance to prefilter the
56 56 input, and share the namespace between the interpreter instance used
57 57 to execute the statements and the ipython0 used for code
58 58 completion...
59 59 """
60 60
61 61 def __init__(self, ipython0=None, *args, **kwargs):
62 62 """ Parameters:
63 63 -----------
64 64
65 65 ipython0: an optional ipython0 instance to use for command
66 66 prefiltering and completion.
67 67 """
68 68 self.save_output_hooks()
69 69 if ipython0 is None:
70 70 # Instanciate an IPython0 interpreter to be able to use the
71 71 # prefiltering.
72 72 # XXX: argv=[] is a bit bold.
73 73 ipython0 = make_IPython(argv=[])
74 74 self.ipython0 = ipython0
75 75 # Set the pager:
76 76 self.ipython0.set_hook('show_in_pager',
77 77 lambda s, string: self.write("\n" + string))
78 78 self.ipython0.write = self.write
79 79 self._ip = _ip = IPApi(self.ipython0)
80 80 # Make sure the raw system call doesn't get called, as we don't
81 81 # have a stdin accessible.
82 82 self._ip.system = self.system_call
83 83 # XXX: Muck around with magics so that they work better
84 84 # in our environment
85 85 self.ipython0.magic_ls = mk_system_call(self.system_call,
86 86 'ls -CF')
87 87 # And now clean up the mess created by ipython0
88 88 self.release_output()
89 89 if not 'banner' in kwargs and self.banner is None:
90 90 kwargs['banner'] = self.ipython0.BANNER + """
91 91 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
92 92
93 93 LineFrontEndBase.__init__(self, *args, **kwargs)
94 94 # XXX: Hack: mix the two namespaces
95 self.shell.user_ns = self.ipython0.user_ns
96 self.shell.user_global_ns = self.ipython0.user_global_ns
95 self.shell.user_ns.update(self.ipython0.user_ns)
96 self.ipython0.user_ns = self.shell.user_ns
97 self.shell.user_global_ns.update(self.ipython0.user_global_ns)
98 self.ipython0.user_global_ns = self.shell.user_global_ns
97 99
98 100 self.shell.output_trap = RedirectorOutputTrap(
99 101 out_callback=self.write,
100 102 err_callback=self.write,
101 103 )
102 104 self.shell.traceback_trap = SyncTracebackTrap(
103 105 formatters=self.shell.traceback_trap.formatters,
104 106 )
105 107
106 108 #--------------------------------------------------------------------------
107 109 # FrontEndBase interface
108 110 #--------------------------------------------------------------------------
109 111
110 112 def show_traceback(self):
111 113 """ Use ipython0 to capture the last traceback and display it.
112 114 """
113 115 self.capture_output()
114 116 self.ipython0.showtraceback()
115 117 self.release_output()
116 118
117 119
118 120 def execute(self, python_string, raw_string=None):
119 121 if self.debug:
120 122 print 'Executing Python code:', repr(python_string)
121 123 self.capture_output()
122 124 LineFrontEndBase.execute(self, python_string,
123 125 raw_string=raw_string)
124 126 self.release_output()
125 127
126 128
127 129 def save_output_hooks(self):
128 130 """ Store all the output hooks we can think of, to be able to
129 131 restore them.
130 132
131 133 We need to do this early, as starting the ipython0 instance will
132 134 screw ouput hooks.
133 135 """
134 136 self.__old_cout_write = Term.cout.write
135 137 self.__old_cerr_write = Term.cerr.write
136 138 self.__old_stdout = sys.stdout
137 139 self.__old_stderr= sys.stderr
138 140 self.__old_help_output = pydoc.help.output
139 141 self.__old_display_hook = sys.displayhook
140 142
141 143
142 144 def capture_output(self):
143 145 """ Capture all the output mechanisms we can think of.
144 146 """
145 147 self.save_output_hooks()
146 148 Term.cout.write = self.write
147 149 Term.cerr.write = self.write
148 150 sys.stdout = Term.cout
149 151 sys.stderr = Term.cerr
150 152 pydoc.help.output = self.shell.output_trap.out
151 153
152 154
153 155 def release_output(self):
154 156 """ Release all the different captures we have made.
155 157 """
156 158 Term.cout.write = self.__old_cout_write
157 159 Term.cerr.write = self.__old_cerr_write
158 160 sys.stdout = self.__old_stdout
159 161 sys.stderr = self.__old_stderr
160 162 pydoc.help.output = self.__old_help_output
161 163 sys.displayhook = self.__old_display_hook
162 164
163 165
164 166 def complete(self, line):
165 167 word = line.split('\n')[-1].split(' ')[-1]
166 168 completions = self.ipython0.complete(word)
167 169 # FIXME: The proper sort should be done in the complete method.
168 170 key = lambda x: x.replace('_', '')
169 171 completions.sort(key=key)
170 172 if completions:
171 173 prefix = common_prefix(completions)
172 174 line = line[:-len(word)] + prefix
173 175 return line, completions
174 176
175 177
176 178 #--------------------------------------------------------------------------
177 179 # LineFrontEndBase interface
178 180 #--------------------------------------------------------------------------
179 181
180 182 def prefilter_input(self, input_string):
181 183 """ Using IPython0 to prefilter the commands to turn them
182 184 in executable statements that are valid Python strings.
183 185 """
184 186 input_string = LineFrontEndBase.prefilter_input(self, input_string)
185 187 filtered_lines = []
186 188 # The IPython0 prefilters sometime produce output. We need to
187 189 # capture it.
188 190 self.capture_output()
189 191 self.last_result = dict(number=self.prompt_number)
190 192 try:
191 193 for line in input_string.split('\n'):
192 194 filtered_lines.append(
193 195 self.ipython0.prefilter(line, False).rstrip())
194 196 except:
195 197 # XXX: probably not the right thing to do.
196 198 self.ipython0.showsyntaxerror()
197 199 self.after_execute()
198 200 finally:
199 201 self.release_output()
200 202
201 203 # Clean up the trailing whitespace, to avoid indentation errors
202 204 filtered_string = '\n'.join(filtered_lines)
203 205 return filtered_string
204 206
205 207
206 208 #--------------------------------------------------------------------------
207 209 # PrefilterFrontEnd interface
208 210 #--------------------------------------------------------------------------
209 211
210 212 def system_call(self, command_string):
211 213 """ Allows for frontend to define their own system call, to be
212 214 able capture output and redirect input.
213 215 """
214 216 return os.system(command_string)
215 217
216 218
217 219 def do_exit(self):
218 220 """ Exit the shell, cleanup and save the history.
219 221 """
220 222 self.ipython0.atexit_operations()
221 223
@@ -1,157 +1,180 b''
1 1 # encoding: utf-8
2 2 """
3 3 Test process execution and IO redirection.
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2008 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is
12 12 # in the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 from cStringIO import StringIO
16 16 import string
17 17
18 18 from IPython.ipapi import get as get_ipython0
19 19 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
20 from copy import deepcopy
20 21
21 22 class TestPrefilterFrontEnd(PrefilterFrontEnd):
22 23
23 24 input_prompt_template = string.Template('')
24 25 output_prompt_template = string.Template('')
25 26 banner = ''
26 27
27 28 def __init__(self):
28 29 ipython0 = get_ipython0().IP
29 30 self.out = StringIO()
30 31 PrefilterFrontEnd.__init__(self, ipython0=ipython0)
31 32 # Clean up the namespace for isolation between tests
32 33 user_ns = self.ipython0.user_ns
33 34 # We need to keep references to things so that they don't
34 35 # get garbage collected (this stinks).
35 36 self.shadow_ns = dict()
36 37 for i in self.ipython0.magic_who_ls():
37 38 self.shadow_ns[i] = user_ns.pop(i)
38 39 # Some more code for isolation (yeah, crazy)
39 40 self._on_enter()
40 41 self.out.flush()
41 42 self.out.reset()
42 43 self.out.truncate()
43 44
44 45 def write(self, string, *args, **kwargs):
45 46 self.out.write(string)
46 47
47 48 def _on_enter(self):
48 49 self.input_buffer += '\n'
49 50 PrefilterFrontEnd._on_enter(self)
50 51
51 52
53 def isolate_ipython0(func):
54 """ Decorator to isolate execution that involves an iptyhon0.
55 """
56 def my_func(*args, **kwargs):
57 ipython0 = get_ipython0().IP
58 user_ns = deepcopy(ipython0.user_ns)
59 global_ns = deepcopy(ipython0.global_ns)
60 try:
61 func(*args, **kwargs)
62 finally:
63 ipython0.user_ns = user_ns
64 ipython0.global_ns = global_ns
65
66 return my_func
67
68
69 @isolate_ipython0
52 70 def test_execution():
53 71 """ Test execution of a command.
54 72 """
55 73 f = TestPrefilterFrontEnd()
56 74 f.input_buffer = 'print 1'
57 75 f._on_enter()
58 76 out_value = f.out.getvalue()
59 77 assert out_value == '1\n'
60 78
61 79
80 @isolate_ipython0
62 81 def test_multiline():
63 82 """ Test execution of a multiline command.
64 83 """
65 84 f = TestPrefilterFrontEnd()
66 85 f.input_buffer = 'if True:'
67 86 f._on_enter()
68 87 f.input_buffer += 'print 1'
69 88 f._on_enter()
70 89 out_value = f.out.getvalue()
71 90 assert out_value == ''
72 91 f._on_enter()
73 92 out_value = f.out.getvalue()
74 93 assert out_value == '1\n'
75 94 f = TestPrefilterFrontEnd()
76 95 f.input_buffer='(1 +'
77 96 f._on_enter()
78 97 f.input_buffer += '0)'
79 98 f._on_enter()
80 99 out_value = f.out.getvalue()
81 100 assert out_value == ''
82 101 f._on_enter()
83 102 out_value = f.out.getvalue()
84 103 assert out_value == '1\n'
85 104
86 105
106 @isolate_ipython0
87 107 def test_capture():
88 108 """ Test the capture of output in different channels.
89 109 """
90 110 # Test on the OS-level stdout, stderr.
91 111 f = TestPrefilterFrontEnd()
92 112 f.input_buffer = \
93 113 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
94 114 f._on_enter()
95 115 out_value = f.out.getvalue()
96 116 assert out_value == '1'
97 117 f = TestPrefilterFrontEnd()
98 118 f.input_buffer = \
99 119 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
100 120 f._on_enter()
101 121 out_value = f.out.getvalue()
102 122 assert out_value == '1'
103 123
104 124
125 @isolate_ipython0
105 126 def test_magic():
106 127 """ Test the magic expansion and history.
107 128
108 129 This test is fairly fragile and will break when magics change.
109 130 """
110 131 f = TestPrefilterFrontEnd()
111 132 f.input_buffer += '%who'
112 133 f._on_enter()
113 134 out_value = f.out.getvalue()
114 135 assert out_value == 'Interactive namespace is empty.\n'
115 136
116 137
138 @isolate_ipython0
117 139 def test_help():
118 140 """ Test object inspection.
119 141 """
120 142 f = TestPrefilterFrontEnd()
121 143 f.input_buffer += "def f():"
122 144 f._on_enter()
123 145 f.input_buffer += "'foobar'"
124 146 f._on_enter()
125 147 f.input_buffer += "pass"
126 148 f._on_enter()
127 149 f._on_enter()
128 150 f.input_buffer += "f?"
129 151 f._on_enter()
130 152 assert 'traceback' not in f.last_result
131 153 ## XXX: ipython doctest magic breaks this. I have no clue why
132 154 #out_value = f.out.getvalue()
133 155 #assert out_value.split()[-1] == 'foobar'
134 156
135 157
158 @isolate_ipython0
136 159 def test_completion():
137 160 """ Test command-line completion.
138 161 """
139 162 f = TestPrefilterFrontEnd()
140 163 f.input_buffer = 'zzza = 1'
141 164 f._on_enter()
142 165 f.input_buffer = 'zzzb = 2'
143 166 f._on_enter()
144 167 f.input_buffer = 'zz'
145 168 f.complete_current_input()
146 169 out_value = f.out.getvalue()
147 170 assert out_value == '\nzzza zzzb '
148 171 assert f.input_buffer == 'zzz'
149 172
150 173
151 174 if __name__ == '__main__':
152 175 test_magic()
153 176 test_help()
154 177 test_execution()
155 178 test_multiline()
156 179 test_capture()
157 180 test_completion()
General Comments 0
You need to be logged in to leave comments. Login now