##// END OF EJS Templates
Merging Gael's branch into trunk. ...
Brian Granger -
r1664:5771a5f8 merge
parent child Browse files
Show More
@@ -0,0 +1,26 b''
1 # encoding: utf-8
2
3 """This file contains unittests for the interpreter.py module."""
4
5 __docformat__ = "restructuredtext en"
6
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
13
14 #-----------------------------------------------------------------------------
15 # Imports
16 #-----------------------------------------------------------------------------
17
18 from IPython.kernel.core.interpreter import Interpreter
19
20 def test_unicode():
21 """ Test unicode handling with the interpreter.
22 """
23 i = Interpreter()
24 i.execute_python(u'print "ù"')
25 i.execute_python('print "ù"')
26
@@ -50,7 +50,6 b' import subprocess'
50 50 from subprocess import PIPE
51 51 import sys
52 52 import os
53 import time
54 53 import types
55 54
56 55 try:
@@ -69,8 +68,16 b' except ImportError:'
69 68
70 69 mswindows = (sys.platform == "win32")
71 70
71 skip = False
72
72 73 if mswindows:
73 import winprocess
74 import platform
75 if platform.uname()[3] == '' or platform.uname()[3] > '6.0.6000':
76 # Killable process does not work under vista when starting for
77 # something else than cmd.
78 skip = True
79 else:
80 import winprocess
74 81 else:
75 82 import signal
76 83
@@ -78,7 +85,11 b' if not mswindows:'
78 85 def DoNothing(*args):
79 86 pass
80 87
81 class Popen(subprocess.Popen):
88
89 if skip:
90 Popen = subprocess.Popen
91 else:
92 class Popen(subprocess.Popen):
82 93 if not mswindows:
83 94 # Override __init__ to set a preexec_fn
84 95 def __init__(self, *args, **kwargs):
@@ -50,7 +50,7 b' class PipedProcess(Thread):'
50 50 """
51 51 env = os.environ
52 52 env['TERM'] = 'xterm'
53 process = Popen((self.command_string + ' 2>&1', ), shell=True,
53 process = Popen(self.command_string + ' 2>&1', shell=True,
54 54 env=env,
55 55 universal_newlines=True,
56 56 stdout=PIPE, stdin=PIPE, )
@@ -20,6 +20,8 b' import re'
20 20
21 21 import IPython
22 22 import sys
23 import codeop
24 import traceback
23 25
24 26 from frontendbase import FrontEndBase
25 27 from IPython.kernel.core.interpreter import Interpreter
@@ -76,6 +78,11 b' class LineFrontEndBase(FrontEndBase):'
76 78
77 79 if banner is not None:
78 80 self.banner = banner
81
82 def start(self):
83 """ Put the frontend in a state where it is ready for user
84 interaction.
85 """
79 86 if self.banner is not None:
80 87 self.write(self.banner, refresh=False)
81 88
@@ -141,9 +148,18 b' class LineFrontEndBase(FrontEndBase):'
141 148 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
142 149 return False
143 150 else:
144 # Add line returns here, to make sure that the statement is
145 # complete.
146 return FrontEndBase.is_complete(self, string.rstrip() + '\n\n')
151 self.capture_output()
152 try:
153 # Add line returns here, to make sure that the statement is
154 # complete.
155 is_complete = codeop.compile_command(string.rstrip() + '\n\n',
156 "<string>", "exec")
157 self.release_output()
158 except Exception, e:
159 # XXX: Hack: return True so that the
160 # code gets executed and the error captured.
161 is_complete = True
162 return is_complete
147 163
148 164
149 165 def write(self, string, refresh=True):
@@ -181,7 +197,7 b' class LineFrontEndBase(FrontEndBase):'
181 197 #--------------------------------------------------------------------------
182 198
183 199 def prefilter_input(self, string):
184 """ Priflter the input to turn it in valid python.
200 """ Prefilter the input to turn it in valid python.
185 201 """
186 202 string = string.replace('\r\n', '\n')
187 203 string = string.replace('\t', 4*' ')
@@ -210,9 +226,12 b' class LineFrontEndBase(FrontEndBase):'
210 226 line = self.input_buffer
211 227 new_line, completions = self.complete(line)
212 228 if len(completions)>1:
213 self.write_completion(completions)
214 self.input_buffer = new_line
229 self.write_completion(completions, new_line=new_line)
230 elif not line == new_line:
231 self.input_buffer = new_line
215 232 if self.debug:
233 print >>sys.__stdout__, 'line', line
234 print >>sys.__stdout__, 'new_line', new_line
216 235 print >>sys.__stdout__, completions
217 236
218 237
@@ -222,10 +241,15 b' class LineFrontEndBase(FrontEndBase):'
222 241 return 80
223 242
224 243
225 def write_completion(self, possibilities):
244 def write_completion(self, possibilities, new_line=None):
226 245 """ Write the list of possible completions.
246
247 new_line is the completed input line that should be displayed
248 after the completion are writen. If None, the input_buffer
249 before the completion is used.
227 250 """
228 current_buffer = self.input_buffer
251 if new_line is None:
252 new_line = self.input_buffer
229 253
230 254 self.write('\n')
231 255 max_len = len(max(possibilities, key=len)) + 1
@@ -246,7 +270,7 b' class LineFrontEndBase(FrontEndBase):'
246 270 self.write(''.join(buf))
247 271 self.new_prompt(self.input_prompt_template.substitute(
248 272 number=self.last_result['number'] + 1))
249 self.input_buffer = current_buffer
273 self.input_buffer = new_line
250 274
251 275
252 276 def new_prompt(self, prompt):
@@ -275,6 +299,8 b' class LineFrontEndBase(FrontEndBase):'
275 299 else:
276 300 self.input_buffer += self._get_indent_string(
277 301 current_buffer[:-1])
302 if len(current_buffer.split('\n')) == 2:
303 self.input_buffer += '\t\t'
278 304 if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
279 305 self.input_buffer += '\t'
280 306
@@ -24,6 +24,7 b' __docformat__ = "restructuredtext en"'
24 24 import sys
25 25
26 26 from linefrontendbase import LineFrontEndBase, common_prefix
27 from frontendbase import FrontEndBase
27 28
28 29 from IPython.ipmaker import make_IPython
29 30 from IPython.ipapi import IPApi
@@ -34,6 +35,7 b' from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap'
34 35 from IPython.genutils import Term
35 36 import pydoc
36 37 import os
38 import sys
37 39
38 40
39 41 def mk_system_call(system_call_function, command):
@@ -57,6 +59,8 b' class PrefilterFrontEnd(LineFrontEndBase):'
57 59 to execute the statements and the ipython0 used for code
58 60 completion...
59 61 """
62
63 debug = False
60 64
61 65 def __init__(self, ipython0=None, *args, **kwargs):
62 66 """ Parameters:
@@ -65,12 +69,24 b' class PrefilterFrontEnd(LineFrontEndBase):'
65 69 ipython0: an optional ipython0 instance to use for command
66 70 prefiltering and completion.
67 71 """
72 LineFrontEndBase.__init__(self, *args, **kwargs)
73 self.shell.output_trap = RedirectorOutputTrap(
74 out_callback=self.write,
75 err_callback=self.write,
76 )
77 self.shell.traceback_trap = SyncTracebackTrap(
78 formatters=self.shell.traceback_trap.formatters,
79 )
80
81 # Start the ipython0 instance:
68 82 self.save_output_hooks()
69 83 if ipython0 is None:
70 84 # Instanciate an IPython0 interpreter to be able to use the
71 85 # prefiltering.
72 86 # XXX: argv=[] is a bit bold.
73 ipython0 = make_IPython(argv=[])
87 ipython0 = make_IPython(argv=[],
88 user_ns=self.shell.user_ns,
89 user_global_ns=self.shell.user_global_ns)
74 90 self.ipython0 = ipython0
75 91 # Set the pager:
76 92 self.ipython0.set_hook('show_in_pager',
@@ -86,24 +102,13 b' class PrefilterFrontEnd(LineFrontEndBase):'
86 102 'ls -CF')
87 103 # And now clean up the mess created by ipython0
88 104 self.release_output()
105
106
89 107 if not 'banner' in kwargs and self.banner is None:
90 kwargs['banner'] = self.ipython0.BANNER + """
108 self.banner = self.ipython0.BANNER + """
91 109 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
92 110
93 LineFrontEndBase.__init__(self, *args, **kwargs)
94 # XXX: Hack: mix the two namespaces
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
99
100 self.shell.output_trap = RedirectorOutputTrap(
101 out_callback=self.write,
102 err_callback=self.write,
103 )
104 self.shell.traceback_trap = SyncTracebackTrap(
105 formatters=self.shell.traceback_trap.formatters,
106 )
111 self.start()
107 112
108 113 #--------------------------------------------------------------------------
109 114 # FrontEndBase interface
@@ -113,7 +118,7 b' This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""'
113 118 """ Use ipython0 to capture the last traceback and display it.
114 119 """
115 120 self.capture_output()
116 self.ipython0.showtraceback()
121 self.ipython0.showtraceback(tb_offset=-1)
117 122 self.release_output()
118 123
119 124
@@ -164,6 +169,8 b' This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""'
164 169
165 170
166 171 def complete(self, line):
172 # FIXME: This should be factored out in the linefrontendbase
173 # method.
167 174 word = line.split('\n')[-1].split(' ')[-1]
168 175 completions = self.ipython0.complete(word)
169 176 # FIXME: The proper sort should be done in the complete method.
@@ -20,8 +20,6 b' from IPython.frontend._process import PipedProcess'
20 20 from IPython.testing import decorators as testdec
21 21
22 22
23 # FIXME
24 @testdec.skip("This doesn't work under Windows")
25 23 def test_capture_out():
26 24 """ A simple test to see if we can execute a process and get the output.
27 25 """
@@ -33,8 +31,6 b' def test_capture_out():'
33 31 assert result == '1'
34 32
35 33
36 # FIXME
37 @testdec.skip("This doesn't work under Windows")
38 34 def test_io():
39 35 """ Checks that we can send characters on stdin to the process.
40 36 """
@@ -51,8 +47,6 b' def test_io():'
51 47 assert result == test_string
52 48
53 49
54 # FIXME
55 @testdec.skip("This doesn't work under Windows")
56 50 def test_kill():
57 51 """ Check that we can kill a process, and its subprocess.
58 52 """
@@ -23,6 +23,7 b' import wx'
23 23 import wx.stc as stc
24 24
25 25 from wx.py import editwindow
26 import time
26 27 import sys
27 28 LINESEP = '\n'
28 29 if sys.platform == 'win32':
@@ -115,12 +116,15 b' class ConsoleWidget(editwindow.EditWindow):'
115 116 # The color of the carret (call _apply_style() after setting)
116 117 carret_color = 'BLACK'
117 118
119 # Store the last time a refresh was done
120 _last_refresh_time = 0
121
118 122 #--------------------------------------------------------------------------
119 123 # Public API
120 124 #--------------------------------------------------------------------------
121 125
122 126 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
123 size=wx.DefaultSize, style=0, ):
127 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
124 128 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
125 129 self._configure_scintilla()
126 130
@@ -168,9 +172,14 b' class ConsoleWidget(editwindow.EditWindow):'
168 172
169 173 self.GotoPos(self.GetLength())
170 174 if refresh:
171 # Maybe this is faster than wx.Yield()
172 self.ProcessEvent(wx.PaintEvent())
173 #wx.Yield()
175 current_time = time.time()
176 if current_time - self._last_refresh_time > 0.03:
177 if sys.platform == 'win32':
178 wx.SafeYield()
179 else:
180 wx.Yield()
181 # self.ProcessEvent(wx.PaintEvent())
182 self._last_refresh_time = current_time
174 183
175 184
176 185 def new_prompt(self, prompt):
@@ -183,7 +192,6 b' class ConsoleWidget(editwindow.EditWindow):'
183 192 # now we update our cursor giving end of prompt
184 193 self.current_prompt_pos = self.GetLength()
185 194 self.current_prompt_line = self.GetCurrentLine()
186 wx.Yield()
187 195 self.EnsureCaretVisible()
188 196
189 197
@@ -128,6 +128,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
128 128 # while it is being swapped
129 129 _out_buffer_lock = Lock()
130 130
131 # The different line markers used to higlight the prompts.
131 132 _markers = dict()
132 133
133 134 #--------------------------------------------------------------------------
@@ -135,12 +136,16 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
135 136 #--------------------------------------------------------------------------
136 137
137 138 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
138 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
139 size=wx.DefaultSize,
140 style=wx.CLIP_CHILDREN|wx.WANTS_CHARS,
139 141 *args, **kwds):
140 142 """ Create Shell instance.
141 143 """
142 144 ConsoleWidget.__init__(self, parent, id, pos, size, style)
143 145 PrefilterFrontEnd.__init__(self, **kwds)
146
147 # Stick in our own raw_input:
148 self.ipython0.raw_input = self.raw_input
144 149
145 150 # Marker for complete buffer.
146 151 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
@@ -164,9 +169,11 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
164 169 # Inject self in namespace, for debug
165 170 if self.debug:
166 171 self.shell.user_ns['self'] = self
172 # Inject our own raw_input in namespace
173 self.shell.user_ns['raw_input'] = self.raw_input
167 174
168 175
169 def raw_input(self, prompt):
176 def raw_input(self, prompt=''):
170 177 """ A replacement from python's raw_input.
171 178 """
172 179 self.new_prompt(prompt)
@@ -174,15 +181,13 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
174 181 if hasattr(self, '_cursor'):
175 182 del self._cursor
176 183 self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
177 self.waiting = True
178 184 self.__old_on_enter = self._on_enter
185 event_loop = wx.EventLoop()
179 186 def my_on_enter():
180 self.waiting = False
187 event_loop.Exit()
181 188 self._on_enter = my_on_enter
182 # XXX: Busy waiting, ugly.
183 while self.waiting:
184 wx.Yield()
185 sleep(0.1)
189 # XXX: Running a separate event_loop. Ugly.
190 event_loop.Run()
186 191 self._on_enter = self.__old_on_enter
187 192 self._input_state = 'buffering'
188 193 self._cursor = wx.BusyCursor()
@@ -191,16 +196,18 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
191 196
192 197 def system_call(self, command_string):
193 198 self._input_state = 'subprocess'
199 event_loop = wx.EventLoop()
200 def _end_system_call():
201 self._input_state = 'buffering'
202 self._running_process = False
203 event_loop.Exit()
204
194 205 self._running_process = PipedProcess(command_string,
195 206 out_callback=self.buffered_write,
196 end_callback = self._end_system_call)
207 end_callback = _end_system_call)
197 208 self._running_process.start()
198 # XXX: another one of these polling loops to have a blocking
199 # call
200 wx.Yield()
201 while self._running_process:
202 wx.Yield()
203 sleep(0.1)
209 # XXX: Running a separate event_loop. Ugly.
210 event_loop.Run()
204 211 # Be sure to flush the buffer.
205 212 self._buffer_flush(event=None)
206 213
@@ -226,8 +233,9 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
226 233 for name in symbol_string.split('.')[1:] + ['__doc__']:
227 234 symbol = getattr(symbol, name)
228 235 self.AutoCompCancel()
229 wx.Yield()
230 self.CallTipShow(self.GetCurrentPos(), symbol)
236 # Check that the symbol can indeed be converted to a string:
237 symbol += ''
238 wx.CallAfter(self.CallTipShow, self.GetCurrentPos(), symbol)
231 239 except:
232 240 # The retrieve symbol couldn't be converted to a string
233 241 pass
@@ -238,9 +246,9 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
238 246 true, open the menu.
239 247 """
240 248 if self.debug:
241 print >>sys.__stdout__, "_popup_completion",
249 print >>sys.__stdout__, "_popup_completion"
242 250 line = self.input_buffer
243 if (self.AutoCompActive() and not line[-1] == '.') \
251 if (self.AutoCompActive() and line and not line[-1] == '.') \
244 252 or create==True:
245 253 suggestion, completions = self.complete(line)
246 254 offset=0
@@ -284,19 +292,21 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
284 292 if i in self._markers:
285 293 self.MarkerDeleteHandle(self._markers[i])
286 294 self._markers[i] = self.MarkerAdd(i, _COMPLETE_BUFFER_MARKER)
287 # Update the display:
288 wx.Yield()
289 self.GotoPos(self.GetLength())
290 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
295 # Use a callafter to update the display robustly under windows
296 def callback():
297 self.GotoPos(self.GetLength())
298 PrefilterFrontEnd.execute(self, python_string,
299 raw_string=raw_string)
300 wx.CallAfter(callback)
291 301
292 302 def save_output_hooks(self):
293 303 self.__old_raw_input = __builtin__.raw_input
294 304 PrefilterFrontEnd.save_output_hooks(self)
295 305
296 306 def capture_output(self):
297 __builtin__.raw_input = self.raw_input
298 307 self.SetLexer(stc.STC_LEX_NULL)
299 308 PrefilterFrontEnd.capture_output(self)
309 __builtin__.raw_input = self.raw_input
300 310
301 311
302 312 def release_output(self):
@@ -316,12 +326,24 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
316 326 def show_traceback(self):
317 327 start_line = self.GetCurrentLine()
318 328 PrefilterFrontEnd.show_traceback(self)
319 wx.Yield()
329 self.ProcessEvent(wx.PaintEvent())
330 #wx.Yield()
320 331 for i in range(start_line, self.GetCurrentLine()):
321 332 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
322 333
323 334
324 335 #--------------------------------------------------------------------------
336 # FrontEndBase interface
337 #--------------------------------------------------------------------------
338
339 def render_error(self, e):
340 start_line = self.GetCurrentLine()
341 self.write('\n' + e + '\n')
342 for i in range(start_line, self.GetCurrentLine()):
343 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
344
345
346 #--------------------------------------------------------------------------
325 347 # ConsoleWidget interface
326 348 #--------------------------------------------------------------------------
327 349
@@ -351,7 +373,8 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
351 373 if self._input_state == 'subprocess':
352 374 if self.debug:
353 375 print >>sys.__stderr__, 'Killing running process'
354 self._running_process.process.kill()
376 if hasattr(self._running_process, 'process'):
377 self._running_process.process.kill()
355 378 elif self._input_state == 'buffering':
356 379 if self.debug:
357 380 print >>sys.__stderr__, 'Raising KeyboardInterrupt'
@@ -376,7 +399,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
376 399 char = '\04'
377 400 self._running_process.process.stdin.write(char)
378 401 self._running_process.process.stdin.flush()
379 elif event.KeyCode in (ord('('), 57):
402 elif event.KeyCode in (ord('('), 57, 53):
380 403 # Calltips
381 404 event.Skip()
382 405 self.do_calltip()
@@ -410,8 +433,8 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
410 433 self.input_buffer = new_buffer
411 434 # Tab-completion
412 435 elif event.KeyCode == ord('\t'):
413 last_line = self.input_buffer.split('\n')[-1]
414 if not re.match(r'^\s*$', last_line):
436 current_line, current_line_number = self.CurLine
437 if not re.match(r'^\s*$', current_line):
415 438 self.complete_current_input()
416 439 if self.AutoCompActive():
417 440 wx.CallAfter(self._popup_completion, create=True)
@@ -427,7 +450,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
427 450 if event.KeyCode in (59, ord('.')):
428 451 # Intercepting '.'
429 452 event.Skip()
430 self._popup_completion(create=True)
453 wx.CallAfter(self._popup_completion, create=True)
431 454 else:
432 455 ConsoleWidget._on_key_up(self, event, skip=skip)
433 456
@@ -456,13 +479,6 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
456 479 # Private API
457 480 #--------------------------------------------------------------------------
458 481
459 def _end_system_call(self):
460 """ Called at the end of a system call.
461 """
462 self._input_state = 'buffering'
463 self._running_process = False
464
465
466 482 def _buffer_flush(self, event):
467 483 """ Called by the timer to flush the write buffer.
468 484
@@ -680,6 +680,13 b' class Interpreter(object):'
680 680 # how trailing whitespace is handled, but this seems to work.
681 681 python = python.strip()
682 682
683 # The compiler module does not like unicode. We need to convert
684 # it encode it:
685 if isinstance(python, unicode):
686 # Use the utf-8-sig BOM so the compiler detects this a UTF-8
687 # encode string.
688 python = '\xef\xbb\xbf' + python.encode('utf-8')
689
683 690 # The compiler module will parse the code into an abstract syntax tree.
684 691 ast = compiler.parse(python)
685 692
@@ -1,6 +1,5 b''
1 1 # Set this prefix to where you want to install the plugin
2 PREFIX=~/usr/local
3 PREFIX=~/tmp/local
2 PREFIX=/usr/local
4 3
5 4 NOSE0=nosetests -vs --with-doctest --doctest-tests --detailed-errors
6 5 NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt \
@@ -1,14 +1,8 b''
1 1 #!/usr/bin/env python
2 2 """Wrapper to run setup.py using setuptools."""
3 3
4 import os
5 4 import sys
6 5
7 # Add my local path to sys.path
8 home = os.environ['HOME']
9 sys.path.insert(0,'%s/usr/local/lib/python%s/site-packages' %
10 (home,sys.version[:3]))
11
12 6 # now, import setuptools and call the actual setup
13 7 import setuptools
14 8 # print sys.argv
General Comments 0
You need to be logged in to leave comments. Login now