##// END OF EJS Templates
Several small fixes during code review with Brian....
Fernando Perez -
Show More
@@ -1,995 +1,995 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Prefiltering components.
4 Prefiltering components.
5
5
6 Prefilters transform user input before it is exec'd by Python. These
6 Prefilters transform user input before it is exec'd by Python. These
7 transforms are used to implement additional syntax such as !ls and %magic.
7 transforms are used to implement additional syntax such as !ls and %magic.
8
8
9 Authors:
9 Authors:
10
10
11 * Brian Granger
11 * Brian Granger
12 * Fernando Perez
12 * Fernando Perez
13 * Dan Milstein
13 * Dan Milstein
14 * Ville Vainio
14 * Ville Vainio
15 """
15 """
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2008-2009 The IPython Development Team
18 # Copyright (C) 2008-2009 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 import __builtin__
28 import __builtin__
29 import codeop
29 import codeop
30 import keyword
30 import keyword
31 import os
31 import os
32 import re
32 import re
33 import sys
33 import sys
34
34
35 from IPython.core.alias import AliasManager
35 from IPython.core.alias import AliasManager
36 from IPython.core.autocall import IPyAutocall
36 from IPython.core.autocall import IPyAutocall
37 from IPython.core.component import Component
37 from IPython.core.component import Component
38 from IPython.core.splitinput import split_user_input
38 from IPython.core.splitinput import split_user_input
39 from IPython.core.page import page
39 from IPython.core.page import page
40
40
41 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool
41 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool
42 from IPython.utils.genutils import make_quoted_expr
42 from IPython.utils.genutils import make_quoted_expr, Term
43 from IPython.utils.autoattr import auto_attr
43 from IPython.utils.autoattr import auto_attr
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Global utilities, errors and constants
46 # Global utilities, errors and constants
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 # Warning, these cannot be changed unless various regular expressions
49 # Warning, these cannot be changed unless various regular expressions
50 # are updated in a number of places. Not great, but at least we told you.
50 # are updated in a number of places. Not great, but at least we told you.
51 ESC_SHELL = '!'
51 ESC_SHELL = '!'
52 ESC_SH_CAP = '!!'
52 ESC_SH_CAP = '!!'
53 ESC_HELP = '?'
53 ESC_HELP = '?'
54 ESC_MAGIC = '%'
54 ESC_MAGIC = '%'
55 ESC_QUOTE = ','
55 ESC_QUOTE = ','
56 ESC_QUOTE2 = ';'
56 ESC_QUOTE2 = ';'
57 ESC_PAREN = '/'
57 ESC_PAREN = '/'
58
58
59
59
60 class PrefilterError(Exception):
60 class PrefilterError(Exception):
61 pass
61 pass
62
62
63
63
64 # RegExp to identify potential function names
64 # RegExp to identify potential function names
65 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
65 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
66
66
67 # RegExp to exclude strings with this start from autocalling. In
67 # RegExp to exclude strings with this start from autocalling. In
68 # particular, all binary operators should be excluded, so that if foo is
68 # particular, all binary operators should be excluded, so that if foo is
69 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
69 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
70 # characters '!=()' don't need to be checked for, as the checkPythonChars
70 # characters '!=()' don't need to be checked for, as the checkPythonChars
71 # routine explicitely does so, to catch direct calls and rebindings of
71 # routine explicitely does so, to catch direct calls and rebindings of
72 # existing names.
72 # existing names.
73
73
74 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
74 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
75 # it affects the rest of the group in square brackets.
75 # it affects the rest of the group in square brackets.
76 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
76 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
77 r'|^is |^not |^in |^and |^or ')
77 r'|^is |^not |^in |^and |^or ')
78
78
79 # try to catch also methods for stuff in lists/tuples/dicts: off
79 # try to catch also methods for stuff in lists/tuples/dicts: off
80 # (experimental). For this to work, the line_split regexp would need
80 # (experimental). For this to work, the line_split regexp would need
81 # to be modified so it wouldn't break things at '['. That line is
81 # to be modified so it wouldn't break things at '['. That line is
82 # nasty enough that I shouldn't change it until I can test it _well_.
82 # nasty enough that I shouldn't change it until I can test it _well_.
83 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
83 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
84
84
85
85
86 # Handler Check Utilities
86 # Handler Check Utilities
87 def is_shadowed(identifier, ip):
87 def is_shadowed(identifier, ip):
88 """Is the given identifier defined in one of the namespaces which shadow
88 """Is the given identifier defined in one of the namespaces which shadow
89 the alias and magic namespaces? Note that an identifier is different
89 the alias and magic namespaces? Note that an identifier is different
90 than ifun, because it can not contain a '.' character."""
90 than ifun, because it can not contain a '.' character."""
91 # This is much safer than calling ofind, which can change state
91 # This is much safer than calling ofind, which can change state
92 return (identifier in ip.user_ns \
92 return (identifier in ip.user_ns \
93 or identifier in ip.internal_ns \
93 or identifier in ip.internal_ns \
94 or identifier in ip.ns_table['builtin'])
94 or identifier in ip.ns_table['builtin'])
95
95
96
96
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98 # The LineInfo class used throughout
98 # The LineInfo class used throughout
99 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
100
100
101
101
102 class LineInfo(object):
102 class LineInfo(object):
103 """A single line of input and associated info.
103 """A single line of input and associated info.
104
104
105 Includes the following as properties:
105 Includes the following as properties:
106
106
107 line
107 line
108 The original, raw line
108 The original, raw line
109
109
110 continue_prompt
110 continue_prompt
111 Is this line a continuation in a sequence of multiline input?
111 Is this line a continuation in a sequence of multiline input?
112
112
113 pre
113 pre
114 The initial esc character or whitespace.
114 The initial esc character or whitespace.
115
115
116 pre_char
116 pre_char
117 The escape character(s) in pre or the empty string if there isn't one.
117 The escape character(s) in pre or the empty string if there isn't one.
118 Note that '!!' is a possible value for pre_char. Otherwise it will
118 Note that '!!' is a possible value for pre_char. Otherwise it will
119 always be a single character.
119 always be a single character.
120
120
121 pre_whitespace
121 pre_whitespace
122 The leading whitespace from pre if it exists. If there is a pre_char,
122 The leading whitespace from pre if it exists. If there is a pre_char,
123 this is just ''.
123 this is just ''.
124
124
125 ifun
125 ifun
126 The 'function part', which is basically the maximal initial sequence
126 The 'function part', which is basically the maximal initial sequence
127 of valid python identifiers and the '.' character. This is what is
127 of valid python identifiers and the '.' character. This is what is
128 checked for alias and magic transformations, used for auto-calling,
128 checked for alias and magic transformations, used for auto-calling,
129 etc.
129 etc.
130
130
131 the_rest
131 the_rest
132 Everything else on the line.
132 Everything else on the line.
133 """
133 """
134 def __init__(self, line, continue_prompt):
134 def __init__(self, line, continue_prompt):
135 self.line = line
135 self.line = line
136 self.continue_prompt = continue_prompt
136 self.continue_prompt = continue_prompt
137 self.pre, self.ifun, self.the_rest = split_user_input(line)
137 self.pre, self.ifun, self.the_rest = split_user_input(line)
138
138
139 self.pre_char = self.pre.strip()
139 self.pre_char = self.pre.strip()
140 if self.pre_char:
140 if self.pre_char:
141 self.pre_whitespace = '' # No whitespace allowd before esc chars
141 self.pre_whitespace = '' # No whitespace allowd before esc chars
142 else:
142 else:
143 self.pre_whitespace = self.pre
143 self.pre_whitespace = self.pre
144
144
145 self._oinfo = None
145 self._oinfo = None
146
146
147 def ofind(self, ip):
147 def ofind(self, ip):
148 """Do a full, attribute-walking lookup of the ifun in the various
148 """Do a full, attribute-walking lookup of the ifun in the various
149 namespaces for the given IPython InteractiveShell instance.
149 namespaces for the given IPython InteractiveShell instance.
150
150
151 Return a dict with keys: found,obj,ospace,ismagic
151 Return a dict with keys: found,obj,ospace,ismagic
152
152
153 Note: can cause state changes because of calling getattr, but should
153 Note: can cause state changes because of calling getattr, but should
154 only be run if autocall is on and if the line hasn't matched any
154 only be run if autocall is on and if the line hasn't matched any
155 other, less dangerous handlers.
155 other, less dangerous handlers.
156
156
157 Does cache the results of the call, so can be called multiple times
157 Does cache the results of the call, so can be called multiple times
158 without worrying about *further* damaging state.
158 without worrying about *further* damaging state.
159 """
159 """
160 if not self._oinfo:
160 if not self._oinfo:
161 self._oinfo = ip._ofind(self.ifun)
161 self._oinfo = ip._ofind(self.ifun)
162 return self._oinfo
162 return self._oinfo
163
163
164 def __str__(self):
164 def __str__(self):
165 return "Lineinfo [%s|%s|%s]" %(self.pre,self.ifun,self.the_rest)
165 return "Lineinfo [%s|%s|%s]" %(self.pre,self.ifun,self.the_rest)
166
166
167
167
168 #-----------------------------------------------------------------------------
168 #-----------------------------------------------------------------------------
169 # Main Prefilter manager
169 # Main Prefilter manager
170 #-----------------------------------------------------------------------------
170 #-----------------------------------------------------------------------------
171
171
172
172
173 class PrefilterManager(Component):
173 class PrefilterManager(Component):
174 """Main prefilter component.
174 """Main prefilter component.
175
175
176 The IPython prefilter is run on all user input before it is run. The
176 The IPython prefilter is run on all user input before it is run. The
177 prefilter consumes lines of input and produces transformed lines of
177 prefilter consumes lines of input and produces transformed lines of
178 input.
178 input.
179
179
180 The iplementation consists of two phases:
180 The iplementation consists of two phases:
181
181
182 1. Transformers
182 1. Transformers
183 2. Checkers and handlers
183 2. Checkers and handlers
184
184
185 Over time, we plan on deprecating the checkers and handlers and doing
185 Over time, we plan on deprecating the checkers and handlers and doing
186 everything in the transformers.
186 everything in the transformers.
187
187
188 The transformers are instances of :class:`PrefilterTransformer` and have
188 The transformers are instances of :class:`PrefilterTransformer` and have
189 a single method :meth:`transform` that takes a line and returns a
189 a single method :meth:`transform` that takes a line and returns a
190 transformed line. The transformation can be accomplished using any
190 transformed line. The transformation can be accomplished using any
191 tool, but our current ones use regular expressions for speed. We also
191 tool, but our current ones use regular expressions for speed. We also
192 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
192 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
193
193
194 After all the transformers have been run, the line is fed to the checkers,
194 After all the transformers have been run, the line is fed to the checkers,
195 which are instances of :class:`PrefilterChecker`. The line is passed to
195 which are instances of :class:`PrefilterChecker`. The line is passed to
196 the :meth:`check` method, which either returns `None` or a
196 the :meth:`check` method, which either returns `None` or a
197 :class:`PrefilterHandler` instance. If `None` is returned, the other
197 :class:`PrefilterHandler` instance. If `None` is returned, the other
198 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
198 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
199 the line is passed to the :meth:`handle` method of the returned
199 the line is passed to the :meth:`handle` method of the returned
200 handler and no further checkers are tried.
200 handler and no further checkers are tried.
201
201
202 Both transformers and checkers have a `priority` attribute, that determines
202 Both transformers and checkers have a `priority` attribute, that determines
203 the order in which they are called. Smaller priorities are tried first.
203 the order in which they are called. Smaller priorities are tried first.
204
204
205 Both transformers and checkers also have `enabled` attribute, which is
205 Both transformers and checkers also have `enabled` attribute, which is
206 a boolean that determines if the instance is used.
206 a boolean that determines if the instance is used.
207
207
208 Users or developers can change the priority or enabled attribute of
208 Users or developers can change the priority or enabled attribute of
209 transformers or checkers, but they must call the :meth:`sort_checkers`
209 transformers or checkers, but they must call the :meth:`sort_checkers`
210 or :meth:`sort_transformers` method after changing the priority.
210 or :meth:`sort_transformers` method after changing the priority.
211 """
211 """
212
212
213 multi_line_specials = CBool(True, config=True)
213 multi_line_specials = CBool(True, config=True)
214
214
215 def __init__(self, parent, config=None):
215 def __init__(self, parent, config=None):
216 super(PrefilterManager, self).__init__(parent, config=config)
216 super(PrefilterManager, self).__init__(parent, config=config)
217 self.init_transformers()
217 self.init_transformers()
218 self.init_handlers()
218 self.init_handlers()
219 self.init_checkers()
219 self.init_checkers()
220
220
221 @auto_attr
221 @auto_attr
222 def shell(self):
222 def shell(self):
223 return Component.get_instances(
223 return Component.get_instances(
224 root=self.root,
224 root=self.root,
225 klass='IPython.core.iplib.InteractiveShell')[0]
225 klass='IPython.core.iplib.InteractiveShell')[0]
226
226
227 #-------------------------------------------------------------------------
227 #-------------------------------------------------------------------------
228 # API for managing transformers
228 # API for managing transformers
229 #-------------------------------------------------------------------------
229 #-------------------------------------------------------------------------
230
230
231 def init_transformers(self):
231 def init_transformers(self):
232 """Create the default transformers."""
232 """Create the default transformers."""
233 self._transformers = []
233 self._transformers = []
234 for transformer_cls in _default_transformers:
234 for transformer_cls in _default_transformers:
235 transformer_cls(self, config=self.config)
235 transformer_cls(self, config=self.config)
236
236
237 def sort_transformers(self):
237 def sort_transformers(self):
238 """Sort the transformers by priority.
238 """Sort the transformers by priority.
239
239
240 This must be called after the priority of a transformer is changed.
240 This must be called after the priority of a transformer is changed.
241 The :meth:`register_transformer` method calls this automatically.
241 The :meth:`register_transformer` method calls this automatically.
242 """
242 """
243 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
243 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
244
244
245 @property
245 @property
246 def transformers(self):
246 def transformers(self):
247 """Return a list of checkers, sorted by priority."""
247 """Return a list of checkers, sorted by priority."""
248 return self._transformers
248 return self._transformers
249
249
250 def register_transformer(self, transformer):
250 def register_transformer(self, transformer):
251 """Register a transformer instance."""
251 """Register a transformer instance."""
252 if transformer not in self._transformers:
252 if transformer not in self._transformers:
253 self._transformers.append(transformer)
253 self._transformers.append(transformer)
254 self.sort_transformers()
254 self.sort_transformers()
255
255
256 def unregister_transformer(self, transformer):
256 def unregister_transformer(self, transformer):
257 """Unregister a transformer instance."""
257 """Unregister a transformer instance."""
258 if transformer in self._transformers:
258 if transformer in self._transformers:
259 self._transformers.remove(transformer)
259 self._transformers.remove(transformer)
260
260
261 #-------------------------------------------------------------------------
261 #-------------------------------------------------------------------------
262 # API for managing checkers
262 # API for managing checkers
263 #-------------------------------------------------------------------------
263 #-------------------------------------------------------------------------
264
264
265 def init_checkers(self):
265 def init_checkers(self):
266 """Create the default checkers."""
266 """Create the default checkers."""
267 self._checkers = []
267 self._checkers = []
268 for checker in _default_checkers:
268 for checker in _default_checkers:
269 checker(self, config=self.config)
269 checker(self, config=self.config)
270
270
271 def sort_checkers(self):
271 def sort_checkers(self):
272 """Sort the checkers by priority.
272 """Sort the checkers by priority.
273
273
274 This must be called after the priority of a checker is changed.
274 This must be called after the priority of a checker is changed.
275 The :meth:`register_checker` method calls this automatically.
275 The :meth:`register_checker` method calls this automatically.
276 """
276 """
277 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
277 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
278
278
279 @property
279 @property
280 def checkers(self):
280 def checkers(self):
281 """Return a list of checkers, sorted by priority."""
281 """Return a list of checkers, sorted by priority."""
282 return self._checkers
282 return self._checkers
283
283
284 def register_checker(self, checker):
284 def register_checker(self, checker):
285 """Register a checker instance."""
285 """Register a checker instance."""
286 if checker not in self._checkers:
286 if checker not in self._checkers:
287 self._checkers.append(checker)
287 self._checkers.append(checker)
288 self.sort_checkers()
288 self.sort_checkers()
289
289
290 def unregister_checker(self, checker):
290 def unregister_checker(self, checker):
291 """Unregister a checker instance."""
291 """Unregister a checker instance."""
292 if checker in self._checkers:
292 if checker in self._checkers:
293 self._checkers.remove(checker)
293 self._checkers.remove(checker)
294
294
295 #-------------------------------------------------------------------------
295 #-------------------------------------------------------------------------
296 # API for managing checkers
296 # API for managing checkers
297 #-------------------------------------------------------------------------
297 #-------------------------------------------------------------------------
298
298
299 def init_handlers(self):
299 def init_handlers(self):
300 """Create the default handlers."""
300 """Create the default handlers."""
301 self._handlers = {}
301 self._handlers = {}
302 self._esc_handlers = {}
302 self._esc_handlers = {}
303 for handler in _default_handlers:
303 for handler in _default_handlers:
304 handler(self, config=self.config)
304 handler(self, config=self.config)
305
305
306 @property
306 @property
307 def handlers(self):
307 def handlers(self):
308 """Return a dict of all the handlers."""
308 """Return a dict of all the handlers."""
309 return self._handlers
309 return self._handlers
310
310
311 def register_handler(self, name, handler, esc_strings):
311 def register_handler(self, name, handler, esc_strings):
312 """Register a handler instance by name with esc_strings."""
312 """Register a handler instance by name with esc_strings."""
313 self._handlers[name] = handler
313 self._handlers[name] = handler
314 for esc_str in esc_strings:
314 for esc_str in esc_strings:
315 self._esc_handlers[esc_str] = handler
315 self._esc_handlers[esc_str] = handler
316
316
317 def unregister_handler(self, name, handler, esc_strings):
317 def unregister_handler(self, name, handler, esc_strings):
318 """Unregister a handler instance by name with esc_strings."""
318 """Unregister a handler instance by name with esc_strings."""
319 try:
319 try:
320 del self._handlers[name]
320 del self._handlers[name]
321 except KeyError:
321 except KeyError:
322 pass
322 pass
323 for esc_str in esc_strings:
323 for esc_str in esc_strings:
324 h = self._esc_handlers.get(esc_str)
324 h = self._esc_handlers.get(esc_str)
325 if h is handler:
325 if h is handler:
326 del self._esc_handlers[esc_str]
326 del self._esc_handlers[esc_str]
327
327
328 def get_handler_by_name(self, name):
328 def get_handler_by_name(self, name):
329 """Get a handler by its name."""
329 """Get a handler by its name."""
330 return self._handlers.get(name)
330 return self._handlers.get(name)
331
331
332 def get_handler_by_esc(self, esc_str):
332 def get_handler_by_esc(self, esc_str):
333 """Get a handler by its escape string."""
333 """Get a handler by its escape string."""
334 return self._esc_handlers.get(esc_str)
334 return self._esc_handlers.get(esc_str)
335
335
336 #-------------------------------------------------------------------------
336 #-------------------------------------------------------------------------
337 # Main prefiltering API
337 # Main prefiltering API
338 #-------------------------------------------------------------------------
338 #-------------------------------------------------------------------------
339
339
340 def prefilter_line_info(self, line_info):
340 def prefilter_line_info(self, line_info):
341 """Prefilter a line that has been converted to a LineInfo object.
341 """Prefilter a line that has been converted to a LineInfo object.
342
342
343 This implements the checker/handler part of the prefilter pipe.
343 This implements the checker/handler part of the prefilter pipe.
344 """
344 """
345 # print "prefilter_line_info: ", line_info
345 # print "prefilter_line_info: ", line_info
346 handler = self.find_handler(line_info)
346 handler = self.find_handler(line_info)
347 return handler.handle(line_info)
347 return handler.handle(line_info)
348
348
349 def find_handler(self, line_info):
349 def find_handler(self, line_info):
350 """Find a handler for the line_info by trying checkers."""
350 """Find a handler for the line_info by trying checkers."""
351 for checker in self.checkers:
351 for checker in self.checkers:
352 if checker.enabled:
352 if checker.enabled:
353 handler = checker.check(line_info)
353 handler = checker.check(line_info)
354 if handler:
354 if handler:
355 return handler
355 return handler
356 return self.get_handler_by_name('normal')
356 return self.get_handler_by_name('normal')
357
357
358 def transform_line(self, line, continue_prompt):
358 def transform_line(self, line, continue_prompt):
359 """Calls the enabled transformers in order of increasing priority."""
359 """Calls the enabled transformers in order of increasing priority."""
360 for transformer in self.transformers:
360 for transformer in self.transformers:
361 if transformer.enabled:
361 if transformer.enabled:
362 line = transformer.transform(line, continue_prompt)
362 line = transformer.transform(line, continue_prompt)
363 return line
363 return line
364
364
365 def prefilter_line(self, line, continue_prompt):
365 def prefilter_line(self, line, continue_prompt):
366 """Prefilter a single input line as text.
366 """Prefilter a single input line as text.
367
367
368 This method prefilters a single line of text by calling the
368 This method prefilters a single line of text by calling the
369 transformers and then the checkers/handlers.
369 transformers and then the checkers/handlers.
370 """
370 """
371
371
372 # print "prefilter_line: ", line, continue_prompt
372 # print "prefilter_line: ", line, continue_prompt
373 # All handlers *must* return a value, even if it's blank ('').
373 # All handlers *must* return a value, even if it's blank ('').
374
374
375 # Lines are NOT logged here. Handlers should process the line as
375 # Lines are NOT logged here. Handlers should process the line as
376 # needed, update the cache AND log it (so that the input cache array
376 # needed, update the cache AND log it (so that the input cache array
377 # stays synced).
377 # stays synced).
378
378
379 # save the line away in case we crash, so the post-mortem handler can
379 # save the line away in case we crash, so the post-mortem handler can
380 # record it
380 # record it
381 self.shell._last_input_line = line
381 self.shell._last_input_line = line
382
382
383 if not line:
383 if not line:
384 # Return immediately on purely empty lines, so that if the user
384 # Return immediately on purely empty lines, so that if the user
385 # previously typed some whitespace that started a continuation
385 # previously typed some whitespace that started a continuation
386 # prompt, he can break out of that loop with just an empty line.
386 # prompt, he can break out of that loop with just an empty line.
387 # This is how the default python prompt works.
387 # This is how the default python prompt works.
388
388
389 # Only return if the accumulated input buffer was just whitespace!
389 # Only return if the accumulated input buffer was just whitespace!
390 if ''.join(self.shell.buffer).isspace():
390 if ''.join(self.shell.buffer).isspace():
391 self.shell.buffer[:] = []
391 self.shell.buffer[:] = []
392 return ''
392 return ''
393
393
394 # At this point, we invoke our transformers.
394 # At this point, we invoke our transformers.
395 if not continue_prompt or (continue_prompt and self.multi_line_specials):
395 if not continue_prompt or (continue_prompt and self.multi_line_specials):
396 line = self.transform_line(line, continue_prompt)
396 line = self.transform_line(line, continue_prompt)
397
397
398 # Now we compute line_info for the checkers and handlers
398 # Now we compute line_info for the checkers and handlers
399 line_info = LineInfo(line, continue_prompt)
399 line_info = LineInfo(line, continue_prompt)
400
400
401 # the input history needs to track even empty lines
401 # the input history needs to track even empty lines
402 stripped = line.strip()
402 stripped = line.strip()
403
403
404 normal_handler = self.get_handler_by_name('normal')
404 normal_handler = self.get_handler_by_name('normal')
405 if not stripped:
405 if not stripped:
406 if not continue_prompt:
406 if not continue_prompt:
407 self.shell.outputcache.prompt_count -= 1
407 self.shell.outputcache.prompt_count -= 1
408
408
409 return normal_handler.handle(line_info)
409 return normal_handler.handle(line_info)
410
410
411 # special handlers are only allowed for single line statements
411 # special handlers are only allowed for single line statements
412 if continue_prompt and not self.multi_line_specials:
412 if continue_prompt and not self.multi_line_specials:
413 return normal_handler.handle(line_info)
413 return normal_handler.handle(line_info)
414
414
415 prefiltered = self.prefilter_line_info(line_info)
415 prefiltered = self.prefilter_line_info(line_info)
416 # print "prefiltered line: %r" % prefiltered
416 # print "prefiltered line: %r" % prefiltered
417 return prefiltered
417 return prefiltered
418
418
419 def prefilter_lines(self, lines, continue_prompt):
419 def prefilter_lines(self, lines, continue_prompt):
420 """Prefilter multiple input lines of text.
420 """Prefilter multiple input lines of text.
421
421
422 This is the main entry point for prefiltering multiple lines of
422 This is the main entry point for prefiltering multiple lines of
423 input. This simply calls :meth:`prefilter_line` for each line of
423 input. This simply calls :meth:`prefilter_line` for each line of
424 input.
424 input.
425
425
426 This covers cases where there are multiple lines in the user entry,
426 This covers cases where there are multiple lines in the user entry,
427 which is the case when the user goes back to a multiline history
427 which is the case when the user goes back to a multiline history
428 entry and presses enter.
428 entry and presses enter.
429 """
429 """
430 out = []
430 out = []
431 for line in lines.rstrip('\n').split('\n'):
431 for line in lines.rstrip('\n').split('\n'):
432 out.append(self.prefilter_line(line, continue_prompt))
432 out.append(self.prefilter_line(line, continue_prompt))
433 return '\n'.join(out)
433 return '\n'.join(out)
434
434
435
435
436 #-----------------------------------------------------------------------------
436 #-----------------------------------------------------------------------------
437 # Prefilter transformers
437 # Prefilter transformers
438 #-----------------------------------------------------------------------------
438 #-----------------------------------------------------------------------------
439
439
440
440
441 class PrefilterTransformer(Component):
441 class PrefilterTransformer(Component):
442 """Transform a line of user input."""
442 """Transform a line of user input."""
443
443
444 priority = Int(100, config=True)
444 priority = Int(100, config=True)
445 shell = Any
445 shell = Any
446 prefilter_manager = Any
446 prefilter_manager = Any
447 enabled = Bool(True, config=True)
447 enabled = Bool(True, config=True)
448
448
449 def __init__(self, parent, config=None):
449 def __init__(self, parent, config=None):
450 super(PrefilterTransformer, self).__init__(parent, config=config)
450 super(PrefilterTransformer, self).__init__(parent, config=config)
451 self.prefilter_manager.register_transformer(self)
451 self.prefilter_manager.register_transformer(self)
452
452
453 @auto_attr
453 @auto_attr
454 def shell(self):
454 def shell(self):
455 return Component.get_instances(
455 return Component.get_instances(
456 root=self.root,
456 root=self.root,
457 klass='IPython.core.iplib.InteractiveShell')[0]
457 klass='IPython.core.iplib.InteractiveShell')[0]
458
458
459 @auto_attr
459 @auto_attr
460 def prefilter_manager(self):
460 def prefilter_manager(self):
461 return PrefilterManager.get_instances(root=self.root)[0]
461 return PrefilterManager.get_instances(root=self.root)[0]
462
462
463 def transform(self, line, continue_prompt):
463 def transform(self, line, continue_prompt):
464 """Transform a line, returning the new one."""
464 """Transform a line, returning the new one."""
465 return None
465 return None
466
466
467 def __repr__(self):
467 def __repr__(self):
468 return "<%s(priority=%r, enabled=%r)>" % (
468 return "<%s(priority=%r, enabled=%r)>" % (
469 self.__class__.__name__, self.priority, self.enabled)
469 self.__class__.__name__, self.priority, self.enabled)
470
470
471
471
472 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
472 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
473 r'\s*=\s*!(?P<cmd>.*)')
473 r'\s*=\s*!(?P<cmd>.*)')
474
474
475
475
476 class AssignSystemTransformer(PrefilterTransformer):
476 class AssignSystemTransformer(PrefilterTransformer):
477 """Handle the `files = !ls` syntax."""
477 """Handle the `files = !ls` syntax."""
478
478
479 priority = Int(100, config=True)
479 priority = Int(100, config=True)
480
480
481 def transform(self, line, continue_prompt):
481 def transform(self, line, continue_prompt):
482 m = _assign_system_re.match(line)
482 m = _assign_system_re.match(line)
483 if m is not None:
483 if m is not None:
484 cmd = m.group('cmd')
484 cmd = m.group('cmd')
485 lhs = m.group('lhs')
485 lhs = m.group('lhs')
486 expr = make_quoted_expr("sc -l =%s" % cmd)
486 expr = make_quoted_expr("sc -l =%s" % cmd)
487 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
487 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
488 return new_line
488 return new_line
489 return line
489 return line
490
490
491
491
492 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
492 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
493 r'\s*=\s*%(?P<cmd>.*)')
493 r'\s*=\s*%(?P<cmd>.*)')
494
494
495 class AssignMagicTransformer(PrefilterTransformer):
495 class AssignMagicTransformer(PrefilterTransformer):
496 """Handle the `a = %who` syntax."""
496 """Handle the `a = %who` syntax."""
497
497
498 priority = Int(200, config=True)
498 priority = Int(200, config=True)
499
499
500 def transform(self, line, continue_prompt):
500 def transform(self, line, continue_prompt):
501 m = _assign_magic_re.match(line)
501 m = _assign_magic_re.match(line)
502 if m is not None:
502 if m is not None:
503 cmd = m.group('cmd')
503 cmd = m.group('cmd')
504 lhs = m.group('lhs')
504 lhs = m.group('lhs')
505 expr = make_quoted_expr(cmd)
505 expr = make_quoted_expr(cmd)
506 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
506 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
507 return new_line
507 return new_line
508 return line
508 return line
509
509
510
510
511 #-----------------------------------------------------------------------------
511 #-----------------------------------------------------------------------------
512 # Prefilter checkers
512 # Prefilter checkers
513 #-----------------------------------------------------------------------------
513 #-----------------------------------------------------------------------------
514
514
515
515
516 class PrefilterChecker(Component):
516 class PrefilterChecker(Component):
517 """Inspect an input line and return a handler for that line."""
517 """Inspect an input line and return a handler for that line."""
518
518
519 priority = Int(100, config=True)
519 priority = Int(100, config=True)
520 shell = Any
520 shell = Any
521 prefilter_manager = Any
521 prefilter_manager = Any
522 enabled = Bool(True, config=True)
522 enabled = Bool(True, config=True)
523
523
524 def __init__(self, parent, config=None):
524 def __init__(self, parent, config=None):
525 super(PrefilterChecker, self).__init__(parent, config=config)
525 super(PrefilterChecker, self).__init__(parent, config=config)
526 self.prefilter_manager.register_checker(self)
526 self.prefilter_manager.register_checker(self)
527
527
528 @auto_attr
528 @auto_attr
529 def shell(self):
529 def shell(self):
530 return Component.get_instances(
530 return Component.get_instances(
531 root=self.root,
531 root=self.root,
532 klass='IPython.core.iplib.InteractiveShell')[0]
532 klass='IPython.core.iplib.InteractiveShell')[0]
533
533
534 @auto_attr
534 @auto_attr
535 def prefilter_manager(self):
535 def prefilter_manager(self):
536 return PrefilterManager.get_instances(root=self.root)[0]
536 return PrefilterManager.get_instances(root=self.root)[0]
537
537
538 def check(self, line_info):
538 def check(self, line_info):
539 """Inspect line_info and return a handler instance or None."""
539 """Inspect line_info and return a handler instance or None."""
540 return None
540 return None
541
541
542 def __repr__(self):
542 def __repr__(self):
543 return "<%s(priority=%r, enabled=%r)>" % (
543 return "<%s(priority=%r, enabled=%r)>" % (
544 self.__class__.__name__, self.priority, self.enabled)
544 self.__class__.__name__, self.priority, self.enabled)
545
545
546
546
547 class EmacsChecker(PrefilterChecker):
547 class EmacsChecker(PrefilterChecker):
548
548
549 priority = Int(100, config=True)
549 priority = Int(100, config=True)
550 enabled = Bool(False, config=True)
550 enabled = Bool(False, config=True)
551
551
552 def check(self, line_info):
552 def check(self, line_info):
553 "Emacs ipython-mode tags certain input lines."
553 "Emacs ipython-mode tags certain input lines."
554 if line_info.line.endswith('# PYTHON-MODE'):
554 if line_info.line.endswith('# PYTHON-MODE'):
555 return self.prefilter_manager.get_handler_by_name('emacs')
555 return self.prefilter_manager.get_handler_by_name('emacs')
556 else:
556 else:
557 return None
557 return None
558
558
559
559
560 class ShellEscapeChecker(PrefilterChecker):
560 class ShellEscapeChecker(PrefilterChecker):
561
561
562 priority = Int(200, config=True)
562 priority = Int(200, config=True)
563
563
564 def check(self, line_info):
564 def check(self, line_info):
565 if line_info.line.lstrip().startswith(ESC_SHELL):
565 if line_info.line.lstrip().startswith(ESC_SHELL):
566 return self.prefilter_manager.get_handler_by_name('shell')
566 return self.prefilter_manager.get_handler_by_name('shell')
567
567
568
568
569 class IPyAutocallChecker(PrefilterChecker):
569 class IPyAutocallChecker(PrefilterChecker):
570
570
571 priority = Int(300, config=True)
571 priority = Int(300, config=True)
572
572
573 def check(self, line_info):
573 def check(self, line_info):
574 "Instances of IPyAutocall in user_ns get autocalled immediately"
574 "Instances of IPyAutocall in user_ns get autocalled immediately"
575 obj = self.shell.user_ns.get(line_info.ifun, None)
575 obj = self.shell.user_ns.get(line_info.ifun, None)
576 if isinstance(obj, IPyAutocall):
576 if isinstance(obj, IPyAutocall):
577 obj.set_ip(self.shell)
577 obj.set_ip(self.shell)
578 return self.prefilter_manager.get_handler_by_name('auto')
578 return self.prefilter_manager.get_handler_by_name('auto')
579 else:
579 else:
580 return None
580 return None
581
581
582
582
583 class MultiLineMagicChecker(PrefilterChecker):
583 class MultiLineMagicChecker(PrefilterChecker):
584
584
585 priority = Int(400, config=True)
585 priority = Int(400, config=True)
586
586
587 def check(self, line_info):
587 def check(self, line_info):
588 "Allow ! and !! in multi-line statements if multi_line_specials is on"
588 "Allow ! and !! in multi-line statements if multi_line_specials is on"
589 # Note that this one of the only places we check the first character of
589 # Note that this one of the only places we check the first character of
590 # ifun and *not* the pre_char. Also note that the below test matches
590 # ifun and *not* the pre_char. Also note that the below test matches
591 # both ! and !!.
591 # both ! and !!.
592 if line_info.continue_prompt \
592 if line_info.continue_prompt \
593 and self.prefilter_manager.multi_line_specials:
593 and self.prefilter_manager.multi_line_specials:
594 if line_info.ifun.startswith(ESC_MAGIC):
594 if line_info.ifun.startswith(ESC_MAGIC):
595 return self.prefilter_manager.get_handler_by_name('magic')
595 return self.prefilter_manager.get_handler_by_name('magic')
596 else:
596 else:
597 return None
597 return None
598
598
599
599
600 class EscCharsChecker(PrefilterChecker):
600 class EscCharsChecker(PrefilterChecker):
601
601
602 priority = Int(500, config=True)
602 priority = Int(500, config=True)
603
603
604 def check(self, line_info):
604 def check(self, line_info):
605 """Check for escape character and return either a handler to handle it,
605 """Check for escape character and return either a handler to handle it,
606 or None if there is no escape char."""
606 or None if there is no escape char."""
607 if line_info.line[-1] == ESC_HELP \
607 if line_info.line[-1] == ESC_HELP \
608 and line_info.pre_char != ESC_SHELL \
608 and line_info.pre_char != ESC_SHELL \
609 and line_info.pre_char != ESC_SH_CAP:
609 and line_info.pre_char != ESC_SH_CAP:
610 # the ? can be at the end, but *not* for either kind of shell escape,
610 # the ? can be at the end, but *not* for either kind of shell escape,
611 # because a ? can be a vaild final char in a shell cmd
611 # because a ? can be a vaild final char in a shell cmd
612 return self.prefilter_manager.get_handler_by_name('help')
612 return self.prefilter_manager.get_handler_by_name('help')
613 else:
613 else:
614 # This returns None like it should if no handler exists
614 # This returns None like it should if no handler exists
615 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
615 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
616
616
617
617
618 class AssignmentChecker(PrefilterChecker):
618 class AssignmentChecker(PrefilterChecker):
619
619
620 priority = Int(600, config=True)
620 priority = Int(600, config=True)
621
621
622 def check(self, line_info):
622 def check(self, line_info):
623 """Check to see if user is assigning to a var for the first time, in
623 """Check to see if user is assigning to a var for the first time, in
624 which case we want to avoid any sort of automagic / autocall games.
624 which case we want to avoid any sort of automagic / autocall games.
625
625
626 This allows users to assign to either alias or magic names true python
626 This allows users to assign to either alias or magic names true python
627 variables (the magic/alias systems always take second seat to true
627 variables (the magic/alias systems always take second seat to true
628 python code). E.g. ls='hi', or ls,that=1,2"""
628 python code). E.g. ls='hi', or ls,that=1,2"""
629 if line_info.the_rest:
629 if line_info.the_rest:
630 if line_info.the_rest[0] in '=,':
630 if line_info.the_rest[0] in '=,':
631 return self.prefilter_manager.get_handler_by_name('normal')
631 return self.prefilter_manager.get_handler_by_name('normal')
632 else:
632 else:
633 return None
633 return None
634
634
635
635
636 class AutoMagicChecker(PrefilterChecker):
636 class AutoMagicChecker(PrefilterChecker):
637
637
638 priority = Int(700, config=True)
638 priority = Int(700, config=True)
639
639
640 def check(self, line_info):
640 def check(self, line_info):
641 """If the ifun is magic, and automagic is on, run it. Note: normal,
641 """If the ifun is magic, and automagic is on, run it. Note: normal,
642 non-auto magic would already have been triggered via '%' in
642 non-auto magic would already have been triggered via '%' in
643 check_esc_chars. This just checks for automagic. Also, before
643 check_esc_chars. This just checks for automagic. Also, before
644 triggering the magic handler, make sure that there is nothing in the
644 triggering the magic handler, make sure that there is nothing in the
645 user namespace which could shadow it."""
645 user namespace which could shadow it."""
646 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
646 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
647 return None
647 return None
648
648
649 # We have a likely magic method. Make sure we should actually call it.
649 # We have a likely magic method. Make sure we should actually call it.
650 if line_info.continue_prompt and not self.shell.multi_line_specials:
650 if line_info.continue_prompt and not self.shell.multi_line_specials:
651 return None
651 return None
652
652
653 head = line_info.ifun.split('.',1)[0]
653 head = line_info.ifun.split('.',1)[0]
654 if is_shadowed(head, self.shell):
654 if is_shadowed(head, self.shell):
655 return None
655 return None
656
656
657 return self.prefilter_manager.get_handler_by_name('magic')
657 return self.prefilter_manager.get_handler_by_name('magic')
658
658
659
659
660 class AliasChecker(PrefilterChecker):
660 class AliasChecker(PrefilterChecker):
661
661
662 priority = Int(800, config=True)
662 priority = Int(800, config=True)
663
663
664 @auto_attr
664 @auto_attr
665 def alias_manager(self):
665 def alias_manager(self):
666 return AliasManager.get_instances(root=self.root)[0]
666 return AliasManager.get_instances(root=self.root)[0]
667
667
668 def check(self, line_info):
668 def check(self, line_info):
669 "Check if the initital identifier on the line is an alias."
669 "Check if the initital identifier on the line is an alias."
670 # Note: aliases can not contain '.'
670 # Note: aliases can not contain '.'
671 head = line_info.ifun.split('.',1)[0]
671 head = line_info.ifun.split('.',1)[0]
672 if line_info.ifun not in self.alias_manager \
672 if line_info.ifun not in self.alias_manager \
673 or head not in self.alias_manager \
673 or head not in self.alias_manager \
674 or is_shadowed(head, self.shell):
674 or is_shadowed(head, self.shell):
675 return None
675 return None
676
676
677 return self.prefilter_manager.get_handler_by_name('alias')
677 return self.prefilter_manager.get_handler_by_name('alias')
678
678
679
679
680 class PythonOpsChecker(PrefilterChecker):
680 class PythonOpsChecker(PrefilterChecker):
681
681
682 priority = Int(900, config=True)
682 priority = Int(900, config=True)
683
683
684 def check(self, line_info):
684 def check(self, line_info):
685 """If the 'rest' of the line begins with a function call or pretty much
685 """If the 'rest' of the line begins with a function call or pretty much
686 any python operator, we should simply execute the line (regardless of
686 any python operator, we should simply execute the line (regardless of
687 whether or not there's a possible autocall expansion). This avoids
687 whether or not there's a possible autocall expansion). This avoids
688 spurious (and very confusing) geattr() accesses."""
688 spurious (and very confusing) geattr() accesses."""
689 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
689 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
690 return self.prefilter_manager.get_handler_by_name('normal')
690 return self.prefilter_manager.get_handler_by_name('normal')
691 else:
691 else:
692 return None
692 return None
693
693
694
694
695 class AutocallChecker(PrefilterChecker):
695 class AutocallChecker(PrefilterChecker):
696
696
697 priority = Int(1000, config=True)
697 priority = Int(1000, config=True)
698
698
699 def check(self, line_info):
699 def check(self, line_info):
700 "Check if the initial word/function is callable and autocall is on."
700 "Check if the initial word/function is callable and autocall is on."
701 if not self.shell.autocall:
701 if not self.shell.autocall:
702 return None
702 return None
703
703
704 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
704 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
705 if not oinfo['found']:
705 if not oinfo['found']:
706 return None
706 return None
707
707
708 if callable(oinfo['obj']) \
708 if callable(oinfo['obj']) \
709 and (not re_exclude_auto.match(line_info.the_rest)) \
709 and (not re_exclude_auto.match(line_info.the_rest)) \
710 and re_fun_name.match(line_info.ifun):
710 and re_fun_name.match(line_info.ifun):
711 return self.prefilter_manager.get_handler_by_name('auto')
711 return self.prefilter_manager.get_handler_by_name('auto')
712 else:
712 else:
713 return None
713 return None
714
714
715
715
716 #-----------------------------------------------------------------------------
716 #-----------------------------------------------------------------------------
717 # Prefilter handlers
717 # Prefilter handlers
718 #-----------------------------------------------------------------------------
718 #-----------------------------------------------------------------------------
719
719
720
720
721 class PrefilterHandler(Component):
721 class PrefilterHandler(Component):
722
722
723 handler_name = Str('normal')
723 handler_name = Str('normal')
724 esc_strings = List([])
724 esc_strings = List([])
725 shell = Any
725 shell = Any
726 prefilter_manager = Any
726 prefilter_manager = Any
727
727
728 def __init__(self, parent, config=None):
728 def __init__(self, parent, config=None):
729 super(PrefilterHandler, self).__init__(parent, config=config)
729 super(PrefilterHandler, self).__init__(parent, config=config)
730 self.prefilter_manager.register_handler(
730 self.prefilter_manager.register_handler(
731 self.handler_name,
731 self.handler_name,
732 self,
732 self,
733 self.esc_strings
733 self.esc_strings
734 )
734 )
735
735
736 @auto_attr
736 @auto_attr
737 def shell(self):
737 def shell(self):
738 return Component.get_instances(
738 return Component.get_instances(
739 root=self.root,
739 root=self.root,
740 klass='IPython.core.iplib.InteractiveShell')[0]
740 klass='IPython.core.iplib.InteractiveShell')[0]
741
741
742 @auto_attr
742 @auto_attr
743 def prefilter_manager(self):
743 def prefilter_manager(self):
744 return PrefilterManager.get_instances(root=self.root)[0]
744 return PrefilterManager.get_instances(root=self.root)[0]
745
745
746 def handle(self, line_info):
746 def handle(self, line_info):
747 # print "normal: ", line_info
747 # print "normal: ", line_info
748 """Handle normal input lines. Use as a template for handlers."""
748 """Handle normal input lines. Use as a template for handlers."""
749
749
750 # With autoindent on, we need some way to exit the input loop, and I
750 # With autoindent on, we need some way to exit the input loop, and I
751 # don't want to force the user to have to backspace all the way to
751 # don't want to force the user to have to backspace all the way to
752 # clear the line. The rule will be in this case, that either two
752 # clear the line. The rule will be in this case, that either two
753 # lines of pure whitespace in a row, or a line of pure whitespace but
753 # lines of pure whitespace in a row, or a line of pure whitespace but
754 # of a size different to the indent level, will exit the input loop.
754 # of a size different to the indent level, will exit the input loop.
755 line = line_info.line
755 line = line_info.line
756 continue_prompt = line_info.continue_prompt
756 continue_prompt = line_info.continue_prompt
757
757
758 if (continue_prompt and self.shell.autoindent and line.isspace() and
758 if (continue_prompt and self.shell.autoindent and line.isspace() and
759 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2 or
759 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2 or
760 (self.shell.buffer[-1]).isspace() )):
760 (self.shell.buffer[-1]).isspace() )):
761 line = ''
761 line = ''
762
762
763 self.shell.log(line, line, continue_prompt)
763 self.shell.log(line, line, continue_prompt)
764 return line
764 return line
765
765
766 def __str__(self):
766 def __str__(self):
767 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
767 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
768
768
769
769
770 class AliasHandler(PrefilterHandler):
770 class AliasHandler(PrefilterHandler):
771
771
772 handler_name = Str('alias')
772 handler_name = Str('alias')
773
773
774 @auto_attr
774 @auto_attr
775 def alias_manager(self):
775 def alias_manager(self):
776 return AliasManager.get_instances(root=self.root)[0]
776 return AliasManager.get_instances(root=self.root)[0]
777
777
778 def handle(self, line_info):
778 def handle(self, line_info):
779 """Handle alias input lines. """
779 """Handle alias input lines. """
780 transformed = self.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
780 transformed = self.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
781 # pre is needed, because it carries the leading whitespace. Otherwise
781 # pre is needed, because it carries the leading whitespace. Otherwise
782 # aliases won't work in indented sections.
782 # aliases won't work in indented sections.
783 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
783 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
784 make_quoted_expr(transformed))
784 make_quoted_expr(transformed))
785
785
786 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
786 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
787 return line_out
787 return line_out
788
788
789
789
790 class ShellEscapeHandler(PrefilterHandler):
790 class ShellEscapeHandler(PrefilterHandler):
791
791
792 handler_name = Str('shell')
792 handler_name = Str('shell')
793 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
793 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
794
794
795 def handle(self, line_info):
795 def handle(self, line_info):
796 """Execute the line in a shell, empty return value"""
796 """Execute the line in a shell, empty return value"""
797 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
797 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
798
798
799 line = line_info.line
799 line = line_info.line
800 if line.lstrip().startswith(ESC_SH_CAP):
800 if line.lstrip().startswith(ESC_SH_CAP):
801 # rewrite LineInfo's line, ifun and the_rest to properly hold the
801 # rewrite LineInfo's line, ifun and the_rest to properly hold the
802 # call to %sx and the actual command to be executed, so
802 # call to %sx and the actual command to be executed, so
803 # handle_magic can work correctly. Note that this works even if
803 # handle_magic can work correctly. Note that this works even if
804 # the line is indented, so it handles multi_line_specials
804 # the line is indented, so it handles multi_line_specials
805 # properly.
805 # properly.
806 new_rest = line.lstrip()[2:]
806 new_rest = line.lstrip()[2:]
807 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
807 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
808 line_info.ifun = 'sx'
808 line_info.ifun = 'sx'
809 line_info.the_rest = new_rest
809 line_info.the_rest = new_rest
810 return magic_handler.handle(line_info)
810 return magic_handler.handle(line_info)
811 else:
811 else:
812 cmd = line.lstrip().lstrip(ESC_SHELL)
812 cmd = line.lstrip().lstrip(ESC_SHELL)
813 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
813 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
814 make_quoted_expr(cmd))
814 make_quoted_expr(cmd))
815 # update cache/log and return
815 # update cache/log and return
816 self.shell.log(line, line_out, line_info.continue_prompt)
816 self.shell.log(line, line_out, line_info.continue_prompt)
817 return line_out
817 return line_out
818
818
819
819
820 class MagicHandler(PrefilterHandler):
820 class MagicHandler(PrefilterHandler):
821
821
822 handler_name = Str('magic')
822 handler_name = Str('magic')
823 esc_strings = List([ESC_MAGIC])
823 esc_strings = List([ESC_MAGIC])
824
824
825 def handle(self, line_info):
825 def handle(self, line_info):
826 """Execute magic functions."""
826 """Execute magic functions."""
827 ifun = line_info.ifun
827 ifun = line_info.ifun
828 the_rest = line_info.the_rest
828 the_rest = line_info.the_rest
829 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
829 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
830 make_quoted_expr(ifun + " " + the_rest))
830 make_quoted_expr(ifun + " " + the_rest))
831 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
831 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
832 return cmd
832 return cmd
833
833
834
834
835 class AutoHandler(PrefilterHandler):
835 class AutoHandler(PrefilterHandler):
836
836
837 handler_name = Str('auto')
837 handler_name = Str('auto')
838 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
838 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
839
839
840 def handle(self, line_info):
840 def handle(self, line_info):
841 """Hande lines which can be auto-executed, quoting if requested."""
841 """Hande lines which can be auto-executed, quoting if requested."""
842 line = line_info.line
842 line = line_info.line
843 ifun = line_info.ifun
843 ifun = line_info.ifun
844 the_rest = line_info.the_rest
844 the_rest = line_info.the_rest
845 pre = line_info.pre
845 pre = line_info.pre
846 continue_prompt = line_info.continue_prompt
846 continue_prompt = line_info.continue_prompt
847 obj = line_info.ofind(self)['obj']
847 obj = line_info.ofind(self)['obj']
848
848
849 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
849 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
850
850
851 # This should only be active for single-line input!
851 # This should only be active for single-line input!
852 if continue_prompt:
852 if continue_prompt:
853 self.log(line,line,continue_prompt)
853 self.log(line,line,continue_prompt)
854 return line
854 return line
855
855
856 force_auto = isinstance(obj, IPyAutocall)
856 force_auto = isinstance(obj, IPyAutocall)
857 auto_rewrite = True
857 auto_rewrite = True
858
858
859 if pre == ESC_QUOTE:
859 if pre == ESC_QUOTE:
860 # Auto-quote splitting on whitespace
860 # Auto-quote splitting on whitespace
861 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
861 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
862 elif pre == ESC_QUOTE2:
862 elif pre == ESC_QUOTE2:
863 # Auto-quote whole string
863 # Auto-quote whole string
864 newcmd = '%s("%s")' % (ifun,the_rest)
864 newcmd = '%s("%s")' % (ifun,the_rest)
865 elif pre == ESC_PAREN:
865 elif pre == ESC_PAREN:
866 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
866 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
867 else:
867 else:
868 # Auto-paren.
868 # Auto-paren.
869 # We only apply it to argument-less calls if the autocall
869 # We only apply it to argument-less calls if the autocall
870 # parameter is set to 2. We only need to check that autocall is <
870 # parameter is set to 2. We only need to check that autocall is <
871 # 2, since this function isn't called unless it's at least 1.
871 # 2, since this function isn't called unless it's at least 1.
872 if not the_rest and (self.shell.autocall < 2) and not force_auto:
872 if not the_rest and (self.shell.autocall < 2) and not force_auto:
873 newcmd = '%s %s' % (ifun,the_rest)
873 newcmd = '%s %s' % (ifun,the_rest)
874 auto_rewrite = False
874 auto_rewrite = False
875 else:
875 else:
876 if not force_auto and the_rest.startswith('['):
876 if not force_auto and the_rest.startswith('['):
877 if hasattr(obj,'__getitem__'):
877 if hasattr(obj,'__getitem__'):
878 # Don't autocall in this case: item access for an object
878 # Don't autocall in this case: item access for an object
879 # which is BOTH callable and implements __getitem__.
879 # which is BOTH callable and implements __getitem__.
880 newcmd = '%s %s' % (ifun,the_rest)
880 newcmd = '%s %s' % (ifun,the_rest)
881 auto_rewrite = False
881 auto_rewrite = False
882 else:
882 else:
883 # if the object doesn't support [] access, go ahead and
883 # if the object doesn't support [] access, go ahead and
884 # autocall
884 # autocall
885 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
885 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
886 elif the_rest.endswith(';'):
886 elif the_rest.endswith(';'):
887 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
887 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
888 else:
888 else:
889 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
889 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
890
890
891 if auto_rewrite:
891 if auto_rewrite:
892 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
892 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
893
893
894 try:
894 try:
895 # plain ascii works better w/ pyreadline, on some machines, so
895 # plain ascii works better w/ pyreadline, on some machines, so
896 # we use it and only print uncolored rewrite if we have unicode
896 # we use it and only print uncolored rewrite if we have unicode
897 rw = str(rw)
897 rw = str(rw)
898 print >>Term.cout, rw
898 print >>Term.cout, rw
899 except UnicodeEncodeError:
899 except UnicodeEncodeError:
900 print "-------------->" + newcmd
900 print "-------------->" + newcmd
901
901
902 # log what is now valid Python, not the actual user input (without the
902 # log what is now valid Python, not the actual user input (without the
903 # final newline)
903 # final newline)
904 self.shell.log(line,newcmd,continue_prompt)
904 self.shell.log(line,newcmd,continue_prompt)
905 return newcmd
905 return newcmd
906
906
907
907
908 class HelpHandler(PrefilterHandler):
908 class HelpHandler(PrefilterHandler):
909
909
910 handler_name = Str('help')
910 handler_name = Str('help')
911 esc_strings = List([ESC_HELP])
911 esc_strings = List([ESC_HELP])
912
912
913 def handle(self, line_info):
913 def handle(self, line_info):
914 """Try to get some help for the object.
914 """Try to get some help for the object.
915
915
916 obj? or ?obj -> basic information.
916 obj? or ?obj -> basic information.
917 obj?? or ??obj -> more details.
917 obj?? or ??obj -> more details.
918 """
918 """
919 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
919 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
920 line = line_info.line
920 line = line_info.line
921 # We need to make sure that we don't process lines which would be
921 # We need to make sure that we don't process lines which would be
922 # otherwise valid python, such as "x=1 # what?"
922 # otherwise valid python, such as "x=1 # what?"
923 try:
923 try:
924 codeop.compile_command(line)
924 codeop.compile_command(line)
925 except SyntaxError:
925 except SyntaxError:
926 # We should only handle as help stuff which is NOT valid syntax
926 # We should only handle as help stuff which is NOT valid syntax
927 if line[0]==ESC_HELP:
927 if line[0]==ESC_HELP:
928 line = line[1:]
928 line = line[1:]
929 elif line[-1]==ESC_HELP:
929 elif line[-1]==ESC_HELP:
930 line = line[:-1]
930 line = line[:-1]
931 self.shell.log(line, '#?'+line, line_info.continue_prompt)
931 self.shell.log(line, '#?'+line, line_info.continue_prompt)
932 if line:
932 if line:
933 #print 'line:<%r>' % line # dbg
933 #print 'line:<%r>' % line # dbg
934 self.shell.magic_pinfo(line)
934 self.shell.magic_pinfo(line)
935 else:
935 else:
936 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
936 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
937 return '' # Empty string is needed here!
937 return '' # Empty string is needed here!
938 except:
938 except:
939 raise
939 raise
940 # Pass any other exceptions through to the normal handler
940 # Pass any other exceptions through to the normal handler
941 return normal_handler.handle(line_info)
941 return normal_handler.handle(line_info)
942 else:
942 else:
943 raise
943 raise
944 # If the code compiles ok, we should handle it normally
944 # If the code compiles ok, we should handle it normally
945 return normal_handler.handle(line_info)
945 return normal_handler.handle(line_info)
946
946
947
947
948 class EmacsHandler(PrefilterHandler):
948 class EmacsHandler(PrefilterHandler):
949
949
950 handler_name = Str('emacs')
950 handler_name = Str('emacs')
951 esc_strings = List([])
951 esc_strings = List([])
952
952
953 def handle(self, line_info):
953 def handle(self, line_info):
954 """Handle input lines marked by python-mode."""
954 """Handle input lines marked by python-mode."""
955
955
956 # Currently, nothing is done. Later more functionality can be added
956 # Currently, nothing is done. Later more functionality can be added
957 # here if needed.
957 # here if needed.
958
958
959 # The input cache shouldn't be updated
959 # The input cache shouldn't be updated
960 return line_info.line
960 return line_info.line
961
961
962
962
963 #-----------------------------------------------------------------------------
963 #-----------------------------------------------------------------------------
964 # Defaults
964 # Defaults
965 #-----------------------------------------------------------------------------
965 #-----------------------------------------------------------------------------
966
966
967
967
968 _default_transformers = [
968 _default_transformers = [
969 AssignSystemTransformer,
969 AssignSystemTransformer,
970 AssignMagicTransformer
970 AssignMagicTransformer
971 ]
971 ]
972
972
973 _default_checkers = [
973 _default_checkers = [
974 EmacsChecker,
974 EmacsChecker,
975 ShellEscapeChecker,
975 ShellEscapeChecker,
976 IPyAutocallChecker,
976 IPyAutocallChecker,
977 MultiLineMagicChecker,
977 MultiLineMagicChecker,
978 EscCharsChecker,
978 EscCharsChecker,
979 AssignmentChecker,
979 AssignmentChecker,
980 AutoMagicChecker,
980 AutoMagicChecker,
981 AliasChecker,
981 AliasChecker,
982 PythonOpsChecker,
982 PythonOpsChecker,
983 AutocallChecker
983 AutocallChecker
984 ]
984 ]
985
985
986 _default_handlers = [
986 _default_handlers = [
987 PrefilterHandler,
987 PrefilterHandler,
988 AliasHandler,
988 AliasHandler,
989 ShellEscapeHandler,
989 ShellEscapeHandler,
990 MagicHandler,
990 MagicHandler,
991 AutoHandler,
991 AutoHandler,
992 HelpHandler,
992 HelpHandler,
993 EmacsHandler
993 EmacsHandler
994 ]
994 ]
995
995
@@ -1,457 +1,455 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The ipcluster application.
4 The ipcluster application.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import logging
18 import logging
19 import os
19 import os
20 import signal
20 import signal
21 import sys
21 import sys
22
22
23 if os.name=='posix':
23 if os.name=='posix':
24 from twisted.scripts._twistd_unix import daemonize
24 from twisted.scripts._twistd_unix import daemonize
25
25
26 from IPython.core import release
26 from IPython.core import release
27 from IPython.external import argparse
27 from IPython.external import argparse
28 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
28 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
29 from IPython.utils.importstring import import_item
29 from IPython.utils.importstring import import_item
30
30
31 from IPython.kernel.clusterdir import (
31 from IPython.kernel.clusterdir import (
32 ApplicationWithClusterDir, ClusterDirError, PIDFileError
32 ApplicationWithClusterDir, ClusterDirError, PIDFileError
33 )
33 )
34
34
35 from twisted.internet import reactor, defer
35 from twisted.internet import reactor, defer
36 from twisted.python import log, failure
36 from twisted.python import log, failure
37
37
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # The ipcluster application
40 # The ipcluster application
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43
43
44 # Exit codes for ipcluster
44 # Exit codes for ipcluster
45
45
46 # This will be the exit code if the ipcluster appears to be running because
46 # This will be the exit code if the ipcluster appears to be running because
47 # a .pid file exists
47 # a .pid file exists
48 ALREADY_STARTED = 10
48 ALREADY_STARTED = 10
49
49
50 # This will be the exit code if ipcluster stop is run, but there is not .pid
50 # This will be the exit code if ipcluster stop is run, but there is not .pid
51 # file to be found.
51 # file to be found.
52 ALREADY_STOPPED = 11
52 ALREADY_STOPPED = 11
53
53
54
54
55 class IPClusterCLLoader(ArgParseConfigLoader):
55 class IPClusterCLLoader(ArgParseConfigLoader):
56
56
57 def _add_arguments(self):
57 def _add_arguments(self):
58 # This has all the common options that all subcommands use
58 # This has all the common options that all subcommands use
59 parent_parser1 = argparse.ArgumentParser(add_help=False)
59 parent_parser1 = argparse.ArgumentParser(add_help=False)
60 parent_parser1.add_argument('--ipython-dir',
60 parent_parser1.add_argument('--ipython-dir',
61 dest='Global.ipython_dir',type=unicode,
61 dest='Global.ipython_dir',type=unicode,
62 help='Set to override default location of Global.ipython_dir.',
62 help='Set to override default location of Global.ipython_dir.',
63 default=NoConfigDefault,
63 default=NoConfigDefault,
64 metavar='Global.ipython_dir')
64 metavar='Global.ipython_dir')
65 parent_parser1.add_argument('--log-level',
65 parent_parser1.add_argument('--log-level',
66 dest="Global.log_level",type=int,
66 dest="Global.log_level",type=int,
67 help='Set the log level (0,10,20,30,40,50). Default is 30.',
67 help='Set the log level (0,10,20,30,40,50). Default is 30.',
68 default=NoConfigDefault,
68 default=NoConfigDefault,
69 metavar='Global.log_level')
69 metavar='Global.log_level')
70
70
71 # This has all the common options that other subcommands use
71 # This has all the common options that other subcommands use
72 parent_parser2 = argparse.ArgumentParser(add_help=False)
72 parent_parser2 = argparse.ArgumentParser(add_help=False)
73 parent_parser2.add_argument('-p','--profile',
73 parent_parser2.add_argument('-p','--profile',
74 dest='Global.profile',type=unicode,
74 dest='Global.profile',type=unicode,
75 default=NoConfigDefault,
76 help='The string name of the profile to be used. This determines '
75 help='The string name of the profile to be used. This determines '
77 'the name of the cluster dir as: cluster_<profile>. The default profile '
76 'the name of the cluster dir as: cluster_<profile>. The default profile '
78 'is named "default". The cluster directory is resolve this way '
77 'is named "default". The cluster directory is resolve this way '
79 'if the --cluster-dir option is not used.',
78 'if the --cluster-dir option is not used.',
80 default=NoConfigDefault,
79 default=NoConfigDefault,
81 metavar='Global.profile')
80 metavar='Global.profile')
82 parent_parser2.add_argument('--cluster-dir',
81 parent_parser2.add_argument('--cluster-dir',
83 dest='Global.cluster_dir',type=unicode,
82 dest='Global.cluster_dir',type=unicode,
84 default=NoConfigDefault,
85 help='Set the cluster dir. This overrides the logic used by the '
83 help='Set the cluster dir. This overrides the logic used by the '
86 '--profile option.',
84 '--profile option.',
87 default=NoConfigDefault,
85 default=NoConfigDefault,
88 metavar='Global.cluster_dir'),
86 metavar='Global.cluster_dir'),
89 parent_parser2.add_argument('--work-dir',
87 parent_parser2.add_argument('--work-dir',
90 dest='Global.work_dir',type=unicode,
88 dest='Global.work_dir',type=unicode,
91 help='Set the working dir for the process.',
89 help='Set the working dir for the process.',
92 default=NoConfigDefault,
90 default=NoConfigDefault,
93 metavar='Global.work_dir')
91 metavar='Global.work_dir')
94 parent_parser2.add_argument('--log-to-file',
92 parent_parser2.add_argument('--log-to-file',
95 action='store_true', dest='Global.log_to_file',
93 action='store_true', dest='Global.log_to_file',
96 default=NoConfigDefault,
94 default=NoConfigDefault,
97 help='Log to a file in the log directory (default is stdout)'
95 help='Log to a file in the log directory (default is stdout)'
98 )
96 )
99
97
100 subparsers = self.parser.add_subparsers(
98 subparsers = self.parser.add_subparsers(
101 dest='Global.subcommand',
99 dest='Global.subcommand',
102 title='ipcluster subcommands',
100 title='ipcluster subcommands',
103 description='ipcluster has a variety of subcommands. '
101 description='ipcluster has a variety of subcommands. '
104 'The general way of running ipcluster is "ipcluster <cmd> '
102 'The general way of running ipcluster is "ipcluster <cmd> '
105 ' [options]""',
103 ' [options]""',
106 help='For more help, type "ipcluster <cmd> -h"')
104 help='For more help, type "ipcluster <cmd> -h"')
107
105
108 parser_list = subparsers.add_parser(
106 parser_list = subparsers.add_parser(
109 'list',
107 'list',
110 help='List all clusters in cwd and ipython_dir.',
108 help='List all clusters in cwd and ipython_dir.',
111 parents=[parent_parser1]
109 parents=[parent_parser1]
112 )
110 )
113
111
114 parser_create = subparsers.add_parser(
112 parser_create = subparsers.add_parser(
115 'create',
113 'create',
116 help='Create a new cluster directory.',
114 help='Create a new cluster directory.',
117 parents=[parent_parser1, parent_parser2]
115 parents=[parent_parser1, parent_parser2]
118 )
116 )
119 parser_create.add_argument(
117 parser_create.add_argument(
120 '--reset-config',
118 '--reset-config',
121 dest='Global.reset_config', action='store_true',
119 dest='Global.reset_config', action='store_true',
122 default=NoConfigDefault,
120 default=NoConfigDefault,
123 help='Recopy the default config files to the cluster directory. '
121 help='Recopy the default config files to the cluster directory. '
124 'You will loose any modifications you have made to these files.'
122 'You will loose any modifications you have made to these files.'
125 )
123 )
126
124
127 parser_start = subparsers.add_parser(
125 parser_start = subparsers.add_parser(
128 'start',
126 'start',
129 help='Start a cluster.',
127 help='Start a cluster.',
130 parents=[parent_parser1, parent_parser2]
128 parents=[parent_parser1, parent_parser2]
131 )
129 )
132 parser_start.add_argument(
130 parser_start.add_argument(
133 '-n', '--number',
131 '-n', '--number',
134 type=int, dest='Global.n',
132 type=int, dest='Global.n',
135 default=NoConfigDefault,
133 default=NoConfigDefault,
136 help='The number of engines to start.',
134 help='The number of engines to start.',
137 metavar='Global.n'
135 metavar='Global.n'
138 )
136 )
139 parser_start.add_argument('--clean-logs',
137 parser_start.add_argument('--clean-logs',
140 dest='Global.clean_logs', action='store_true',
138 dest='Global.clean_logs', action='store_true',
141 help='Delete old log flies before starting.',
139 help='Delete old log flies before starting.',
142 default=NoConfigDefault
140 default=NoConfigDefault
143 )
141 )
144 parser_start.add_argument('--no-clean-logs',
142 parser_start.add_argument('--no-clean-logs',
145 dest='Global.clean_logs', action='store_false',
143 dest='Global.clean_logs', action='store_false',
146 help="Don't delete old log flies before starting.",
144 help="Don't delete old log flies before starting.",
147 default=NoConfigDefault
145 default=NoConfigDefault
148 )
146 )
149 parser_start.add_argument('--daemon',
147 parser_start.add_argument('--daemon',
150 dest='Global.daemonize', action='store_true',
148 dest='Global.daemonize', action='store_true',
151 help='Daemonize the ipcluster program. This implies --log-to-file',
149 help='Daemonize the ipcluster program. This implies --log-to-file',
152 default=NoConfigDefault
150 default=NoConfigDefault
153 )
151 )
154 parser_start.add_argument('--no-daemon',
152 parser_start.add_argument('--no-daemon',
155 dest='Global.daemonize', action='store_false',
153 dest='Global.daemonize', action='store_false',
156 help="Dont't daemonize the ipcluster program.",
154 help="Dont't daemonize the ipcluster program.",
157 default=NoConfigDefault
155 default=NoConfigDefault
158 )
156 )
159
157
160 parser_start = subparsers.add_parser(
158 parser_start = subparsers.add_parser(
161 'stop',
159 'stop',
162 help='Stop a cluster.',
160 help='Stop a cluster.',
163 parents=[parent_parser1, parent_parser2]
161 parents=[parent_parser1, parent_parser2]
164 )
162 )
165 parser_start.add_argument('--signal',
163 parser_start.add_argument('--signal',
166 dest='Global.signal', type=int,
164 dest='Global.signal', type=int,
167 help="The signal number to use in stopping the cluster (default=2).",
165 help="The signal number to use in stopping the cluster (default=2).",
168 metavar="Global.signal",
166 metavar="Global.signal",
169 default=NoConfigDefault
167 default=NoConfigDefault
170 )
168 )
171
169
172
170
173 default_config_file_name = u'ipcluster_config.py'
171 default_config_file_name = u'ipcluster_config.py'
174
172
175
173
176 class IPClusterApp(ApplicationWithClusterDir):
174 class IPClusterApp(ApplicationWithClusterDir):
177
175
178 name = u'ipcluster'
176 name = u'ipcluster'
179 description = 'Start an IPython cluster (controller and engines).'
177 description = 'Start an IPython cluster (controller and engines).'
180 config_file_name = default_config_file_name
178 config_file_name = default_config_file_name
181 default_log_level = logging.INFO
179 default_log_level = logging.INFO
182 auto_create_cluster_dir = False
180 auto_create_cluster_dir = False
183
181
184 def create_default_config(self):
182 def create_default_config(self):
185 super(IPClusterApp, self).create_default_config()
183 super(IPClusterApp, self).create_default_config()
186 self.default_config.Global.controller_launcher = \
184 self.default_config.Global.controller_launcher = \
187 'IPython.kernel.launcher.LocalControllerLauncher'
185 'IPython.kernel.launcher.LocalControllerLauncher'
188 self.default_config.Global.engine_launcher = \
186 self.default_config.Global.engine_launcher = \
189 'IPython.kernel.launcher.LocalEngineSetLauncher'
187 'IPython.kernel.launcher.LocalEngineSetLauncher'
190 self.default_config.Global.n = 2
188 self.default_config.Global.n = 2
191 self.default_config.Global.reset_config = False
189 self.default_config.Global.reset_config = False
192 self.default_config.Global.clean_logs = True
190 self.default_config.Global.clean_logs = True
193 self.default_config.Global.signal = 2
191 self.default_config.Global.signal = 2
194 self.default_config.Global.daemonize = False
192 self.default_config.Global.daemonize = False
195
193
196 def create_command_line_config(self):
194 def create_command_line_config(self):
197 """Create and return a command line config loader."""
195 """Create and return a command line config loader."""
198 return IPClusterCLLoader(
196 return IPClusterCLLoader(
199 description=self.description,
197 description=self.description,
200 version=release.version
198 version=release.version
201 )
199 )
202
200
203 def find_resources(self):
201 def find_resources(self):
204 subcommand = self.command_line_config.Global.subcommand
202 subcommand = self.command_line_config.Global.subcommand
205 if subcommand=='list':
203 if subcommand=='list':
206 self.list_cluster_dirs()
204 self.list_cluster_dirs()
207 # Exit immediately because there is nothing left to do.
205 # Exit immediately because there is nothing left to do.
208 self.exit()
206 self.exit()
209 elif subcommand=='create':
207 elif subcommand=='create':
210 self.auto_create_cluster_dir = True
208 self.auto_create_cluster_dir = True
211 super(IPClusterApp, self).find_resources()
209 super(IPClusterApp, self).find_resources()
212 elif subcommand=='start' or subcommand=='stop':
210 elif subcommand=='start' or subcommand=='stop':
213 self.auto_create_cluster_dir = False
211 self.auto_create_cluster_dir = False
214 try:
212 try:
215 super(IPClusterApp, self).find_resources()
213 super(IPClusterApp, self).find_resources()
216 except ClusterDirError:
214 except ClusterDirError:
217 raise ClusterDirError(
215 raise ClusterDirError(
218 "Could not find a cluster directory. A cluster dir must "
216 "Could not find a cluster directory. A cluster dir must "
219 "be created before running 'ipcluster start'. Do "
217 "be created before running 'ipcluster start'. Do "
220 "'ipcluster create -h' or 'ipcluster list -h' for more "
218 "'ipcluster create -h' or 'ipcluster list -h' for more "
221 "information about creating and listing cluster dirs."
219 "information about creating and listing cluster dirs."
222 )
220 )
223
221
224 def list_cluster_dirs(self):
222 def list_cluster_dirs(self):
225 # Find the search paths
223 # Find the search paths
226 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
224 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
227 if cluster_dir_paths:
225 if cluster_dir_paths:
228 cluster_dir_paths = cluster_dir_paths.split(':')
226 cluster_dir_paths = cluster_dir_paths.split(':')
229 else:
227 else:
230 cluster_dir_paths = []
228 cluster_dir_paths = []
231 try:
229 try:
232 ipython_dir = self.command_line_config.Global.ipython_dir
230 ipython_dir = self.command_line_config.Global.ipython_dir
233 except AttributeError:
231 except AttributeError:
234 ipython_dir = self.default_config.Global.ipython_dir
232 ipython_dir = self.default_config.Global.ipython_dir
235 paths = [os.getcwd(), ipython_dir] + \
233 paths = [os.getcwd(), ipython_dir] + \
236 cluster_dir_paths
234 cluster_dir_paths
237 paths = list(set(paths))
235 paths = list(set(paths))
238
236
239 self.log.info('Searching for cluster dirs in paths: %r' % paths)
237 self.log.info('Searching for cluster dirs in paths: %r' % paths)
240 for path in paths:
238 for path in paths:
241 files = os.listdir(path)
239 files = os.listdir(path)
242 for f in files:
240 for f in files:
243 full_path = os.path.join(path, f)
241 full_path = os.path.join(path, f)
244 if os.path.isdir(full_path) and f.startswith('cluster_'):
242 if os.path.isdir(full_path) and f.startswith('cluster_'):
245 profile = full_path.split('_')[-1]
243 profile = full_path.split('_')[-1]
246 start_cmd = '"ipcluster start -n 4 -p %s"' % profile
244 start_cmd = '"ipcluster start -n 4 -p %s"' % profile
247 print start_cmd + " ==> " + full_path
245 print start_cmd + " ==> " + full_path
248
246
249 def pre_construct(self):
247 def pre_construct(self):
250 # IPClusterApp.pre_construct() is where we cd to the working directory.
248 # IPClusterApp.pre_construct() is where we cd to the working directory.
251 super(IPClusterApp, self).pre_construct()
249 super(IPClusterApp, self).pre_construct()
252 config = self.master_config
250 config = self.master_config
253 try:
251 try:
254 daemon = config.Global.daemonize
252 daemon = config.Global.daemonize
255 if daemon:
253 if daemon:
256 config.Global.log_to_file = True
254 config.Global.log_to_file = True
257 except AttributeError:
255 except AttributeError:
258 pass
256 pass
259
257
260 def construct(self):
258 def construct(self):
261 config = self.master_config
259 config = self.master_config
262 if config.Global.subcommand=='list':
260 if config.Global.subcommand=='list':
263 pass
261 pass
264 elif config.Global.subcommand=='create':
262 elif config.Global.subcommand=='create':
265 self.log.info('Copying default config files to cluster directory '
263 self.log.info('Copying default config files to cluster directory '
266 '[overwrite=%r]' % (config.Global.reset_config,))
264 '[overwrite=%r]' % (config.Global.reset_config,))
267 self.cluster_dir_obj.copy_all_config_files(overwrite=config.Global.reset_config)
265 self.cluster_dir_obj.copy_all_config_files(overwrite=config.Global.reset_config)
268 elif config.Global.subcommand=='start':
266 elif config.Global.subcommand=='start':
269 self.start_logging()
267 self.start_logging()
270 reactor.callWhenRunning(self.start_launchers)
268 reactor.callWhenRunning(self.start_launchers)
271
269
272 def start_launchers(self):
270 def start_launchers(self):
273 config = self.master_config
271 config = self.master_config
274
272
275 # Create the launchers. In both bases, we set the work_dir of
273 # Create the launchers. In both bases, we set the work_dir of
276 # the launcher to the cluster_dir. This is where the launcher's
274 # the launcher to the cluster_dir. This is where the launcher's
277 # subprocesses will be launched. It is not where the controller
275 # subprocesses will be launched. It is not where the controller
278 # and engine will be launched.
276 # and engine will be launched.
279 el_class = import_item(config.Global.engine_launcher)
277 el_class = import_item(config.Global.engine_launcher)
280 self.engine_launcher = el_class(
278 self.engine_launcher = el_class(
281 work_dir=self.cluster_dir, config=config
279 work_dir=self.cluster_dir, config=config
282 )
280 )
283 cl_class = import_item(config.Global.controller_launcher)
281 cl_class = import_item(config.Global.controller_launcher)
284 self.controller_launcher = cl_class(
282 self.controller_launcher = cl_class(
285 work_dir=self.cluster_dir, config=config
283 work_dir=self.cluster_dir, config=config
286 )
284 )
287
285
288 # Setup signals
286 # Setup signals
289 signal.signal(signal.SIGINT, self.sigint_handler)
287 signal.signal(signal.SIGINT, self.sigint_handler)
290
288
291 # Setup the observing of stopping. If the controller dies, shut
289 # Setup the observing of stopping. If the controller dies, shut
292 # everything down as that will be completely fatal for the engines.
290 # everything down as that will be completely fatal for the engines.
293 d1 = self.controller_launcher.observe_stop()
291 d1 = self.controller_launcher.observe_stop()
294 d1.addCallback(self.stop_launchers)
292 d1.addCallback(self.stop_launchers)
295 # But, we don't monitor the stopping of engines. An engine dying
293 # But, we don't monitor the stopping of engines. An engine dying
296 # is just fine and in principle a user could start a new engine.
294 # is just fine and in principle a user could start a new engine.
297 # Also, if we did monitor engine stopping, it is difficult to
295 # Also, if we did monitor engine stopping, it is difficult to
298 # know what to do when only some engines die. Currently, the
296 # know what to do when only some engines die. Currently, the
299 # observing of engine stopping is inconsistent. Some launchers
297 # observing of engine stopping is inconsistent. Some launchers
300 # might trigger on a single engine stopping, other wait until
298 # might trigger on a single engine stopping, other wait until
301 # all stop. TODO: think more about how to handle this.
299 # all stop. TODO: think more about how to handle this.
302
300
303 # Start the controller and engines
301 # Start the controller and engines
304 self._stopping = False # Make sure stop_launchers is not called 2x.
302 self._stopping = False # Make sure stop_launchers is not called 2x.
305 d = self.start_controller()
303 d = self.start_controller()
306 d.addCallback(self.start_engines)
304 d.addCallback(self.start_engines)
307 d.addCallback(self.startup_message)
305 d.addCallback(self.startup_message)
308 # If the controller or engines fail to start, stop everything
306 # If the controller or engines fail to start, stop everything
309 d.addErrback(self.stop_launchers)
307 d.addErrback(self.stop_launchers)
310 return d
308 return d
311
309
312 def startup_message(self, r=None):
310 def startup_message(self, r=None):
313 log.msg("IPython cluster: started")
311 log.msg("IPython cluster: started")
314 return r
312 return r
315
313
316 def start_controller(self, r=None):
314 def start_controller(self, r=None):
317 # log.msg("In start_controller")
315 # log.msg("In start_controller")
318 config = self.master_config
316 config = self.master_config
319 d = self.controller_launcher.start(
317 d = self.controller_launcher.start(
320 cluster_dir=config.Global.cluster_dir
318 cluster_dir=config.Global.cluster_dir
321 )
319 )
322 return d
320 return d
323
321
324 def start_engines(self, r=None):
322 def start_engines(self, r=None):
325 # log.msg("In start_engines")
323 # log.msg("In start_engines")
326 config = self.master_config
324 config = self.master_config
327 d = self.engine_launcher.start(
325 d = self.engine_launcher.start(
328 config.Global.n,
326 config.Global.n,
329 cluster_dir=config.Global.cluster_dir
327 cluster_dir=config.Global.cluster_dir
330 )
328 )
331 return d
329 return d
332
330
333 def stop_controller(self, r=None):
331 def stop_controller(self, r=None):
334 # log.msg("In stop_controller")
332 # log.msg("In stop_controller")
335 if self.controller_launcher.running:
333 if self.controller_launcher.running:
336 d = self.controller_launcher.stop()
334 d = self.controller_launcher.stop()
337 d.addErrback(self.log_err)
335 d.addErrback(self.log_err)
338 return d
336 return d
339 else:
337 else:
340 return defer.succeed(None)
338 return defer.succeed(None)
341
339
342 def stop_engines(self, r=None):
340 def stop_engines(self, r=None):
343 # log.msg("In stop_engines")
341 # log.msg("In stop_engines")
344 if self.engine_launcher.running:
342 if self.engine_launcher.running:
345 d = self.engine_launcher.stop()
343 d = self.engine_launcher.stop()
346 d.addErrback(self.log_err)
344 d.addErrback(self.log_err)
347 return d
345 return d
348 else:
346 else:
349 return defer.succeed(None)
347 return defer.succeed(None)
350
348
351 def log_err(self, f):
349 def log_err(self, f):
352 log.msg(f.getTraceback())
350 log.msg(f.getTraceback())
353 return None
351 return None
354
352
355 def stop_launchers(self, r=None):
353 def stop_launchers(self, r=None):
356 if not self._stopping:
354 if not self._stopping:
357 self._stopping = True
355 self._stopping = True
358 if isinstance(r, failure.Failure):
356 if isinstance(r, failure.Failure):
359 log.msg('Unexpected error in ipcluster:')
357 log.msg('Unexpected error in ipcluster:')
360 log.msg(r.getTraceback())
358 log.msg(r.getTraceback())
361 log.msg("IPython cluster: stopping")
359 log.msg("IPython cluster: stopping")
362 d= self.stop_engines()
360 d= self.stop_engines()
363 d2 = self.stop_controller()
361 d2 = self.stop_controller()
364 # Wait a few seconds to let things shut down.
362 # Wait a few seconds to let things shut down.
365 reactor.callLater(3.0, reactor.stop)
363 reactor.callLater(3.0, reactor.stop)
366
364
367 def sigint_handler(self, signum, frame):
365 def sigint_handler(self, signum, frame):
368 self.stop_launchers()
366 self.stop_launchers()
369
367
370 def start_logging(self):
368 def start_logging(self):
371 # Remove old log files of the controller and engine
369 # Remove old log files of the controller and engine
372 if self.master_config.Global.clean_logs:
370 if self.master_config.Global.clean_logs:
373 log_dir = self.master_config.Global.log_dir
371 log_dir = self.master_config.Global.log_dir
374 for f in os.listdir(log_dir):
372 for f in os.listdir(log_dir):
375 if f.startswith('ipengine' + '-'):
373 if f.startswith('ipengine' + '-'):
376 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
374 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
377 os.remove(os.path.join(log_dir, f))
375 os.remove(os.path.join(log_dir, f))
378 if f.startswith('ipcontroller' + '-'):
376 if f.startswith('ipcontroller' + '-'):
379 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
377 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
380 os.remove(os.path.join(log_dir, f))
378 os.remove(os.path.join(log_dir, f))
381 # This will remote old log files for ipcluster itself
379 # This will remote old log files for ipcluster itself
382 super(IPClusterApp, self).start_logging()
380 super(IPClusterApp, self).start_logging()
383
381
384 def start_app(self):
382 def start_app(self):
385 """Start the application, depending on what subcommand is used."""
383 """Start the application, depending on what subcommand is used."""
386 subcmd = self.master_config.Global.subcommand
384 subcmd = self.master_config.Global.subcommand
387 if subcmd=='create' or subcmd=='list':
385 if subcmd=='create' or subcmd=='list':
388 return
386 return
389 elif subcmd=='start':
387 elif subcmd=='start':
390 self.start_app_start()
388 self.start_app_start()
391 elif subcmd=='stop':
389 elif subcmd=='stop':
392 self.start_app_stop()
390 self.start_app_stop()
393
391
394 def start_app_start(self):
392 def start_app_start(self):
395 """Start the app for the start subcommand."""
393 """Start the app for the start subcommand."""
396 config = self.master_config
394 config = self.master_config
397 # First see if the cluster is already running
395 # First see if the cluster is already running
398 try:
396 try:
399 pid = self.get_pid_from_file()
397 pid = self.get_pid_from_file()
400 except PIDFileError:
398 except PIDFileError:
401 pass
399 pass
402 else:
400 else:
403 self.log.critical(
401 self.log.critical(
404 'Cluster is already running with [pid=%s]. '
402 'Cluster is already running with [pid=%s]. '
405 'use "ipcluster stop" to stop the cluster.' % pid
403 'use "ipcluster stop" to stop the cluster.' % pid
406 )
404 )
407 # Here I exit with a unusual exit status that other processes
405 # Here I exit with a unusual exit status that other processes
408 # can watch for to learn how I existed.
406 # can watch for to learn how I existed.
409 self.exit(ALREADY_STARTED)
407 self.exit(ALREADY_STARTED)
410
408
411 # Now log and daemonize
409 # Now log and daemonize
412 self.log.info(
410 self.log.info(
413 'Starting ipcluster with [daemon=%r]' % config.Global.daemonize
411 'Starting ipcluster with [daemon=%r]' % config.Global.daemonize
414 )
412 )
415 if config.Global.daemonize:
413 if config.Global.daemonize:
416 if os.name=='posix':
414 if os.name=='posix':
417 daemonize()
415 daemonize()
418
416
419 # Now write the new pid file AFTER our new forked pid is active.
417 # Now write the new pid file AFTER our new forked pid is active.
420 self.write_pid_file()
418 self.write_pid_file()
421 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
419 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
422 reactor.run()
420 reactor.run()
423
421
424 def start_app_stop(self):
422 def start_app_stop(self):
425 """Start the app for the stop subcommand."""
423 """Start the app for the stop subcommand."""
426 config = self.master_config
424 config = self.master_config
427 try:
425 try:
428 pid = self.get_pid_from_file()
426 pid = self.get_pid_from_file()
429 except PIDFileError:
427 except PIDFileError:
430 self.log.critical(
428 self.log.critical(
431 'Problem reading pid file, cluster is probably not running.'
429 'Problem reading pid file, cluster is probably not running.'
432 )
430 )
433 # Here I exit with a unusual exit status that other processes
431 # Here I exit with a unusual exit status that other processes
434 # can watch for to learn how I existed.
432 # can watch for to learn how I existed.
435 self.exit(ALREADY_STOPPED)
433 self.exit(ALREADY_STOPPED)
436 else:
434 else:
437 if os.name=='posix':
435 if os.name=='posix':
438 sig = config.Global.signal
436 sig = config.Global.signal
439 self.log.info(
437 self.log.info(
440 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
438 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
441 )
439 )
442 os.kill(pid, sig)
440 os.kill(pid, sig)
443 elif os.name=='nt':
441 elif os.name=='nt':
444 # As of right now, we don't support daemonize on Windows, so
442 # As of right now, we don't support daemonize on Windows, so
445 # stop will not do anything. Minimally, it should clean up the
443 # stop will not do anything. Minimally, it should clean up the
446 # old .pid files.
444 # old .pid files.
447 self.remove_pid_file()
445 self.remove_pid_file()
448
446
449 def launch_new_instance():
447 def launch_new_instance():
450 """Create and run the IPython cluster."""
448 """Create and run the IPython cluster."""
451 app = IPClusterApp()
449 app = IPClusterApp()
452 app.start()
450 app.start()
453
451
454
452
455 if __name__ == '__main__':
453 if __name__ == '__main__':
456 launch_new_instance()
454 launch_new_instance()
457
455
@@ -1,91 +1,93 b''
1 # Makefile for Sphinx documentation
1 # Makefile for Sphinx documentation
2 #
2 #
3
3
4 # You can set these variables from the command line.
4 # You can set these variables from the command line.
5 SPHINXOPTS =
5 SPHINXOPTS =
6 SPHINXBUILD = sphinx-build
6 SPHINXBUILD = sphinx-build
7 PAPER =
7 PAPER =
8 SRCDIR = source
8 SRCDIR = source
9
9
10 # Internal variables.
10 # Internal variables.
11 PAPEROPT_a4 = -D latex_paper_size=a4
11 PAPEROPT_a4 = -D latex_paper_size=a4
12 PAPEROPT_letter = -D latex_paper_size=letter
12 PAPEROPT_letter = -D latex_paper_size=letter
13 ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR)
13 ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR)
14
14
15 .PHONY: help clean html web pickle htmlhelp latex changes linkcheck api
15 .PHONY: help clean html web pickle htmlhelp latex changes linkcheck api
16
16
17 default: html
18
17 help:
19 help:
18 @echo "Please use \`make <target>' where <target> is one of"
20 @echo "Please use \`make <target>' where <target> is one of"
19 @echo " html to make standalone HTML files"
21 @echo " html to make standalone HTML files"
20 @echo " pickle to make pickle files (usable by e.g. sphinx-web)"
22 @echo " pickle to make pickle files (usable by e.g. sphinx-web)"
21 @echo " htmlhelp to make HTML files and a HTML help project"
23 @echo " htmlhelp to make HTML files and a HTML help project"
22 @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
24 @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
23 @echo " changes to make an overview over all changed/added/deprecated items"
25 @echo " changes to make an overview over all changed/added/deprecated items"
24 @echo " linkcheck to check all external links for integrity"
26 @echo " linkcheck to check all external links for integrity"
25 @echo
27 @echo
26 @echo "Compound utility targets:"
28 @echo "Compound utility targets:"
27 @echo "pdf latex and then runs the PDF generation"
29 @echo "pdf latex and then runs the PDF generation"
28 @echo "all html and pdf"
30 @echo "all html and pdf"
29 @echo "dist all, and then puts the results in dist/"
31 @echo "dist all, and then puts the results in dist/"
30
32
31 clean:
33 clean:
32 -rm -rf build/* dist/* $(SRCDIR)/api/generated
34 -rm -rf build/* dist/* $(SRCDIR)/api/generated
33
35
34 pdf: latex
36 pdf: latex
35 cd build/latex && make all-pdf
37 cd build/latex && make all-pdf
36
38
37 all: html pdf
39 all: html pdf
38
40
39 dist: clean all
41 dist: clean all
40 mkdir -p dist
42 mkdir -p dist
41 ln build/latex/ipython.pdf dist/
43 ln build/latex/ipython.pdf dist/
42 cp -al build/html dist/
44 cp -al build/html dist/
43 @echo "Build finished. Final docs are in dist/"
45 @echo "Build finished. Final docs are in dist/"
44
46
45 html: api
47 html: api
46 mkdir -p build/html build/doctrees
48 mkdir -p build/html build/doctrees
47 $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
49 $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
48 @echo
50 @echo
49 @echo "Build finished. The HTML pages are in build/html."
51 @echo "Build finished. The HTML pages are in build/html."
50
52
51 api:
53 api:
52 python autogen_api.py
54 python autogen_api.py
53 @echo "Build API docs finished."
55 @echo "Build API docs finished."
54
56
55 pickle:
57 pickle:
56 mkdir -p build/pickle build/doctrees
58 mkdir -p build/pickle build/doctrees
57 $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
59 $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
58 @echo
60 @echo
59 @echo "Build finished; now you can process the pickle files or run"
61 @echo "Build finished; now you can process the pickle files or run"
60 @echo " sphinx-web build/pickle"
62 @echo " sphinx-web build/pickle"
61 @echo "to start the sphinx-web server."
63 @echo "to start the sphinx-web server."
62
64
63 web: pickle
65 web: pickle
64
66
65 htmlhelp:
67 htmlhelp:
66 mkdir -p build/htmlhelp build/doctrees
68 mkdir -p build/htmlhelp build/doctrees
67 $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
69 $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
68 @echo
70 @echo
69 @echo "Build finished; now you can run HTML Help Workshop with the" \
71 @echo "Build finished; now you can run HTML Help Workshop with the" \
70 ".hhp project file in build/htmlhelp."
72 ".hhp project file in build/htmlhelp."
71
73
72 latex:
74 latex:
73 mkdir -p build/latex build/doctrees
75 mkdir -p build/latex build/doctrees
74 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
76 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
75 @echo
77 @echo
76 @echo "Build finished; the LaTeX files are in build/latex."
78 @echo "Build finished; the LaTeX files are in build/latex."
77 @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
79 @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
78 "run these through (pdf)latex."
80 "run these through (pdf)latex."
79
81
80 changes:
82 changes:
81 mkdir -p build/changes build/doctrees
83 mkdir -p build/changes build/doctrees
82 $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
84 $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
83 @echo
85 @echo
84 @echo "The overview file is in build/changes."
86 @echo "The overview file is in build/changes."
85
87
86 linkcheck:
88 linkcheck:
87 mkdir -p build/linkcheck build/doctrees
89 mkdir -p build/linkcheck build/doctrees
88 $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
90 $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
89 @echo
91 @echo
90 @echo "Link check complete; look for any errors in the above output " \
92 @echo "Link check complete; look for any errors in the above output " \
91 "or in build/linkcheck/output.txt."
93 "or in build/linkcheck/output.txt."
@@ -1,42 +1,43 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Script to auto-generate our API docs.
2 """Script to auto-generate our API docs.
3 """
3 """
4 # stdlib imports
4 # stdlib imports
5 import os
5 import os
6 import sys
6 import sys
7
7
8 # local imports
8 # local imports
9 sys.path.append(os.path.abspath('sphinxext'))
9 sys.path.append(os.path.abspath('sphinxext'))
10 from apigen import ApiDocWriter
10 from apigen import ApiDocWriter
11
11
12 #*****************************************************************************
12 #*****************************************************************************
13 if __name__ == '__main__':
13 if __name__ == '__main__':
14 pjoin = os.path.join
14 pjoin = os.path.join
15 package = 'IPython'
15 package = 'IPython'
16 outdir = pjoin('source','api','generated')
16 outdir = pjoin('source','api','generated')
17 docwriter = ApiDocWriter(package,rst_extension='.txt')
17 docwriter = ApiDocWriter(package,rst_extension='.txt')
18 # You have to escape the . here because . is a special char for regexps.
18 # You have to escape the . here because . is a special char for regexps.
19 # You must do make clean if you change this!
19 # You must do make clean if you change this!
20 docwriter.package_skip_patterns += [r'\.fixes$',
20 docwriter.package_skip_patterns += [r'\.fixes$',
21 r'\.external$',
21 r'\.external$',
22 r'\.extensions',
22 r'\.extensions',
23 r'\.kernel\.config',
23 r'\.kernel\.config',
24 r'\.attic',
24 r'\.attic',
25 r'\.quarantine',
25 r'\.quarantine',
26 r'\.deathrow',
26 r'\.deathrow',
27 r'\.config\.default',
27 r'\.config\.default',
28 r'\.config\.profile',
28 r'\.config\.profile',
29 r'\.frontend',
29 r'\.frontend',
30 r'\.gui'
30 r'\.gui'
31 ]
31 ]
32 docwriter.module_skip_patterns += [ r'\.core\.fakemodule',
32 docwriter.module_skip_patterns += [ r'\.core\.fakemodule',
33 r'\.cocoa',
33 r'\.cocoa',
34 r'\.ipdoctest',
34 r'\.ipdoctest',
35 r'\.Gnuplot',
35 r'\.Gnuplot',
36 r'\.frontend\.process\.winprocess',
36 r'\.frontend\.process\.winprocess',
37 r'\.Shell',
37 ]
38 ]
38 docwriter.write_api_docs(outdir)
39 docwriter.write_api_docs(outdir)
39 docwriter.write_index(outdir, 'gen',
40 docwriter.write_index(outdir, 'gen',
40 relative_to = pjoin('source','api')
41 relative_to = pjoin('source','api')
41 )
42 )
42 print '%d files written' % len(docwriter.written_modules)
43 print '%d files written' % len(docwriter.written_modules)
@@ -1,192 +1,192 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 #
2 #
3 # IPython documentation build configuration file.
3 # IPython documentation build configuration file.
4
4
5 # NOTE: This file has been edited manually from the auto-generated one from
5 # NOTE: This file has been edited manually from the auto-generated one from
6 # sphinx. Do NOT delete and re-generate. If any changes from sphinx are
6 # sphinx. Do NOT delete and re-generate. If any changes from sphinx are
7 # needed, generate a scratch one and merge by hand any new fields needed.
7 # needed, generate a scratch one and merge by hand any new fields needed.
8
8
9 #
9 #
10 # This file is execfile()d with the current directory set to its containing dir.
10 # This file is execfile()d with the current directory set to its containing dir.
11 #
11 #
12 # The contents of this file are pickled, so don't put values in the namespace
12 # The contents of this file are pickled, so don't put values in the namespace
13 # that aren't pickleable (module imports are okay, they're removed automatically).
13 # that aren't pickleable (module imports are okay, they're removed automatically).
14 #
14 #
15 # All configuration values have a default value; values that are commented out
15 # All configuration values have a default value; values that are commented out
16 # serve to show the default value.
16 # serve to show the default value.
17
17
18 import sys, os
18 import sys, os
19
19
20 # If your extensions are in another directory, add it here. If the directory
20 # If your extensions are in another directory, add it here. If the directory
21 # is relative to the documentation root, use os.path.abspath to make it
21 # is relative to the documentation root, use os.path.abspath to make it
22 # absolute, like shown here.
22 # absolute, like shown here.
23 sys.path.append(os.path.abspath('../sphinxext'))
23 sys.path.append(os.path.abspath('../sphinxext'))
24
24
25 # Import support for ipython console session syntax highlighting (lives
25 # Import support for ipython console session syntax highlighting (lives
26 # in the sphinxext directory defined above)
26 # in the sphinxext directory defined above)
27 import ipython_console_highlighting
27 import ipython_console_highlighting
28
28
29 # We load the ipython release info into a dict by explicit execution
29 # We load the ipython release info into a dict by explicit execution
30 iprelease = {}
30 iprelease = {}
31 execfile('../../IPython/core/release.py',iprelease)
31 execfile('../../IPython/core/release.py',iprelease)
32
32
33 # General configuration
33 # General configuration
34 # ---------------------
34 # ---------------------
35
35
36 # Add any Sphinx extension module names here, as strings. They can be extensions
36 # Add any Sphinx extension module names here, as strings. They can be extensions
37 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
37 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
38 extensions = [
38 extensions = [
39 # 'matplotlib.sphinxext.mathmpl',
39 # 'matplotlib.sphinxext.mathmpl',
40 'matplotlib.sphinxext.only_directives',
40 'matplotlib.sphinxext.only_directives',
41 # 'matplotlib.sphinxext.plot_directive',
41 # 'matplotlib.sphinxext.plot_directive',
42 'sphinx.ext.autodoc',
42 'sphinx.ext.autodoc',
43 'sphinx.ext.doctest',
43 'sphinx.ext.doctest',
44 'inheritance_diagram',
44 'inheritance_diagram',
45 'ipython_console_highlighting',
45 'ipython_console_highlighting',
46 'numpydoc', # to preprocess docstrings
46 'numpydoc', # to preprocess docstrings
47 ]
47 ]
48
48
49 # Add any paths that contain templates here, relative to this directory.
49 # Add any paths that contain templates here, relative to this directory.
50 templates_path = ['_templates']
50 templates_path = ['_templates']
51
51
52 # The suffix of source filenames.
52 # The suffix of source filenames.
53 source_suffix = '.txt'
53 source_suffix = '.txt'
54
54
55 # The master toctree document.
55 # The master toctree document.
56 master_doc = 'index'
56 master_doc = 'index'
57
57
58 # General substitutions.
58 # General substitutions.
59 project = 'IPython'
59 project = 'IPython'
60 copyright = '2008, The IPython Development Team'
60 copyright = '2008, The IPython Development Team'
61
61
62 # The default replacements for |version| and |release|, also used in various
62 # The default replacements for |version| and |release|, also used in various
63 # other places throughout the built documents.
63 # other places throughout the built documents.
64 #
64 #
65 # The full version, including alpha/beta/rc tags.
65 # The full version, including alpha/beta/rc tags.
66 release = iprelease['version']
66 release = iprelease['version']
67 # The short X.Y version.
67 # The short X.Y version.
68 version = '.'.join(release.split('.',2)[:2])
68 version = '.'.join(release.split('.',2)[:2])
69
69
70
70
71 # There are two options for replacing |today|: either, you set today to some
71 # There are two options for replacing |today|: either, you set today to some
72 # non-false value, then it is used:
72 # non-false value, then it is used:
73 #today = ''
73 #today = ''
74 # Else, today_fmt is used as the format for a strftime call.
74 # Else, today_fmt is used as the format for a strftime call.
75 today_fmt = '%B %d, %Y'
75 today_fmt = '%B %d, %Y'
76
76
77 # List of documents that shouldn't be included in the build.
77 # List of documents that shouldn't be included in the build.
78 #unused_docs = []
78 #unused_docs = []
79
79
80 # List of directories, relative to source directories, that shouldn't be searched
80 # List of directories, relative to source directories, that shouldn't be searched
81 # for source files.
81 # for source files.
82 exclude_dirs = ['attic']
82 exclude_dirs = ['attic']
83
83
84 # If true, '()' will be appended to :func: etc. cross-reference text.
84 # If true, '()' will be appended to :func: etc. cross-reference text.
85 #add_function_parentheses = True
85 #add_function_parentheses = True
86
86
87 # If true, the current module name will be prepended to all description
87 # If true, the current module name will be prepended to all description
88 # unit titles (such as .. function::).
88 # unit titles (such as .. function::).
89 #add_module_names = True
89 #add_module_names = True
90
90
91 # If true, sectionauthor and moduleauthor directives will be shown in the
91 # If true, sectionauthor and moduleauthor directives will be shown in the
92 # output. They are ignored by default.
92 # output. They are ignored by default.
93 #show_authors = False
93 #show_authors = False
94
94
95 # The name of the Pygments (syntax highlighting) style to use.
95 # The name of the Pygments (syntax highlighting) style to use.
96 pygments_style = 'sphinx'
96 pygments_style = 'sphinx'
97
97
98
98
99 # Options for HTML output
99 # Options for HTML output
100 # -----------------------
100 # -----------------------
101
101
102 # The style sheet to use for HTML and HTML Help pages. A file of that name
102 # The style sheet to use for HTML and HTML Help pages. A file of that name
103 # must exist either in Sphinx' static/ path, or in one of the custom paths
103 # must exist either in Sphinx' static/ path, or in one of the custom paths
104 # given in html_static_path.
104 # given in html_static_path.
105 html_style = 'default.css'
105 html_style = 'default.css'
106
106
107 # The name for this set of Sphinx documents. If None, it defaults to
107 # The name for this set of Sphinx documents. If None, it defaults to
108 # "<project> v<release> documentation".
108 # "<project> v<release> documentation".
109 #html_title = None
109 #html_title = None
110
110
111 # The name of an image file (within the static path) to place at the top of
111 # The name of an image file (within the static path) to place at the top of
112 # the sidebar.
112 # the sidebar.
113 #html_logo = None
113 #html_logo = None
114
114
115 # Add any paths that contain custom static files (such as style sheets) here,
115 # Add any paths that contain custom static files (such as style sheets) here,
116 # relative to this directory. They are copied after the builtin static files,
116 # relative to this directory. They are copied after the builtin static files,
117 # so a file named "default.css" will overwrite the builtin "default.css".
117 # so a file named "default.css" will overwrite the builtin "default.css".
118 html_static_path = ['_static']
118 html_static_path = ['_static']
119
119
120 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
120 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
121 # using the given strftime format.
121 # using the given strftime format.
122 html_last_updated_fmt = '%b %d, %Y'
122 html_last_updated_fmt = '%b %d, %Y'
123
123
124 # If true, SmartyPants will be used to convert quotes and dashes to
124 # If true, SmartyPants will be used to convert quotes and dashes to
125 # typographically correct entities.
125 # typographically correct entities.
126 #html_use_smartypants = True
126 #html_use_smartypants = True
127
127
128 # Custom sidebar templates, maps document names to template names.
128 # Custom sidebar templates, maps document names to template names.
129 #html_sidebars = {}
129 #html_sidebars = {}
130
130
131 # Additional templates that should be rendered to pages, maps page names to
131 # Additional templates that should be rendered to pages, maps page names to
132 # template names.
132 # template names.
133 #html_additional_pages = {}
133 #html_additional_pages = {}
134
134
135 # If false, no module index is generated.
135 # If false, no module index is generated.
136 #html_use_modindex = True
136 #html_use_modindex = True
137
137
138 # If true, the reST sources are included in the HTML build as _sources/<name>.
138 # If true, the reST sources are included in the HTML build as _sources/<name>.
139 #html_copy_source = True
139 #html_copy_source = True
140
140
141 # If true, an OpenSearch description file will be output, and all pages will
141 # If true, an OpenSearch description file will be output, and all pages will
142 # contain a <link> tag referring to it. The value of this option must be the
142 # contain a <link> tag referring to it. The value of this option must be the
143 # base URL from which the finished HTML is served.
143 # base URL from which the finished HTML is served.
144 #html_use_opensearch = ''
144 #html_use_opensearch = ''
145
145
146 # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
146 # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
147 #html_file_suffix = ''
147 #html_file_suffix = ''
148
148
149 # Output file base name for HTML help builder.
149 # Output file base name for HTML help builder.
150 htmlhelp_basename = 'ipythondoc'
150 htmlhelp_basename = 'ipythondoc'
151
151
152
152
153 # Options for LaTeX output
153 # Options for LaTeX output
154 # ------------------------
154 # ------------------------
155
155
156 # The paper size ('letter' or 'a4').
156 # The paper size ('letter' or 'a4').
157 latex_paper_size = 'letter'
157 latex_paper_size = 'letter'
158
158
159 # The font size ('10pt', '11pt' or '12pt').
159 # The font size ('10pt', '11pt' or '12pt').
160 latex_font_size = '11pt'
160 latex_font_size = '11pt'
161
161
162 # Grouping the document tree into LaTeX files. List of tuples
162 # Grouping the document tree into LaTeX files. List of tuples
163 # (source start file, target name, title, author, document class [howto/manual]).
163 # (source start file, target name, title, author, document class [howto/manual]).
164
164
165 latex_documents = [ ('index', 'ipython.tex', 'IPython Documentation',
165 latex_documents = [ ('index', 'ipython.tex', 'IPython Documentation',
166 ur"""The IPython Development Team""",
166 ur"""The IPython Development Team""",
167 'manual', True),
167 'manual', True),
168 ]
168 ]
169
169
170 # The name of an image file (relative to this directory) to place at the top of
170 # The name of an image file (relative to this directory) to place at the top of
171 # the title page.
171 # the title page.
172 #latex_logo = None
172 #latex_logo = None
173
173
174 # For "manual" documents, if this is true, then toplevel headings are parts,
174 # For "manual" documents, if this is true, then toplevel headings are parts,
175 # not chapters.
175 # not chapters.
176 #latex_use_parts = False
176 #latex_use_parts = False
177
177
178 # Additional stuff for the LaTeX preamble.
178 # Additional stuff for the LaTeX preamble.
179 #latex_preamble = ''
179 #latex_preamble = ''
180
180
181 # Documents to append as an appendix to all manuals.
181 # Documents to append as an appendix to all manuals.
182 #latex_appendices = []
182 #latex_appendices = []
183
183
184 # If false, no module index is generated.
184 # If false, no module index is generated.
185 #latex_use_modindex = True
185 latex_use_modindex = True
186
186
187
187
188 # Cleanup
188 # Cleanup
189 # -------
189 # -------
190 # delete release info to avoid pickling errors from sphinx
190 # delete release info to avoid pickling errors from sphinx
191
191
192 del iprelease
192 del iprelease
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (811 lines changed) Show them Hide them
General Comments 0
You need to be logged in to leave comments. Login now