Show More
@@ -0,0 +1,90 b'' | |||||
|
1 | # encoding: utf-8 | |||
|
2 | """ | |||
|
3 | Test process execution and IO redirection. | |||
|
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.prefilterfrontend import PrefilterFrontEnd | |||
|
16 | from cStringIO import StringIO | |||
|
17 | import string | |||
|
18 | ||||
|
19 | class TestPrefilterFrontEnd(PrefilterFrontEnd): | |||
|
20 | ||||
|
21 | input_prompt_template = string.Template('') | |||
|
22 | output_prompt_template = string.Template('') | |||
|
23 | ||||
|
24 | ||||
|
25 | def __init__(self, edit_buffer=''): | |||
|
26 | self.edit_buffer = edit_buffer | |||
|
27 | self.out = StringIO() | |||
|
28 | PrefilterFrontEnd.__init__(self) | |||
|
29 | ||||
|
30 | def get_current_edit_buffer(self): | |||
|
31 | return self.edit_buffer | |||
|
32 | ||||
|
33 | def add_to_edit_buffer(self, string): | |||
|
34 | self.edit_buffer += string | |||
|
35 | ||||
|
36 | def write(self, string): | |||
|
37 | self.out.write(string) | |||
|
38 | ||||
|
39 | def _on_enter(self): | |||
|
40 | self.add_to_edit_buffer('\n') | |||
|
41 | PrefilterFrontEnd._on_enter(self) | |||
|
42 | ||||
|
43 | ||||
|
44 | def test_execution(): | |||
|
45 | """ Test execution of a command. | |||
|
46 | """ | |||
|
47 | f = TestPrefilterFrontEnd(edit_buffer='print 1\n') | |||
|
48 | f._on_enter() | |||
|
49 | assert f.out.getvalue() == '1\n' | |||
|
50 | ||||
|
51 | ||||
|
52 | def test_multiline(): | |||
|
53 | """ Test execution of a multiline command. | |||
|
54 | """ | |||
|
55 | f = TestPrefilterFrontEnd(edit_buffer='if True:') | |||
|
56 | f._on_enter() | |||
|
57 | f.add_to_edit_buffer('print 1') | |||
|
58 | f._on_enter() | |||
|
59 | assert f.out.getvalue() == '' | |||
|
60 | f._on_enter() | |||
|
61 | assert f.out.getvalue() == '1\n' | |||
|
62 | f = TestPrefilterFrontEnd(edit_buffer='(1 +') | |||
|
63 | f._on_enter() | |||
|
64 | f.add_to_edit_buffer('0)') | |||
|
65 | f._on_enter() | |||
|
66 | assert f.out.getvalue() == '' | |||
|
67 | f._on_enter() | |||
|
68 | assert f.out.getvalue() == '1\n' | |||
|
69 | ||||
|
70 | ||||
|
71 | def test_capture(): | |||
|
72 | """ Test the capture of output in different channels. | |||
|
73 | """ | |||
|
74 | f = TestPrefilterFrontEnd( | |||
|
75 | edit_buffer='import os; out=os.fdopen(1, "w"); out.write("1")') | |||
|
76 | f._on_enter() | |||
|
77 | f._on_enter() | |||
|
78 | assert f.out.getvalue() == '1' | |||
|
79 | f = TestPrefilterFrontEnd( | |||
|
80 | edit_buffer='import os; out=os.fdopen(2, "w"); out.write("1")') | |||
|
81 | f._on_enter() | |||
|
82 | f._on_enter() | |||
|
83 | assert f.out.getvalue() == '1' | |||
|
84 | ||||
|
85 | ||||
|
86 | ||||
|
87 | if __name__ == '__main__': | |||
|
88 | test_execution() | |||
|
89 | test_multiline() | |||
|
90 | test_capture() |
@@ -173,9 +173,6 b' class FrontEndBase(object):' | |||||
173 |
|
173 | |||
174 | history_cursor = 0 |
|
174 | history_cursor = 0 | |
175 |
|
175 | |||
176 | current_indent_level = 0 |
|
|||
177 |
|
||||
178 |
|
||||
179 | input_prompt_template = string.Template(rc.prompt_in1) |
|
176 | input_prompt_template = string.Template(rc.prompt_in1) | |
180 | output_prompt_template = string.Template(rc.prompt_out) |
|
177 | output_prompt_template = string.Template(rc.prompt_out) | |
181 | continuation_prompt_template = string.Template(rc.prompt_in2) |
|
178 | continuation_prompt_template = string.Template(rc.prompt_in2) | |
@@ -336,7 +333,7 b' class FrontEndBase(object):' | |||||
336 | return result when finished. |
|
333 | return result when finished. | |
337 | """ |
|
334 | """ | |
338 |
|
335 | |||
339 | return result |
|
336 | raise NotImplementedError | |
340 |
|
337 | |||
341 |
|
338 | |||
342 | def render_result(self, result): |
|
339 | def render_result(self, result): | |
@@ -347,7 +344,7 b' class FrontEndBase(object):' | |||||
347 | should thus return result when finished. |
|
344 | should thus return result when finished. | |
348 | """ |
|
345 | """ | |
349 |
|
346 | |||
350 | return result |
|
347 | raise NotImplementedError | |
351 |
|
348 | |||
352 |
|
349 | |||
353 | def render_error(self, failure): |
|
350 | def render_error(self, failure): | |
@@ -358,7 +355,7 b' class FrontEndBase(object):' | |||||
358 | should thus return result when finished. |
|
355 | should thus return result when finished. | |
359 | """ |
|
356 | """ | |
360 |
|
357 | |||
361 | return failure |
|
358 | raise NotImplementedError | |
362 |
|
359 | |||
363 |
|
360 | |||
364 |
|
361 |
@@ -19,6 +19,7 b' __docformat__ = "restructuredtext en"' | |||||
19 | import re |
|
19 | import re | |
20 |
|
20 | |||
21 | import IPython |
|
21 | import IPython | |
|
22 | import sys | |||
22 |
|
23 | |||
23 | from frontendbase import FrontEndBase |
|
24 | from frontendbase import FrontEndBase | |
24 | from IPython.kernel.core.interpreter import Interpreter |
|
25 | from IPython.kernel.core.interpreter import Interpreter | |
@@ -63,9 +64,7 b' class LineFrontEndBase(FrontEndBase):' | |||||
63 | shell = Interpreter() |
|
64 | shell = Interpreter() | |
64 | FrontEndBase.__init__(self, shell=shell, history=history) |
|
65 | FrontEndBase.__init__(self, shell=shell, history=history) | |
65 |
|
66 | |||
66 | #FIXME: print banner. |
|
67 | self.new_prompt(self.input_prompt_template.substitute(number=1)) | |
67 | banner = """IPython1 %s -- An enhanced Interactive Python.""" \ |
|
|||
68 | % IPython.__version__ |
|
|||
69 |
|
68 | |||
70 |
|
69 | |||
71 | def complete(self, line): |
|
70 | def complete(self, line): | |
@@ -96,7 +95,8 b' class LineFrontEndBase(FrontEndBase):' | |||||
96 | self.write('\n' + result['stdout']) |
|
95 | self.write('\n' + result['stdout']) | |
97 | if 'display' in result and result['display']: |
|
96 | if 'display' in result and result['display']: | |
98 | self.write("%s%s\n" % ( |
|
97 | self.write("%s%s\n" % ( | |
99 |
self.output_prompt |
|
98 | self.output_prompt_template.substitute( | |
|
99 | number=result['number']), | |||
100 | result['display']['pprint'] |
|
100 | result['display']['pprint'] | |
101 | ) ) |
|
101 | ) ) | |
102 |
|
102 | |||
@@ -104,7 +104,7 b' class LineFrontEndBase(FrontEndBase):' | |||||
104 | def render_error(self, failure): |
|
104 | def render_error(self, failure): | |
105 | """ Frontend-specific rendering of error. |
|
105 | """ Frontend-specific rendering of error. | |
106 | """ |
|
106 | """ | |
107 |
self. |
|
107 | self.write('\n\n'+str(failure)+'\n\n') | |
108 | return failure |
|
108 | return failure | |
109 |
|
109 | |||
110 |
|
110 | |||
@@ -129,7 +129,37 b' class LineFrontEndBase(FrontEndBase):' | |||||
129 | # Add line returns here, to make sure that the statement is |
|
129 | # Add line returns here, to make sure that the statement is | |
130 | # complete. |
|
130 | # complete. | |
131 | return FrontEndBase.is_complete(self, string.rstrip() + '\n\n') |
|
131 | return FrontEndBase.is_complete(self, string.rstrip() + '\n\n') | |
|
132 | ||||
|
133 | ||||
|
134 | def get_current_edit_buffer(self): | |||
|
135 | """ Return the current buffer being entered. | |||
|
136 | """ | |||
|
137 | raise NotImplementedError | |||
|
138 | ||||
|
139 | ||||
|
140 | def write(self, string): | |||
|
141 | """ Write some characters to the display. | |||
|
142 | ||||
|
143 | Subclass should overide this method. | |||
|
144 | """ | |||
|
145 | print >>sys.__stderr__, string | |||
|
146 | ||||
132 |
|
147 | |||
|
148 | def add_to_edit_buffer(self, string): | |||
|
149 | """ Add the given string to the current edit buffer. | |||
|
150 | """ | |||
|
151 | raise NotImplementedError | |||
|
152 | ||||
|
153 | ||||
|
154 | def new_prompt(self, prompt): | |||
|
155 | """ Prints a prompt and starts a new editing buffer. | |||
|
156 | ||||
|
157 | Subclasses should use this method to make sure that the | |||
|
158 | terminal is put in a state favorable for a new line | |||
|
159 | input. | |||
|
160 | """ | |||
|
161 | self.write(prompt) | |||
|
162 | ||||
133 |
|
163 | |||
134 | def execute(self, python_string, raw_string=None): |
|
164 | def execute(self, python_string, raw_string=None): | |
135 | """ Stores the raw_string in the history, and sends the |
|
165 | """ Stores the raw_string in the history, and sends the | |
@@ -167,7 +197,8 b' class LineFrontEndBase(FrontEndBase):' | |||||
167 | terminal back in a shape where it is usable. |
|
197 | terminal back in a shape where it is usable. | |
168 | """ |
|
198 | """ | |
169 | self.prompt_number += 1 |
|
199 | self.prompt_number += 1 | |
170 |
self.new_prompt(self.prompt |
|
200 | self.new_prompt(self.input_prompt_template.substitute( | |
|
201 | number=(self.last_result['number'] + 1))) | |||
171 | # Start a new empty history entry |
|
202 | # Start a new empty history entry | |
172 | self._add_history(None, '') |
|
203 | self._add_history(None, '') | |
173 | self.history_cursor = len(self.history.input_cache) - 1 |
|
204 | self.history_cursor = len(self.history.input_cache) - 1 | |
@@ -186,10 +217,10 b' class LineFrontEndBase(FrontEndBase):' | |||||
186 | if self.is_complete(cleaned_buffer): |
|
217 | if self.is_complete(cleaned_buffer): | |
187 | self.execute(cleaned_buffer, raw_string=current_buffer) |
|
218 | self.execute(cleaned_buffer, raw_string=current_buffer) | |
188 | else: |
|
219 | else: | |
189 |
self. |
|
220 | self.add_to_edit_buffer(self._get_indent_string( | |
190 | current_buffer[:-1])) |
|
221 | current_buffer[:-1])) | |
191 | if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'): |
|
222 | if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'): | |
192 |
self. |
|
223 | self.add_to_edit_buffer('\t') | |
193 |
|
224 | |||
194 |
|
225 | |||
195 | def _get_indent_string(self, string): |
|
226 | def _get_indent_string(self, string): |
@@ -175,7 +175,7 b' class PrefilterFrontEnd(LineFrontEndBase):' | |||||
175 |
|
175 | |||
176 |
|
176 | |||
177 | #-------------------------------------------------------------------------- |
|
177 | #-------------------------------------------------------------------------- | |
178 |
# Prefilter |
|
178 | # PrefilterFrontEnd interface | |
179 | #-------------------------------------------------------------------------- |
|
179 | #-------------------------------------------------------------------------- | |
180 |
|
180 | |||
181 | def system_call(self, command_string): |
|
181 | def system_call(self, command_string): |
@@ -44,9 +44,6 b' def test_io():' | |||||
44 |
|
44 | |||
45 |
|
45 | |||
46 | def test_kill(): |
|
46 | def test_kill(): | |
47 | pass |
|
|||
48 |
|
||||
49 | if True: |
|
|||
50 | """ Check that we can kill a process, and its subprocess. |
|
47 | """ Check that we can kill a process, and its subprocess. | |
51 | """ |
|
48 | """ | |
52 | s = StringIO() |
|
49 | s = StringIO() |
@@ -106,11 +106,6 b' class ConsoleWidget(editwindow.EditWindow):' | |||||
106 | editwindow.EditWindow.__init__(self, parent, id, pos, size, style) |
|
106 | editwindow.EditWindow.__init__(self, parent, id, pos, size, style) | |
107 | self._configure_scintilla() |
|
107 | self._configure_scintilla() | |
108 |
|
108 | |||
109 | # FIXME: we need to retrieve this from the interpreter. |
|
|||
110 | self.prompt = \ |
|
|||
111 | '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02' |
|
|||
112 | self.new_prompt(self.prompt % 1) |
|
|||
113 |
|
||||
114 | self.Bind(wx.EVT_KEY_DOWN, self._on_key_down) |
|
109 | self.Bind(wx.EVT_KEY_DOWN, self._on_key_down) | |
115 | self.Bind(wx.EVT_KEY_UP, self._on_key_up) |
|
110 | self.Bind(wx.EVT_KEY_UP, self._on_key_up) | |
116 |
|
111 | |||
@@ -229,7 +224,10 b' class ConsoleWidget(editwindow.EditWindow):' | |||||
229 | buf.append(symbol.rstrip() + '\n') |
|
224 | buf.append(symbol.rstrip() + '\n') | |
230 | pos = 1 |
|
225 | pos = 1 | |
231 | self.write(''.join(buf)) |
|
226 | self.write(''.join(buf)) | |
232 | self.new_prompt(self.prompt % (self.last_result['number'] + 1)) |
|
227 | # FIXME: I have some mixing of interfaces between console_widget | |
|
228 | # and wx_frontend, here. | |||
|
229 | self.new_prompt(self.input_prompt_template.substitute( | |||
|
230 | number=self.last_result['number'] + 1)) | |||
233 | self.replace_current_edit_buffer(current_buffer) |
|
231 | self.replace_current_edit_buffer(current_buffer) | |
234 |
|
232 | |||
235 | #-------------------------------------------------------------------------- |
|
233 | #-------------------------------------------------------------------------- |
@@ -38,7 +38,8 b' class IPythonXController(WxController):' | |||||
38 | self.release_output() |
|
38 | self.release_output() | |
39 | wx.Yield() |
|
39 | wx.Yield() | |
40 | if not self.ipython0.exit_now: |
|
40 | if not self.ipython0.exit_now: | |
41 |
self.new_prompt(self.prompt |
|
41 | self.new_prompt(self.input_prompt_template.substitute( | |
|
42 | number=self.last_result['number'] + 1)) | |||
42 |
|
43 | |||
43 |
|
44 | |||
44 | def do_exit(self): |
|
45 | def do_exit(self): |
@@ -28,6 +28,7 b' import __builtin__' | |||||
28 | from time import sleep |
|
28 | from time import sleep | |
29 | import sys |
|
29 | import sys | |
30 | from threading import Lock |
|
30 | from threading import Lock | |
|
31 | import string | |||
31 |
|
32 | |||
32 | import wx |
|
33 | import wx | |
33 | from wx import stc |
|
34 | from wx import stc | |
@@ -48,6 +49,12 b" _ERROR_BG = '#FFF1F1' # Nice red" | |||||
48 | _RUNNING_BUFFER_MARKER = 31 |
|
49 | _RUNNING_BUFFER_MARKER = 31 | |
49 | _ERROR_MARKER = 30 |
|
50 | _ERROR_MARKER = 30 | |
50 |
|
51 | |||
|
52 | prompt_in1 = \ | |||
|
53 | '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02' | |||
|
54 | ||||
|
55 | prompt_out = \ | |||
|
56 | '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02' | |||
|
57 | ||||
51 | #------------------------------------------------------------------------------- |
|
58 | #------------------------------------------------------------------------------- | |
52 | # Classes to implement the Wx frontend |
|
59 | # Classes to implement the Wx frontend | |
53 | #------------------------------------------------------------------------------- |
|
60 | #------------------------------------------------------------------------------- | |
@@ -59,9 +66,9 b' class WxController(PrefilterFrontEnd, ConsoleWidget):' | |||||
59 | widget to provide a text-rendering widget suitable for a terminal. |
|
66 | widget to provide a text-rendering widget suitable for a terminal. | |
60 | """ |
|
67 | """ | |
61 |
|
68 | |||
62 | # FIXME: this shouldn't be there. |
|
69 | output_prompt_template = string.Template(prompt_out) | |
63 | output_prompt = \ |
|
70 | ||
64 | '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02' |
|
71 | input_prompt_template = string.Template(prompt_in1) | |
65 |
|
72 | |||
66 | # Print debug info on what is happening to the console. |
|
73 | # Print debug info on what is happening to the console. | |
67 | debug = True |
|
74 | debug = True | |
@@ -283,6 +290,13 b' class WxController(PrefilterFrontEnd, ConsoleWidget):' | |||||
283 | self.MarkerAdd(i, _ERROR_MARKER) |
|
290 | self.MarkerAdd(i, _ERROR_MARKER) | |
284 |
|
291 | |||
285 |
|
292 | |||
|
293 | def add_to_edit_buffer(self, string): | |||
|
294 | """ Add the given string to the current edit buffer. | |||
|
295 | """ | |||
|
296 | # XXX: I should check the input_state here. | |||
|
297 | self.write(string) | |||
|
298 | ||||
|
299 | ||||
286 | #-------------------------------------------------------------------------- |
|
300 | #-------------------------------------------------------------------------- | |
287 | # ConsoleWidget interface |
|
301 | # ConsoleWidget interface | |
288 | #-------------------------------------------------------------------------- |
|
302 | #-------------------------------------------------------------------------- | |
@@ -294,6 +308,18 b' class WxController(PrefilterFrontEnd, ConsoleWidget):' | |||||
294 | ConsoleWidget.new_prompt(self, prompt) |
|
308 | ConsoleWidget.new_prompt(self, prompt) | |
295 |
|
309 | |||
296 |
|
310 | |||
|
311 | def write(self, *args, **kwargs): | |||
|
312 | # Avoid multiple inheritence, be explicit about which | |||
|
313 | # parent method class gets called | |||
|
314 | ConsoleWidget.write(self, *args, **kwargs) | |||
|
315 | ||||
|
316 | ||||
|
317 | def get_current_edit_buffer(self): | |||
|
318 | # Avoid multiple inheritence, be explicit about which | |||
|
319 | # parent method class gets called | |||
|
320 | return ConsoleWidget.get_current_edit_buffer(self) | |||
|
321 | ||||
|
322 | ||||
297 | def _on_key_down(self, event, skip=True): |
|
323 | def _on_key_down(self, event, skip=True): | |
298 | """ Capture the character events, let the parent |
|
324 | """ Capture the character events, let the parent | |
299 | widget handle them, and put our logic afterward. |
|
325 | widget handle them, and put our logic afterward. | |
@@ -399,7 +425,6 b' class WxController(PrefilterFrontEnd, ConsoleWidget):' | |||||
399 | def _end_system_call(self): |
|
425 | def _end_system_call(self): | |
400 | """ Called at the end of a system call. |
|
426 | """ Called at the end of a system call. | |
401 | """ |
|
427 | """ | |
402 | print >>sys.__stderr__, 'End of system call' |
|
|||
403 | self._input_state = 'buffering' |
|
428 | self._input_state = 'buffering' | |
404 | self._running_process = False |
|
429 | self._running_process = False | |
405 |
|
430 |
General Comments 0
You need to be logged in to leave comments.
Login now