##// END OF EJS Templates
Split the frontend base class in different files and add a base class...
Gael Varoquaux -
Show More
@@ -0,0 +1,93 b''
1 """
2 Base front end class for all async frontends.
3 """
4 __docformat__ = "restructuredtext en"
5
6 #-------------------------------------------------------------------------------
7 # Copyright (C) 2008 The IPython Development Team
8 #
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
11 #-------------------------------------------------------------------------------
12
13
14 #-------------------------------------------------------------------------------
15 # Imports
16 #-------------------------------------------------------------------------------
17 import uuid
18
19 try:
20 from zope.interface import Interface, Attribute, implements, classProvides
21 except ImportError:
22 #zope.interface is not available
23 Interface = object
24 def Attribute(name, doc): pass
25 def implements(interface): pass
26 def classProvides(interface): pass
27
28
29
30 from frontendbase import FrontEndBase, IFrontEnd, IFrontEndFactory
31
32 from IPython.kernel.engineservice import IEngineCore
33 from IPython.kernel.core.history import FrontEndHistory
34
35 try:
36 from twisted.python.failure import Failure
37 except ImportError:
38 #Twisted not available
39 Failure = Exception
40
41
42
43
44 class AsyncFrontEndBase(FrontEndBase):
45 """
46 Overrides FrontEndBase to wrap execute in a deferred result.
47 All callbacks are made as callbacks on the deferred result.
48 """
49
50 implements(IFrontEnd)
51 classProvides(IFrontEndFactory)
52
53 def __init__(self, engine=None, history=None):
54 assert(engine==None or IEngineCore.providedBy(engine))
55 self.engine = IEngineCore(engine)
56 if history is None:
57 self.history = FrontEndHistory(input_cache=[''])
58 else:
59 self.history = history
60
61
62 def execute(self, block, blockID=None):
63 """Execute the block and return the deferred result.
64
65 Parameters:
66 block : {str, AST}
67 blockID : any
68 Caller may provide an ID to identify this block.
69 result['blockID'] := blockID
70
71 Result:
72 Deferred result of self.interpreter.execute
73 """
74
75 if(not self.is_complete(block)):
76 return Failure(Exception("Block is not compilable"))
77
78 if(blockID == None):
79 blockID = uuid.uuid4() #random UUID
80
81 d = self.engine.execute(block)
82 d.addCallback(self._add_history, block=block)
83 d.addCallbacks(self._add_block_id_for_result,
84 errback=self._add_block_id_for_failure,
85 callbackArgs=(blockID,),
86 errbackArgs=(blockID,))
87 d.addBoth(self.update_cell_prompt, blockID=blockID)
88 d.addCallbacks(self.render_result,
89 errback=self.render_error)
90
91 return d
92
93
@@ -0,0 +1,123 b''
1 """
2 Base front end class for all line-oriented frontends.
3
4 Currently this focuses on synchronous frontends.
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 in
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
14
15 #-------------------------------------------------------------------------------
16 # Imports
17 #-------------------------------------------------------------------------------
18 import re
19
20 import IPython
21
22
23 from frontendbase import FrontEndBase
24 from IPython.kernel.core.interpreter import Interpreter
25
26 #-------------------------------------------------------------------------------
27 # Base class for the line-oriented front ends
28 #-------------------------------------------------------------------------------
29 class LineFrontEndBase(FrontEndBase):
30
31 # Are we entering multi line input?
32 multi_line_input = False
33
34 # The added tab stop to the string. It may, for instance, come from
35 # copy and pasting something with tabs.
36 tab_stop = 0
37 # FIXME: We still have to deal with this.
38
39 #--------------------------------------------------------------------------
40 # Public API
41 #--------------------------------------------------------------------------
42
43 def __init__(self, shell=None, history=None):
44 if shell is None:
45 shell = Interpreter()
46 FrontEndBase.__init__(self, shell=shell, history=history)
47
48 #FIXME: print banner.
49 banner = """IPython1 %s -- An enhanced Interactive Python.""" \
50 % IPython.__version__
51
52
53 def complete(self, token):
54 """Complete token in engine's user_ns
55
56 Parameters
57 ----------
58 token : string
59
60 Result
61 ------
62 Deferred result of
63 IPython.kernel.engineservice.IEngineBase.complete
64 """
65
66 return self.shell.complete(token)
67
68
69 def render_result(self, result):
70 if 'stdout' in result and result['stdout']:
71 self.write('\n' + result['stdout'])
72 if 'display' in result and result['display']:
73 self.write("%s%s\n" % (
74 self.output_prompt % result['number'],
75 result['display']['pprint']
76 ) )
77
78
79 def render_error(self, failure):
80 self.insert_text('\n\n'+str(failure)+'\n\n')
81 return failure
82
83
84 def on_enter(self):
85 """ Called when the return key is pressed in a line editing
86 buffer.
87 """
88 current_buffer = self.get_current_edit_buffer()
89 current_buffer = current_buffer.replace('\r\n', '\n')
90 current_buffer = current_buffer.replace('\t', 4*' ')
91 cleaned_buffer = '\n'.join(l.rstrip()
92 for l in current_buffer.split('\n'))
93 if ( not self.multi_line_input
94 or re.findall(r"\n[\t ]*$", cleaned_buffer)):
95 if self.is_complete(cleaned_buffer):
96 self._add_history(None, cleaned_buffer.rstrip())
97 result = self.shell.execute(cleaned_buffer)
98 self.render_result(result)
99 self.new_prompt(self.prompt % (result['number'] + 1))
100 self.multi_line_input = False
101 else:
102 if self.multi_line_input:
103 self.write('\n' + self._get_indent_string(current_buffer))
104 else:
105 self.multi_line_input = True
106 self.write('\n\t')
107 else:
108 self.write('\n'+self._get_indent_string(current_buffer))
109
110
111 #--------------------------------------------------------------------------
112 # Private API
113 #--------------------------------------------------------------------------
114
115 def _get_indent_string(self, string):
116 string = string.split('\n')[-1]
117 indent_chars = len(string) - len(string.lstrip())
118 indent_string = '\t'*(indent_chars // 4) + \
119 ' '*(indent_chars % 4)
120
121 return indent_string
122
123
@@ -40,7 +40,7 b' from pprint import saferepr'
40
40
41 import IPython
41 import IPython
42 from IPython.kernel.engineservice import ThreadedEngineService
42 from IPython.kernel.engineservice import ThreadedEngineService
43 from IPython.frontend.frontendbase import AsyncFrontEndBase
43 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
44
44
45 from twisted.internet.threads import blockingCallFromThread
45 from twisted.internet.threads import blockingCallFromThread
46 from twisted.python.failure import Failure
46 from twisted.python.failure import Failure
@@ -37,12 +37,6 b' from IPython.kernel.core.history import FrontEndHistory'
37 from IPython.kernel.core.util import Bunch
37 from IPython.kernel.core.util import Bunch
38 from IPython.kernel.engineservice import IEngineCore
38 from IPython.kernel.engineservice import IEngineCore
39
39
40 try:
41 from twisted.python.failure import Failure
42 except ImportError:
43 #Twisted not available
44 Failure = Exception
45
46 ##############################################################################
40 ##############################################################################
47 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
41 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
48 # not
42 # not
@@ -355,53 +349,4 b' class FrontEndBase(object):'
355
349
356
350
357
351
358 class AsyncFrontEndBase(FrontEndBase):
359 """
360 Overrides FrontEndBase to wrap execute in a deferred result.
361 All callbacks are made as callbacks on the deferred result.
362 """
363
364 implements(IFrontEnd)
365 classProvides(IFrontEndFactory)
366
367 def __init__(self, engine=None, history=None):
368 assert(engine==None or IEngineCore.providedBy(engine))
369 self.engine = IEngineCore(engine)
370 if history is None:
371 self.history = FrontEndHistory(input_cache=[''])
372 else:
373 self.history = history
374
375
376 def execute(self, block, blockID=None):
377 """Execute the block and return the deferred result.
378
379 Parameters:
380 block : {str, AST}
381 blockID : any
382 Caller may provide an ID to identify this block.
383 result['blockID'] := blockID
384
385 Result:
386 Deferred result of self.interpreter.execute
387 """
388
389 if(not self.is_complete(block)):
390 return Failure(Exception("Block is not compilable"))
391
392 if(blockID == None):
393 blockID = uuid.uuid4() #random UUID
394
395 d = self.engine.execute(block)
396 d.addCallback(self._add_history, block=block)
397 d.addCallbacks(self._add_block_id_for_result,
398 errback=self._add_block_id_for_failure,
399 callbackArgs=(blockID,),
400 errbackArgs=(blockID,))
401 d.addBoth(self.update_cell_prompt, blockID=blockID)
402 d.addCallbacks(self.render_result,
403 errback=self.render_error)
404
405 return d
406
407
352
@@ -23,11 +23,8 b' __docformat__ = "restructuredtext en"'
23
23
24 import wx
24 import wx
25 from console_widget import ConsoleWidget
25 from console_widget import ConsoleWidget
26 import re
27
26
28 import IPython
27 from IPython.frontend.linefrontendbase import LineFrontEndBase
29 from IPython.kernel.engineservice import EngineService
30 from IPython.frontend.frontendbase import FrontEndBase
31
28
32 #-------------------------------------------------------------------------------
29 #-------------------------------------------------------------------------------
33 # Classes to implement the Wx frontend
30 # Classes to implement the Wx frontend
@@ -36,19 +33,11 b' from IPython.frontend.frontendbase import FrontEndBase'
36
33
37
34
38
35
39 class IPythonWxController(FrontEndBase, ConsoleWidget):
36 class IPythonWxController(LineFrontEndBase, ConsoleWidget):
40
37
41 output_prompt = \
38 output_prompt = \
42 '\n\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
39 '\n\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
43
40
44 # Are we entering multi line input?
45 multi_line_input = False
46
47 # The added tab stop to the string. It may, for instance, come from
48 # copy and pasting something with tabs.
49 tab_stop = 0
50 # FIXME: We still have to deal with this.
51
52 #--------------------------------------------------------------------------
41 #--------------------------------------------------------------------------
53 # Public API
42 # Public API
54 #--------------------------------------------------------------------------
43 #--------------------------------------------------------------------------
@@ -59,61 +48,11 b' class IPythonWxController(FrontEndBase, ConsoleWidget):'
59 """ Create Shell instance.
48 """ Create Shell instance.
60 """
49 """
61 ConsoleWidget.__init__(self, parent, id, pos, size, style)
50 ConsoleWidget.__init__(self, parent, id, pos, size, style)
62 FrontEndBase.__init__(self, engine=EngineService(),
51 LineFrontEndBase.__init__(self)
63 )
64
65 # FIXME: Something is wrong with the history, I instanciate it
66 # with an empty cache, but this is not the way to do.
67 self.lines = {}
68
69 # Start the IPython engine
70 self.engine.startService()
71
52
72 # Capture Character keys
53 # Capture Character keys
73 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
54 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
74
55
75 #FIXME: print banner.
76 banner = """IPython1 %s -- An enhanced Interactive Python.""" \
77 % IPython.__version__
78
79
80 def appWillTerminate_(self, notification):
81 """appWillTerminate"""
82
83 self.engine.stopService()
84
85
86 def complete(self, token):
87 """Complete token in engine's user_ns
88
89 Parameters
90 ----------
91 token : string
92
93 Result
94 ------
95 Deferred result of
96 IPython.kernel.engineservice.IEngineBase.complete
97 """
98
99 return self.engine.complete(token)
100
101
102 def render_result(self, result):
103 if 'stdout' in result and result['stdout']:
104 self.write('\n' + result['stdout'])
105 if 'display' in result and result['display']:
106 self.write("%s%s\n" % (
107 self.output_prompt % result['number'],
108 result['display']['pprint']
109 ) )
110
111
112 def render_error(self, failure):
113 self.insert_text('\n\n'+str(failure)+'\n\n')
114 return failure
115
116
117 #--------------------------------------------------------------------------
56 #--------------------------------------------------------------------------
118 # Private API
57 # Private API
119 #--------------------------------------------------------------------------
58 #--------------------------------------------------------------------------
@@ -127,7 +66,7 b' class IPythonWxController(FrontEndBase, ConsoleWidget):'
127 # Capture enter
66 # Capture enter
128 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
67 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
129 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
68 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
130 self._on_enter()
69 self.on_enter()
131 # Up history
70 # Up history
132 elif event.KeyCode == wx.WXK_UP and (
71 elif event.KeyCode == wx.WXK_UP and (
133 ( current_line_number == self.current_prompt_line and
72 ( current_line_number == self.current_prompt_line and
@@ -149,41 +88,6 b' class IPythonWxController(FrontEndBase, ConsoleWidget):'
149 ConsoleWidget._on_key_down(self, event, skip=True)
88 ConsoleWidget._on_key_down(self, event, skip=True)
150
89
151
90
152 def _on_enter(self):
153 """ Called when the return key is pressed in a line editing
154 buffer.
155 """
156 current_buffer = self.get_current_edit_buffer()
157 current_buffer = current_buffer.replace('\r\n', '\n')
158 current_buffer = current_buffer.replace('\t', 4*' ')
159 cleaned_buffer = '\n'.join(l.rstrip()
160 for l in current_buffer.split('\n'))
161 if ( not self.multi_line_input
162 or re.findall(r"\n[\t ]*$", cleaned_buffer)):
163 if self.is_complete(cleaned_buffer):
164 self._add_history(None, cleaned_buffer.rstrip())
165 result = self.engine.shell.execute(cleaned_buffer)
166 self.render_result(result)
167 self.new_prompt(self.prompt % (result['number'] + 1))
168 self.multi_line_input = False
169 else:
170 if self.multi_line_input:
171 self.write('\n' + self._get_indent_string(current_buffer))
172 else:
173 self.multi_line_input = True
174 self.write('\n\t')
175 else:
176 self.write('\n'+self._get_indent_string(current_buffer))
177
178
179 def _get_indent_string(self, string):
180 string = string.split('\n')[-1]
181 indent_chars = len(string) - len(string.lstrip())
182 indent_string = '\t'*(indent_chars // 4) + \
183 ' '*(indent_chars % 4)
184
185 return indent_string
186
187
91
188
92
189 if __name__ == '__main__':
93 if __name__ == '__main__':
General Comments 0
You need to be logged in to leave comments. Login now