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