##// END OF EJS Templates
for code review
Barry Wark -
Show More
@@ -1,254 +1,295 b''
1 1 # encoding: utf-8
2 2 """
3 FrontEndBase: Base classes for frontends.
3 frontendbase provides an interface and base class for GUI frontends for IPython.kernel/IPython.kernel.core.
4 4
5 Todo:
6 - synchronous and asynchronous interfaces
7 - adapter to add async to FrontEndBase
5 Frontend implementations will likely want to subclass FrontEndBase.
6
7 Author: Barry Wark
8 8 """
9 9 __docformat__ = "restructuredtext en"
10 10
11 11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 Barry Wark <barrywark at gmail _dot_ com>
12 # Copyright (C) 2008 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-------------------------------------------------------------------------------
17 17
18 18 #-------------------------------------------------------------------------------
19 19 # Imports
20 20 #-------------------------------------------------------------------------------
21 21 import string
22 22 import uuid
23 23
24 24
25 25 from IPython.kernel.core.history import FrontEndHistory
26 26 from IPython.kernel.core.util import Bunch
27 27
28 28 from IPython.kernel.engineservice import IEngineCore
29 29
30 30 import zope.interface as zi
31 31
32 32 import _ast
33 33
34 34 ##############################################################################
35 35 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
36 36 # not
37 37
38 38 rc = Bunch()
39 39 rc.prompt_in1 = r'In [$number]: '
40 40 rc.prompt_in2 = r'...'
41 41 rc.prompt_out = r'Out [$number]: '
42 42
43 43 ##############################################################################
44 44
45 class IFrontEnd(zi.Interface):
46 """Interface for frontends. All methods return t.i.d.Deferred"""
45 class IFrontEndFactory(zi.Interface):
46 """Factory interface for frontends."""
47 47
48 zi.Attribute("input_prompt_template", "string.Template instance substituteable with execute result.")
49 zi.Attribute("output_prompt_template", "string.Template instance substituteable with execute result.")
50 zi.Attribute("continuation_prompt_template", "string.Template instance substituteable with execute result.")
51
52 def __init__(engine=None, history=None):
48 def __call__(engine=None, history=None):
53 49 """
54 50 Parameters:
55 51 interpreter : IPython.kernel.engineservice.IEngineCore
56 52 """
53
57 54 pass
55
56
57
58 class IFrontEnd(zi.Interface):
59 """Interface for frontends. All methods return t.i.d.Deferred"""
60
61 zi.Attribute("input_prompt_template", "string.Template instance substituteable with execute result.")
62 zi.Attribute("output_prompt_template", "string.Template instance substituteable with execute result.")
63 zi.Attribute("continuation_prompt_template", "string.Template instance substituteable with execute result.")
58 64
59 65 def update_cell_prompt(self, result):
60 66 """Subclass may override to update the input prompt for a block.
61 67 Since this method will be called as a twisted.internet.defer.Deferred's callback,
62 68 implementations should return result when finished."""
63 69
64 return result
70 pass
65 71
66 72 def render_result(self, result):
67 73 """Render the result of an execute call. Implementors may choose the method of rendering.
68 74 For example, a notebook-style frontend might render a Chaco plot inline.
69 75
70 76 Parameters:
71 77 result : dict (result of IEngineBase.execute )
72 78
73 79 Result:
74 80 Output of frontend rendering
75 81 """
76 82
77 return result
83 pass
78 84
79 85 def render_error(self, failure):
80 86 """Subclasses must override to render the failure. Since this method will be called as a
81 87 twisted.internet.defer.Deferred's callback, implementations should return result
82 88 when finished."""
83 89
84 return failure
90 pass
91
92
93 def inputPrompt(result={}):
94 """Returns the input prompt by subsituting into self.input_prompt_template"""
95 pass
96
97 def outputPrompt(result):
98 """Returns the output prompt by subsituting into self.output_prompt_template"""
99
100 pass
101
102 def continuationPrompt():
103 """Returns the continuation prompt by subsituting into self.continuation_prompt_template"""
104
105 pass
106
107 def is_complete(block):
108 """Returns True if block is complete, False otherwise."""
109
110 pass
111
112 def compile_ast(block):
113 """Compiles block to an _ast.AST"""
114
115 pass
116
117
118 def get_history_item_previous(currentBlock):
119 """Returns the block previous in the history."""
120 pass
121
122 def get_history_item_next(currentBlock):
123 """Returns the next block in the history."""
124
125 pass
85 126
86 # TODO: finish interface
87 127
88 128 class FrontEndBase(object):
89 129 """
90 130 FrontEndBase manages the state tasks for a CLI frontend:
91 131 - Input and output history management
92 132 - Input/continuation and output prompt generation
93 133
94 134 Some issues (due to possibly unavailable engine):
95 135 - How do we get the current cell number for the engine?
96 136 - How do we handle completions?
97 137 """
98 138
99 139 zi.implements(IFrontEnd)
140 zi.classProvides(IFrontEndFactory)
100 141
101 142 history_cursor = 0
102 143
103 144 current_indent_level = 0
104 145
105 146
106 147 input_prompt_template = string.Template(rc.prompt_in1)
107 148 output_prompt_template = string.Template(rc.prompt_out)
108 149 continuation_prompt_template = string.Template(rc.prompt_in2)
109 150
110 151 def __init__(self, engine=None, history=None):
111 152 assert(engine==None or IEngineCore.providedBy(engine))
112 153 self.engine = IEngineCore(engine)
113 154 if history is None:
114 155 self.history = FrontEndHistory(input_cache=[''])
115 156 else:
116 157 self.history = history
117 158
118 159
119 160 def inputPrompt(self, result={}):
120 161 """Returns the current input prompt
121 162
122 163 It would be great to use ipython1.core.prompts.Prompt1 here
123 164 """
124 165
125 166 result.setdefault('number','')
126 167
127 168 return self.input_prompt_template.safe_substitute(result)
128 169
129 170
130 171 def continuationPrompt(self):
131 172 """Returns the current continuation prompt"""
132 173
133 174 return self.continuation_prompt_template.safe_substitute()
134 175
135 176 def outputPrompt(self, result):
136 177 """Returns the output prompt for result"""
137 178
138 179 return self.output_prompt_template.safe_substitute(result)
139 180
140 181
141 182 def is_complete(self, block):
142 183 """Determine if block is complete.
143 184
144 185 Parameters
145 186 block : string
146 187
147 188 Result
148 189 True if block can be sent to the engine without compile errors.
149 190 False otherwise.
150 191 """
151 192
152 193 try:
153 194 self.compile_ast(block)
154 195 return True
155 196 except:
156 197 return False
157 198
158 199
159 200 def compile_ast(self, block):
160 201 """Compile block to an AST
161 202
162 203 Parameters:
163 204 block : str
164 205
165 206 Result:
166 207 AST
167 208
168 209 Throws:
169 210 Exception if block cannot be compiled
170 211 """
171 212
172 213 return compile(block, "<string>", "exec", _ast.PyCF_ONLY_AST)
173 214
174 215
175 216 def execute(self, block, blockID=None):
176 217 """Execute the block and return result.
177 218
178 219 Parameters:
179 220 block : {str, AST}
180 221 blockID : any
181 222 Caller may provide an ID to identify this block. result['blockID'] := blockID
182 223
183 224 Result:
184 225 Deferred result of self.interpreter.execute
185 226 """
186 227 # if(not isinstance(block, _ast.AST)):
187 228 # block = self.compile_ast(block)
188 229
189 230 if(blockID == None):
190 231 blockID = uuid.uuid4() #random UUID
191 232
192 233 d = self.engine.execute(block)
193 234 d.addCallback(self._add_block_id, blockID)
194 235 d.addCallback(self.update_cell_prompt)
195 236 d.addCallbacks(self.render_result, errback=self.render_error)
196 237
197 238 return d
198 239
199 240 def _add_block_id(self, result, blockID):
200 241 """add_block_id"""
201 242
202 243 result['blockID'] = blockID
203 244
204 245 return result
205 246
206 247
207 def get_history_item_previous(self, current_block):
248 def get_history_item_previous(self, currentBlock):
208 249 """ Returns previous history string and decrement history cursor.
209 250 """
210 251 command = self.history.get_history_item(self.history_cursor - 1)
211 252 if command is not None:
212 self.history.input_cache[self.history_cursor] = current_block
253 self.history.input_cache[self.history_cursor] = currentBlock
213 254 self.history_cursor -= 1
214 255 return command
215 256
216 257
217 def get_history_item_next(self, current_block):
258 def get_history_item_next(self, currentBlock):
218 259 """ Returns next history string and increment history cursor.
219 260 """
220 261 command = self.history.get_history_item(self.history_cursor + 1)
221 262 if command is not None:
222 self.history.input_cache[self.history_cursor] = current_block
263 self.history.input_cache[self.history_cursor] = currentBlock
223 264 self.history_cursor += 1
224 265 return command
225 266
226 267 ###
227 268 # Subclasses probably want to override these methods...
228 269 ###
229 270
230 271 def update_cell_prompt(self, result):
231 272 """Subclass may override to update the input prompt for a block.
232 273 Since this method will be called as a twisted.internet.defer.Deferred's callback,
233 274 implementations should return result when finished."""
234 275
235 276 return result
236 277
237 278
238 279 def render_result(self, result):
239 280 """Subclasses must override to render result. Since this method will be called as a
240 281 twisted.internet.defer.Deferred's callback, implementations should return result
241 282 when finished."""
242 283
243 284 return result
244 285
245 286
246 287 def render_error(self, failure):
247 288 """Subclasses must override to render the failure. Since this method will be called as a
248 289 twisted.internet.defer.Deferred's callback, implementations should return result
249 290 when finished."""
250 291
251 292 return failure
252 293
253 294
254 295
General Comments 0
You need to be logged in to leave comments. Login now