##// END OF EJS Templates
Fixing minor bugs in tests.
Brian Granger -
r1559:2353c578 merge
parent child Browse files
Show More
@@ -1,92 +1,76 b''
1 """
1 """
2 Base front end class for all async frontends.
2 Base front end class for all async frontends.
3 """
3 """
4 __docformat__ = "restructuredtext en"
4 __docformat__ = "restructuredtext en"
5
5
6 #-------------------------------------------------------------------------------
6 #-------------------------------------------------------------------------------
7 # Copyright (C) 2008 The IPython Development Team
7 # Copyright (C) 2008 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-------------------------------------------------------------------------------
11 #-------------------------------------------------------------------------------
12
12
13
13
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17 import uuid
17 import uuid
18
18
19 try:
20 from zope.interface import Interface, Attribute, implements, classProvides
21 except ImportError, e:
22 e.message = """%s
23 ________________________________________________________________________________
24 zope.interface is required to run asynchronous frontends.""" % e.message
25 e.args = (e.message, ) + e.args[1:]
26
27 from frontendbase import FrontEndBase, IFrontEnd, IFrontEndFactory
28
19
20 from zope.interface import Interface, Attribute, implements, classProvides
21 from twisted.python.failure import Failure
22 from IPython.frontend.frontendbase import FrontEndBase, IFrontEnd, IFrontEndFactory
29 from IPython.kernel.core.history import FrontEndHistory
23 from IPython.kernel.core.history import FrontEndHistory
30
24 from IPython.kernel.engineservice import IEngineCore
31 try:
32 from IPython.kernel.engineservice import IEngineCore
33 from twisted.python.failure import Failure
34 except ImportError, e:
35 e.message = """%s
36 ________________________________________________________________________________
37 twisted is required to run asynchronous frontends.""" % e.message
38 e.args = (e.message, ) + e.args[1:]
39
40
41
25
42
26
43 class AsyncFrontEndBase(FrontEndBase):
27 class AsyncFrontEndBase(FrontEndBase):
44 """
28 """
45 Overrides FrontEndBase to wrap execute in a deferred result.
29 Overrides FrontEndBase to wrap execute in a deferred result.
46 All callbacks are made as callbacks on the deferred result.
30 All callbacks are made as callbacks on the deferred result.
47 """
31 """
48
32
49 implements(IFrontEnd)
33 implements(IFrontEnd)
50 classProvides(IFrontEndFactory)
34 classProvides(IFrontEndFactory)
51
35
52 def __init__(self, engine=None, history=None):
36 def __init__(self, engine=None, history=None):
53 assert(engine==None or IEngineCore.providedBy(engine))
37 assert(engine==None or IEngineCore.providedBy(engine))
54 self.engine = IEngineCore(engine)
38 self.engine = IEngineCore(engine)
55 if history is None:
39 if history is None:
56 self.history = FrontEndHistory(input_cache=[''])
40 self.history = FrontEndHistory(input_cache=[''])
57 else:
41 else:
58 self.history = history
42 self.history = history
59
43
60
44
61 def execute(self, block, blockID=None):
45 def execute(self, block, blockID=None):
62 """Execute the block and return the deferred result.
46 """Execute the block and return the deferred result.
63
47
64 Parameters:
48 Parameters:
65 block : {str, AST}
49 block : {str, AST}
66 blockID : any
50 blockID : any
67 Caller may provide an ID to identify this block.
51 Caller may provide an ID to identify this block.
68 result['blockID'] := blockID
52 result['blockID'] := blockID
69
53
70 Result:
54 Result:
71 Deferred result of self.interpreter.execute
55 Deferred result of self.interpreter.execute
72 """
56 """
73
57
74 if(not self.is_complete(block)):
58 if(not self.is_complete(block)):
75 return Failure(Exception("Block is not compilable"))
59 return Failure(Exception("Block is not compilable"))
76
60
77 if(blockID == None):
61 if(blockID == None):
78 blockID = uuid.uuid4() #random UUID
62 blockID = uuid.uuid4() #random UUID
79
63
80 d = self.engine.execute(block)
64 d = self.engine.execute(block)
81 d.addCallback(self._add_history, block=block)
65 d.addCallback(self._add_history, block=block)
82 d.addCallbacks(self._add_block_id_for_result,
66 d.addCallbacks(self._add_block_id_for_result,
83 errback=self._add_block_id_for_failure,
67 errback=self._add_block_id_for_failure,
84 callbackArgs=(blockID,),
68 callbackArgs=(blockID,),
85 errbackArgs=(blockID,))
69 errbackArgs=(blockID,))
86 d.addBoth(self.update_cell_prompt, blockID=blockID)
70 d.addBoth(self.update_cell_prompt, blockID=blockID)
87 d.addCallbacks(self.render_result,
71 d.addCallbacks(self.render_result,
88 errback=self.render_error)
72 errback=self.render_error)
89
73
90 return d
74 return d
91
75
92
76
@@ -1,358 +1,362 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
3 """
3 """
4 frontendbase provides an interface and base class for GUI frontends for
4 frontendbase provides an interface and base class for GUI frontends for
5 IPython.kernel/IPython.kernel.core.
5 IPython.kernel/IPython.kernel.core.
6
6
7 Frontend implementations will likely want to subclass FrontEndBase.
7 Frontend implementations will likely want to subclass FrontEndBase.
8
8
9 Author: Barry Wark
9 Author: Barry Wark
10 """
10 """
11 __docformat__ = "restructuredtext en"
11 __docformat__ = "restructuredtext en"
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import string
23 import string
24 import uuid
24 import uuid
25 import _ast
25 import _ast
26
26
27 from zopeinterface import Interface, Attribute, implements, classProvides
27 from IPython.frontend.zopeinterface import (
28
28 Interface,
29 Attribute,
30 implements,
31 classProvides
32 )
29 from IPython.kernel.core.history import FrontEndHistory
33 from IPython.kernel.core.history import FrontEndHistory
30 from IPython.kernel.core.util import Bunch
34 from IPython.kernel.core.util import Bunch
31
35
32 ##############################################################################
36 ##############################################################################
33 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
37 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
34 # not
38 # not
35
39
36 rc = Bunch()
40 rc = Bunch()
37 rc.prompt_in1 = r'In [$number]: '
41 rc.prompt_in1 = r'In [$number]: '
38 rc.prompt_in2 = r'...'
42 rc.prompt_in2 = r'...'
39 rc.prompt_out = r'Out [$number]: '
43 rc.prompt_out = r'Out [$number]: '
40
44
41 ##############################################################################
45 ##############################################################################
42 # Interface definitions
46 # Interface definitions
43 ##############################################################################
47 ##############################################################################
44
48
45 class IFrontEndFactory(Interface):
49 class IFrontEndFactory(Interface):
46 """Factory interface for frontends."""
50 """Factory interface for frontends."""
47
51
48 def __call__(engine=None, history=None):
52 def __call__(engine=None, history=None):
49 """
53 """
50 Parameters:
54 Parameters:
51 interpreter : IPython.kernel.engineservice.IEngineCore
55 interpreter : IPython.kernel.engineservice.IEngineCore
52 """
56 """
53
57
54 pass
58 pass
55
59
56
60
57 class IFrontEnd(Interface):
61 class IFrontEnd(Interface):
58 """Interface for frontends. All methods return t.i.d.Deferred"""
62 """Interface for frontends. All methods return t.i.d.Deferred"""
59
63
60 Attribute("input_prompt_template", "string.Template instance\
64 Attribute("input_prompt_template", "string.Template instance\
61 substituteable with execute result.")
65 substituteable with execute result.")
62 Attribute("output_prompt_template", "string.Template instance\
66 Attribute("output_prompt_template", "string.Template instance\
63 substituteable with execute result.")
67 substituteable with execute result.")
64 Attribute("continuation_prompt_template", "string.Template instance\
68 Attribute("continuation_prompt_template", "string.Template instance\
65 substituteable with execute result.")
69 substituteable with execute result.")
66
70
67 def update_cell_prompt(result, blockID=None):
71 def update_cell_prompt(result, blockID=None):
68 """Subclass may override to update the input prompt for a block.
72 """Subclass may override to update the input prompt for a block.
69
73
70 In asynchronous frontends, this method will be called as a
74 In asynchronous frontends, this method will be called as a
71 twisted.internet.defer.Deferred's callback/errback.
75 twisted.internet.defer.Deferred's callback/errback.
72 Implementations should thus return result when finished.
76 Implementations should thus return result when finished.
73
77
74 Result is a result dict in case of success, and a
78 Result is a result dict in case of success, and a
75 twisted.python.util.failure.Failure in case of an error
79 twisted.python.util.failure.Failure in case of an error
76 """
80 """
77
81
78 pass
82 pass
79
83
80 def render_result(result):
84 def render_result(result):
81 """Render the result of an execute call. Implementors may choose the
85 """Render the result of an execute call. Implementors may choose the
82 method of rendering.
86 method of rendering.
83 For example, a notebook-style frontend might render a Chaco plot
87 For example, a notebook-style frontend might render a Chaco plot
84 inline.
88 inline.
85
89
86 Parameters:
90 Parameters:
87 result : dict (result of IEngineBase.execute )
91 result : dict (result of IEngineBase.execute )
88 blockID = result['blockID']
92 blockID = result['blockID']
89
93
90 Result:
94 Result:
91 Output of frontend rendering
95 Output of frontend rendering
92 """
96 """
93
97
94 pass
98 pass
95
99
96 def render_error(failure):
100 def render_error(failure):
97 """Subclasses must override to render the failure.
101 """Subclasses must override to render the failure.
98
102
99 In asynchronous frontend, since this method will be called as a
103 In asynchronous frontend, since this method will be called as a
100 twisted.internet.defer.Deferred's callback. Implementations
104 twisted.internet.defer.Deferred's callback. Implementations
101 should thus return result when finished.
105 should thus return result when finished.
102
106
103 blockID = failure.blockID
107 blockID = failure.blockID
104 """
108 """
105
109
106 pass
110 pass
107
111
108 def input_prompt(number=''):
112 def input_prompt(number=''):
109 """Returns the input prompt by subsituting into
113 """Returns the input prompt by subsituting into
110 self.input_prompt_template
114 self.input_prompt_template
111 """
115 """
112 pass
116 pass
113
117
114 def output_prompt(number=''):
118 def output_prompt(number=''):
115 """Returns the output prompt by subsituting into
119 """Returns the output prompt by subsituting into
116 self.output_prompt_template
120 self.output_prompt_template
117 """
121 """
118
122
119 pass
123 pass
120
124
121 def continuation_prompt():
125 def continuation_prompt():
122 """Returns the continuation prompt by subsituting into
126 """Returns the continuation prompt by subsituting into
123 self.continuation_prompt_template
127 self.continuation_prompt_template
124 """
128 """
125
129
126 pass
130 pass
127
131
128 def is_complete(block):
132 def is_complete(block):
129 """Returns True if block is complete, False otherwise."""
133 """Returns True if block is complete, False otherwise."""
130
134
131 pass
135 pass
132
136
133 def compile_ast(block):
137 def compile_ast(block):
134 """Compiles block to an _ast.AST"""
138 """Compiles block to an _ast.AST"""
135
139
136 pass
140 pass
137
141
138 def get_history_previous(current_block):
142 def get_history_previous(current_block):
139 """Returns the block previous in the history. Saves currentBlock if
143 """Returns the block previous in the history. Saves currentBlock if
140 the history_cursor is currently at the end of the input history"""
144 the history_cursor is currently at the end of the input history"""
141 pass
145 pass
142
146
143 def get_history_next():
147 def get_history_next():
144 """Returns the next block in the history."""
148 """Returns the next block in the history."""
145
149
146 pass
150 pass
147
151
148 def complete(self, line):
152 def complete(self, line):
149 """Returns the list of possible completions, and the completed
153 """Returns the list of possible completions, and the completed
150 line.
154 line.
151
155
152 The input argument is the full line to be completed. This method
156 The input argument is the full line to be completed. This method
153 returns both the line completed as much as possible, and the list
157 returns both the line completed as much as possible, and the list
154 of further possible completions (full words).
158 of further possible completions (full words).
155 """
159 """
156 pass
160 pass
157
161
158
162
159 ##############################################################################
163 ##############################################################################
160 # Base class for all the frontends.
164 # Base class for all the frontends.
161 ##############################################################################
165 ##############################################################################
162
166
163 class FrontEndBase(object):
167 class FrontEndBase(object):
164 """
168 """
165 FrontEndBase manages the state tasks for a CLI frontend:
169 FrontEndBase manages the state tasks for a CLI frontend:
166 - Input and output history management
170 - Input and output history management
167 - Input/continuation and output prompt generation
171 - Input/continuation and output prompt generation
168
172
169 Some issues (due to possibly unavailable engine):
173 Some issues (due to possibly unavailable engine):
170 - How do we get the current cell number for the engine?
174 - How do we get the current cell number for the engine?
171 - How do we handle completions?
175 - How do we handle completions?
172 """
176 """
173
177
174 history_cursor = 0
178 history_cursor = 0
175
179
176 input_prompt_template = string.Template(rc.prompt_in1)
180 input_prompt_template = string.Template(rc.prompt_in1)
177 output_prompt_template = string.Template(rc.prompt_out)
181 output_prompt_template = string.Template(rc.prompt_out)
178 continuation_prompt_template = string.Template(rc.prompt_in2)
182 continuation_prompt_template = string.Template(rc.prompt_in2)
179
183
180 def __init__(self, shell=None, history=None):
184 def __init__(self, shell=None, history=None):
181 self.shell = shell
185 self.shell = shell
182 if history is None:
186 if history is None:
183 self.history = FrontEndHistory(input_cache=[''])
187 self.history = FrontEndHistory(input_cache=[''])
184 else:
188 else:
185 self.history = history
189 self.history = history
186
190
187
191
188 def input_prompt(self, number=''):
192 def input_prompt(self, number=''):
189 """Returns the current input prompt
193 """Returns the current input prompt
190
194
191 It would be great to use ipython1.core.prompts.Prompt1 here
195 It would be great to use ipython1.core.prompts.Prompt1 here
192 """
196 """
193 return self.input_prompt_template.safe_substitute({'number':number})
197 return self.input_prompt_template.safe_substitute({'number':number})
194
198
195
199
196 def continuation_prompt(self):
200 def continuation_prompt(self):
197 """Returns the current continuation prompt"""
201 """Returns the current continuation prompt"""
198
202
199 return self.continuation_prompt_template.safe_substitute()
203 return self.continuation_prompt_template.safe_substitute()
200
204
201 def output_prompt(self, number=''):
205 def output_prompt(self, number=''):
202 """Returns the output prompt for result"""
206 """Returns the output prompt for result"""
203
207
204 return self.output_prompt_template.safe_substitute({'number':number})
208 return self.output_prompt_template.safe_substitute({'number':number})
205
209
206
210
207 def is_complete(self, block):
211 def is_complete(self, block):
208 """Determine if block is complete.
212 """Determine if block is complete.
209
213
210 Parameters
214 Parameters
211 block : string
215 block : string
212
216
213 Result
217 Result
214 True if block can be sent to the engine without compile errors.
218 True if block can be sent to the engine without compile errors.
215 False otherwise.
219 False otherwise.
216 """
220 """
217
221
218 try:
222 try:
219 ast = self.compile_ast(block)
223 ast = self.compile_ast(block)
220 except:
224 except:
221 return False
225 return False
222
226
223 lines = block.split('\n')
227 lines = block.split('\n')
224 return (len(lines)==1 or str(lines[-1])=='')
228 return (len(lines)==1 or str(lines[-1])=='')
225
229
226
230
227 def compile_ast(self, block):
231 def compile_ast(self, block):
228 """Compile block to an AST
232 """Compile block to an AST
229
233
230 Parameters:
234 Parameters:
231 block : str
235 block : str
232
236
233 Result:
237 Result:
234 AST
238 AST
235
239
236 Throws:
240 Throws:
237 Exception if block cannot be compiled
241 Exception if block cannot be compiled
238 """
242 """
239
243
240 return compile(block, "<string>", "exec", _ast.PyCF_ONLY_AST)
244 return compile(block, "<string>", "exec", _ast.PyCF_ONLY_AST)
241
245
242
246
243 def execute(self, block, blockID=None):
247 def execute(self, block, blockID=None):
244 """Execute the block and return the result.
248 """Execute the block and return the result.
245
249
246 Parameters:
250 Parameters:
247 block : {str, AST}
251 block : {str, AST}
248 blockID : any
252 blockID : any
249 Caller may provide an ID to identify this block.
253 Caller may provide an ID to identify this block.
250 result['blockID'] := blockID
254 result['blockID'] := blockID
251
255
252 Result:
256 Result:
253 Deferred result of self.interpreter.execute
257 Deferred result of self.interpreter.execute
254 """
258 """
255
259
256 if(not self.is_complete(block)):
260 if(not self.is_complete(block)):
257 raise Exception("Block is not compilable")
261 raise Exception("Block is not compilable")
258
262
259 if(blockID == None):
263 if(blockID == None):
260 blockID = uuid.uuid4() #random UUID
264 blockID = uuid.uuid4() #random UUID
261
265
262 try:
266 try:
263 result = self.shell.execute(block)
267 result = self.shell.execute(block)
264 except Exception,e:
268 except Exception,e:
265 e = self._add_block_id_for_failure(e, blockID=blockID)
269 e = self._add_block_id_for_failure(e, blockID=blockID)
266 e = self.update_cell_prompt(e, blockID=blockID)
270 e = self.update_cell_prompt(e, blockID=blockID)
267 e = self.render_error(e)
271 e = self.render_error(e)
268 else:
272 else:
269 result = self._add_block_id_for_result(result, blockID=blockID)
273 result = self._add_block_id_for_result(result, blockID=blockID)
270 result = self.update_cell_prompt(result, blockID=blockID)
274 result = self.update_cell_prompt(result, blockID=blockID)
271 result = self.render_result(result)
275 result = self.render_result(result)
272
276
273 return result
277 return result
274
278
275
279
276 def _add_block_id_for_result(self, result, blockID):
280 def _add_block_id_for_result(self, result, blockID):
277 """Add the blockID to result or failure. Unfortunatley, we have to
281 """Add the blockID to result or failure. Unfortunatley, we have to
278 treat failures differently than result dicts.
282 treat failures differently than result dicts.
279 """
283 """
280
284
281 result['blockID'] = blockID
285 result['blockID'] = blockID
282
286
283 return result
287 return result
284
288
285 def _add_block_id_for_failure(self, failure, blockID):
289 def _add_block_id_for_failure(self, failure, blockID):
286 """_add_block_id_for_failure"""
290 """_add_block_id_for_failure"""
287 failure.blockID = blockID
291 failure.blockID = blockID
288 return failure
292 return failure
289
293
290
294
291 def _add_history(self, result, block=None):
295 def _add_history(self, result, block=None):
292 """Add block to the history"""
296 """Add block to the history"""
293
297
294 assert(block != None)
298 assert(block != None)
295 self.history.add_items([block])
299 self.history.add_items([block])
296 self.history_cursor += 1
300 self.history_cursor += 1
297
301
298 return result
302 return result
299
303
300
304
301 def get_history_previous(self, current_block):
305 def get_history_previous(self, current_block):
302 """ Returns previous history string and decrement history cursor.
306 """ Returns previous history string and decrement history cursor.
303 """
307 """
304 command = self.history.get_history_item(self.history_cursor - 1)
308 command = self.history.get_history_item(self.history_cursor - 1)
305
309
306 if command is not None:
310 if command is not None:
307 if(self.history_cursor+1 == len(self.history.input_cache)):
311 if(self.history_cursor+1 == len(self.history.input_cache)):
308 self.history.input_cache[self.history_cursor] = current_block
312 self.history.input_cache[self.history_cursor] = current_block
309 self.history_cursor -= 1
313 self.history_cursor -= 1
310 return command
314 return command
311
315
312
316
313 def get_history_next(self):
317 def get_history_next(self):
314 """ Returns next history string and increment history cursor.
318 """ Returns next history string and increment history cursor.
315 """
319 """
316 command = self.history.get_history_item(self.history_cursor+1)
320 command = self.history.get_history_item(self.history_cursor+1)
317
321
318 if command is not None:
322 if command is not None:
319 self.history_cursor += 1
323 self.history_cursor += 1
320 return command
324 return command
321
325
322 ###
326 ###
323 # Subclasses probably want to override these methods...
327 # Subclasses probably want to override these methods...
324 ###
328 ###
325
329
326 def update_cell_prompt(self, result, blockID=None):
330 def update_cell_prompt(self, result, blockID=None):
327 """Subclass may override to update the input prompt for a block.
331 """Subclass may override to update the input prompt for a block.
328
332
329 This method only really makes sens in asyncrhonous frontend.
333 This method only really makes sens in asyncrhonous frontend.
330 Since this method will be called as a
334 Since this method will be called as a
331 twisted.internet.defer.Deferred's callback, implementations should
335 twisted.internet.defer.Deferred's callback, implementations should
332 return result when finished.
336 return result when finished.
333 """
337 """
334
338
335 raise NotImplementedError
339 raise NotImplementedError
336
340
337
341
338 def render_result(self, result):
342 def render_result(self, result):
339 """Subclasses must override to render result.
343 """Subclasses must override to render result.
340
344
341 In asynchronous frontends, this method will be called as a
345 In asynchronous frontends, this method will be called as a
342 twisted.internet.defer.Deferred's callback. Implementations
346 twisted.internet.defer.Deferred's callback. Implementations
343 should thus return result when finished.
347 should thus return result when finished.
344 """
348 """
345
349
346 raise NotImplementedError
350 raise NotImplementedError
347
351
348
352
349 def render_error(self, failure):
353 def render_error(self, failure):
350 """Subclasses must override to render the failure.
354 """Subclasses must override to render the failure.
351
355
352 In asynchronous frontends, this method will be called as a
356 In asynchronous frontends, this method will be called as a
353 twisted.internet.defer.Deferred's callback. Implementations
357 twisted.internet.defer.Deferred's callback. Implementations
354 should thus return result when finished.
358 should thus return result when finished.
355 """
359 """
356
360
357 raise NotImplementedError
361 raise NotImplementedError
358
362
@@ -1,401 +1,391 b''
1 .. _development:
1 .. _development:
2
2
3 ==================================
3 ==================================
4 IPython development guidelines
4 IPython development guidelines
5 ==================================
5 ==================================
6
6
7 .. contents::
7 .. contents::
8
8
9
9
10 Overview
10 Overview
11 ========
11 ========
12
12
13 IPython is the next generation of IPython. It is named such for two reasons:
13 IPython is the next generation of IPython. It is named such for two reasons:
14
14
15 - Eventually, IPython will become IPython version 1.0.
15 - Eventually, IPython will become IPython version 1.0.
16 - This new code base needs to be able to co-exist with the existing IPython until
16 - This new code base needs to be able to co-exist with the existing IPython until
17 it is a full replacement for it. Thus we needed a different name. We couldn't
17 it is a full replacement for it. Thus we needed a different name. We couldn't
18 use ``ipython`` (lowercase) as some files systems are case insensitive.
18 use ``ipython`` (lowercase) as some files systems are case insensitive.
19
19
20 There are two, no three, main goals of the IPython effort:
20 There are two, no three, main goals of the IPython effort:
21
21
22 1. Clean up the existing codebase and write lots of tests.
22 1. Clean up the existing codebase and write lots of tests.
23 2. Separate the core functionality of IPython from the terminal to enable IPython
23 2. Separate the core functionality of IPython from the terminal to enable IPython
24 to be used from within a variety of GUI applications.
24 to be used from within a variety of GUI applications.
25 3. Implement a system for interactive parallel computing.
25 3. Implement a system for interactive parallel computing.
26
26
27 While the third goal may seem a bit unrelated to the main focus of IPython, it turns
27 While the third goal may seem a bit unrelated to the main focus of IPython, it turns
28 out that the technologies required for this goal are nearly identical with those
28 out that the technologies required for this goal are nearly identical with those
29 required for goal two. This is the main reason the interactive parallel computing
29 required for goal two. This is the main reason the interactive parallel computing
30 capabilities are being put into IPython proper. Currently the third of these goals is
30 capabilities are being put into IPython proper. Currently the third of these goals is
31 furthest along.
31 furthest along.
32
32
33 This document describes IPython from the perspective of developers.
33 This document describes IPython from the perspective of developers.
34
34
35
35
36 Project organization
36 Project organization
37 ====================
37 ====================
38
38
39 Subpackages
39 Subpackages
40 -----------
40 -----------
41
41
42 IPython is organized into semi self-contained subpackages. Each of the subpackages will have its own:
42 IPython is organized into semi self-contained subpackages. Each of the subpackages will have its own:
43
43
44 - **Dependencies**. One of the most important things to keep in mind in
44 - **Dependencies**. One of the most important things to keep in mind in
45 partitioning code amongst subpackages, is that they should be used to cleanly
45 partitioning code amongst subpackages, is that they should be used to cleanly
46 encapsulate dependencies.
46 encapsulate dependencies.
47 - **Tests**. Each subpackage shoud have its own ``tests`` subdirectory that
47 - **Tests**. Each subpackage shoud have its own ``tests`` subdirectory that
48 contains all of the tests for that package. For information about writing tests
48 contains all of the tests for that package. For information about writing tests
49 for IPython, see the `Testing System`_ section of this document.
49 for IPython, see the `Testing System`_ section of this document.
50 - **Configuration**. Each subpackage should have its own ``config`` subdirectory
50 - **Configuration**. Each subpackage should have its own ``config`` subdirectory
51 that contains the configuration information for the components of the
51 that contains the configuration information for the components of the
52 subpackage. For information about how the IPython configuration system
52 subpackage. For information about how the IPython configuration system
53 works, see the `Configuration System`_ section of this document.
53 works, see the `Configuration System`_ section of this document.
54 - **Scripts**. Each subpackage should have its own ``scripts`` subdirectory that
54 - **Scripts**. Each subpackage should have its own ``scripts`` subdirectory that
55 contains all of the command line scripts associated with the subpackage.
55 contains all of the command line scripts associated with the subpackage.
56
56
57 Installation and dependencies
57 Installation and dependencies
58 -----------------------------
58 -----------------------------
59
59
60 IPython will not use `setuptools`_ for installation. Instead, we will use standard
60 IPython will not use `setuptools`_ for installation. Instead, we will use standard
61 ``setup.py`` scripts that use `distutils`_. While there are a number a extremely nice
61 ``setup.py`` scripts that use `distutils`_. While there are a number a extremely nice
62 features that `setuptools`_ has (like namespace packages), the current implementation
62 features that `setuptools`_ has (like namespace packages), the current implementation
63 of `setuptools`_ has performance problems, particularly on shared file systems. In
63 of `setuptools`_ has performance problems, particularly on shared file systems. In
64 particular, when Python packages are installed on NSF file systems, import times
64 particular, when Python packages are installed on NSF file systems, import times
65 become much too long (up towards 10 seconds).
65 become much too long (up towards 10 seconds).
66
66
67 Because IPython is being used extensively in the context of high performance
67 Because IPython is being used extensively in the context of high performance
68 computing, where performance is critical but shared file systems are common, we feel
68 computing, where performance is critical but shared file systems are common, we feel
69 these performance hits are not acceptable. Thus, until the performance problems
69 these performance hits are not acceptable. Thus, until the performance problems
70 associated with `setuptools`_ are addressed, we will stick with plain `distutils`_. We
70 associated with `setuptools`_ are addressed, we will stick with plain `distutils`_. We
71 are hopeful that these problems will be addressed and that we will eventually begin
71 are hopeful that these problems will be addressed and that we will eventually begin
72 using `setuptools`_. Because of this, we are trying to organize IPython in a way that
72 using `setuptools`_. Because of this, we are trying to organize IPython in a way that
73 will make the eventual transition to `setuptools`_ as painless as possible.
73 will make the eventual transition to `setuptools`_ as painless as possible.
74
74
75 Because we will be using `distutils`_, there will be no method for automatically installing dependencies. Instead, we are following the approach of `Matplotlib`_ which can be summarized as follows:
75 Because we will be using `distutils`_, there will be no method for automatically installing dependencies. Instead, we are following the approach of `Matplotlib`_ which can be summarized as follows:
76
76
77 - Distinguish between required and optional dependencies. However, the required
77 - Distinguish between required and optional dependencies. However, the required
78 dependencies for IPython should be only the Python standard library.
78 dependencies for IPython should be only the Python standard library.
79 - Upon installation check to see which optional dependencies are present and tell
79 - Upon installation check to see which optional dependencies are present and tell
80 the user which parts of IPython need which optional dependencies.
80 the user which parts of IPython need which optional dependencies.
81
81
82 It is absolutely critical that each subpackage of IPython has a clearly specified set
82 It is absolutely critical that each subpackage of IPython has a clearly specified set
83 of dependencies and that dependencies are not carelessly inherited from other IPython
83 of dependencies and that dependencies are not carelessly inherited from other IPython
84 subpackages. Furthermore, tests that have certain dependencies should not fail if
84 subpackages. Furthermore, tests that have certain dependencies should not fail if
85 those dependencies are not present. Instead they should be skipped and print a
85 those dependencies are not present. Instead they should be skipped and print a
86 message.
86 message.
87
87
88 .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
88 .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
89 .. _distutils: http://docs.python.org/lib/module-distutils.html
89 .. _distutils: http://docs.python.org/lib/module-distutils.html
90 .. _Matplotlib: http://matplotlib.sourceforge.net/
90 .. _Matplotlib: http://matplotlib.sourceforge.net/
91
91
92 Specific subpackages
92 Specific subpackages
93 --------------------
93 --------------------
94
94
95 ``core``
95 ``core``
96 This is the core functionality of IPython that is independent of the
96 This is the core functionality of IPython that is independent of the
97 terminal, network and GUIs. Most of the code that is in the current
97 terminal, network and GUIs. Most of the code that is in the current
98 IPython trunk will be refactored, cleaned up and moved here.
98 IPython trunk will be refactored, cleaned up and moved here.
99
99
100 ``kernel``
100 ``kernel``
101 The enables the IPython core to be expose to a the network. This is
101 The enables the IPython core to be expose to a the network. This is
102 also where all of the parallel computing capabilities are to be found.
102 also where all of the parallel computing capabilities are to be found.
103
103
104 ``config``
104 ``config``
105 The configuration package used by IPython.
105 The configuration package used by IPython.
106
106
107 ``frontends``
107 ``frontends``
108 The various frontends for IPython. A frontend is the end-user application
108 The various frontends for IPython. A frontend is the end-user application
109 that exposes the capabilities of IPython to the user. The most basic frontend
109 that exposes the capabilities of IPython to the user. The most basic frontend
110 will simply be a terminal based application that looks just like today 's
110 will simply be a terminal based application that looks just like today 's
111 IPython. Other frontends will likely be more powerful and based on GUI toolkits.
111 IPython. Other frontends will likely be more powerful and based on GUI toolkits.
112
112
113 ``notebook``
113 ``notebook``
114 An application that allows users to work with IPython notebooks.
114 An application that allows users to work with IPython notebooks.
115
115
116 ``tools``
116 ``tools``
117 This is where general utilities go.
117 This is where general utilities go.
118
118
119
119
120 Version control
120 Version control
121 ===============
121 ===============
122
122
123 In the past, IPython development has been done using `Subversion`__. Recently, we made the transition to using `Bazaar`__ and `Launchpad`__. This makes it much easier for people
123 In the past, IPython development has been done using `Subversion`__. Recently, we made the transition to using `Bazaar`__ and `Launchpad`__. This makes it much easier for people
124 to contribute code to IPython. Here is a sketch of how to use Bazaar for IPython
124 to contribute code to IPython. Here is a sketch of how to use Bazaar for IPython
125 development. First, you should install Bazaar. After you have done that, make
125 development. First, you should install Bazaar. After you have done that, make
126 sure that it is working by getting the latest main branch of IPython::
126 sure that it is working by getting the latest main branch of IPython::
127
127
128 $ bzr branch lp:ipython
128 $ bzr branch lp:ipython
129
129
130 Now you can create a new branch for you to do your work in::
130 Now you can create a new branch for you to do your work in::
131
131
132 $ bzr branch ipython ipython-mybranch
132 $ bzr branch ipython ipython-mybranch
133
133
134 The typical work cycle in this branch will be to make changes in `ipython-mybranch`
134 The typical work cycle in this branch will be to make changes in `ipython-mybranch`
135 and then commit those changes using the commit command::
135 and then commit those changes using the commit command::
136
136
137 $ ...do work in ipython-mybranch...
137 $ ...do work in ipython-mybranch...
138 $ bzr ci -m "the commit message goes here"
138 $ bzr ci -m "the commit message goes here"
139
139
140 Please note that since we now don't use an old-style linear ChangeLog
140 Please note that since we now don't use an old-style linear ChangeLog
141 (that tends to cause problems with distributed version control
141 (that tends to cause problems with distributed version control
142 systems), you should ensure that your log messages are reasonably
142 systems), you should ensure that your log messages are reasonably
143 detailed. Use a docstring-like approach in the commit messages
143 detailed. Use a docstring-like approach in the commit messages
144 (including the second line being left *blank*)::
144 (including the second line being left *blank*)::
145
145
146 Single line summary of changes being committed.
146 Single line summary of changes being committed.
147
147
148 - more details when warranted ...
148 - more details when warranted ...
149 - including crediting outside contributors if they sent the
149 - including crediting outside contributors if they sent the
150 code/bug/idea!
150 code/bug/idea!
151
151
152 If we couple this with a policy of making single commits for each
152 If we couple this with a policy of making single commits for each
153 reasonably atomic change, the bzr log should give an excellent view of
153 reasonably atomic change, the bzr log should give an excellent view of
154 the project, and the `--short` log option becomes a nice summary.
154 the project, and the `--short` log option becomes a nice summary.
155
155
156 While working with this branch, it is a good idea to merge in changes that have been
156 While working with this branch, it is a good idea to merge in changes that have been
157 made upstream in the parent branch. This can be done by doing::
157 made upstream in the parent branch. This can be done by doing::
158
158
159 $ bzr pull
159 $ bzr pull
160
160
161 If this command shows that the branches have diverged, then you should do a merge
161 If this command shows that the branches have diverged, then you should do a merge
162 instead::
162 instead::
163
163
164 $ bzr merge lp:ipython
164 $ bzr merge lp:ipython
165
165
166 If you want others to be able to see your branch, you can create an account with
166 If you want others to be able to see your branch, you can create an account with
167 launchpad and push the branch to your own workspace::
167 launchpad and push the branch to your own workspace::
168
168
169 $ bzr push bzr+ssh://<me>@bazaar.launchpad.net/~<me>/+junk/ipython-mybranch
169 $ bzr push bzr+ssh://<me>@bazaar.launchpad.net/~<me>/+junk/ipython-mybranch
170
170
171 Finally, once the work in your branch is done, you can merge your changes back into
171 Finally, once the work in your branch is done, you can merge your changes back into
172 the `ipython` branch by using merge::
172 the `ipython` branch by using merge::
173
173
174 $ cd ipython
174 $ cd ipython
175 $ merge ../ipython-mybranch
175 $ merge ../ipython-mybranch
176 [resolve any conflicts]
176 [resolve any conflicts]
177 $ bzr ci -m "Fixing that bug"
177 $ bzr ci -m "Fixing that bug"
178 $ bzr push
178 $ bzr push
179
179
180 But this will require you to have write permissions to the `ipython` branch. It you don't
180 But this will require you to have write permissions to the `ipython` branch. It you don't
181 you can tell one of the IPython devs about your branch and they can do the merge for you.
181 you can tell one of the IPython devs about your branch and they can do the merge for you.
182
182
183 More information about Bazaar workflows can be found `here`__.
183 More information about Bazaar workflows can be found `here`__.
184
184
185 .. __: http://subversion.tigris.org/
185 .. __: http://subversion.tigris.org/
186 .. __: http://bazaar-vcs.org/
186 .. __: http://bazaar-vcs.org/
187 .. __: http://www.launchpad.net/ipython
187 .. __: http://www.launchpad.net/ipython
188 .. __: http://doc.bazaar-vcs.org/bzr.dev/en/user-guide/index.html
188 .. __: http://doc.bazaar-vcs.org/bzr.dev/en/user-guide/index.html
189
189
190 Documentation
190 Documentation
191 =============
191 =============
192
192
193 Standalone documentation
193 Standalone documentation
194 ------------------------
194 ------------------------
195
195
196 All standalone documentation should be written in plain text (``.txt``) files using
196 All standalone documentation should be written in plain text (``.txt``) files using
197 `reStructuredText`_ for markup and formatting. All such documentation should be placed
197 `reStructuredText`_ for markup and formatting. All such documentation should be placed
198 in the top level directory ``docs`` of the IPython source tree. Or, when appropriate,
198 in the top level directory ``docs`` of the IPython source tree. Or, when appropriate,
199 a suitably named subdirectory should be used. The documentation in this location will
199 a suitably named subdirectory should be used. The documentation in this location will
200 serve as the main source for IPython documentation and all existing documentation
200 serve as the main source for IPython documentation and all existing documentation
201 should be converted to this format.
201 should be converted to this format.
202
202
203 In the future, the text files in the ``docs`` directory will be used to generate all
203 In the future, the text files in the ``docs`` directory will be used to generate all
204 forms of documentation for IPython. This include documentation on the IPython website
204 forms of documentation for IPython. This include documentation on the IPython website
205 as well as *pdf* documentation.
205 as well as *pdf* documentation.
206
206
207 .. _reStructuredText: http://docutils.sourceforge.net/rst.html
207 .. _reStructuredText: http://docutils.sourceforge.net/rst.html
208
208
209 Docstring format
209 Docstring format
210 ----------------
210 ----------------
211
211
212 Good docstrings are very important. All new code will use `Epydoc`_ for generating API
212 Good docstrings are very important. All new code will use `Epydoc`_ for generating API
213 docs, so we will follow the `Epydoc`_ conventions. More specifically, we will use
213 docs, so we will follow the `Epydoc`_ conventions. More specifically, we will use
214 `reStructuredText`_ for markup and formatting, since it is understood by a wide
214 `reStructuredText`_ for markup and formatting, since it is understood by a wide
215 variety of tools. This means that if in the future we have any reason to change from
215 variety of tools. This means that if in the future we have any reason to change from
216 `Epydoc`_ to something else, we'll have fewer transition pains.
216 `Epydoc`_ to something else, we'll have fewer transition pains.
217
217
218 Details about using `reStructuredText`_ for docstrings can be found `here
218 Details about using `reStructuredText`_ for docstrings can be found `here
219 <http://epydoc.sourceforge.net/manual-othermarkup.html>`_.
219 <http://epydoc.sourceforge.net/manual-othermarkup.html>`_.
220
220
221 .. _Epydoc: http://epydoc.sourceforge.net/
221 .. _Epydoc: http://epydoc.sourceforge.net/
222
222
223 Additional PEPs of interest regarding documentation of code:
223 Additional PEPs of interest regarding documentation of code:
224
224
225 - `Docstring Conventions <http://www.python.org/peps/pep-0257.html>`_
225 - `Docstring Conventions <http://www.python.org/peps/pep-0257.html>`_
226 - `Docstring Processing System Framework <http://www.python.org/peps/pep-0256.html>`_
226 - `Docstring Processing System Framework <http://www.python.org/peps/pep-0256.html>`_
227 - `Docutils Design Specification <http://www.python.org/peps/pep-0258.html>`_
227 - `Docutils Design Specification <http://www.python.org/peps/pep-0258.html>`_
228
228
229
229
230 Coding conventions
230 Coding conventions
231 ==================
231 ==================
232
232
233 General
233 General
234 -------
234 -------
235
235
236 In general, we'll try to follow the standard Python style conventions as described here:
236 In general, we'll try to follow the standard Python style conventions as described here:
237
237
238 - `Style Guide for Python Code <http://www.python.org/peps/pep-0008.html>`_
238 - `Style Guide for Python Code <http://www.python.org/peps/pep-0008.html>`_
239
239
240
240
241 Other comments:
241 Other comments:
242
242
243 - In a large file, top level classes and functions should be
243 - In a large file, top level classes and functions should be
244 separated by 2-3 lines to make it easier to separate them visually.
244 separated by 2-3 lines to make it easier to separate them visually.
245 - Use 4 spaces for indentation.
245 - Use 4 spaces for indentation.
246 - Keep the ordering of methods the same in classes that have the same
246 - Keep the ordering of methods the same in classes that have the same
247 methods. This is particularly true for classes that implement
247 methods. This is particularly true for classes that implement
248 similar interfaces and for interfaces that are similar.
248 similar interfaces and for interfaces that are similar.
249
249
250 Naming conventions
250 Naming conventions
251 ------------------
251 ------------------
252
252
253 In terms of naming conventions, we'll follow the guidelines from the `Style Guide for
253 In terms of naming conventions, we'll follow the guidelines from the `Style Guide for
254 Python Code`_.
254 Python Code`_.
255
255
256 For all new IPython code (and much existing code is being refactored), we'll use:
256 For all new IPython code (and much existing code is being refactored), we'll use:
257
257
258 - All ``lowercase`` module names.
258 - All ``lowercase`` module names.
259
259
260 - ``CamelCase`` for class names.
260 - ``CamelCase`` for class names.
261
261
262 - ``lowercase_with_underscores`` for methods, functions, variables and attributes.
262 - ``lowercase_with_underscores`` for methods, functions, variables and attributes.
263
263
264 This may be confusing as most of the existing IPython codebase uses a different convention (``lowerCamelCase`` for methods and attributes). Slowly, we will move IPython over to the new
264 This may be confusing as most of the existing IPython codebase uses a different convention (``lowerCamelCase`` for methods and attributes). Slowly, we will move IPython over to the new
265 convention, providing shadow names for backward compatibility in public interfaces.
265 convention, providing shadow names for backward compatibility in public interfaces.
266
266
267 There are, however, some important exceptions to these rules. In some cases, IPython
267 There are, however, some important exceptions to these rules. In some cases, IPython
268 code will interface with packages (Twisted, Wx, Qt) that use other conventions. At some level this makes it impossible to adhere to our own standards at all times. In particular, when subclassing classes that use other naming conventions, you must follow their naming conventions. To deal with cases like this, we propose the following policy:
268 code will interface with packages (Twisted, Wx, Qt) that use other conventions. At some level this makes it impossible to adhere to our own standards at all times. In particular, when subclassing classes that use other naming conventions, you must follow their naming conventions. To deal with cases like this, we propose the following policy:
269
269
270 - If you are subclassing a class that uses different conventions, use its
270 - If you are subclassing a class that uses different conventions, use its
271 naming conventions throughout your subclass. Thus, if you are creating a
271 naming conventions throughout your subclass. Thus, if you are creating a
272 Twisted Protocol class, used Twisted's ``namingSchemeForMethodsAndAttributes.``
272 Twisted Protocol class, used Twisted's ``namingSchemeForMethodsAndAttributes.``
273
273
274 - All IPython's official interfaces should use our conventions. In some cases
274 - All IPython's official interfaces should use our conventions. In some cases
275 this will mean that you need to provide shadow names (first implement ``fooBar``
275 this will mean that you need to provide shadow names (first implement ``fooBar``
276 and then ``foo_bar = fooBar``). We want to avoid this at all costs, but it
276 and then ``foo_bar = fooBar``). We want to avoid this at all costs, but it
277 will probably be necessary at times. But, please use this sparingly!
277 will probably be necessary at times. But, please use this sparingly!
278
278
279 Implementation-specific *private* methods will use ``_single_underscore_prefix``.
279 Implementation-specific *private* methods will use ``_single_underscore_prefix``.
280 Names with a leading double underscore will *only* be used in special cases, as they
280 Names with a leading double underscore will *only* be used in special cases, as they
281 makes subclassing difficult (such names are not easily seen by child classes).
281 makes subclassing difficult (such names are not easily seen by child classes).
282
282
283 Occasionally some run-in lowercase names are used, but mostly for very short names or
283 Occasionally some run-in lowercase names are used, but mostly for very short names or
284 where we are implementing methods very similar to existing ones in a base class (like
284 where we are implementing methods very similar to existing ones in a base class (like
285 ``runlines()`` where ``runsource()`` and ``runcode()`` had established precedent).
285 ``runlines()`` where ``runsource()`` and ``runcode()`` had established precedent).
286
286
287 The old IPython codebase has a big mix of classes and modules prefixed with an
287 The old IPython codebase has a big mix of classes and modules prefixed with an
288 explicit ``IP``. In Python this is mostly unnecessary, redundant and frowned upon, as
288 explicit ``IP``. In Python this is mostly unnecessary, redundant and frowned upon, as
289 namespaces offer cleaner prefixing. The only case where this approach is justified is
289 namespaces offer cleaner prefixing. The only case where this approach is justified is
290 for classes which are expected to be imported into external namespaces and a very
290 for classes which are expected to be imported into external namespaces and a very
291 generic name (like Shell) is too likely to clash with something else. We'll need to
291 generic name (like Shell) is too likely to clash with something else. We'll need to
292 revisit this issue as we clean up and refactor the code, but in general we should
292 revisit this issue as we clean up and refactor the code, but in general we should
293 remove as many unnecessary ``IP``/``ip`` prefixes as possible. However, if a prefix
293 remove as many unnecessary ``IP``/``ip`` prefixes as possible. However, if a prefix
294 seems absolutely necessary the more specific ``IPY`` or ``ipy`` are preferred.
294 seems absolutely necessary the more specific ``IPY`` or ``ipy`` are preferred.
295
295
296 .. _devel_testing:
296 .. _devel_testing:
297
297
298 Testing system
298 Testing system
299 ==============
299 ==============
300
300
301 It is extremely important that all code contributed to IPython has tests. Tests should
301 It is extremely important that all code contributed to IPython has tests. Tests should
302 be written as unittests, doctests or as entities that the `Nose`_ testing package will
302 be written as unittests, doctests or as entities that the `Nose`_ testing package will
303 find. Regardless of how the tests are written, we will use `Nose`_ for discovering and
303 find. Regardless of how the tests are written, we will use `Nose`_ for discovering and
304 running the tests. `Nose`_ will be required to run the IPython test suite, but will
304 running the tests. `Nose`_ will be required to run the IPython test suite, but will
305 not be required to simply use IPython.
305 not be required to simply use IPython.
306
306
307 .. _Nose: http://code.google.com/p/python-nose/
307 .. _Nose: http://code.google.com/p/python-nose/
308
308
309 Tests of `Twisted`__ using code should be written by subclassing the ``TestCase`` class
309 Tests of `Twisted`__ using code should be written by subclassing the ``TestCase`` class
310 that comes with ``twisted.trial.unittest``. When this is done, `Nose`_ will be able to
310 that comes with ``twisted.trial.unittest``. When this is done, `Nose`_ will be able to
311 run the tests and the twisted reactor will be handled correctly.
311 run the tests and the twisted reactor will be handled correctly.
312
312
313 .. __: http://www.twistedmatrix.com
313 .. __: http://www.twistedmatrix.com
314
314
315 Each subpackage in IPython should have its own ``tests`` directory that contains all
315 Each subpackage in IPython should have its own ``tests`` directory that contains all
316 of the tests for that subpackage. This allows each subpackage to be self-contained. If
316 of the tests for that subpackage. This allows each subpackage to be self-contained. If
317 a subpackage has any dependencies beyond the Python standard library, the tests for
317 a subpackage has any dependencies beyond the Python standard library, the tests for
318 that subpackage should be skipped if the dependencies are not found. This is very
318 that subpackage should be skipped if the dependencies are not found. This is very
319 important so users don't get tests failing simply because they don't have dependencies.
319 important so users don't get tests failing simply because they don't have dependencies.
320
320
321 We also need to look into use Noses ability to tag tests to allow a more modular
321 We also need to look into use Noses ability to tag tests to allow a more modular
322 approach of running tests.
322 approach of running tests.
323
323
324 .. _devel_config:
324 .. _devel_config:
325
325
326 Configuration system
326 Configuration system
327 ====================
327 ====================
328
328
329 IPython uses `.ini`_ files for configuration purposes. This represents a huge
329 IPython uses `.ini`_ files for configuration purposes. This represents a huge
330 improvement over the configuration system used in IPython. IPython works with these
330 improvement over the configuration system used in IPython. IPython works with these
331 files using the `ConfigObj`_ package, which IPython includes as
331 files using the `ConfigObj`_ package, which IPython includes as
332 ``ipython1/external/configobj.py``.
332 ``ipython1/external/configobj.py``.
333
333
334 Currently, we are using raw `ConfigObj`_ objects themselves. Each subpackage of IPython
334 Currently, we are using raw `ConfigObj`_ objects themselves. Each subpackage of IPython
335 should contain a ``config`` subdirectory that contains all of the configuration
335 should contain a ``config`` subdirectory that contains all of the configuration
336 information for the subpackage. To see how configuration information is defined (along
336 information for the subpackage. To see how configuration information is defined (along
337 with defaults) see at the examples in ``ipython1/kernel/config`` and
337 with defaults) see at the examples in ``ipython1/kernel/config`` and
338 ``ipython1/core/config``. Likewise, to see how the configuration information is used,
338 ``ipython1/core/config``. Likewise, to see how the configuration information is used,
339 see examples in ``ipython1/kernel/scripts/ipengine.py``.
339 see examples in ``ipython1/kernel/scripts/ipengine.py``.
340
340
341 Eventually, we will add a new layer on top of the raw `ConfigObj`_ objects. We are
341 Eventually, we will add a new layer on top of the raw `ConfigObj`_ objects. We are
342 calling this new layer, ``tconfig``, as it will use a `Traits`_-like validation model.
342 calling this new layer, ``tconfig``, as it will use a `Traits`_-like validation model.
343 We won't actually use `Traits`_, but will implement something similar in pure Python.
343 We won't actually use `Traits`_, but will implement something similar in pure Python.
344 But, even in this new system, we will still use `ConfigObj`_ and `.ini`_ files
344 But, even in this new system, we will still use `ConfigObj`_ and `.ini`_ files
345 underneath the hood. Talk to Fernando if you are interested in working on this part of
345 underneath the hood. Talk to Fernando if you are interested in working on this part of
346 IPython. The current prototype of ``tconfig`` is located in the IPython sandbox.
346 IPython. The current prototype of ``tconfig`` is located in the IPython sandbox.
347
347
348 .. _.ini: http://docs.python.org/lib/module-ConfigParser.html
348 .. _.ini: http://docs.python.org/lib/module-ConfigParser.html
349 .. _ConfigObj: http://www.voidspace.org.uk/python/configobj.html
349 .. _ConfigObj: http://www.voidspace.org.uk/python/configobj.html
350 .. _Traits: http://code.enthought.com/traits/
350 .. _Traits: http://code.enthought.com/traits/
351
351
352 Installation and testing scenarios
352 Installation and testing scenarios
353 ==================================
353 ==================================
354
354
355 This section outlines the various scenarios that we need to test before we release an IPython version. These scenarios represent different ways of installing IPython and its dependencies.
355 This section outlines the various scenarios that we need to test before we release an IPython version. These scenarios represent different ways of installing IPython and its dependencies.
356
356
357 Installation scenarios
357 Installation scenarios
358 ----------------------
358 ----------------------
359
359
360 1. Install from tarball using `python setup.py install`.
360 1. Install from tarball using `python setup.py install`.
361 a. With only readline+nose dependencies installed (test1)
361 a. With only readline+nose dependencies installed.
362
363 virtualenv --no-site-packages test1
364 # Activate it
365 easy_install nose
366 easy_install readline # On OS X or pyreadline on win32
367 cd ipython-0.9.beta3
368 python setup.py install
369
370 b. With all dependencies installed (readline, zope.interface,
362 b. With all dependencies installed (readline, zope.interface,
371 Twisted, foolscap, Sphinx, nose, pyOpenSSL) (test2)
363 Twisted, foolscap, Sphinx, nose, pyOpenSSL).
372 2. Install using easy_install.
364 2. Install using easy_install.
373 a. With only readline+nose dependencies installed (test3)
365 a. With only readline+nose dependencies installed.
374 i. Default dependencies.
366 i. Default dependencies: `easy_install ipython-0.9.beta3-py2.5.egg`
375 ii. Optional dependency sets (kernel, doc, test, security)
367 ii. Optional dependency sets: `easy_install -f ipython-0.9.beta3-py2.5.egg IPython[kernel,doc,test,security]`
376 easy_install -f ipython-0.9.beta3-py2.5.egg IPython[kernel,doc,test,security]
368 b. With all dependencies already installed.
377
378 b. With all dependencies already installed (test2)
379
369
380
370
381 Tests to run for these scenarios
371 Tests to run for these scenarios
382 --------------------------------
372 --------------------------------
383
373
384 1. Run the full test suite.
374 1. Run the full test suite.
385 2. Start a controller and engines and try a few things by hand.
375 2. Start a controller and engines and try a few things by hand.
386 a. Using ipcluster.
376 a. Using ipcluster.
387 b. Using ipcontroller/ipengine by hand.
377 b. Using ipcontroller/ipengine by hand.
388 3. Run a few of the parallel examples.
378 3. Run a few of the parallel examples.
389 4. Try the kernel with and without security with and without PyOpenSSL
379 4. Try the kernel with and without security with and without PyOpenSSL
390 installed.
380 installed.
391 5. Beat on the IPython terminal a bunch.
381 5. Beat on the IPython terminal a bunch.
392 6. Make sure that furl files are being put in proper locations.
382 6. Make sure that furl files are being put in proper locations.
393
383
394
384
395
385
396
386
397
387
398
388
399
389
400
390
401
391
General Comments 0
You need to be logged in to leave comments. Login now