##// END OF EJS Templates
main branch resync
laurent.dufrechou@gmail.com -
r1824:34b4cf01 merge
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

This diff has been collapsed as it changes many lines, (1867 lines changed) Show them Hide them
@@ -0,0 +1,1867 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright � 2006 Steven J. Bethard <steven.bethard@gmail.com>.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted under the terms of the 3-clause BSD
7 # license. No warranty expressed or implied.
8 # For details, see the accompanying file LICENSE.txt.
9
10 """Command-line parsing library
11
12 This module is an optparse-inspired command-line parsing library that:
13
14 * handles both optional and positional arguments
15 * produces highly informative usage messages
16 * supports parsers that dispatch to sub-parsers
17
18 The following is a simple usage example that sums integers from the
19 command-line and writes the result to a file:
20
21 parser = argparse.ArgumentParser(
22 description='sum the integers at the command line')
23 parser.add_argument(
24 'integers', metavar='int', nargs='+', type=int,
25 help='an integer to be summed')
26 parser.add_argument(
27 '--log', default=sys.stdout, type=argparse.FileType('w'),
28 help='the file where the sum should be written')
29 args = parser.parse_args()
30 args.log.write('%s' % sum(args.integers))
31 args.log.close()
32
33 The module contains the following public classes:
34
35 ArgumentParser -- The main entry point for command-line parsing. As the
36 example above shows, the add_argument() method is used to populate
37 the parser with actions for optional and positional arguments. Then
38 the parse_args() method is invoked to convert the args at the
39 command-line into an object with attributes.
40
41 ArgumentError -- The exception raised by ArgumentParser objects when
42 there are errors with the parser's actions. Errors raised while
43 parsing the command-line are caught by ArgumentParser and emitted
44 as command-line messages.
45
46 FileType -- A factory for defining types of files to be created. As the
47 example above shows, instances of FileType are typically passed as
48 the type= argument of add_argument() calls.
49
50 Action -- The base class for parser actions. Typically actions are
51 selected by passing strings like 'store_true' or 'append_const' to
52 the action= argument of add_argument(). However, for greater
53 customization of ArgumentParser actions, subclasses of Action may
54 be defined and passed as the action= argument.
55
56 HelpFormatter, RawDescriptionHelpFormatter -- Formatter classes which
57 may be passed as the formatter_class= argument to the
58 ArgumentParser constructor. HelpFormatter is the default, while
59 RawDescriptionHelpFormatter tells the parser not to perform any
60 line-wrapping on description text.
61
62 All other classes in this module are considered implementation details.
63 (Also note that HelpFormatter and RawDescriptionHelpFormatter are only
64 considered public as object names -- the API of the formatter objects is
65 still considered an implementation detail.)
66 """
67
68 __version__ = '0.8.0'
69
70 import os as _os
71 import re as _re
72 import sys as _sys
73 import textwrap as _textwrap
74
75 from gettext import gettext as _
76
77 SUPPRESS = '==SUPPRESS=='
78
79 OPTIONAL = '?'
80 ZERO_OR_MORE = '*'
81 ONE_OR_MORE = '+'
82 PARSER = '==PARSER=='
83
84 # =============================
85 # Utility functions and classes
86 # =============================
87
88 class _AttributeHolder(object):
89 """Abstract base class that provides __repr__.
90
91 The __repr__ method returns a string in the format:
92 ClassName(attr=name, attr=name, ...)
93 The attributes are determined either by a class-level attribute,
94 '_kwarg_names', or by inspecting the instance __dict__.
95 """
96
97 def __repr__(self):
98 type_name = type(self).__name__
99 arg_strings = []
100 for arg in self._get_args():
101 arg_strings.append(repr(arg))
102 for name, value in self._get_kwargs():
103 arg_strings.append('%s=%r' % (name, value))
104 return '%s(%s)' % (type_name, ', '.join(arg_strings))
105
106 def _get_kwargs(self):
107 return sorted(self.__dict__.items())
108
109 def _get_args(self):
110 return []
111
112 def _ensure_value(namespace, name, value):
113 if getattr(namespace, name, None) is None:
114 setattr(namespace, name, value)
115 return getattr(namespace, name)
116
117
118
119 # ===============
120 # Formatting Help
121 # ===============
122
123 class HelpFormatter(object):
124
125 def __init__(self,
126 prog,
127 indent_increment=2,
128 max_help_position=24,
129 width=None):
130
131 # default setting for width
132 if width is None:
133 try:
134 width = int(_os.environ['COLUMNS'])
135 except (KeyError, ValueError):
136 width = 80
137 width -= 2
138
139 self._prog = prog
140 self._indent_increment = indent_increment
141 self._max_help_position = max_help_position
142 self._width = width
143
144 self._current_indent = 0
145 self._level = 0
146 self._action_max_length = 0
147
148 self._root_section = self._Section(self, None)
149 self._current_section = self._root_section
150
151 self._whitespace_matcher = _re.compile(r'\s+')
152 self._long_break_matcher = _re.compile(r'\n\n\n+')
153
154 # ===============================
155 # Section and indentation methods
156 # ===============================
157
158 def _indent(self):
159 self._current_indent += self._indent_increment
160 self._level += 1
161
162 def _dedent(self):
163 self._current_indent -= self._indent_increment
164 assert self._current_indent >= 0, 'Indent decreased below 0.'
165 self._level -= 1
166
167 class _Section(object):
168 def __init__(self, formatter, parent, heading=None):
169 self.formatter = formatter
170 self.parent = parent
171 self.heading = heading
172 self.items = []
173
174 def format_help(self):
175 # format the indented section
176 if self.parent is not None:
177 self.formatter._indent()
178 join = self.formatter._join_parts
179 for func, args in self.items:
180 func(*args)
181 item_help = join(func(*args) for func, args in self.items)
182 if self.parent is not None:
183 self.formatter._dedent()
184
185 # return nothing if the section was empty
186 if not item_help:
187 return ''
188
189 # add the heading if the section was non-empty
190 if self.heading is not SUPPRESS and self.heading is not None:
191 current_indent = self.formatter._current_indent
192 heading = '%*s%s:\n' % (current_indent, '', self.heading)
193 else:
194 heading = ''
195
196 # join the section-initial newline, the heading and the help
197 return join(['\n', heading, item_help, '\n'])
198
199 def _add_item(self, func, args):
200 self._current_section.items.append((func, args))
201
202 # ========================
203 # Message building methods
204 # ========================
205
206 def start_section(self, heading):
207 self._indent()
208 section = self._Section(self, self._current_section, heading)
209 self._add_item(section.format_help, [])
210 self._current_section = section
211
212 def end_section(self):
213 self._current_section = self._current_section.parent
214 self._dedent()
215
216 def add_text(self, text):
217 if text is not SUPPRESS and text is not None:
218 self._add_item(self._format_text, [text])
219
220 def add_usage(self, usage, optionals, positionals, prefix=None):
221 if usage is not SUPPRESS:
222 args = usage, optionals, positionals, prefix
223 self._add_item(self._format_usage, args)
224
225 def add_argument(self, action):
226 if action.help is not SUPPRESS:
227
228 # find all invocations
229 get_invocation = self._format_action_invocation
230 invocations = [get_invocation(action)]
231 for subaction in self._iter_indented_subactions(action):
232 invocations.append(get_invocation(subaction))
233
234 # update the maximum item length
235 invocation_length = max(len(s) for s in invocations)
236 action_length = invocation_length + self._current_indent
237 self._action_max_length = max(self._action_max_length,
238 action_length)
239
240 # add the item to the list
241 self._add_item(self._format_action, [action])
242
243 def add_arguments(self, actions):
244 for action in actions:
245 self.add_argument(action)
246
247 # =======================
248 # Help-formatting methods
249 # =======================
250
251 def format_help(self):
252 help = self._root_section.format_help() % dict(prog=self._prog)
253 if help:
254 help = self._long_break_matcher.sub('\n\n', help)
255 help = help.strip('\n') + '\n'
256 return help
257
258 def _join_parts(self, part_strings):
259 return ''.join(part
260 for part in part_strings
261 if part and part is not SUPPRESS)
262
263 def _format_usage(self, usage, optionals, positionals, prefix):
264 if prefix is None:
265 prefix = _('usage: ')
266
267 # if no optionals or positionals are available, usage is just prog
268 if usage is None and not optionals and not positionals:
269 usage = '%(prog)s'
270
271 # if optionals and positionals are available, calculate usage
272 elif usage is None:
273 usage = '%(prog)s' % dict(prog=self._prog)
274
275 # determine width of "usage: PROG" and width of text
276 prefix_width = len(prefix) + len(usage) + 1
277 prefix_indent = self._current_indent + prefix_width
278 text_width = self._width - self._current_indent
279
280 # put them on one line if they're short enough
281 format = self._format_actions_usage
282 action_usage = format(optionals + positionals)
283 if prefix_width + len(action_usage) + 1 < text_width:
284 usage = '%s %s' % (usage, action_usage)
285
286 # if they're long, wrap optionals and positionals individually
287 else:
288 optional_usage = format(optionals)
289 positional_usage = format(positionals)
290 indent = ' ' * prefix_indent
291
292 # usage is made of PROG, optionals and positionals
293 parts = [usage, ' ']
294
295 # options always get added right after PROG
296 if optional_usage:
297 parts.append(_textwrap.fill(
298 optional_usage, text_width,
299 initial_indent=indent,
300 subsequent_indent=indent).lstrip())
301
302 # if there were options, put arguments on the next line
303 # otherwise, start them right after PROG
304 if positional_usage:
305 part = _textwrap.fill(
306 positional_usage, text_width,
307 initial_indent=indent,
308 subsequent_indent=indent).lstrip()
309 if optional_usage:
310 part = '\n' + indent + part
311 parts.append(part)
312 usage = ''.join(parts)
313
314 # prefix with 'usage:'
315 return '%s%s\n\n' % (prefix, usage)
316
317 def _format_actions_usage(self, actions):
318 parts = []
319 for action in actions:
320 if action.help is SUPPRESS:
321 continue
322
323 # produce all arg strings
324 if not action.option_strings:
325 parts.append(self._format_args(action, action.dest))
326
327 # produce the first way to invoke the option in brackets
328 else:
329 option_string = action.option_strings[0]
330
331 # if the Optional doesn't take a value, format is:
332 # -s or --long
333 if action.nargs == 0:
334 part = '%s' % option_string
335
336 # if the Optional takes a value, format is:
337 # -s ARGS or --long ARGS
338 else:
339 default = action.dest.upper()
340 args_string = self._format_args(action, default)
341 part = '%s %s' % (option_string, args_string)
342
343 # make it look optional if it's not required
344 if not action.required:
345 part = '[%s]' % part
346 parts.append(part)
347
348 return ' '.join(parts)
349
350 def _format_text(self, text):
351 text_width = self._width - self._current_indent
352 indent = ' ' * self._current_indent
353 return self._fill_text(text, text_width, indent) + '\n\n'
354
355 def _format_action(self, action):
356 # determine the required width and the entry label
357 help_position = min(self._action_max_length + 2,
358 self._max_help_position)
359 help_width = self._width - help_position
360 action_width = help_position - self._current_indent - 2
361 action_header = self._format_action_invocation(action)
362
363 # ho nelp; start on same line and add a final newline
364 if not action.help:
365 tup = self._current_indent, '', action_header
366 action_header = '%*s%s\n' % tup
367
368 # short action name; start on the same line and pad two spaces
369 elif len(action_header) <= action_width:
370 tup = self._current_indent, '', action_width, action_header
371 action_header = '%*s%-*s ' % tup
372 indent_first = 0
373
374 # long action name; start on the next line
375 else:
376 tup = self._current_indent, '', action_header
377 action_header = '%*s%s\n' % tup
378 indent_first = help_position
379
380 # collect the pieces of the action help
381 parts = [action_header]
382
383 # if there was help for the action, add lines of help text
384 if action.help:
385 help_text = self._expand_help(action)
386 help_lines = self._split_lines(help_text, help_width)
387 parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))
388 for line in help_lines[1:]:
389 parts.append('%*s%s\n' % (help_position, '', line))
390
391 # or add a newline if the description doesn't end with one
392 elif not action_header.endswith('\n'):
393 parts.append('\n')
394
395 # if there are any sub-actions, add their help as well
396 for subaction in self._iter_indented_subactions(action):
397 parts.append(self._format_action(subaction))
398
399 # return a single string
400 return self._join_parts(parts)
401
402 def _format_action_invocation(self, action):
403 if not action.option_strings:
404 return self._format_metavar(action, action.dest)
405
406 else:
407 parts = []
408
409 # if the Optional doesn't take a value, format is:
410 # -s, --long
411 if action.nargs == 0:
412 parts.extend(action.option_strings)
413
414 # if the Optional takes a value, format is:
415 # -s ARGS, --long ARGS
416 else:
417 default = action.dest.upper()
418 args_string = self._format_args(action, default)
419 for option_string in action.option_strings:
420 parts.append('%s %s' % (option_string, args_string))
421
422 return ', '.join(parts)
423
424 def _format_metavar(self, action, default_metavar):
425 if action.metavar is not None:
426 name = action.metavar
427 elif action.choices is not None:
428 choice_strs = (str(choice) for choice in action.choices)
429 name = '{%s}' % ','.join(choice_strs)
430 else:
431 name = default_metavar
432 return name
433
434 def _format_args(self, action, default_metavar):
435 name = self._format_metavar(action, default_metavar)
436 if action.nargs is None:
437 result = name
438 elif action.nargs == OPTIONAL:
439 result = '[%s]' % name
440 elif action.nargs == ZERO_OR_MORE:
441 result = '[%s [%s ...]]' % (name, name)
442 elif action.nargs == ONE_OR_MORE:
443 result = '%s [%s ...]' % (name, name)
444 elif action.nargs is PARSER:
445 result = '%s ...' % name
446 else:
447 result = ' '.join([name] * action.nargs)
448 return result
449
450 def _expand_help(self, action):
451 params = dict(vars(action), prog=self._prog)
452 for name, value in params.items():
453 if value is SUPPRESS:
454 del params[name]
455 if params.get('choices') is not None:
456 choices_str = ', '.join(str(c) for c in params['choices'])
457 params['choices'] = choices_str
458 return action.help % params
459
460 def _iter_indented_subactions(self, action):
461 try:
462 get_subactions = action._get_subactions
463 except AttributeError:
464 pass
465 else:
466 self._indent()
467 for subaction in get_subactions():
468 yield subaction
469 self._dedent()
470
471 def _split_lines(self, text, width):
472 text = self._whitespace_matcher.sub(' ', text).strip()
473 return _textwrap.wrap(text, width)
474
475 def _fill_text(self, text, width, indent):
476 text = self._whitespace_matcher.sub(' ', text).strip()
477 return _textwrap.fill(text, width, initial_indent=indent,
478 subsequent_indent=indent)
479
480 class RawDescriptionHelpFormatter(HelpFormatter):
481
482 def _fill_text(self, text, width, indent):
483 return ''.join(indent + line for line in text.splitlines(True))
484
485 class RawTextHelpFormatter(RawDescriptionHelpFormatter):
486
487 def _split_lines(self, text, width):
488 return text.splitlines()
489
490 # =====================
491 # Options and Arguments
492 # =====================
493
494 class ArgumentError(Exception):
495 """ArgumentError(message, argument)
496
497 Raised whenever there was an error creating or using an argument
498 (optional or positional).
499
500 The string value of this exception is the message, augmented with
501 information about the argument that caused it.
502 """
503
504 def __init__(self, argument, message):
505 if argument.option_strings:
506 self.argument_name = '/'.join(argument.option_strings)
507 elif argument.metavar not in (None, SUPPRESS):
508 self.argument_name = argument.metavar
509 elif argument.dest not in (None, SUPPRESS):
510 self.argument_name = argument.dest
511 else:
512 self.argument_name = None
513 self.message = message
514
515 def __str__(self):
516 if self.argument_name is None:
517 format = '%(message)s'
518 else:
519 format = 'argument %(argument_name)s: %(message)s'
520 return format % dict(message=self.message,
521 argument_name=self.argument_name)
522
523 # ==============
524 # Action classes
525 # ==============
526
527 class Action(_AttributeHolder):
528 """Action(*strings, **options)
529
530 Action objects hold the information necessary to convert a
531 set of command-line arguments (possibly including an initial option
532 string) into the desired Python object(s).
533
534 Keyword Arguments:
535
536 option_strings -- A list of command-line option strings which
537 should be associated with this action.
538
539 dest -- The name of the attribute to hold the created object(s)
540
541 nargs -- The number of command-line arguments that should be consumed.
542 By default, one argument will be consumed and a single value will
543 be produced. Other values include:
544 * N (an integer) consumes N arguments (and produces a list)
545 * '?' consumes zero or one arguments
546 * '*' consumes zero or more arguments (and produces a list)
547 * '+' consumes one or more arguments (and produces a list)
548 Note that the difference between the default and nargs=1 is that
549 with the default, a single value will be produced, while with
550 nargs=1, a list containing a single value will be produced.
551
552 const -- The value to be produced if the option is specified and the
553 option uses an action that takes no values.
554
555 default -- The value to be produced if the option is not specified.
556
557 type -- The type which the command-line arguments should be converted
558 to, should be one of 'string', 'int', 'float', 'complex' or a
559 callable object that accepts a single string argument. If None,
560 'string' is assumed.
561
562 choices -- A container of values that should be allowed. If not None,
563 after a command-line argument has been converted to the appropriate
564 type, an exception will be raised if it is not a member of this
565 collection.
566
567 required -- True if the action must always be specified at the command
568 line. This is only meaningful for optional command-line arguments.
569
570 help -- The help string describing the argument.
571
572 metavar -- The name to be used for the option's argument with the help
573 string. If None, the 'dest' value will be used as the name.
574 """
575
576
577 def __init__(self,
578 option_strings,
579 dest,
580 nargs=None,
581 const=None,
582 default=None,
583 type=None,
584 choices=None,
585 required=False,
586 help=None,
587 metavar=None):
588 self.option_strings = option_strings
589 self.dest = dest
590 self.nargs = nargs
591 self.const = const
592 self.default = default
593 self.type = type
594 self.choices = choices
595 self.required = required
596 self.help = help
597 self.metavar = metavar
598
599 def _get_kwargs(self):
600 names = [
601 'option_strings',
602 'dest',
603 'nargs',
604 'const',
605 'default',
606 'type',
607 'choices',
608 'help',
609 'metavar'
610 ]
611 return [(name, getattr(self, name)) for name in names]
612
613 def __call__(self, parser, namespace, values, option_string=None):
614 raise NotImplementedError(_('.__call__() not defined'))
615
616 class _StoreAction(Action):
617 def __init__(self,
618 option_strings,
619 dest,
620 nargs=None,
621 const=None,
622 default=None,
623 type=None,
624 choices=None,
625 required=False,
626 help=None,
627 metavar=None):
628 if nargs == 0:
629 raise ValueError('nargs must be > 0')
630 if const is not None and nargs != OPTIONAL:
631 raise ValueError('nargs must be %r to supply const' % OPTIONAL)
632 super(_StoreAction, self).__init__(
633 option_strings=option_strings,
634 dest=dest,
635 nargs=nargs,
636 const=const,
637 default=default,
638 type=type,
639 choices=choices,
640 required=required,
641 help=help,
642 metavar=metavar)
643
644 def __call__(self, parser, namespace, values, option_string=None):
645 setattr(namespace, self.dest, values)
646
647 class _StoreConstAction(Action):
648 def __init__(self,
649 option_strings,
650 dest,
651 const,
652 default=None,
653 required=False,
654 help=None,
655 metavar=None):
656 super(_StoreConstAction, self).__init__(
657 option_strings=option_strings,
658 dest=dest,
659 nargs=0,
660 const=const,
661 default=default,
662 required=required,
663 help=help)
664
665 def __call__(self, parser, namespace, values, option_string=None):
666 setattr(namespace, self.dest, self.const)
667
668 class _StoreTrueAction(_StoreConstAction):
669 def __init__(self,
670 option_strings,
671 dest,
672 default=False,
673 required=False,
674 help=None):
675 super(_StoreTrueAction, self).__init__(
676 option_strings=option_strings,
677 dest=dest,
678 const=True,
679 default=default,
680 required=required,
681 help=help)
682
683 class _StoreFalseAction(_StoreConstAction):
684 def __init__(self,
685 option_strings,
686 dest,
687 default=True,
688 required=False,
689 help=None):
690 super(_StoreFalseAction, self).__init__(
691 option_strings=option_strings,
692 dest=dest,
693 const=False,
694 default=default,
695 required=required,
696 help=help)
697
698 class _AppendAction(Action):
699 def __init__(self,
700 option_strings,
701 dest,
702 nargs=None,
703 const=None,
704 default=None,
705 type=None,
706 choices=None,
707 required=False,
708 help=None,
709 metavar=None):
710 if nargs == 0:
711 raise ValueError('nargs must be > 0')
712 if const is not None and nargs != OPTIONAL:
713 raise ValueError('nargs must be %r to supply const' % OPTIONAL)
714 super(_AppendAction, self).__init__(
715 option_strings=option_strings,
716 dest=dest,
717 nargs=nargs,
718 const=const,
719 default=default,
720 type=type,
721 choices=choices,
722 required=required,
723 help=help,
724 metavar=metavar)
725
726 def __call__(self, parser, namespace, values, option_string=None):
727 _ensure_value(namespace, self.dest, []).append(values)
728
729 class _AppendConstAction(Action):
730 def __init__(self,
731 option_strings,
732 dest,
733 const,
734 default=None,
735 required=False,
736 help=None,
737 metavar=None):
738 super(_AppendConstAction, self).__init__(
739 option_strings=option_strings,
740 dest=dest,
741 nargs=0,
742 const=const,
743 default=default,
744 required=required,
745 help=help,
746 metavar=metavar)
747
748 def __call__(self, parser, namespace, values, option_string=None):
749 _ensure_value(namespace, self.dest, []).append(self.const)
750
751 class _CountAction(Action):
752 def __init__(self,
753 option_strings,
754 dest,
755 default=None,
756 required=False,
757 help=None):
758 super(_CountAction, self).__init__(
759 option_strings=option_strings,
760 dest=dest,
761 nargs=0,
762 default=default,
763 required=required,
764 help=help)
765
766 def __call__(self, parser, namespace, values, option_string=None):
767 new_count = _ensure_value(namespace, self.dest, 0) + 1
768 setattr(namespace, self.dest, new_count)
769
770 class _HelpAction(Action):
771 def __init__(self,
772 option_strings,
773 dest=SUPPRESS,
774 default=SUPPRESS,
775 help=None):
776 super(_HelpAction, self).__init__(
777 option_strings=option_strings,
778 dest=dest,
779 default=default,
780 nargs=0,
781 help=help)
782
783 def __call__(self, parser, namespace, values, option_string=None):
784 parser.print_help()
785 parser.exit()
786
787 class _VersionAction(Action):
788 def __init__(self,
789 option_strings,
790 dest=SUPPRESS,
791 default=SUPPRESS,
792 help=None):
793 super(_VersionAction, self).__init__(
794 option_strings=option_strings,
795 dest=dest,
796 default=default,
797 nargs=0,
798 help=help)
799
800 def __call__(self, parser, namespace, values, option_string=None):
801 parser.print_version()
802 parser.exit()
803
804 class _SubParsersAction(Action):
805
806 class _ChoicesPseudoAction(Action):
807 def __init__(self, name, help):
808 sup = super(_SubParsersAction._ChoicesPseudoAction, self)
809 sup.__init__(option_strings=[], dest=name, help=help)
810
811
812 def __init__(self,
813 option_strings,
814 prog,
815 parser_class,
816 dest=SUPPRESS,
817 help=None,
818 metavar=None):
819
820 self._prog_prefix = prog
821 self._parser_class = parser_class
822 self._name_parser_map = {}
823 self._choices_actions = []
824
825 super(_SubParsersAction, self).__init__(
826 option_strings=option_strings,
827 dest=dest,
828 nargs=PARSER,
829 choices=self._name_parser_map,
830 help=help,
831 metavar=metavar)
832
833 def add_parser(self, name, **kwargs):
834 # set prog from the existing prefix
835 if kwargs.get('prog') is None:
836 kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
837
838 # create a pseudo-action to hold the choice help
839 if 'help' in kwargs:
840 help = kwargs.pop('help')
841 choice_action = self._ChoicesPseudoAction(name, help)
842 self._choices_actions.append(choice_action)
843
844 # create the parser and add it to the map
845 parser = self._parser_class(**kwargs)
846 self._name_parser_map[name] = parser
847 return parser
848
849 def _get_subactions(self):
850 return self._choices_actions
851
852 def __call__(self, parser, namespace, values, option_string=None):
853 parser_name = values[0]
854 arg_strings = values[1:]
855
856 # set the parser name if requested
857 if self.dest is not SUPPRESS:
858 setattr(namespace, self.dest, parser_name)
859
860 # select the parser
861 try:
862 parser = self._name_parser_map[parser_name]
863 except KeyError:
864 tup = parser_name, ', '.join(self._name_parser_map)
865 msg = _('unknown parser %r (choices: %s)' % tup)
866 raise ArgumentError(self, msg)
867
868 # parse all the remaining options into the namespace
869 parser.parse_args(arg_strings, namespace)
870
871
872 # ==============
873 # Type classes
874 # ==============
875
876 class FileType(object):
877 """Factory for creating file object types
878
879 Instances of FileType are typically passed as type= arguments to the
880 ArgumentParser add_argument() method.
881
882 Keyword Arguments:
883 mode -- A string indicating how the file is to be opened. Accepts the
884 same values as the builtin open() function.
885 bufsize -- The file's desired buffer size. Accepts the same values as
886 the builtin open() function.
887 """
888 def __init__(self, mode='r', bufsize=None):
889 self._mode = mode
890 self._bufsize = bufsize
891
892 def __call__(self, string):
893 # the special argument "-" means sys.std{in,out}
894 if string == '-':
895 if self._mode == 'r':
896 return _sys.stdin
897 elif self._mode == 'w':
898 return _sys.stdout
899 else:
900 msg = _('argument "-" with mode %r' % self._mode)
901 raise ValueError(msg)
902
903 # all other arguments are used as file names
904 if self._bufsize:
905 return open(string, self._mode, self._bufsize)
906 else:
907 return open(string, self._mode)
908
909
910 # ===========================
911 # Optional and Positional Parsing
912 # ===========================
913
914 class Namespace(_AttributeHolder):
915
916 def __init__(self, **kwargs):
917 for name, value in kwargs.iteritems():
918 setattr(self, name, value)
919
920 def __eq__(self, other):
921 return vars(self) == vars(other)
922
923 def __ne__(self, other):
924 return not (self == other)
925
926
927 class _ActionsContainer(object):
928 def __init__(self,
929 description,
930 prefix_chars,
931 argument_default,
932 conflict_handler):
933 super(_ActionsContainer, self).__init__()
934
935 self.description = description
936 self.argument_default = argument_default
937 self.prefix_chars = prefix_chars
938 self.conflict_handler = conflict_handler
939
940 # set up registries
941 self._registries = {}
942
943 # register actions
944 self.register('action', None, _StoreAction)
945 self.register('action', 'store', _StoreAction)
946 self.register('action', 'store_const', _StoreConstAction)
947 self.register('action', 'store_true', _StoreTrueAction)
948 self.register('action', 'store_false', _StoreFalseAction)
949 self.register('action', 'append', _AppendAction)
950 self.register('action', 'append_const', _AppendConstAction)
951 self.register('action', 'count', _CountAction)
952 self.register('action', 'help', _HelpAction)
953 self.register('action', 'version', _VersionAction)
954 self.register('action', 'parsers', _SubParsersAction)
955
956 # raise an exception if the conflict handler is invalid
957 self._get_handler()
958
959 # action storage
960 self._optional_actions_list = []
961 self._positional_actions_list = []
962 self._positional_actions_full_list = []
963 self._option_strings = {}
964
965 # defaults storage
966 self._defaults = {}
967
968 # ====================
969 # Registration methods
970 # ====================
971
972 def register(self, registry_name, value, object):
973 registry = self._registries.setdefault(registry_name, {})
974 registry[value] = object
975
976 def _registry_get(self, registry_name, value, default=None):
977 return self._registries[registry_name].get(value, default)
978
979 # ==================================
980 # Namespace default settings methods
981 # ==================================
982
983 def set_defaults(self, **kwargs):
984 self._defaults.update(kwargs)
985
986 # if these defaults match any existing arguments, replace
987 # the previous default on the object with the new one
988 for action_list in [self._option_strings.values(),
989 self._positional_actions_full_list]:
990 for action in action_list:
991 if action.dest in kwargs:
992 action.default = kwargs[action.dest]
993
994 # =======================
995 # Adding argument actions
996 # =======================
997
998 def add_argument(self, *args, **kwargs):
999 """
1000 add_argument(dest, ..., name=value, ...)
1001 add_argument(option_string, option_string, ..., name=value, ...)
1002 """
1003
1004 # if no positional args are supplied or only one is supplied and
1005 # it doesn't look like an option string, parse a positional
1006 # argument
1007 chars = self.prefix_chars
1008 if not args or len(args) == 1 and args[0][0] not in chars:
1009 kwargs = self._get_positional_kwargs(*args, **kwargs)
1010
1011 # otherwise, we're adding an optional argument
1012 else:
1013 kwargs = self._get_optional_kwargs(*args, **kwargs)
1014
1015 # if no default was supplied, use the parser-level default
1016 if 'default' not in kwargs:
1017 dest = kwargs['dest']
1018 if dest in self._defaults:
1019 kwargs['default'] = self._defaults[dest]
1020 elif self.argument_default is not None:
1021 kwargs['default'] = self.argument_default
1022
1023 # create the action object, and add it to the parser
1024 action_class = self._pop_action_class(kwargs)
1025 action = action_class(**kwargs)
1026 return self._add_action(action)
1027
1028 def _add_action(self, action):
1029 # resolve any conflicts
1030 self._check_conflict(action)
1031
1032 # add to optional or positional list
1033 if action.option_strings:
1034 self._optional_actions_list.append(action)
1035 else:
1036 self._positional_actions_list.append(action)
1037 self._positional_actions_full_list.append(action)
1038 action.container = self
1039
1040 # index the action by any option strings it has
1041 for option_string in action.option_strings:
1042 self._option_strings[option_string] = action
1043
1044 # return the created action
1045 return action
1046
1047 def _add_container_actions(self, container):
1048 for action in container._optional_actions_list:
1049 self._add_action(action)
1050 for action in container._positional_actions_list:
1051 self._add_action(action)
1052
1053 def _get_positional_kwargs(self, dest, **kwargs):
1054 # make sure required is not specified
1055 if 'required' in kwargs:
1056 msg = _("'required' is an invalid argument for positionals")
1057 raise TypeError(msg)
1058
1059 # return the keyword arguments with no option strings
1060 return dict(kwargs, dest=dest, option_strings=[])
1061
1062 def _get_optional_kwargs(self, *args, **kwargs):
1063 # determine short and long option strings
1064 option_strings = []
1065 long_option_strings = []
1066 for option_string in args:
1067 # error on one-or-fewer-character option strings
1068 if len(option_string) < 2:
1069 msg = _('invalid option string %r: '
1070 'must be at least two characters long')
1071 raise ValueError(msg % option_string)
1072
1073 # error on strings that don't start with an appropriate prefix
1074 if not option_string[0] in self.prefix_chars:
1075 msg = _('invalid option string %r: '
1076 'must start with a character %r')
1077 tup = option_string, self.prefix_chars
1078 raise ValueError(msg % tup)
1079
1080 # error on strings that are all prefix characters
1081 if not (set(option_string) - set(self.prefix_chars)):
1082 msg = _('invalid option string %r: '
1083 'must contain characters other than %r')
1084 tup = option_string, self.prefix_chars
1085 raise ValueError(msg % tup)
1086
1087 # strings starting with two prefix characters are long options
1088 option_strings.append(option_string)
1089 if option_string[0] in self.prefix_chars:
1090 if option_string[1] in self.prefix_chars:
1091 long_option_strings.append(option_string)
1092
1093 # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
1094 dest = kwargs.pop('dest', None)
1095 if dest is None:
1096 if long_option_strings:
1097 dest_option_string = long_option_strings[0]
1098 else:
1099 dest_option_string = option_strings[0]
1100 dest = dest_option_string.lstrip(self.prefix_chars)
1101 dest = dest.replace('-', '_')
1102
1103 # return the updated keyword arguments
1104 return dict(kwargs, dest=dest, option_strings=option_strings)
1105
1106 def _pop_action_class(self, kwargs, default=None):
1107 action = kwargs.pop('action', default)
1108 return self._registry_get('action', action, action)
1109
1110 def _get_handler(self):
1111 # determine function from conflict handler string
1112 handler_func_name = '_handle_conflict_%s' % self.conflict_handler
1113 try:
1114 return getattr(self, handler_func_name)
1115 except AttributeError:
1116 msg = _('invalid conflict_resolution value: %r')
1117 raise ValueError(msg % self.conflict_handler)
1118
1119 def _check_conflict(self, action):
1120
1121 # find all options that conflict with this option
1122 confl_optionals = []
1123 for option_string in action.option_strings:
1124 if option_string in self._option_strings:
1125 confl_optional = self._option_strings[option_string]
1126 confl_optionals.append((option_string, confl_optional))
1127
1128 # resolve any conflicts
1129 if confl_optionals:
1130 conflict_handler = self._get_handler()
1131 conflict_handler(action, confl_optionals)
1132
1133 def _handle_conflict_error(self, action, conflicting_actions):
1134 message = _('conflicting option string(s): %s')
1135 conflict_string = ', '.join(option_string
1136 for option_string, action
1137 in conflicting_actions)
1138 raise ArgumentError(action, message % conflict_string)
1139
1140 def _handle_conflict_resolve(self, action, conflicting_actions):
1141
1142 # remove all conflicting options
1143 for option_string, action in conflicting_actions:
1144
1145 # remove the conflicting option
1146 action.option_strings.remove(option_string)
1147 self._option_strings.pop(option_string, None)
1148
1149 # if the option now has no option string, remove it from the
1150 # container holding it
1151 if not action.option_strings:
1152 action.container._optional_actions_list.remove(action)
1153
1154
1155 class _ArgumentGroup(_ActionsContainer):
1156
1157 def __init__(self, container, title=None, description=None, **kwargs):
1158 # add any missing keyword arguments by checking the container
1159 update = kwargs.setdefault
1160 update('conflict_handler', container.conflict_handler)
1161 update('prefix_chars', container.prefix_chars)
1162 update('argument_default', container.argument_default)
1163 super_init = super(_ArgumentGroup, self).__init__
1164 super_init(description=description, **kwargs)
1165
1166 self.title = title
1167 self._registries = container._registries
1168 self._positional_actions_full_list = container._positional_actions_full_list
1169 self._option_strings = container._option_strings
1170 self._defaults = container._defaults
1171
1172
1173 class ArgumentParser(_AttributeHolder, _ActionsContainer):
1174
1175 def __init__(self,
1176 prog=None,
1177 usage=None,
1178 description=None,
1179 epilog=None,
1180 version=None,
1181 parents=[],
1182 formatter_class=HelpFormatter,
1183 prefix_chars='-',
1184 argument_default=None,
1185 conflict_handler='error',
1186 add_help=True):
1187
1188 superinit = super(ArgumentParser, self).__init__
1189 superinit(description=description,
1190 prefix_chars=prefix_chars,
1191 argument_default=argument_default,
1192 conflict_handler=conflict_handler)
1193
1194 # default setting for prog
1195 if prog is None:
1196 prog = _os.path.basename(_sys.argv[0])
1197
1198 self.prog = prog
1199 self.usage = usage
1200 self.epilog = epilog
1201 self.version = version
1202 self.formatter_class = formatter_class
1203 self.add_help = add_help
1204
1205 self._argument_group_class = _ArgumentGroup
1206 self._has_subparsers = False
1207 self._argument_groups = []
1208
1209 # register types
1210 def identity(string):
1211 return string
1212 self.register('type', None, identity)
1213
1214 # add help and version arguments if necessary
1215 # (using explicit default to override global argument_default)
1216 if self.add_help:
1217 self.add_argument(
1218 '-h', '--help', action='help', default=SUPPRESS,
1219 help=_('show this help message and exit'))
1220 if self.version:
1221 self.add_argument(
1222 '-v', '--version', action='version', default=SUPPRESS,
1223 help=_("show program's version number and exit"))
1224
1225 # add parent arguments and defaults
1226 for parent in parents:
1227 self._add_container_actions(parent)
1228 try:
1229 defaults = parent._defaults
1230 except AttributeError:
1231 pass
1232 else:
1233 self._defaults.update(defaults)
1234
1235 # determines whether an "option" looks like a negative number
1236 self._negative_number_matcher = _re.compile(r'^-\d+|-\d*.\d+$')
1237
1238
1239 # =======================
1240 # Pretty __repr__ methods
1241 # =======================
1242
1243 def _get_kwargs(self):
1244 names = [
1245 'prog',
1246 'usage',
1247 'description',
1248 'version',
1249 'formatter_class',
1250 'conflict_handler',
1251 'add_help',
1252 ]
1253 return [(name, getattr(self, name)) for name in names]
1254
1255 # ==================================
1256 # Optional/Positional adding methods
1257 # ==================================
1258
1259 def add_argument_group(self, *args, **kwargs):
1260 group = self._argument_group_class(self, *args, **kwargs)
1261 self._argument_groups.append(group)
1262 return group
1263
1264 def add_subparsers(self, **kwargs):
1265 if self._has_subparsers:
1266 self.error(_('cannot have multiple subparser arguments'))
1267
1268 # add the parser class to the arguments if it's not present
1269 kwargs.setdefault('parser_class', type(self))
1270
1271 # prog defaults to the usage message of this parser, skipping
1272 # optional arguments and with no "usage:" prefix
1273 if kwargs.get('prog') is None:
1274 formatter = self._get_formatter()
1275 formatter.add_usage(self.usage, [],
1276 self._get_positional_actions(), '')
1277 kwargs['prog'] = formatter.format_help().strip()
1278
1279 # create the parsers action and add it to the positionals list
1280 parsers_class = self._pop_action_class(kwargs, 'parsers')
1281 action = parsers_class(option_strings=[], **kwargs)
1282 self._positional_actions_list.append(action)
1283 self._positional_actions_full_list.append(action)
1284 self._has_subparsers = True
1285
1286 # return the created parsers action
1287 return action
1288
1289 def _add_container_actions(self, container):
1290 super(ArgumentParser, self)._add_container_actions(container)
1291 try:
1292 groups = container._argument_groups
1293 except AttributeError:
1294 pass
1295 else:
1296 for group in groups:
1297 new_group = self.add_argument_group(
1298 title=group.title,
1299 description=group.description,
1300 conflict_handler=group.conflict_handler)
1301 new_group._add_container_actions(group)
1302
1303 def _get_optional_actions(self):
1304 actions = []
1305 actions.extend(self._optional_actions_list)
1306 for argument_group in self._argument_groups:
1307 actions.extend(argument_group._optional_actions_list)
1308 return actions
1309
1310 def _get_positional_actions(self):
1311 return list(self._positional_actions_full_list)
1312
1313
1314 # =====================================
1315 # Command line argument parsing methods
1316 # =====================================
1317
1318 def parse_args(self, args=None, namespace=None):
1319 # args default to the system args
1320 if args is None:
1321 args = _sys.argv[1:]
1322
1323 # default Namespace built from parser defaults
1324 if namespace is None:
1325 namespace = Namespace()
1326
1327 # add any action defaults that aren't present
1328 optional_actions = self._get_optional_actions()
1329 positional_actions = self._get_positional_actions()
1330 for action in optional_actions + positional_actions:
1331 if action.dest is not SUPPRESS:
1332 if not hasattr(namespace, action.dest):
1333 if action.default is not SUPPRESS:
1334 default = action.default
1335 if isinstance(action.default, basestring):
1336 default = self._get_value(action, default)
1337 setattr(namespace, action.dest, default)
1338
1339 # add any parser defaults that aren't present
1340 for dest, value in self._defaults.iteritems():
1341 if not hasattr(namespace, dest):
1342 setattr(namespace, dest, value)
1343
1344 # parse the arguments and exit if there are any errors
1345 try:
1346 result = self._parse_args(args, namespace)
1347 except ArgumentError, err:
1348 self.error(str(err))
1349
1350 # make sure all required optionals are present
1351 for action in self._get_optional_actions():
1352 if action.required:
1353 if getattr(result, action.dest, None) is None:
1354 opt_strs = '/'.join(action.option_strings)
1355 msg = _('option %s is required' % opt_strs)
1356 self.error(msg)
1357
1358 # return the parsed arguments
1359 return result
1360
1361 def _parse_args(self, arg_strings, namespace):
1362
1363 # find all option indices, and determine the arg_string_pattern
1364 # which has an 'O' if there is an option at an index,
1365 # an 'A' if there is an argument, or a '-' if there is a '--'
1366 option_string_indices = {}
1367 arg_string_pattern_parts = []
1368 arg_strings_iter = iter(arg_strings)
1369 for i, arg_string in enumerate(arg_strings_iter):
1370
1371 # all args after -- are non-options
1372 if arg_string == '--':
1373 arg_string_pattern_parts.append('-')
1374 for arg_string in arg_strings_iter:
1375 arg_string_pattern_parts.append('A')
1376
1377 # otherwise, add the arg to the arg strings
1378 # and note the index if it was an option
1379 else:
1380 option_tuple = self._parse_optional(arg_string)
1381 if option_tuple is None:
1382 pattern = 'A'
1383 else:
1384 option_string_indices[i] = option_tuple
1385 pattern = 'O'
1386 arg_string_pattern_parts.append(pattern)
1387
1388 # join the pieces together to form the pattern
1389 arg_strings_pattern = ''.join(arg_string_pattern_parts)
1390
1391 # converts arg strings to the appropriate and then takes the action
1392 def take_action(action, argument_strings, option_string=None):
1393 argument_values = self._get_values(action, argument_strings)
1394 # take the action if we didn't receive a SUPPRESS value
1395 # (e.g. from a default)
1396 if argument_values is not SUPPRESS:
1397 action(self, namespace, argument_values, option_string)
1398
1399 # function to convert arg_strings into an optional action
1400 def consume_optional(start_index):
1401
1402 # determine the optional action and parse any explicit
1403 # argument out of the option string
1404 option_tuple = option_string_indices[start_index]
1405 action, option_string, explicit_arg = option_tuple
1406
1407 # loop because single-dash options can be chained
1408 # (e.g. -xyz is the same as -x -y -z if no args are required)
1409 match_argument = self._match_argument
1410 action_tuples = []
1411 while True:
1412
1413 # if we found no optional action, raise an error
1414 if action is None:
1415 self.error(_('no such option: %s') % option_string)
1416
1417 # if there is an explicit argument, try to match the
1418 # optional's string arguments to only this
1419 if explicit_arg is not None:
1420 arg_count = match_argument(action, 'A')
1421
1422 # if the action is a single-dash option and takes no
1423 # arguments, try to parse more single-dash options out
1424 # of the tail of the option string
1425 chars = self.prefix_chars
1426 if arg_count == 0 and option_string[1] not in chars:
1427 action_tuples.append((action, [], option_string))
1428 parse_optional = self._parse_optional
1429 for char in self.prefix_chars:
1430 option_string = char + explicit_arg
1431 option_tuple = parse_optional(option_string)
1432 if option_tuple[0] is not None:
1433 break
1434 else:
1435 msg = _('ignored explicit argument %r')
1436 raise ArgumentError(action, msg % explicit_arg)
1437
1438 # set the action, etc. for the next loop iteration
1439 action, option_string, explicit_arg = option_tuple
1440
1441 # if the action expect exactly one argument, we've
1442 # successfully matched the option; exit the loop
1443 elif arg_count == 1:
1444 stop = start_index + 1
1445 args = [explicit_arg]
1446 action_tuples.append((action, args, option_string))
1447 break
1448
1449 # error if a double-dash option did not use the
1450 # explicit argument
1451 else:
1452 msg = _('ignored explicit argument %r')
1453 raise ArgumentError(action, msg % explicit_arg)
1454
1455 # if there is no explicit argument, try to match the
1456 # optional's string arguments with the following strings
1457 # if successful, exit the loop
1458 else:
1459 start = start_index + 1
1460 selected_patterns = arg_strings_pattern[start:]
1461 arg_count = match_argument(action, selected_patterns)
1462 stop = start + arg_count
1463 args = arg_strings[start:stop]
1464 action_tuples.append((action, args, option_string))
1465 break
1466
1467 # add the Optional to the list and return the index at which
1468 # the Optional's string args stopped
1469 assert action_tuples
1470 for action, args, option_string in action_tuples:
1471 take_action(action, args, option_string)
1472 return stop
1473
1474 # the list of Positionals left to be parsed; this is modified
1475 # by consume_positionals()
1476 positionals = self._get_positional_actions()
1477
1478 # function to convert arg_strings into positional actions
1479 def consume_positionals(start_index):
1480 # match as many Positionals as possible
1481 match_partial = self._match_arguments_partial
1482 selected_pattern = arg_strings_pattern[start_index:]
1483 arg_counts = match_partial(positionals, selected_pattern)
1484
1485 # slice off the appropriate arg strings for each Positional
1486 # and add the Positional and its args to the list
1487 for action, arg_count in zip(positionals, arg_counts):
1488 args = arg_strings[start_index: start_index + arg_count]
1489 start_index += arg_count
1490 take_action(action, args)
1491
1492 # slice off the Positionals that we just parsed and return the
1493 # index at which the Positionals' string args stopped
1494 positionals[:] = positionals[len(arg_counts):]
1495 return start_index
1496
1497 # consume Positionals and Optionals alternately, until we have
1498 # passed the last option string
1499 start_index = 0
1500 if option_string_indices:
1501 max_option_string_index = max(option_string_indices)
1502 else:
1503 max_option_string_index = -1
1504 while start_index <= max_option_string_index:
1505
1506 # consume any Positionals preceding the next option
1507 next_option_string_index = min(
1508 index
1509 for index in option_string_indices
1510 if index >= start_index)
1511 if start_index != next_option_string_index:
1512 positionals_end_index = consume_positionals(start_index)
1513
1514 # only try to parse the next optional if we didn't consume
1515 # the option string during the positionals parsing
1516 if positionals_end_index > start_index:
1517 start_index = positionals_end_index
1518 continue
1519 else:
1520 start_index = positionals_end_index
1521
1522 # if we consumed all the positionals we could and we're not
1523 # at the index of an option string, there were unparseable
1524 # arguments
1525 if start_index not in option_string_indices:
1526 msg = _('extra arguments found: %s')
1527 extras = arg_strings[start_index:next_option_string_index]
1528 self.error(msg % ' '.join(extras))
1529
1530 # consume the next optional and any arguments for it
1531 start_index = consume_optional(start_index)
1532
1533 # consume any positionals following the last Optional
1534 stop_index = consume_positionals(start_index)
1535
1536 # if we didn't consume all the argument strings, there were too
1537 # many supplied
1538 if stop_index != len(arg_strings):
1539 extras = arg_strings[stop_index:]
1540 self.error(_('extra arguments found: %s') % ' '.join(extras))
1541
1542 # if we didn't use all the Positional objects, there were too few
1543 # arg strings supplied.
1544 if positionals:
1545 self.error(_('too few arguments'))
1546
1547 # return the updated namespace
1548 return namespace
1549
1550 def _match_argument(self, action, arg_strings_pattern):
1551 # match the pattern for this action to the arg strings
1552 nargs_pattern = self._get_nargs_pattern(action)
1553 match = _re.match(nargs_pattern, arg_strings_pattern)
1554
1555 # raise an exception if we weren't able to find a match
1556 if match is None:
1557 nargs_errors = {
1558 None:_('expected one argument'),
1559 OPTIONAL:_('expected at most one argument'),
1560 ONE_OR_MORE:_('expected at least one argument')
1561 }
1562 default = _('expected %s argument(s)') % action.nargs
1563 msg = nargs_errors.get(action.nargs, default)
1564 raise ArgumentError(action, msg)
1565
1566 # return the number of arguments matched
1567 return len(match.group(1))
1568
1569 def _match_arguments_partial(self, actions, arg_strings_pattern):
1570 # progressively shorten the actions list by slicing off the
1571 # final actions until we find a match
1572 result = []
1573 for i in xrange(len(actions), 0, -1):
1574 actions_slice = actions[:i]
1575 pattern = ''.join(self._get_nargs_pattern(action)
1576 for action in actions_slice)
1577 match = _re.match(pattern, arg_strings_pattern)
1578 if match is not None:
1579 result.extend(len(string) for string in match.groups())
1580 break
1581
1582 # return the list of arg string counts
1583 return result
1584
1585 def _parse_optional(self, arg_string):
1586 # if it doesn't start with a prefix, it was meant to be positional
1587 if not arg_string[0] in self.prefix_chars:
1588 return None
1589
1590 # if it's just dashes, it was meant to be positional
1591 if not arg_string.strip('-'):
1592 return None
1593
1594 # if the option string is present in the parser, return the action
1595 if arg_string in self._option_strings:
1596 action = self._option_strings[arg_string]
1597 return action, arg_string, None
1598
1599 # search through all possible prefixes of the option string
1600 # and all actions in the parser for possible interpretations
1601 option_tuples = []
1602 prefix_tuples = self._get_option_prefix_tuples(arg_string)
1603 for option_string in self._option_strings:
1604 for option_prefix, explicit_arg in prefix_tuples:
1605 if option_string.startswith(option_prefix):
1606 action = self._option_strings[option_string]
1607 tup = action, option_string, explicit_arg
1608 option_tuples.append(tup)
1609 break
1610
1611 # if multiple actions match, the option string was ambiguous
1612 if len(option_tuples) > 1:
1613 options = ', '.join(opt_str for _, opt_str, _ in option_tuples)
1614 tup = arg_string, options
1615 self.error(_('ambiguous option: %s could match %s') % tup)
1616
1617 # if exactly one action matched, this segmentation is good,
1618 # so return the parsed action
1619 elif len(option_tuples) == 1:
1620 option_tuple, = option_tuples
1621 return option_tuple
1622
1623 # if it was not found as an option, but it looks like a negative
1624 # number, it was meant to be positional
1625 if self._negative_number_matcher.match(arg_string):
1626 return None
1627
1628 # it was meant to be an optional but there is no such option
1629 # in this parser (though it might be a valid option in a subparser)
1630 return None, arg_string, None
1631
1632 def _get_option_prefix_tuples(self, option_string):
1633 result = []
1634
1635 # option strings starting with two prefix characters are only
1636 # split at the '='
1637 chars = self.prefix_chars
1638 if option_string[0] in chars and option_string[1] in chars:
1639 if '=' in option_string:
1640 option_prefix, explicit_arg = option_string.split('=', 1)
1641 else:
1642 option_prefix = option_string
1643 explicit_arg = None
1644 tup = option_prefix, explicit_arg
1645 result.append(tup)
1646
1647 # option strings starting with a single prefix character are
1648 # split at all indices
1649 else:
1650 for first_index, char in enumerate(option_string):
1651 if char not in self.prefix_chars:
1652 break
1653 for i in xrange(len(option_string), first_index, -1):
1654 tup = option_string[:i], option_string[i:] or None
1655 result.append(tup)
1656
1657 # return the collected prefix tuples
1658 return result
1659
1660 def _get_nargs_pattern(self, action):
1661 # in all examples below, we have to allow for '--' args
1662 # which are represented as '-' in the pattern
1663 nargs = action.nargs
1664
1665 # the default (None) is assumed to be a single argument
1666 if nargs is None:
1667 nargs_pattern = '(-*A-*)'
1668
1669 # allow zero or one arguments
1670 elif nargs == OPTIONAL:
1671 nargs_pattern = '(-*A?-*)'
1672
1673 # allow zero or more arguments
1674 elif nargs == ZERO_OR_MORE:
1675 nargs_pattern = '(-*[A-]*)'
1676
1677 # allow one or more arguments
1678 elif nargs == ONE_OR_MORE:
1679 nargs_pattern = '(-*A[A-]*)'
1680
1681 # allow one argument followed by any number of options or arguments
1682 elif nargs is PARSER:
1683 nargs_pattern = '(-*A[-AO]*)'
1684
1685 # all others should be integers
1686 else:
1687 nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
1688
1689 # if this is an optional action, -- is not allowed
1690 if action.option_strings:
1691 nargs_pattern = nargs_pattern.replace('-*', '')
1692 nargs_pattern = nargs_pattern.replace('-', '')
1693
1694 # return the pattern
1695 return nargs_pattern
1696
1697 # ========================
1698 # Value conversion methods
1699 # ========================
1700
1701 def _get_values(self, action, arg_strings):
1702 # for everything but PARSER args, strip out '--'
1703 if action.nargs is not PARSER:
1704 arg_strings = [s for s in arg_strings if s != '--']
1705
1706 # optional argument produces a default when not present
1707 if not arg_strings and action.nargs == OPTIONAL:
1708 if action.option_strings:
1709 value = action.const
1710 else:
1711 value = action.default
1712 if isinstance(value, basestring):
1713 value = self._get_value(action, value)
1714 self._check_value(action, value)
1715
1716 # when nargs='*' on a positional, if there were no command-line
1717 # args, use the default if it is anything other than None
1718 elif (not arg_strings and action.nargs == ZERO_OR_MORE and
1719 not action.option_strings):
1720 if action.default is not None:
1721 value = action.default
1722 else:
1723 value = arg_strings
1724 self._check_value(action, value)
1725
1726 # single argument or optional argument produces a single value
1727 elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
1728 arg_string, = arg_strings
1729 value = self._get_value(action, arg_string)
1730 self._check_value(action, value)
1731
1732 # PARSER arguments convert all values, but check only the first
1733 elif action.nargs is PARSER:
1734 value = list(self._get_value(action, v) for v in arg_strings)
1735 self._check_value(action, value[0])
1736
1737 # all other types of nargs produce a list
1738 else:
1739 value = list(self._get_value(action, v) for v in arg_strings)
1740 for v in value:
1741 self._check_value(action, v)
1742
1743 # return the converted value
1744 return value
1745
1746 def _get_value(self, action, arg_string):
1747 type_func = self._registry_get('type', action.type, action.type)
1748 if not callable(type_func):
1749 msg = _('%r is not callable')
1750 raise ArgumentError(action, msg % type_func)
1751
1752 # convert the value to the appropriate type
1753 try:
1754 result = type_func(arg_string)
1755
1756 # TypeErrors or ValueErrors indicate errors
1757 except (TypeError, ValueError):
1758 name = getattr(action.type, '__name__', repr(action.type))
1759 msg = _('invalid %s value: %r')
1760 raise ArgumentError(action, msg % (name, arg_string))
1761
1762 # return the converted value
1763 return result
1764
1765 def _check_value(self, action, value):
1766 # converted value must be one of the choices (if specified)
1767 if action.choices is not None and value not in action.choices:
1768 tup = value, ', '.join(map(repr, action.choices))
1769 msg = _('invalid choice: %r (choose from %s)') % tup
1770 raise ArgumentError(action, msg)
1771
1772
1773
1774 # =======================
1775 # Help-formatting methods
1776 # =======================
1777
1778 def format_usage(self):
1779 formatter = self._get_formatter()
1780 formatter.add_usage(self.usage,
1781 self._get_optional_actions(),
1782 self._get_positional_actions())
1783 return formatter.format_help()
1784
1785 def format_help(self):
1786 formatter = self._get_formatter()
1787
1788 # usage
1789 formatter.add_usage(self.usage,
1790 self._get_optional_actions(),
1791 self._get_positional_actions())
1792
1793 # description
1794 formatter.add_text(self.description)
1795
1796 # positionals
1797 formatter.start_section(_('positional arguments'))
1798 formatter.add_arguments(self._positional_actions_list)
1799 formatter.end_section()
1800
1801 # optionals
1802 formatter.start_section(_('optional arguments'))
1803 formatter.add_arguments(self._optional_actions_list)
1804 formatter.end_section()
1805
1806 # user-defined groups
1807 for argument_group in self._argument_groups:
1808 formatter.start_section(argument_group.title)
1809 formatter.add_text(argument_group.description)
1810 formatter.add_arguments(argument_group._positional_actions_list)
1811 formatter.add_arguments(argument_group._optional_actions_list)
1812 formatter.end_section()
1813
1814 # epilog
1815 formatter.add_text(self.epilog)
1816
1817 # determine help from format above
1818 return formatter.format_help()
1819
1820 def format_version(self):
1821 formatter = self._get_formatter()
1822 formatter.add_text(self.version)
1823 return formatter.format_help()
1824
1825 def _get_formatter(self):
1826 return self.formatter_class(prog=self.prog)
1827
1828 # =====================
1829 # Help-printing methods
1830 # =====================
1831
1832 def print_usage(self, file=None):
1833 self._print_message(self.format_usage(), file)
1834
1835 def print_help(self, file=None):
1836 self._print_message(self.format_help(), file)
1837
1838 def print_version(self, file=None):
1839 self._print_message(self.format_version(), file)
1840
1841 def _print_message(self, message, file=None):
1842 if message:
1843 if file is None:
1844 file = _sys.stderr
1845 file.write(message)
1846
1847
1848 # ===============
1849 # Exiting methods
1850 # ===============
1851
1852 def exit(self, status=0, message=None):
1853 if message:
1854 _sys.stderr.write(message)
1855 _sys.exit(status)
1856
1857 def error(self, message):
1858 """error(message: string)
1859
1860 Prints a usage message incorporating the message to stderr and
1861 exits.
1862
1863 If you override this in a subclass, it should not return -- it
1864 should either exit or raise an exception.
1865 """
1866 self.print_usage(_sys.stderr)
1867 self.exit(2, _('%s: error: %s\n') % (self.prog, message))
@@ -0,0 +1,155 b''
1 # encoding: utf-8
2
3 """This file contains unittests for the frontendbase module."""
4
5 __docformat__ = "restructuredtext en"
6
7 #---------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #---------------------------------------------------------------------------
13
14 #---------------------------------------------------------------------------
15 # Imports
16 #---------------------------------------------------------------------------
17
18 import unittest
19
20 try:
21 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
22 from IPython.frontend import frontendbase
23 from IPython.kernel.engineservice import EngineService
24 except ImportError:
25 import nose
26 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
27
28 from IPython.testing.decorators import skip
29
30 class FrontEndCallbackChecker(AsyncFrontEndBase):
31 """FrontEndBase subclass for checking callbacks"""
32 def __init__(self, engine=None, history=None):
33 super(FrontEndCallbackChecker, self).__init__(engine=engine,
34 history=history)
35 self.updateCalled = False
36 self.renderResultCalled = False
37 self.renderErrorCalled = False
38
39 def update_cell_prompt(self, result, blockID=None):
40 self.updateCalled = True
41 return result
42
43 def render_result(self, result):
44 self.renderResultCalled = True
45 return result
46
47
48 def render_error(self, failure):
49 self.renderErrorCalled = True
50 return failure
51
52
53
54
55 class TestAsyncFrontendBase(unittest.TestCase):
56 def setUp(self):
57 """Setup the EngineService and FrontEndBase"""
58
59 self.fb = FrontEndCallbackChecker(engine=EngineService())
60
61 def test_implements_IFrontEnd(self):
62 assert(frontendbase.IFrontEnd.implementedBy(
63 AsyncFrontEndBase))
64
65 def test_is_complete_returns_False_for_incomplete_block(self):
66 """"""
67
68 block = """def test(a):"""
69
70 assert(self.fb.is_complete(block) == False)
71
72 def test_is_complete_returns_True_for_complete_block(self):
73 """"""
74
75 block = """def test(a): pass"""
76
77 assert(self.fb.is_complete(block))
78
79 block = """a=3"""
80
81 assert(self.fb.is_complete(block))
82
83 def test_blockID_added_to_result(self):
84 block = """3+3"""
85
86 d = self.fb.execute(block, blockID='TEST_ID')
87
88 d.addCallback(self.checkBlockID, expected='TEST_ID')
89
90 def test_blockID_added_to_failure(self):
91 block = "raise Exception()"
92
93 d = self.fb.execute(block,blockID='TEST_ID')
94 d.addErrback(self.checkFailureID, expected='TEST_ID')
95
96 def checkBlockID(self, result, expected=""):
97 assert(result['blockID'] == expected)
98
99
100 def checkFailureID(self, failure, expected=""):
101 assert(failure.blockID == expected)
102
103
104 def test_callbacks_added_to_execute(self):
105 """test that
106 update_cell_prompt
107 render_result
108
109 are added to execute request
110 """
111
112 d = self.fb.execute("10+10")
113 d.addCallback(self.checkCallbacks)
114
115 def checkCallbacks(self, result):
116 assert(self.fb.updateCalled)
117 assert(self.fb.renderResultCalled)
118
119 @skip("This test fails and lead to an unhandled error in a Deferred.")
120 def test_error_callback_added_to_execute(self):
121 """test that render_error called on execution error"""
122
123 d = self.fb.execute("raise Exception()")
124 d.addCallback(self.checkRenderError)
125
126 def checkRenderError(self, result):
127 assert(self.fb.renderErrorCalled)
128
129 def test_history_returns_expected_block(self):
130 """Make sure history browsing doesn't fail"""
131
132 blocks = ["a=1","a=2","a=3"]
133 for b in blocks:
134 d = self.fb.execute(b)
135
136 # d is now the deferred for the last executed block
137 d.addCallback(self.historyTests, blocks)
138
139
140 def historyTests(self, result, blocks):
141 """historyTests"""
142
143 assert(len(blocks) >= 3)
144 assert(self.fb.get_history_previous("") == blocks[-2])
145 assert(self.fb.get_history_previous("") == blocks[-3])
146 assert(self.fb.get_history_next() == blocks[-2])
147
148
149 def test_history_returns_none_at_startup(self):
150 """test_history_returns_none_at_startup"""
151
152 assert(self.fb.get_history_previous("")==None)
153 assert(self.fb.get_history_next()==None)
154
155
@@ -0,0 +1,26 b''
1 # encoding: utf-8
2
3 """This file contains unittests for the interpreter.py module."""
4
5 __docformat__ = "restructuredtext en"
6
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
13
14 #-----------------------------------------------------------------------------
15 # Imports
16 #-----------------------------------------------------------------------------
17
18 from IPython.kernel.core.interpreter import Interpreter
19
20 def test_unicode():
21 """ Test unicode handling with the interpreter.
22 """
23 i = Interpreter()
24 i.execute_python(u'print "ù"')
25 i.execute_python('print "ù"')
26
@@ -0,0 +1,53 b''
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """IPython Test Suite Runner.
4 """
5
6 import sys
7 import warnings
8
9 from nose.core import TestProgram
10 import nose.plugins.builtin
11
12 from IPython.testing.plugin.ipdoctest import IPythonDoctest
13
14 def main():
15 """Run the IPython test suite.
16 """
17
18 warnings.filterwarnings('ignore',
19 'This will be removed soon. Use IPython.testing.util instead')
20
21
22 # construct list of plugins, omitting the existing doctest plugin
23 plugins = [IPythonDoctest()]
24 for p in nose.plugins.builtin.plugins:
25 plug = p()
26 if plug.name == 'doctest':
27 continue
28
29 #print 'adding plugin:',plug.name # dbg
30 plugins.append(plug)
31
32 argv = sys.argv + ['--doctest-tests','--doctest-extension=txt',
33 '--detailed-errors',
34
35 # We add --exe because of setuptools' imbecility (it
36 # blindly does chmod +x on ALL files). Nose does the
37 # right thing and it tries to avoid executables,
38 # setuptools unfortunately forces our hand here. This
39 # has been discussed on the distutils list and the
40 # setuptools devs refuse to fix this problem!
41 '--exe',
42 ]
43
44 has_ip = False
45 for arg in sys.argv:
46 if 'IPython' in arg:
47 has_ip = True
48 break
49
50 if not has_ip:
51 argv.append('IPython')
52
53 TestProgram(argv=argv,plugins=plugins)
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
@@ -0,0 +1,161 b''
1 """Tests for the decorators we've created for IPython.
2 """
3
4 # Module imports
5 # Std lib
6 import inspect
7 import sys
8
9 # Third party
10 import nose.tools as nt
11
12 # Our own
13 from IPython.testing import decorators as dec
14
15
16 #-----------------------------------------------------------------------------
17 # Utilities
18
19 # Note: copied from OInspect, kept here so the testing stuff doesn't create
20 # circular dependencies and is easier to reuse.
21 def getargspec(obj):
22 """Get the names and default values of a function's arguments.
23
24 A tuple of four things is returned: (args, varargs, varkw, defaults).
25 'args' is a list of the argument names (it may contain nested lists).
26 'varargs' and 'varkw' are the names of the * and ** arguments or None.
27 'defaults' is an n-tuple of the default values of the last n arguments.
28
29 Modified version of inspect.getargspec from the Python Standard
30 Library."""
31
32 if inspect.isfunction(obj):
33 func_obj = obj
34 elif inspect.ismethod(obj):
35 func_obj = obj.im_func
36 else:
37 raise TypeError, 'arg is not a Python function'
38 args, varargs, varkw = inspect.getargs(func_obj.func_code)
39 return args, varargs, varkw, func_obj.func_defaults
40
41 #-----------------------------------------------------------------------------
42 # Testing functions
43
44 @dec.skip
45 def test_deliberately_broken():
46 """A deliberately broken test - we want to skip this one."""
47 1/0
48
49 @dec.skip('foo')
50 def test_deliberately_broken2():
51 """Another deliberately broken test - we want to skip this one."""
52 1/0
53
54
55 # Verify that we can correctly skip the doctest for a function at will, but
56 # that the docstring itself is NOT destroyed by the decorator.
57 @dec.skip_doctest
58 def doctest_bad(x,y=1,**k):
59 """A function whose doctest we need to skip.
60
61 >>> 1+1
62 3
63 """
64 print 'x:',x
65 print 'y:',y
66 print 'k:',k
67
68
69 def call_doctest_bad():
70 """Check that we can still call the decorated functions.
71
72 >>> doctest_bad(3,y=4)
73 x: 3
74 y: 4
75 k: {}
76 """
77 pass
78
79
80 def test_skip_dt_decorator():
81 """Doctest-skipping decorator should preserve the docstring.
82 """
83 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
84 check = """A function whose doctest we need to skip.
85
86 >>> 1+1
87 3
88 """
89 # Fetch the docstring from doctest_bad after decoration.
90 val = doctest_bad.__doc__
91
92 assert check==val,"doctest_bad docstrings don't match"
93
94 # Doctest skipping should work for class methods too
95 class foo(object):
96 """Foo
97
98 Example:
99
100 >>> 1+1
101 2
102 """
103
104 @dec.skip_doctest
105 def __init__(self,x):
106 """Make a foo.
107
108 Example:
109
110 >>> f = foo(3)
111 junk
112 """
113 print 'Making a foo.'
114 self.x = x
115
116 @dec.skip_doctest
117 def bar(self,y):
118 """Example:
119
120 >>> f = foo(3)
121 >>> f.bar(0)
122 boom!
123 >>> 1/0
124 bam!
125 """
126 return 1/y
127
128 def baz(self,y):
129 """Example:
130
131 >>> f = foo(3)
132 Making a foo.
133 >>> f.baz(3)
134 True
135 """
136 return self.x==y
137
138
139
140 def test_skip_dt_decorator2():
141 """Doctest-skipping decorator should preserve function signature.
142 """
143 # Hardcoded correct answer
144 dtargs = (['x', 'y'], None, 'k', (1,))
145 # Introspect out the value
146 dtargsr = getargspec(doctest_bad)
147 assert dtargsr==dtargs, \
148 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
149
150
151 @dec.skip_linux
152 def test_linux():
153 nt.assert_not_equals(sys.platform,'linux2',"This test can't run under linux")
154
155 @dec.skip_win32
156 def test_win32():
157 nt.assert_not_equals(sys.platform,'win32',"This test can't run under windows")
158
159 @dec.skip_osx
160 def test_osx():
161 nt.assert_not_equals(sys.platform,'darwin',"This test can't run under osx")
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
@@ -0,0 +1,32 b''
1 # encoding: utf-8
2
3 """Tests for genutils.py"""
4
5 __docformat__ = "restructuredtext en"
6
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
13
14 #-----------------------------------------------------------------------------
15 # Imports
16 #-----------------------------------------------------------------------------
17
18 from IPython import genutils
19
20
21 def test_get_home_dir():
22 """Make sure we can get the home directory."""
23 home_dir = genutils.get_home_dir()
24
25 def test_get_ipython_dir():
26 """Make sure we can get the ipython directory."""
27 ipdir = genutils.get_ipython_dir()
28
29 def test_get_security_dir():
30 """Make sure we can get the ipython/security directory."""
31 sdir = genutils.get_security_dir()
32 No newline at end of file
@@ -0,0 +1,21 b''
1 """ Tests for various magic functions
2
3 Needs to be run by nose (to make ipython session available)
4
5 """
6 def test_rehashx():
7 # clear up everything
8 _ip.IP.alias_table.clear()
9 del _ip.db['syscmdlist']
10
11 _ip.magic('rehashx')
12 # Practically ALL ipython development systems will have more than 10 aliases
13
14 assert len(_ip.IP.alias_table) > 10
15 for key, val in _ip.IP.alias_table.items():
16 # we must strip dots from alias names
17 assert '.' not in key
18
19 # rehashx must fill up syscmdlist
20 scoms = _ip.db['syscmdlist']
21 assert len(scoms) > 10
@@ -0,0 +1,22 b''
1 # If you want ipython to appear in a linux app launcher ("start menu"), install this by doing:
2 # sudo desktop-file-install ipython-sh.desktop
3
4 [Desktop Entry]
5 Comment=Perform shell-like tasks in interactive ipython session
6 Exec=ipython -p sh
7 GenericName[en_US]=IPython shell mode
8 GenericName=IPython shell mode
9 Icon=gnome-netstatus-idle
10 MimeType=
11 Name[en_US]=ipython-sh
12 Name=ipython-sh
13 Path=
14 Categories=Development;Utility;
15 StartupNotify=false
16 Terminal=true
17 TerminalOptions=
18 Type=Application
19 X-DBUS-ServiceName=
20 X-DBUS-StartupType=none
21 X-KDE-SubstituteUID=false
22 X-KDE-Username=
@@ -0,0 +1,22 b''
1 # If you want ipython to appear in a linux app launcher ("start menu"), install this by doing:
2 # sudo desktop-file-install ipython.desktop
3
4 [Desktop Entry]
5 Comment=Enhanced interactive Python shell
6 Exec=ipython
7 GenericName[en_US]=IPython
8 GenericName=IPython
9 Icon=gnome-netstatus-idle
10 MimeType=
11 Name[en_US]=ipython
12 Name=ipython
13 Path=
14 Categories=Development;Utility;
15 StartupNotify=false
16 Terminal=true
17 TerminalOptions=
18 Type=Application
19 X-DBUS-ServiceName=
20 X-DBUS-StartupType=none
21 X-KDE-SubstituteUID=false
22 X-KDE-Username=
@@ -0,0 +1,240 b''
1 .. _paralleltask:
2
3 ==========================
4 The IPython task interface
5 ==========================
6
7 .. contents::
8
9 The ``Task`` interface to the controller presents the engines as a fault tolerant, dynamic load-balanced system or workers. Unlike the ``MultiEngine`` interface, in the ``Task`` interface, the user have no direct access to individual engines. In some ways, this interface is simpler, but in other ways it is more powerful. Best of all the user can use both of these interfaces at the same time to take advantage or both of their strengths. When the user can break up the user's work into segments that do not depend on previous execution, the ``Task`` interface is ideal. But it also has more power and flexibility, allowing the user to guide the distribution of jobs, without having to assign Tasks to engines explicitly.
10
11 Starting the IPython controller and engines
12 ===========================================
13
14 To follow along with this tutorial, the user will need to start the IPython
15 controller and four IPython engines. The simplest way of doing this is to
16 use the ``ipcluster`` command::
17
18 $ ipcluster -n 4
19
20 For more detailed information about starting the controller and engines, see our :ref:`introduction <ip1par>` to using IPython for parallel computing.
21
22 The magic here is that this single controller and set of engines is running both the MultiEngine and ``Task`` interfaces simultaneously.
23
24 QuickStart Task Farming
25 =======================
26
27 First, a quick example of how to start running the most basic Tasks.
28 The first step is to import the IPython ``client`` module and then create a ``TaskClient`` instance::
29
30 In [1]: from IPython.kernel import client
31
32 In [2]: tc = client.TaskClient()
33
34 Then the user wrap the commands the user want to run in Tasks::
35
36 In [3]: tasklist = []
37 In [4]: for n in range(1000):
38 ... tasklist.append(client.Task("a = %i"%n, pull="a"))
39
40 The first argument of the ``Task`` constructor is a string, the command to be executed. The most important optional keyword argument is ``pull``, which can be a string or list of strings, and it specifies the variable names to be saved as results of the ``Task``.
41
42 Next, the user need to submit the Tasks to the ``TaskController`` with the ``TaskClient``::
43
44 In [5]: taskids = [ tc.run(t) for t in tasklist ]
45
46 This will give the user a list of the TaskIDs used by the controller to keep track of the Tasks and their results. Now at some point the user are going to want to get those results back. The ``barrier`` method allows the user to wait for the Tasks to finish running::
47
48 In [6]: tc.barrier(taskids)
49
50 This command will block until all the Tasks in ``taskids`` have finished. Now, the user probably want to look at the user's results::
51
52 In [7]: task_results = [ tc.get_task_result(taskid) for taskid in taskids ]
53
54 Now the user have a list of ``TaskResult`` objects, which have the actual result as a dictionary, but also keep track of some useful metadata about the ``Task``::
55
56 In [8]: tr = ``Task``_results[73]
57
58 In [9]: tr
59 Out[9]: ``TaskResult``[ID:73]:{'a':73}
60
61 In [10]: tr.engineid
62 Out[10]: 1
63
64 In [11]: tr.submitted, tr.completed, tr.duration
65 Out[11]: ("2008/03/08 03:41:42", "2008/03/08 03:41:44", 2.12345)
66
67 The actual results are stored in a dictionary, ``tr.results``, and a namespace object ``tr.ns`` which accesses the result keys by attribute::
68
69 In [12]: tr.results['a']
70 Out[12]: 73
71
72 In [13]: tr.ns.a
73 Out[13]: 73
74
75 That should cover the basics of running simple Tasks. There are several more powerful things the user can do with Tasks covered later. The most useful probably being using a ``MutiEngineClient`` interface to initialize all the engines with the import dependencies necessary to run the user's Tasks.
76
77 There are many options for running and managing Tasks. The best way to learn further about the ``Task`` interface is to study the examples in ``docs/examples``. If the user do so and learn a lots about this interface, we encourage the user to expand this documentation about the ``Task`` system.
78
79 Overview of the Task System
80 ===========================
81
82 The user's view of the ``Task`` system has three basic objects: The ``TaskClient``, the ``Task``, and the ``TaskResult``. The names of these three objects well indicate their role.
83
84 The ``TaskClient`` is the user's ``Task`` farming connection to the IPython cluster. Unlike the ``MultiEngineClient``, the ``TaskControler`` handles all the scheduling and distribution of work, so the ``TaskClient`` has no notion of engines, it just submits Tasks and requests their results. The Tasks are described as ``Task`` objects, and their results are wrapped in ``TaskResult`` objects. Thus, there are very few necessary methods for the user to manage.
85
86 Inside the task system is a Scheduler object, which assigns tasks to workers. The default scheduler is a simple FIFO queue. Subclassing the Scheduler should be easy, just implementing your own priority system.
87
88 The TaskClient
89 ==============
90
91 The ``TaskClient`` is the object the user use to connect to the ``Controller`` that is managing the user's Tasks. It is the analog of the ``MultiEngineClient`` for the standard IPython multiplexing interface. As with all client interfaces, the first step is to import the IPython Client Module::
92
93 In [1]: from IPython.kernel import client
94
95 Just as with the ``MultiEngineClient``, the user create the ``TaskClient`` with a tuple, containing the ip-address and port of the ``Controller``. the ``client`` module conveniently has the default address of the ``Task`` interface of the controller. Creating a default ``TaskClient`` object would be done with this::
96
97 In [2]: tc = client.TaskClient(client.default_task_address)
98
99 or, if the user want to specify a non default location of the ``Controller``, the user can specify explicitly::
100
101 In [3]: tc = client.TaskClient(("192.168.1.1", 10113))
102
103 As discussed earlier, the ``TaskClient`` only has a few basic methods.
104
105 * ``tc.run(task)``
106 ``run`` is the method by which the user submits Tasks. It takes exactly one argument, a ``Task`` object. All the advanced control of ``Task`` behavior is handled by properties of the ``Task`` object, rather than the submission command, so they will be discussed later in the `Task`_ section. ``run`` returns an integer, the ``Task``ID by which the ``Task`` and its results can be tracked and retrieved::
107
108 In [4]: ``Task``ID = tc.run(``Task``)
109
110 * ``tc.get_task_result(taskid, block=``False``)``
111 ``get_task_result`` is the method by which results are retrieved. It takes a single integer argument, the ``Task``ID`` of the result the user wish to retrieve. ``get_task_result`` also takes a keyword argument ``block``. ``block`` specifies whether the user actually want to wait for the result. If ``block`` is false, as it is by default, ``get_task_result`` will return immediately. If the ``Task`` has completed, it will return the ``TaskResult`` object for that ``Task``. But if the ``Task`` has not completed, it will return ``None``. If the user specify ``block=``True``, then ``get_task_result`` will wait for the ``Task`` to complete, and always return the ``TaskResult`` for the requested ``Task``.
112 * ``tc.barrier(taskid(s))``
113 ``barrier`` is a synchronization method. It takes exactly one argument, a ``Task``ID or list of taskIDs. ``barrier`` will block until all the specified Tasks have completed. In practice, a barrier is often called between the ``Task`` submission section of the code and the result gathering section::
114
115 In [5]: taskIDs = [ tc.run(``Task``) for ``Task`` in myTasks ]
116
117 In [6]: tc.get_task_result(taskIDs[-1]) is None
118 Out[6]: ``True``
119
120 In [7]: tc.barrier(``Task``ID)
121
122 In [8]: results = [ tc.get_task_result(tid) for tid in taskIDs ]
123
124 * ``tc.queue_status(verbose=``False``)``
125 ``queue_status`` is a method for querying the state of the ``TaskControler``. ``queue_status`` returns a dict of the form::
126
127 {'scheduled': Tasks that have been submitted but yet run
128 'pending' : Tasks that are currently running
129 'succeeded': Tasks that have completed successfully
130 'failed' : Tasks that have finished with a failure
131 }
132
133 if @verbose is not specified (or is ``False``), then the values of the dict are integers - the number of Tasks in each state. if @verbose is ``True``, then each element in the dict is a list of the taskIDs in that state::
134
135 In [8]: tc.queue_status()
136 Out[8]: {'scheduled': 4,
137 'pending' : 2,
138 'succeeded': 5,
139 'failed' : 1
140 }
141
142 In [9]: tc.queue_status(verbose=True)
143 Out[9]: {'scheduled': [8,9,10,11],
144 'pending' : [6,7],
145 'succeeded': [0,1,2,4,5],
146 'failed' : [3]
147 }
148
149 * ``tc.abort(taskid)``
150 ``abort`` allows the user to abort Tasks that have already been submitted. ``abort`` will always return immediately. If the ``Task`` has completed, ``abort`` will raise an ``IndexError ``Task`` Already Completed``. An obvious case for ``abort`` would be where the user submits a long-running ``Task`` with a number of retries (see ``Task``_ section for how to specify retries) in an interactive session, but realizes there has been a typo. The user can then abort the ``Task``, preventing certain failures from cluttering up the queue. It can also be used for parallel search-type problems, where only one ``Task`` will give the solution, so once the user find the solution, the user would want to abort all remaining Tasks to prevent wasted work.
151 * ``tc.spin()``
152 ``spin`` simply triggers the scheduler in the ``TaskControler``. Under most normal circumstances, this will do nothing. The primary known usage case involves the ``Task`` dependency (see `Dependencies`_). The dependency is a function of an Engine's ``properties``, but changing the ``properties`` via the ``MutliEngineClient`` does not trigger a reschedule event. The main example case for this requires the following event sequence:
153 * ``engine`` is available, ``Task`` is submitted, but ``engine`` does not have ``Task``'s dependencies.
154 * ``engine`` gets necessary dependencies while no new Tasks are submitted or completed.
155 * now ``engine`` can run ``Task``, but a ``Task`` event is required for the ``TaskControler`` to try scheduling ``Task`` again.
156
157 ``spin`` is just an empty ping method to ensure that the Controller has scheduled all available Tasks, and should not be needed under most normal circumstances.
158
159 That covers the ``TaskClient``, a simple interface to the cluster. With this, the user can submit jobs (and abort if necessary), request their results, synchronize on arbitrary subsets of jobs.
160
161 .. _task: The Task Object
162
163 The Task Object
164 ===============
165
166 The ``Task`` is the basic object for describing a job. It can be used in a very simple manner, where the user just specifies a command string to be executed as the ``Task``. The usage of this first argument is exactly the same as the ``execute`` method of the ``MultiEngine`` (in fact, ``execute`` is called to run the code)::
167
168 In [1]: t = client.Task("a = str(id)")
169
170 This ``Task`` would run, and store the string representation of the ``id`` element in ``a`` in each worker's namespace, but it is fairly useless because the user does not know anything about the state of the ``worker`` on which it ran at the time of retrieving results. It is important that each ``Task`` not expect the state of the ``worker`` to persist after the ``Task`` is completed.
171 There are many different situations for using ``Task`` Farming, and the ``Task`` object has many attributes for use in customizing the ``Task`` behavior. All of a ``Task``'s attributes may be specified in the constructor, through keyword arguments, or after ``Task`` construction through attribute assignment.
172
173 Data Attributes
174 ***************
175 It is likely that the user may want to move data around before or after executing the ``Task``. We provide methods of sending data to initialize the worker's namespace, and specifying what data to bring back as the ``Task``'s results.
176
177 * pull = []
178 The obvious case is as above, where ``t`` would execute and store the result of ``myfunc`` in ``a``, it is likely that the user would want to bring ``a`` back to their namespace. This is done through the ``pull`` attribute. ``pull`` can be a string or list of strings, and it specifies the names of variables to be retrieved. The ``TaskResult`` object retrieved by ``get_task_result`` will have a dictionary of keys and values, and the ``Task``'s ``pull`` attribute determines what goes into it::
179
180 In [2]: t = client.Task("a = str(id)", pull = "a")
181
182 In [3]: t = client.Task("a = str(id)", pull = ["a", "id"])
183
184 * push = {}
185 A user might also want to initialize some data into the namespace before the code part of the ``Task`` is run. Enter ``push``. ``push`` is a dictionary of key/value pairs to be loaded from the user's namespace into the worker's immediately before execution::
186
187 In [4]: t = client.Task("a = f(submitted)", push=dict(submitted=time.time()), pull="a")
188
189 push and pull result directly in calling an ``engine``'s ``push`` and ``pull`` methods before and after ``Task`` execution respectively, and thus their api is the same.
190
191 Namespace Cleaning
192 ******************
193 When a user is running a large number of Tasks, it is likely that the namespace of the worker's could become cluttered. Some Tasks might be sensitive to clutter, while others might be known to cause namespace pollution. For these reasons, Tasks have two boolean attributes for cleaning up the namespace.
194
195 * ``clear_after``
196 if clear_after is specified ``True``, the worker on which the ``Task`` was run will be reset (via ``engine.reset``) upon completion of the ``Task``. This can be useful for both Tasks that produce clutter or Tasks whose intermediate data one might wish to be kept private::
197
198 In [5]: t = client.Task("a = range(1e10)", pull = "a",clear_after=True)
199
200
201 * ``clear_before``
202 as one might guess, clear_before is identical to ``clear_after``, but it takes place before the ``Task`` is run. This ensures that the ``Task`` runs on a fresh worker::
203
204 In [6]: t = client.Task("a = globals()", pull = "a",clear_before=True)
205
206 Of course, a user can both at the same time, ensuring that all workers are clear except when they are currently running a job. Both of these default to ``False``.
207
208 Fault Tolerance
209 ***************
210 It is possible that Tasks might fail, and there are a variety of reasons this could happen. One might be that the worker it was running on disconnected, and there was nothing wrong with the ``Task`` itself. With the fault tolerance attributes of the ``Task``, the user can specify how many times to resubmit the ``Task``, and what to do if it never succeeds.
211
212 * ``retries``
213 ``retries`` is an integer, specifying the number of times a ``Task`` is to be retried. It defaults to zero. It is often a good idea for this number to be 1 or 2, to protect the ``Task`` from disconnecting engines, but not a large number. If a ``Task`` is failing 100 times, there is probably something wrong with the ``Task``. The canonical bad example:
214
215 In [7]: t = client.Task("os.kill(os.getpid(), 9)", retries=99)
216
217 This would actually take down 100 workers.
218
219 * ``recovery_task``
220 ``recovery_task`` is another ``Task`` object, to be run in the event of the original ``Task`` still failing after running out of retries. Since ``recovery_task`` is another ``Task`` object, it can have its own ``recovery_task``. The chain of Tasks is limitless, except loops are not allowed (that would be bad!).
221
222 Dependencies
223 ************
224 Dependencies are the most powerful part of the ``Task`` farming system, because it allows the user to do some classification of the workers, and guide the ``Task`` distribution without meddling with the controller directly. It makes use of two objects - the ``Task``'s ``depend`` attribute, and the engine's ``properties``. See the `MultiEngine`_ reference for how to use engine properties. The engine properties api exists for extending IPython, allowing conditional execution and new controllers that make decisions based on properties of its engines. Currently the ``Task`` dependency is the only internal use of the properties api.
225
226 .. _MultiEngine: ./parallel_multiengine
227
228 The ``depend`` attribute of a ``Task`` must be a function of exactly one argument, the worker's properties dictionary, and it should return ``True`` if the ``Task`` should be allowed to run on the worker and ``False`` if not. The usage in the controller is fault tolerant, so exceptions raised by ``Task.depend`` will be ignored and functionally equivalent to always returning ``False``. Tasks`` with invalid ``depend`` functions will never be assigned to a worker::
229
230 In [8]: def dep(properties):
231 ... return properties["RAM"] > 2**32 # have at least 4GB
232 In [9]: t = client.Task("a = bigfunc()", depend=dep)
233
234 It is important to note that assignment of values to the properties dict is done entirely by the user, either locally (in the engine) using the EngineAPI, or remotely, through the ``MultiEngineClient``'s get/set_properties methods.
235
236
237
238
239
240
@@ -0,0 +1,33 b''
1 =========================================
2 Notes on the IPython configuration system
3 =========================================
4
5 This document has some random notes on the configuration system.
6
7 To start, an IPython process needs:
8
9 * Configuration files
10 * Command line options
11 * Additional files (FURL files, extra scripts, etc.)
12
13 It feeds these things into the core logic of the process, and as output,
14 produces:
15
16 * Log files
17 * Security files
18
19 There are a number of things that complicate this:
20
21 * A process may need to be started on a different host that doesn't have
22 any of the config files or additional files. Those files need to be
23 moved over and put in a staging area. The process then needs to be told
24 about them.
25 * The location of the output files should somehow be set by config files or
26 command line options.
27 * Our config files are very hierarchical, but command line options are flat,
28 making it difficult to relate command line options to config files.
29 * Some processes (like ipcluster and the daemons) have to manage the input and
30 output files for multiple different subprocesses, each possibly on a
31 different host. Ahhhh!
32 * Our configurations are not singletons. A given user will likely have
33 many different configurations for different clusters.
@@ -0,0 +1,217 b''
1 Overview
2 ========
3
4 This document describes the steps required to install IPython. IPython is organized into a number of subpackages, each of which has its own dependencies. All of the subpackages come with IPython, so you don't need to download and install them separately. However, to use a given subpackage, you will need to install all of its dependencies.
5
6
7 Please let us know if you have problems installing IPython or any of its
8 dependencies. IPython requires Python version 2.4 or greater. We have not tested
9 IPython with the upcoming 2.6 or 3.0 versions.
10
11 .. warning::
12
13 IPython will not work with Python 2.3 or below.
14
15 Some of the installation approaches use the :mod:`setuptools` package and its :command:`easy_install` command line program. In many scenarios, this provides the most simple method of installing IPython and its dependencies. It is not required though. More information about :mod:`setuptools` can be found on its website.
16
17 More general information about installing Python packages can be found in Python's documentation at http://www.python.org/doc/.
18
19 Quickstart
20 ==========
21
22 If you have :mod:`setuptools` installed and you are on OS X or Linux (not Windows), the following will download and install IPython *and* the main optional dependencies::
23
24 $ easy_install ipython[kernel,security,test]
25
26 This will get Twisted, zope.interface and Foolscap, which are needed for IPython's parallel computing features as well as the nose package, which will enable you to run IPython's test suite. To run IPython's test suite, use the :command:`iptest` command::
27
28 $ iptest
29
30 Read on for more specific details and instructions for Windows.
31
32 Installing IPython itself
33 =========================
34
35 Given a properly built Python, the basic interactive IPython shell will work with no external dependencies. However, some Python distributions (particularly on Windows and OS X), don't come with a working :mod:`readline` module. The IPython shell will work without :mod:`readline`, but will lack many features that users depend on, such as tab completion and command line editing. See below for details of how to make sure you have a working :mod:`readline`.
36
37 Installation using easy_install
38 -------------------------------
39
40 If you have :mod:`setuptools` installed, the easiest way of getting IPython is to simple use :command:`easy_install`::
41
42 $ easy_install ipython
43
44 That's it.
45
46 Installation from source
47 ------------------------
48
49 If you don't want to use :command:`easy_install`, or don't have it installed, just grab the latest stable build of IPython from `here <http://ipython.scipy.org/dist/>`_. Then do the following::
50
51 $ tar -xzf ipython.tar.gz
52 $ cd ipython
53 $ python setup.py install
54
55 If you are installing to a location (like ``/usr/local``) that requires higher permissions, you may need to run the last command with :command:`sudo`.
56
57 Windows
58 -------
59
60 There are a few caveats for Windows users. The main issue is that a basic ``python setup.py install`` approach won't create ``.bat`` file or Start Menu shortcuts, which most users want. To get an installation with these, there are two choices:
61
62 1. Install using :command:`easy_install`.
63
64 2. Install using our binary ``.exe`` Windows installer, which can be found at `here <http://ipython.scipy.org/dist/>`_
65
66 3. Install from source, but using :mod:`setuptools` (``python setupegg.py install``).
67
68 Installing the development version
69 ----------------------------------
70
71 It is also possible to install the development version of IPython from our `Bazaar <http://bazaar-vcs.org/>`_ source code
72 repository. To do this you will need to have Bazaar installed on your system. Then just do::
73
74 $ bzr branch lp:ipython
75 $ cd ipython
76 $ python setup.py install
77
78 Again, this last step on Windows won't create ``.bat`` files or Start Menu shortcuts, so you will have to use one of the other approaches listed above.
79
80 Some users want to be able to follow the development branch as it changes. If you have :mod:`setuptools` installed, this is easy. Simply replace the last step by::
81
82 $ python setupegg.py develop
83
84 This creates links in the right places and installs the command line script to the appropriate places. Then, if you want to update your IPython at any time, just do::
85
86 $ bzr pull
87
88 Basic optional dependencies
89 ===========================
90
91 There are a number of basic optional dependencies that most users will want to get. These are:
92
93 * readline (for command line editing, tab completion, etc.)
94 * nose (to run the IPython test suite)
95 * pexpect (to use things like irunner)
96
97 If you are comfortable installing these things yourself, have at it, otherwise read on for more details.
98
99 readline
100 --------
101
102 In principle, all Python distributions should come with a working :mod:`readline` module. But, reality is not quite that simple. There are two common situations where you won't have a working :mod:`readline` module:
103
104 * If you are using the built-in Python on Mac OS X.
105
106 * If you are running Windows, which doesn't have a :mod:`readline` module.
107
108 On OS X, the built-in Python doesn't not have :mod:`readline` because of license issues. Starting with OS X 10.5 (Leopard), Apple's built-in Python has a BSD-licensed not-quite-compatible readline replacement. As of IPython 0.9, many of the issues related to the differences between readline and libedit have been resolved. For many users, libedit may be sufficient.
109
110 Most users on OS X will want to get the full :mod:`readline` module. To get a working :mod:`readline` module, just do (with :mod:`setuptools` installed)::
111
112 $ easy_install readline
113
114 .. note:
115
116 Other Python distributions on OS X (such as fink, MacPorts and the
117 official python.org binaries) already have readline installed so
118 you don't have to do this step.
119
120 If needed, the readline egg can be build and installed from source (see the wiki page at http://ipython.scipy.org/moin/InstallationOSXLeopard).
121
122 On Windows, you will need the PyReadline module. PyReadline is a separate,
123 Windows only implementation of readline that uses native Windows calls through
124 :mod:`ctypes`. The easiest way of installing PyReadline is you use the binary
125 installer available `here <http://ipython.scipy.org/dist/>`_. The
126 :mod:`ctypes` module, which comes with Python 2.5 and greater, is required by
127 PyReadline. It is available for Python 2.4 at
128 http://python.net/crew/theller/ctypes.
129
130 nose
131 ----
132
133 To run the IPython test suite you will need the :mod:`nose` package. Nose provides a great way of sniffing out and running all of the IPython tests. The simplest way of getting nose, is to use :command:`easy_install`::
134
135 $ easy_install nose
136
137 Another way of getting this is to do::
138
139 $ easy_install ipython[test]
140
141 For more installation options, see the `nose website <http://somethingaboutorange.com/mrl/projects/nose/>`_. Once you have nose installed, you can run IPython's test suite using the iptest command::
142
143 $ iptest
144
145
146 pexpect
147 -------
148
149 The `pexpect <http://www.noah.org/wiki/Pexpect>`_ package is used in IPython's :command:`irunner` script. On Unix platforms (including OS X), just do::
150
151 $ easy_install pexpect
152
153 Windows users are out of luck as pexpect does not run there.
154
155 Dependencies for IPython.kernel (parallel computing)
156 ====================================================
157
158 The IPython kernel provides a nice architecture for parallel computing. The main focus of this architecture is on interactive parallel computing. These features require a number of additional packages:
159
160 * zope.interface (yep, we use interfaces)
161 * Twisted (asynchronous networking framework)
162 * Foolscap (a nice, secure network protocol)
163 * pyOpenSSL (security for network connections)
164
165 On a Unix style platform (including OS X), if you want to use :mod:`setuptools`, you can just do::
166
167 $ easy_install ipython[kernel] # the first three
168 $ easy_install ipython[security] # pyOpenSSL
169
170 zope.interface and Twisted
171 --------------------------
172
173 Twisted [Twisted]_ and zope.interface [ZopeInterface]_ are used for networking related things. On Unix
174 style platforms (including OS X), the simplest way of getting the these is to
175 use :command:`easy_install`::
176
177 $ easy_install zope.interface
178 $ easy_install Twisted
179
180 Of course, you can also download the source tarballs from the `Twisted website <twistedmatrix.org>`_ and the `zope.interface page at PyPI <http://pypi.python.org/pypi/zope.interface>`_ and do the usual ``python setup.py install`` if you prefer.
181
182 Windows is a bit different. For zope.interface and Twisted, simply get the latest binary ``.exe`` installer from the Twisted website. This installer includes both zope.interface and Twisted and should just work.
183
184 Foolscap
185 --------
186
187 Foolscap [Foolscap]_ uses Twisted to provide a very nice secure RPC protocol that we use to implement our parallel computing features.
188
189 On all platforms a simple::
190
191 $ easy_install foolscap
192
193 should work. You can also download the source tarballs from the `Foolscap website <http://foolscap.lothar.com/trac>`_ and do ``python setup.py install`` if you prefer.
194
195 pyOpenSSL
196 ---------
197
198 IPython requires an older version of pyOpenSSL [pyOpenSSL]_ (0.6 rather than the current 0.7). There are a couple of options for getting this:
199
200 1. Most Linux distributions have packages for pyOpenSSL.
201 2. The built-in Python 2.5 on OS X 10.5 already has it installed.
202 3. There are source tarballs on the pyOpenSSL website. On Unix-like
203 platforms, these can be built using ``python seutp.py install``.
204 4. There is also a binary ``.exe`` Windows installer on the `pyOpenSSL website <http://pyopenssl.sourceforge.net/>`_.
205
206 Dependencies for IPython.frontend (the IPython GUI)
207 ===================================================
208
209 wxPython
210 --------
211
212 Starting with IPython 0.9, IPython has a new IPython.frontend package that has a nice wxPython based IPython GUI. As you would expect, this GUI requires wxPython. Most Linux distributions have wxPython packages available and the built-in Python on OS X comes with wxPython preinstalled. For Windows, a binary installer is available on the `wxPython website <http://www.wxpython.org/>`_.
213
214 .. [Twisted] Twisted matrix. http://twistedmatrix.org
215 .. [ZopeInterface] http://pypi.python.org/pypi/zope.interface
216 .. [Foolscap] Foolscap network protocol. http://foolscap.lothar.com/trac
217 .. [pyOpenSSL] pyOpenSSL. http://pyopenssl.sourceforge.net No newline at end of file
@@ -0,0 +1,251 b''
1 .. _parallel_process:
2
3 ===========================================
4 Starting the IPython controller and engines
5 ===========================================
6
7 To use IPython for parallel computing, you need to start one instance of
8 the controller and one or more instances of the engine. The controller
9 and each engine can run on different machines or on the same machine.
10 Because of this, there are many different possibilities.
11
12 Broadly speaking, there are two ways of going about starting a controller and engines:
13
14 * In an automated manner using the :command:`ipcluster` command.
15 * In a more manual way using the :command:`ipcontroller` and
16 :command:`ipengine` commands.
17
18 This document describes both of these methods. We recommend that new users start with the :command:`ipcluster` command as it simplifies many common usage cases.
19
20 General considerations
21 ======================
22
23 Before delving into the details about how you can start a controller and engines using the various methods, we outline some of the general issues that come up when starting the controller and engines. These things come up no matter which method you use to start your IPython cluster.
24
25 Let's say that you want to start the controller on ``host0`` and engines on hosts ``host1``-``hostn``. The following steps are then required:
26
27 1. Start the controller on ``host0`` by running :command:`ipcontroller` on
28 ``host0``.
29 2. Move the FURL file (:file:`ipcontroller-engine.furl`) created by the
30 controller from ``host0`` to hosts ``host1``-``hostn``.
31 3. Start the engines on hosts ``host1``-``hostn`` by running
32 :command:`ipengine`. This command has to be told where the FURL file
33 (:file:`ipcontroller-engine.furl`) is located.
34
35 At this point, the controller and engines will be connected. By default, the
36 FURL files created by the controller are put into the
37 :file:`~/.ipython/security` directory. If the engines share a filesystem with
38 the controller, step 2 can be skipped as the engines will automatically look
39 at that location.
40
41 The final step required required to actually use the running controller from a
42 client is to move the FURL files :file:`ipcontroller-mec.furl` and
43 :file:`ipcontroller-tc.furl` from ``host0`` to the host where the clients will
44 be run. If these file are put into the :file:`~/.ipython/security` directory of the client's host, they will be found automatically. Otherwise, the full path to them has to be passed to the client's constructor.
45
46 Using :command:`ipcluster`
47 ==========================
48
49 The :command:`ipcluster` command provides a simple way of starting a controller and engines in the following situations:
50
51 1. When the controller and engines are all run on localhost. This is useful
52 for testing or running on a multicore computer.
53 2. When engines are started using the :command:`mpirun` command that comes
54 with most MPI [MPI]_ implementations
55 3. When engines are started using the PBS [PBS]_ batch system.
56
57 .. note::
58
59 It is also possible for advanced users to add support to
60 :command:`ipcluster` for starting controllers and engines using other
61 methods (like Sun's Grid Engine for example).
62
63 .. note::
64
65 Currently :command:`ipcluster` requires that the
66 :file:`~/.ipython/security` directory live on a shared filesystem that is
67 seen by both the controller and engines. If you don't have a shared file
68 system you will need to use :command:`ipcontroller` and
69 :command:`ipengine` directly.
70
71 Underneath the hood, :command:`ipcluster` just uses :command:`ipcontroller`
72 and :command:`ipengine` to perform the steps described above.
73
74 Using :command:`ipcluster` in local mode
75 ----------------------------------------
76
77 To start one controller and 4 engines on localhost, just do::
78
79 $ ipcluster local -n 4
80
81 To see other command line options for the local mode, do::
82
83 $ ipcluster local -h
84
85 Using :command:`ipcluster` in mpirun mode
86 -----------------------------------------
87
88 The mpirun mode is useful if you:
89
90 1. Have MPI installed.
91 2. Your systems are configured to use the :command:`mpirun` command to start
92 processes.
93
94 If these are satisfied, you can start an IPython cluster using::
95
96 $ ipcluster mpirun -n 4
97
98 This does the following:
99
100 1. Starts the IPython controller on current host.
101 2. Uses :command:`mpirun` to start 4 engines.
102
103 On newer MPI implementations (such as OpenMPI), this will work even if you don't make any calls to MPI or call :func:`MPI_Init`. However, older MPI implementations actually require each process to call :func:`MPI_Init` upon starting. The easiest way of having this done is to install the mpi4py [mpi4py]_ package and then call ipcluster with the ``--mpi`` option::
104
105 $ ipcluster mpirun -n 4 --mpi=mpi4py
106
107 Unfortunately, even this won't work for some MPI implementations. If you are having problems with this, you will likely have to use a custom Python executable that itself calls :func:`MPI_Init` at the appropriate time. Fortunately, mpi4py comes with such a custom Python executable that is easy to install and use. However, this custom Python executable approach will not work with :command:`ipcluster` currently.
108
109 Additional command line options for this mode can be found by doing::
110
111 $ ipcluster mpirun -h
112
113 More details on using MPI with IPython can be found :ref:`here <parallelmpi>`.
114
115
116 Using :command:`ipcluster` in PBS mode
117 --------------------------------------
118
119 The PBS mode uses the Portable Batch System [PBS]_ to start the engines. To use this mode, you first need to create a PBS script template that will be used to start the engines. Here is a sample PBS script template:
120
121 .. sourcecode:: bash
122
123 #PBS -N ipython
124 #PBS -j oe
125 #PBS -l walltime=00:10:00
126 #PBS -l nodes=${n/4}:ppn=4
127 #PBS -q parallel
128
129 cd $$PBS_O_WORKDIR
130 export PATH=$$HOME/usr/local/bin
131 export PYTHONPATH=$$HOME/usr/local/lib/python2.4/site-packages
132 /usr/local/bin/mpiexec -n ${n} ipengine --logfile=$$PBS_O_WORKDIR/ipengine
133
134 There are a few important points about this template:
135
136 1. This template will be rendered at runtime using IPython's :mod:`Itpl`
137 template engine.
138
139 2. Instead of putting in the actual number of engines, use the notation
140 ``${n}`` to indicate the number of engines to be started. You can also uses
141 expressions like ``${n/4}`` in the template to indicate the number of
142 nodes.
143
144 3. Because ``$`` is a special character used by the template engine, you must
145 escape any ``$`` by using ``$$``. This is important when referring to
146 environment variables in the template.
147
148 4. Any options to :command:`ipengine` should be given in the batch script
149 template.
150
151 5. Depending on the configuration of you system, you may have to set
152 environment variables in the script template.
153
154 Once you have created such a script, save it with a name like :file:`pbs.template`. Now you are ready to start your job::
155
156 $ ipcluster pbs -n 128 --pbs-script=pbs.template
157
158 Additional command line options for this mode can be found by doing::
159
160 $ ipcluster pbs -h
161
162 Using the :command:`ipcontroller` and :command:`ipengine` commands
163 ==================================================================
164
165 It is also possible to use the :command:`ipcontroller` and :command:`ipengine` commands to start your controller and engines. This approach gives you full control over all aspects of the startup process.
166
167 Starting the controller and engine on your local machine
168 --------------------------------------------------------
169
170 To use :command:`ipcontroller` and :command:`ipengine` to start things on your
171 local machine, do the following.
172
173 First start the controller::
174
175 $ ipcontroller
176
177 Next, start however many instances of the engine you want using (repeatedly) the command::
178
179 $ ipengine
180
181 The engines should start and automatically connect to the controller using the FURL files in :file:`~./ipython/security`. You are now ready to use the controller and engines from IPython.
182
183 .. warning::
184
185 The order of the above operations is very important. You *must*
186 start the controller before the engines, since the engines connect
187 to the controller as they get started.
188
189 .. note::
190
191 On some platforms (OS X), to put the controller and engine into the
192 background you may need to give these commands in the form ``(ipcontroller
193 &)`` and ``(ipengine &)`` (with the parentheses) for them to work
194 properly.
195
196 Starting the controller and engines on different hosts
197 ------------------------------------------------------
198
199 When the controller and engines are running on different hosts, things are
200 slightly more complicated, but the underlying ideas are the same:
201
202 1. Start the controller on a host using :command:`ipcontroller`.
203 2. Copy :file:`ipcontroller-engine.furl` from :file:`~./ipython/security` on the controller's host to the host where the engines will run.
204 3. Use :command:`ipengine` on the engine's hosts to start the engines.
205
206 The only thing you have to be careful of is to tell :command:`ipengine` where the :file:`ipcontroller-engine.furl` file is located. There are two ways you can do this:
207
208 * Put :file:`ipcontroller-engine.furl` in the :file:`~./ipython/security`
209 directory on the engine's host, where it will be found automatically.
210 * Call :command:`ipengine` with the ``--furl-file=full_path_to_the_file``
211 flag.
212
213 The ``--furl-file`` flag works like this::
214
215 $ ipengine --furl-file=/path/to/my/ipcontroller-engine.furl
216
217 .. note::
218
219 If the controller's and engine's hosts all have a shared file system
220 (:file:`~./ipython/security` is the same on all of them), then things
221 will just work!
222
223 Make FURL files persistent
224 ---------------------------
225
226 At fist glance it may seem that that managing the FURL files is a bit annoying. Going back to the house and key analogy, copying the FURL around each time you start the controller is like having to make a new key every time you want to unlock the door and enter your house. As with your house, you want to be able to create the key (or FURL file) once, and then simply use it at any point in the future.
227
228 This is possible. The only thing you have to do is decide what ports the controller will listen on for the engines and clients. This is done as follows::
229
230 $ ipcontroller -r --client-port=10101 --engine-port=10102
231
232 Then, just copy the furl files over the first time and you are set. You can start and stop the controller and engines any many times as you want in the future, just make sure to tell the controller to use the *same* ports.
233
234 .. note::
235
236 You may ask the question: what ports does the controller listen on if you
237 don't tell is to use specific ones? The default is to use high random port
238 numbers. We do this for two reasons: i) to increase security through
239 obscurity and ii) to multiple controllers on a given host to start and
240 automatically use different ports.
241
242 Log files
243 ---------
244
245 All of the components of IPython have log files associated with them.
246 These log files can be extremely useful in debugging problems with
247 IPython and can be found in the directory :file:`~/.ipython/log`. Sending
248 the log files to us will often help us to debug any problems.
249
250
251 .. [PBS] Portable Batch System. http://www.openpbs.org/
@@ -0,0 +1,363 b''
1 .. _parallelsecurity:
2
3 ===========================
4 Security details of IPython
5 ===========================
6
7 IPython's :mod:`IPython.kernel` package exposes the full power of the Python
8 interpreter over a TCP/IP network for the purposes of parallel computing. This
9 feature brings up the important question of IPython's security model. This
10 document gives details about this model and how it is implemented in IPython's
11 architecture.
12
13 Processs and network topology
14 =============================
15
16 To enable parallel computing, IPython has a number of different processes that
17 run. These processes are discussed at length in the IPython documentation and
18 are summarized here:
19
20 * The IPython *engine*. This process is a full blown Python
21 interpreter in which user code is executed. Multiple
22 engines are started to make parallel computing possible.
23 * The IPython *controller*. This process manages a set of
24 engines, maintaining a queue for each and presenting
25 an asynchronous interface to the set of engines.
26 * The IPython *client*. This process is typically an
27 interactive Python process that is used to coordinate the
28 engines to get a parallel computation done.
29
30 Collectively, these three processes are called the IPython *kernel*.
31
32 These three processes communicate over TCP/IP connections with a well defined
33 topology. The IPython controller is the only process that listens on TCP/IP
34 sockets. Upon starting, an engine connects to a controller and registers
35 itself with the controller. These engine/controller TCP/IP connections persist
36 for the lifetime of each engine.
37
38 The IPython client also connects to the controller using one or more TCP/IP
39 connections. These connections persist for the lifetime of the client only.
40
41 A given IPython controller and set of engines typically has a relatively short
42 lifetime. Typically this lifetime corresponds to the duration of a single
43 parallel simulation performed by a single user. Finally, the controller,
44 engines and client processes typically execute with the permissions of that
45 same user. More specifically, the controller and engines are *not* executed as
46 root or with any other superuser permissions.
47
48 Application logic
49 =================
50
51 When running the IPython kernel to perform a parallel computation, a user
52 utilizes the IPython client to send Python commands and data through the
53 IPython controller to the IPython engines, where those commands are executed
54 and the data processed. The design of IPython ensures that the client is the
55 only access point for the capabilities of the engines. That is, the only way of addressing the engines is through a client.
56
57 A user can utilize the client to instruct the IPython engines to execute
58 arbitrary Python commands. These Python commands can include calls to the
59 system shell, access the filesystem, etc., as required by the user's
60 application code. From this perspective, when a user runs an IPython engine on
61 a host, that engine has the same capabilities and permissions as the user
62 themselves (as if they were logged onto the engine's host with a terminal).
63
64 Secure network connections
65 ==========================
66
67 Overview
68 --------
69
70 All TCP/IP connections between the client and controller as well as the
71 engines and controller are fully encrypted and authenticated. This section
72 describes the details of the encryption and authentication approached used
73 within IPython.
74
75 IPython uses the Foolscap network protocol [Foolscap]_ for all communications
76 between processes. Thus, the details of IPython's security model are directly
77 related to those of Foolscap. Thus, much of the following discussion is
78 actually just a discussion of the security that is built in to Foolscap.
79
80 Encryption
81 ----------
82
83 For encryption purposes, IPython and Foolscap use the well known Secure Socket
84 Layer (SSL) protocol [RFC5246]_. We use the implementation of this protocol
85 provided by the OpenSSL project through the pyOpenSSL [pyOpenSSL]_ Python
86 bindings to OpenSSL.
87
88 Authentication
89 --------------
90
91 IPython clients and engines must also authenticate themselves with the
92 controller. This is handled in a capabilities based security model
93 [Capability]_. In this model, the controller creates a strong cryptographic
94 key or token that represents each set of capability that the controller
95 offers. Any party who has this key and presents it to the controller has full
96 access to the corresponding capabilities of the controller. This model is
97 analogous to using a physical key to gain access to physical items
98 (capabilities) behind a locked door.
99
100 For a capabilities based authentication system to prevent unauthorized access,
101 two things must be ensured:
102
103 * The keys must be cryptographically strong. Otherwise attackers could gain
104 access by a simple brute force key guessing attack.
105 * The actual keys must be distributed only to authorized parties.
106
107 The keys in Foolscap are called Foolscap URL's or FURLs. The following section
108 gives details about how these FURLs are created in Foolscap. The IPython
109 controller creates a number of FURLs for different purposes:
110
111 * One FURL that grants IPython engines access to the controller. Also
112 implicit in this access is permission to execute code sent by an
113 authenticated IPython client.
114 * Two or more FURLs that grant IPython clients access to the controller.
115 Implicit in this access is permission to give the controller's engine code
116 to execute.
117
118 Upon starting, the controller creates these different FURLS and writes them
119 files in the user-read-only directory :file:`$HOME/.ipython/security`. Thus, only the
120 user who starts the controller has access to the FURLs.
121
122 For an IPython client or engine to authenticate with a controller, it must
123 present the appropriate FURL to the controller upon connecting. If the
124 FURL matches what the controller expects for a given capability, access is
125 granted. If not, access is denied. The exchange of FURLs is done after
126 encrypted communications channels have been established to prevent attackers
127 from capturing them.
128
129 .. note::
130
131 The FURL is similar to an unsigned private key in SSH.
132
133 Details of the Foolscap handshake
134 ---------------------------------
135
136 In this section we detail the precise security handshake that takes place at
137 the beginning of any network connection in IPython. For the purposes of this
138 discussion, the SERVER is the IPython controller process and the CLIENT is the
139 IPython engine or client process.
140
141 Upon starting, all IPython processes do the following:
142
143 1. Create a public key x509 certificate (ISO/IEC 9594).
144 2. Create a hash of the contents of the certificate using the SHA-1 algorithm.
145 The base-32 encoded version of this hash is saved by the process as its
146 process id (actually in Foolscap, this is the Tub id, but here refer to
147 it as the process id).
148
149 Upon starting, the IPython controller also does the following:
150
151 1. Save the x509 certificate to disk in a secure location. The CLIENT
152 certificate is never saved to disk.
153 2. Create a FURL for each capability that the controller has. There are
154 separate capabilities the controller offers for clients and engines. The
155 FURL is created using: a) the process id of the SERVER, b) the IP
156 address and port the SERVER is listening on and c) a 160 bit,
157 cryptographically secure string that represents the capability (the
158 "capability id").
159 3. The FURLs are saved to disk in a secure location on the SERVER's host.
160
161 For a CLIENT to be able to connect to the SERVER and access a capability of
162 that SERVER, the CLIENT must have knowledge of the FURL for that SERVER's
163 capability. This typically requires that the file containing the FURL be
164 moved from the SERVER's host to the CLIENT's host. This is done by the end
165 user who started the SERVER and wishes to have a CLIENT connect to the SERVER.
166
167 When a CLIENT connects to the SERVER, the following handshake protocol takes
168 place:
169
170 1. The CLIENT tells the SERVER what process (or Tub) id it expects the SERVER
171 to have.
172 2. If the SERVER has that process id, it notifies the CLIENT that it will now
173 enter encrypted mode. If the SERVER has a different id, the SERVER aborts.
174 3. Both CLIENT and SERVER initiate the SSL handshake protocol.
175 4. Both CLIENT and SERVER request the certificate of their peer and verify
176 that certificate. If this succeeds, all further communications are
177 encrypted.
178 5. Both CLIENT and SERVER send a hello block containing connection parameters
179 and their process id.
180 6. The CLIENT and SERVER check that their peer's stated process id matches the
181 hash of the x509 certificate the peer presented. If not, the connection is
182 aborted.
183 7. The CLIENT verifies that the SERVER's stated id matches the id of the
184 SERVER the CLIENT is intending to connect to. If not, the connection is
185 aborted.
186 8. The CLIENT and SERVER elect a master who decides on the final connection
187 parameters.
188
189 The public/private key pair associated with each process's x509 certificate
190 are completely hidden from this handshake protocol. There are however, used
191 internally by OpenSSL as part of the SSL handshake protocol. Each process
192 keeps their own private key hidden and sends its peer only the public key
193 (embedded in the certificate).
194
195 Finally, when the CLIENT requests access to a particular SERVER capability,
196 the following happens:
197
198 1. The CLIENT asks the SERVER for access to a capability by presenting that
199 capabilities id.
200 2. If the SERVER has a capability with that id, access is granted. If not,
201 access is not granted.
202 3. Once access has been gained, the CLIENT can use the capability.
203
204 Specific security vulnerabilities
205 =================================
206
207 There are a number of potential security vulnerabilities present in IPython's
208 architecture. In this section we discuss those vulnerabilities and detail how
209 the security architecture described above prevents them from being exploited.
210
211 Unauthorized clients
212 --------------------
213
214 The IPython client can instruct the IPython engines to execute arbitrary
215 Python code with the permissions of the user who started the engines. If an
216 attacker were able to connect their own hostile IPython client to the IPython
217 controller, they could instruct the engines to execute code.
218
219 This attack is prevented by the capabilities based client authentication
220 performed after the encrypted channel has been established. The relevant
221 authentication information is encoded into the FURL that clients must
222 present to gain access to the IPython controller. By limiting the distribution
223 of those FURLs, a user can grant access to only authorized persons.
224
225 It is highly unlikely that a client FURL could be guessed by an attacker
226 in a brute force guessing attack. A given instance of the IPython controller
227 only runs for a relatively short amount of time (on the order of hours). Thus
228 an attacker would have only a limited amount of time to test a search space of
229 size 2**320. Furthermore, even if a controller were to run for a longer amount
230 of time, this search space is quite large (larger for instance than that of
231 typical username/password pair).
232
233 Unauthorized engines
234 --------------------
235
236 If an attacker were able to connect a hostile engine to a user's controller,
237 the user might unknowingly send sensitive code or data to the hostile engine.
238 This attacker's engine would then have full access to that code and data.
239
240 This type of attack is prevented in the same way as the unauthorized client
241 attack, through the usage of the capabilities based authentication scheme.
242
243 Unauthorized controllers
244 ------------------------
245
246 It is also possible that an attacker could try to convince a user's IPython
247 client or engine to connect to a hostile IPython controller. That controller
248 would then have full access to the code and data sent between the IPython
249 client and the IPython engines.
250
251 Again, this attack is prevented through the FURLs, which ensure that a
252 client or engine connects to the correct controller. It is also important to
253 note that the FURLs also encode the IP address and port that the
254 controller is listening on, so there is little chance of mistakenly connecting
255 to a controller running on a different IP address and port.
256
257 When starting an engine or client, a user must specify which FURL to use
258 for that connection. Thus, in order to introduce a hostile controller, the
259 attacker must convince the user to use the FURLs associated with the
260 hostile controller. As long as a user is diligent in only using FURLs from
261 trusted sources, this attack is not possible.
262
263 Other security measures
264 =======================
265
266 A number of other measures are taken to further limit the security risks
267 involved in running the IPython kernel.
268
269 First, by default, the IPython controller listens on random port numbers.
270 While this can be overridden by the user, in the default configuration, an
271 attacker would have to do a port scan to even find a controller to attack.
272 When coupled with the relatively short running time of a typical controller
273 (on the order of hours), an attacker would have to work extremely hard and
274 extremely *fast* to even find a running controller to attack.
275
276 Second, much of the time, especially when run on supercomputers or clusters,
277 the controller is running behind a firewall. Thus, for engines or client to
278 connect to the controller:
279
280 * The different processes have to all be behind the firewall.
281
282 or:
283
284 * The user has to use SSH port forwarding to tunnel the
285 connections through the firewall.
286
287 In either case, an attacker is presented with addition barriers that prevent
288 attacking or even probing the system.
289
290 Summary
291 =======
292
293 IPython's architecture has been carefully designed with security in mind. The
294 capabilities based authentication model, in conjunction with the encrypted
295 TCP/IP channels, address the core potential vulnerabilities in the system,
296 while still enabling user's to use the system in open networks.
297
298 Other questions
299 ===============
300
301 About keys
302 ----------
303
304 Can you clarify the roles of the certificate and its keys versus the FURL,
305 which is also called a key?
306
307 The certificate created by IPython processes is a standard public key x509
308 certificate, that is used by the SSL handshake protocol to setup encrypted
309 channel between the controller and the IPython engine or client. This public
310 and private key associated with this certificate are used only by the SSL
311 handshake protocol in setting up this encrypted channel.
312
313 The FURL serves a completely different and independent purpose from the
314 key pair associated with the certificate. When we refer to a FURL as a
315 key, we are using the word "key" in the capabilities based security model
316 sense. This has nothing to do with "key" in the public/private key sense used
317 in the SSL protocol.
318
319 With that said the FURL is used as an cryptographic key, to grant
320 IPython engines and clients access to particular capabilities that the
321 controller offers.
322
323 Self signed certificates
324 ------------------------
325
326 Is the controller creating a self-signed certificate? Is this created for per
327 instance/session, one-time-setup or each-time the controller is started?
328
329 The Foolscap network protocol, which handles the SSL protocol details, creates
330 a self-signed x509 certificate using OpenSSL for each IPython process. The
331 lifetime of the certificate is handled differently for the IPython controller
332 and the engines/client.
333
334 For the IPython engines and client, the certificate is only held in memory for
335 the lifetime of its process. It is never written to disk.
336
337 For the controller, the certificate can be created anew each time the
338 controller starts or it can be created once and reused each time the
339 controller starts. If at any point, the certificate is deleted, a new one is
340 created the next time the controller starts.
341
342 SSL private key
343 ---------------
344
345 How the private key (associated with the certificate) is distributed?
346
347 In the usual implementation of the SSL protocol, the private key is never
348 distributed. We follow this standard always.
349
350 SSL versus Foolscap authentication
351 ----------------------------------
352
353 Many SSL connections only perform one sided authentication (the server to the
354 client). How is the client authentication in IPython's system related to SSL
355 authentication?
356
357 We perform a two way SSL handshake in which both parties request and verify
358 the certificate of their peer. This mutual authentication is handled by the
359 SSL handshake and is separate and independent from the additional
360 authentication steps that the CLIENT and SERVER perform after an encrypted
361 channel is established.
362
363 .. [RFC5246] <http://tools.ietf.org/html/rfc5246>
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100755
NO CONTENT: new file 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -26,6 +26,7 b' def make_color_table(in_class):'
26 Helper function for building the *TermColors classes."""
26 Helper function for building the *TermColors classes."""
27
27
28 color_templates = (
28 color_templates = (
29 # Dark colors
29 ("Black" , "0;30"),
30 ("Black" , "0;30"),
30 ("Red" , "0;31"),
31 ("Red" , "0;31"),
31 ("Green" , "0;32"),
32 ("Green" , "0;32"),
@@ -34,6 +35,7 b' def make_color_table(in_class):'
34 ("Purple" , "0;35"),
35 ("Purple" , "0;35"),
35 ("Cyan" , "0;36"),
36 ("Cyan" , "0;36"),
36 ("LightGray" , "0;37"),
37 ("LightGray" , "0;37"),
38 # Light colors
37 ("DarkGray" , "1;30"),
39 ("DarkGray" , "1;30"),
38 ("LightRed" , "1;31"),
40 ("LightRed" , "1;31"),
39 ("LightGreen" , "1;32"),
41 ("LightGreen" , "1;32"),
@@ -41,7 +43,17 b' def make_color_table(in_class):'
41 ("LightBlue" , "1;34"),
43 ("LightBlue" , "1;34"),
42 ("LightPurple" , "1;35"),
44 ("LightPurple" , "1;35"),
43 ("LightCyan" , "1;36"),
45 ("LightCyan" , "1;36"),
44 ("White" , "1;37"), )
46 ("White" , "1;37"),
47 # Blinking colors. Probably should not be used in anything serious.
48 ("BlinkBlack" , "5;30"),
49 ("BlinkRed" , "5;31"),
50 ("BlinkGreen" , "5;32"),
51 ("BlinkYellow" , "5;33"),
52 ("BlinkBlue" , "5;34"),
53 ("BlinkPurple" , "5;35"),
54 ("BlinkCyan" , "5;36"),
55 ("BlinkLightGray", "5;37"),
56 )
45
57
46 for name,value in color_templates:
58 for name,value in color_templates:
47 setattr(in_class,name,in_class._base % value)
59 setattr(in_class,name,in_class._base % value)
@@ -335,6 +335,12 b' def cd_completer(self, event):'
335 if not found:
335 if not found:
336 if os.path.isdir(relpath):
336 if os.path.isdir(relpath):
337 return [relpath]
337 return [relpath]
338 # if no completions so far, try bookmarks
339 bks = self.db.get('bookmarks',{}).keys()
340 bkmatches = [s for s in bks if s.startswith(event.symbol)]
341 if bkmatches:
342 return bkmatches
343
338 raise IPython.ipapi.TryNext
344 raise IPython.ipapi.TryNext
339
345
340
346
@@ -28,7 +28,8 b' def install_editor(run_template, wait = False):'
28 line = 0
28 line = 0
29 cmd = itplns(run_template, locals())
29 cmd = itplns(run_template, locals())
30 print ">",cmd
30 print ">",cmd
31 os.system(cmd)
31 if os.system(cmd) != 0:
32 raise IPython.ipapi.TryNext()
32 if wait:
33 if wait:
33 raw_input("Press Enter when done editing:")
34 raw_input("Press Enter when done editing:")
34
35
@@ -65,6 +66,9 b' def idle(exe = None):'
65 exe = p + '/idle.py'
66 exe = p + '/idle.py'
66 install_editor(exe + ' "$file"')
67 install_editor(exe + ' "$file"')
67
68
69 def mate(exe = 'mate'):
70 """ TextMate, the missing editor"""
71 install_editor(exe + ' -w -l $line "$file"')
68
72
69 # these are untested, report any problems
73 # these are untested, report any problems
70
74
@@ -8,7 +8,7 b' compatibility)'
8 """
8 """
9
9
10 from IPython import ipapi
10 from IPython import ipapi
11 import os,textwrap
11 import os,re,textwrap
12
12
13 # The import below effectively obsoletes your old-style ipythonrc[.ini],
13 # The import below effectively obsoletes your old-style ipythonrc[.ini],
14 # so consider yourself warned!
14 # so consider yourself warned!
@@ -50,9 +50,15 b' def main():'
50 ip.ex('import os')
50 ip.ex('import os')
51 ip.ex("def up(): os.chdir('..')")
51 ip.ex("def up(): os.chdir('..')")
52 ip.user_ns['LA'] = LastArgFinder()
52 ip.user_ns['LA'] = LastArgFinder()
53 # Nice prompt
54
53
55 o.prompt_in1= r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
54 # You can assign to _prompt_title variable
55 # to provide some extra information for prompt
56 # (e.g. the current mode, host/username...)
57
58 ip.user_ns['_prompt_title'] = ''
59
60 # Nice prompt
61 o.prompt_in1= r'\C_Green${_prompt_title}\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
56 o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green> '
62 o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green> '
57 o.prompt_out= '<\#> '
63 o.prompt_out= '<\#> '
58
64
@@ -98,9 +104,15 b' def main():'
98 for cmd in syscmds:
104 for cmd in syscmds:
99 # print "sys",cmd #dbg
105 # print "sys",cmd #dbg
100 noext, ext = os.path.splitext(cmd)
106 noext, ext = os.path.splitext(cmd)
101 key = mapper(noext)
107 if ext.lower() == '.exe':
108 cmd = noext
109
110 key = mapper(cmd)
102 if key not in ip.IP.alias_table:
111 if key not in ip.IP.alias_table:
103 ip.defalias(key, cmd)
112 # Dots will be removed from alias names, since ipython
113 # assumes names with dots to be python code
114
115 ip.defalias(key.replace('.',''), cmd)
104
116
105 # mglob combines 'find', recursion, exclusion... '%mglob?' to learn more
117 # mglob combines 'find', recursion, exclusion... '%mglob?' to learn more
106 ip.load("IPython.external.mglob")
118 ip.load("IPython.external.mglob")
@@ -117,7 +129,7 b' def main():'
117 # and the next best thing to real 'ls -F'
129 # and the next best thing to real 'ls -F'
118 ip.defalias('d','dir /w /og /on')
130 ip.defalias('d','dir /w /og /on')
119
131
120 ip.set_hook('input_prefilter', dotslash_prefilter_f)
132 ip.set_hook('input_prefilter', slash_prefilter_f)
121 extend_shell_behavior(ip)
133 extend_shell_behavior(ip)
122
134
123 class LastArgFinder:
135 class LastArgFinder:
@@ -139,13 +151,13 b' class LastArgFinder:'
139 return parts[-1]
151 return parts[-1]
140 return ""
152 return ""
141
153
142 def dotslash_prefilter_f(self,line):
154 def slash_prefilter_f(self,line):
143 """ ./foo now runs foo as system command
155 """ ./foo, ~/foo and /bin/foo now run foo as system command
144
156
145 Removes the need for doing !./foo
157 Removes the need for doing !./foo, !~/foo or !/bin/foo
146 """
158 """
147 import IPython.genutils
159 import IPython.genutils
148 if line.startswith("./"):
160 if re.match('(?:[.~]|/[a-zA-Z_0-9]+)/', line):
149 return "_ip.system(" + IPython.genutils.make_quoted_expr(line)+")"
161 return "_ip.system(" + IPython.genutils.make_quoted_expr(line)+")"
150 raise ipapi.TryNext
162 raise ipapi.TryNext
151
163
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -422,7 +422,11 b' python-profiler package from non-free.""")'
422 else:
422 else:
423 fndoc = 'No documentation'
423 fndoc = 'No documentation'
424 else:
424 else:
425 if fn.__doc__:
425 fndoc = fn.__doc__.rstrip()
426 fndoc = fn.__doc__.rstrip()
427 else:
428 fndoc = 'No documentation'
429
426
430
427 if mode == 'rest':
431 if mode == 'rest':
428 rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(self.shell.ESC_MAGIC,
432 rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(self.shell.ESC_MAGIC,
@@ -2328,7 +2332,17 b' Currently the magic system has the following functions:\\n"""'
2328 # do actual editing here
2332 # do actual editing here
2329 print 'Editing...',
2333 print 'Editing...',
2330 sys.stdout.flush()
2334 sys.stdout.flush()
2335 try:
2331 self.shell.hooks.editor(filename,lineno)
2336 self.shell.hooks.editor(filename,lineno)
2337 except IPython.ipapi.TryNext:
2338 warn('Could not open editor')
2339 return
2340
2341 # XXX TODO: should this be generalized for all string vars?
2342 # For now, this is special-cased to blocks created by cpaste
2343 if args.strip() == 'pasted_block':
2344 self.shell.user_ns['pasted_block'] = file_read(filename)
2345
2332 if opts.has_key('x'): # -x prevents actual execution
2346 if opts.has_key('x'): # -x prevents actual execution
2333 print
2347 print
2334 else:
2348 else:
@@ -2338,6 +2352,8 b' Currently the magic system has the following functions:\\n"""'
2338 else:
2352 else:
2339 self.shell.safe_execfile(filename,self.shell.user_ns,
2353 self.shell.safe_execfile(filename,self.shell.user_ns,
2340 self.shell.user_ns)
2354 self.shell.user_ns)
2355
2356
2341 if use_temp:
2357 if use_temp:
2342 try:
2358 try:
2343 return open(filename).read()
2359 return open(filename).read()
@@ -2648,7 +2664,9 b' Defaulting color scheme to \'NoColor\'"""'
2648 # each entry in the alias table must be (N,name),
2664 # each entry in the alias table must be (N,name),
2649 # where N is the number of positional arguments of the
2665 # where N is the number of positional arguments of the
2650 # alias.
2666 # alias.
2651 alias_table[ff] = (0,ff)
2667 # Dots will be removed from alias names, since ipython
2668 # assumes names with dots to be python code
2669 alias_table[ff.replace('.','')] = (0,ff)
2652 syscmdlist.append(ff)
2670 syscmdlist.append(ff)
2653 else:
2671 else:
2654 for pdir in path:
2672 for pdir in path:
@@ -2658,7 +2676,7 b' Defaulting color scheme to \'NoColor\'"""'
2658 if isexec(ff) and base.lower() not in self.shell.no_alias:
2676 if isexec(ff) and base.lower() not in self.shell.no_alias:
2659 if ext.lower() == '.exe':
2677 if ext.lower() == '.exe':
2660 ff = base
2678 ff = base
2661 alias_table[base.lower()] = (0,ff)
2679 alias_table[base.lower().replace('.','')] = (0,ff)
2662 syscmdlist.append(ff)
2680 syscmdlist.append(ff)
2663 # Make sure the alias table doesn't contain keywords or builtins
2681 # Make sure the alias table doesn't contain keywords or builtins
2664 self.shell.alias_table_validate()
2682 self.shell.alias_table_validate()
@@ -3210,14 +3228,24 b' Defaulting color scheme to \'NoColor\'"""'
3210 This assigns the pasted block to variable 'foo' as string, without
3228 This assigns the pasted block to variable 'foo' as string, without
3211 dedenting or executing it (preceding >>> and + is still stripped)
3229 dedenting or executing it (preceding >>> and + is still stripped)
3212
3230
3231 '%cpaste -r' re-executes the block previously entered by cpaste.
3232
3213 Do not be alarmed by garbled output on Windows (it's a readline bug).
3233 Do not be alarmed by garbled output on Windows (it's a readline bug).
3214 Just press enter and type -- (and press enter again) and the block
3234 Just press enter and type -- (and press enter again) and the block
3215 will be what was just pasted.
3235 will be what was just pasted.
3216
3236
3217 IPython statements (magics, shell escapes) are not supported (yet).
3237 IPython statements (magics, shell escapes) are not supported (yet).
3218 """
3238 """
3219 opts,args = self.parse_options(parameter_s,'s:',mode='string')
3239 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
3220 par = args.strip()
3240 par = args.strip()
3241 if opts.has_key('r'):
3242 b = self.user_ns.get('pasted_block', None)
3243 if b is None:
3244 raise UsageError('No previous pasted block available')
3245 print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))
3246 exec b in self.user_ns
3247 return
3248
3221 sentinel = opts.get('s','--')
3249 sentinel = opts.get('s','--')
3222
3250
3223 # Regular expressions that declare text we strip from the input:
3251 # Regular expressions that declare text we strip from the input:
@@ -3245,8 +3273,8 b' Defaulting color scheme to \'NoColor\'"""'
3245 #print "block:\n",block
3273 #print "block:\n",block
3246 if not par:
3274 if not par:
3247 b = textwrap.dedent(block)
3275 b = textwrap.dedent(block)
3248 exec b in self.user_ns
3249 self.user_ns['pasted_block'] = b
3276 self.user_ns['pasted_block'] = b
3277 exec b in self.user_ns
3250 else:
3278 else:
3251 self.user_ns[par] = SList(block.splitlines())
3279 self.user_ns[par] = SList(block.splitlines())
3252 print "Block assigned to '%s'" % par
3280 print "Block assigned to '%s'" % par
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -1,7 +1,5 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Release data for the IPython project.
2 """Release data for the IPython project."""
3
4 $Id: Release.py 3002 2008-02-01 07:17:00Z fperez $"""
5
3
6 #*****************************************************************************
4 #*****************************************************************************
7 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
5 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
@@ -23,9 +21,9 b" name = 'ipython'"
23 # bdist_deb does not accept underscores (a Debian convention).
21 # bdist_deb does not accept underscores (a Debian convention).
24
22
25 development = False # change this to False to do a release
23 development = False # change this to False to do a release
26 version_base = '0.9.beta'
24 version_base = '0.9.1'
27 branch = 'ipython'
25 branch = 'ipython'
28 revision = '1099'
26 revision = '1143'
29
27
30 if development:
28 if development:
31 if branch == 'ipython':
29 if branch == 'ipython':
@@ -36,14 +34,19 b' else:'
36 version = version_base
34 version = version_base
37
35
38
36
39 description = "Tools for interactive development in Python."
37 description = "An interactive computing environment for Python"
40
38
41 long_description = \
39 long_description = \
42 """
40 """
43 IPython provides a replacement for the interactive Python interpreter with
41 The goal of IPython is to create a comprehensive environment for
44 extra functionality.
42 interactive and exploratory computing. To support this goal, IPython
43 has two main components:
44
45 * An enhanced interactive Python shell.
46
47 * An architecture for interactive parallel computing.
45
48
46 Main features:
49 The enhanced interactive Python shell has the following main features:
47
50
48 * Comprehensive object introspection.
51 * Comprehensive object introspection.
49
52
@@ -66,14 +69,33 b' Main features:'
66
69
67 * Access to the system shell with user-extensible alias system.
70 * Access to the system shell with user-extensible alias system.
68
71
69 * Easily embeddable in other Python programs.
72 * Easily embeddable in other Python programs and wxPython GUIs.
70
73
71 * Integrated access to the pdb debugger and the Python profiler.
74 * Integrated access to the pdb debugger and the Python profiler.
72
75
73 The latest development version is always available at the IPython subversion
76 The parallel computing architecture has the following main features:
74 repository_.
77
78 * Quickly parallelize Python code from an interactive Python/IPython session.
79
80 * A flexible and dynamic process model that be deployed on anything from
81 multicore workstations to supercomputers.
82
83 * An architecture that supports many different styles of parallelism, from
84 message passing to task farming.
85
86 * Both blocking and fully asynchronous interfaces.
87
88 * High level APIs that enable many things to be parallelized in a few lines
89 of code.
90
91 * Share live parallel jobs with other users securely.
92
93 * Dynamically load balanced task farming system.
94
95 * Robust error handling in parallel code.
75
96
76 .. _repository: http://ipython.scipy.org/svn/ipython/ipython/trunk#egg=ipython-dev
97 The latest development version is always available from IPython's `Launchpad
98 site <http://launchpad.net/ipython>`_.
77 """
99 """
78
100
79 license = 'BSD'
101 license = 'BSD'
@@ -40,11 +40,12 b' except ImportError:'
40 # IPython imports
40 # IPython imports
41 import IPython
41 import IPython
42 from IPython import ultraTB, ipapi
42 from IPython import ultraTB, ipapi
43 from IPython.Magic import Magic
43 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
44 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
44 from IPython.iplib import InteractiveShell
45 from IPython.iplib import InteractiveShell
45 from IPython.ipmaker import make_IPython
46 from IPython.ipmaker import make_IPython
46 from IPython.Magic import Magic
47 from IPython.ipstruct import Struct
47 from IPython.ipstruct import Struct
48 from IPython.testing import decorators as testdec
48
49
49 # Globals
50 # Globals
50 # global flag to pass around information about Ctrl-C without exceptions
51 # global flag to pass around information about Ctrl-C without exceptions
@@ -414,7 +415,7 b' class MTInteractiveShell(InteractiveShell):'
414 if (self.worker_ident is None
415 if (self.worker_ident is None
415 or self.worker_ident == thread.get_ident() ):
416 or self.worker_ident == thread.get_ident() ):
416 InteractiveShell.runcode(self,code)
417 InteractiveShell.runcode(self,code)
417 return
418 return False
418
419
419 # Case 3
420 # Case 3
420 # Store code in queue, so the execution thread can handle it.
421 # Store code in queue, so the execution thread can handle it.
@@ -608,6 +609,7 b' class MatplotlibShellBase:'
608 if self.mpl_use._called:
609 if self.mpl_use._called:
609 self.matplotlib.rcParams['backend'] = self.mpl_backend
610 self.matplotlib.rcParams['backend'] = self.mpl_backend
610
611
612 @testdec.skip_doctest
611 def magic_run(self,parameter_s=''):
613 def magic_run(self,parameter_s=''):
612 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
614 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
613
615
@@ -774,6 +776,17 b' class IPShellGTK(IPThread):'
774 debug=1,shell_class=MTInteractiveShell):
776 debug=1,shell_class=MTInteractiveShell):
775
777
776 import gtk
778 import gtk
779 # Check for set_interactive, coming up in new pygtk.
780 # Disable it so that this code works, but notify
781 # the user that he has a better option as well.
782 # XXX TODO better support when set_interactive is released
783 try:
784 gtk.set_interactive(False)
785 print "Your PyGtk has set_interactive(), so you can use the"
786 print "more stable single-threaded Gtk mode."
787 print "See https://bugs.launchpad.net/ipython/+bug/270856"
788 except AttributeError:
789 pass
777
790
778 self.gtk = gtk
791 self.gtk = gtk
779 self.gtk_mainloop = hijack_gtk()
792 self.gtk_mainloop = hijack_gtk()
@@ -38,6 +38,8 b' ececute rad = pi/180.'
38 execute print '*** q is an alias for PhysicalQuantityInteractive'
38 execute print '*** q is an alias for PhysicalQuantityInteractive'
39 execute print '*** g = 9.8 m/s^2 has been defined'
39 execute print '*** g = 9.8 m/s^2 has been defined'
40 execute print '*** rad = pi/180 has been defined'
40 execute print '*** rad = pi/180 has been defined'
41 execute import ipy_constants as C
42 execute print '*** C is the physical constants module'
41
43
42 # Files to execute
44 # Files to execute
43 execfile
45 execfile
@@ -314,7 +314,10 b' class IPCompleter(Completer):'
314 # don't want to treat as delimiters in filename matching
314 # don't want to treat as delimiters in filename matching
315 # when escaped with backslash
315 # when escaped with backslash
316
316
317 if sys.platform == 'win32':
317 protectables = ' '
318 protectables = ' '
319 else:
320 protectables = ' ()'
318
321
319 if text.startswith('!'):
322 if text.startswith('!'):
320 text = text[1:]
323 text = text[1:]
@@ -16,13 +16,11 b' __docformat__ = "restructuredtext en"'
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 import os
18 import os
19 from IPython.config.cutils import get_home_dir, get_ipython_dir
19 from os.path import join as pjoin
20
21 from IPython.genutils import get_home_dir, get_ipython_dir
20 from IPython.external.configobj import ConfigObj
22 from IPython.external.configobj import ConfigObj
21
23
22 # Traitlets config imports
23 from IPython.config import traitlets
24 from IPython.config.config import *
25 from traitlets import *
26
24
27 class ConfigObjManager(object):
25 class ConfigObjManager(object):
28
26
@@ -53,7 +51,7 b' class ConfigObjManager(object):'
53
51
54 def write_default_config_file(self):
52 def write_default_config_file(self):
55 ipdir = get_ipython_dir()
53 ipdir = get_ipython_dir()
56 fname = ipdir + '/' + self.filename
54 fname = pjoin(ipdir, self.filename)
57 if not os.path.isfile(fname):
55 if not os.path.isfile(fname):
58 print "Writing the configuration file to: " + fname
56 print "Writing the configuration file to: " + fname
59 self.write_config_obj_to_file(fname)
57 self.write_config_obj_to_file(fname)
@@ -87,11 +85,11 b' class ConfigObjManager(object):'
87
85
88 # In ipythondir if it is set
86 # In ipythondir if it is set
89 if ipythondir is not None:
87 if ipythondir is not None:
90 trythis = ipythondir + '/' + filename
88 trythis = pjoin(ipythondir, filename)
91 if os.path.isfile(trythis):
89 if os.path.isfile(trythis):
92 return trythis
90 return trythis
93
91
94 trythis = get_ipython_dir() + '/' + filename
92 trythis = pjoin(get_ipython_dir(), filename)
95 if os.path.isfile(trythis):
93 if os.path.isfile(trythis):
96 return trythis
94 return trythis
97
95
@@ -22,71 +22,6 b' import sys'
22 # Normal code begins
22 # Normal code begins
23 #---------------------------------------------------------------------------
23 #---------------------------------------------------------------------------
24
24
25 class HomeDirError(Exception):
26 pass
27
28 def get_home_dir():
29 """Return the closest possible equivalent to a 'home' directory.
30
31 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
32
33 Currently only Posix and NT are implemented, a HomeDirError exception is
34 raised for all other OSes. """
35
36 isdir = os.path.isdir
37 env = os.environ
38 try:
39 homedir = env['HOME']
40 if not isdir(homedir):
41 # in case a user stuck some string which does NOT resolve to a
42 # valid path, it's as good as if we hadn't foud it
43 raise KeyError
44 return homedir
45 except KeyError:
46 if os.name == 'posix':
47 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
48 elif os.name == 'nt':
49 # For some strange reason, win9x returns 'nt' for os.name.
50 try:
51 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
52 if not isdir(homedir):
53 homedir = os.path.join(env['USERPROFILE'])
54 if not isdir(homedir):
55 raise HomeDirError
56 return homedir
57 except:
58 try:
59 # Use the registry to get the 'My Documents' folder.
60 import _winreg as wreg
61 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
62 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
63 homedir = wreg.QueryValueEx(key,'Personal')[0]
64 key.Close()
65 if not isdir(homedir):
66 e = ('Invalid "Personal" folder registry key '
67 'typically "My Documents".\n'
68 'Value: %s\n'
69 'This is not a valid directory on your system.' %
70 homedir)
71 raise HomeDirError(e)
72 return homedir
73 except HomeDirError:
74 raise
75 except:
76 return 'C:\\'
77 elif os.name == 'dos':
78 # Desperate, may do absurd things in classic MacOS. May work under DOS.
79 return 'C:\\'
80 else:
81 raise HomeDirError,'support for your operating system not implemented.'
82
83 def get_ipython_dir():
84 ipdir_def = '.ipython'
85 home_dir = get_home_dir()
86 ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
87 os.path.join(home_dir,ipdir_def)))
88 return ipdir
89
90 def import_item(key):
25 def import_item(key):
91 """
26 """
92 Import and return bar given the string foo.bar.
27 Import and return bar given the string foo.bar.
@@ -180,7 +180,7 b' def re_mark(mark):'
180
180
181 class Demo(object):
181 class Demo(object):
182
182
183 re_stop = re_mark('-?\s?stop\s?-?')
183 re_stop = re_mark('-*\s?stop\s?-*')
184 re_silent = re_mark('silent')
184 re_silent = re_mark('silent')
185 re_auto = re_mark('auto')
185 re_auto = re_mark('auto')
186 re_auto_all = re_mark('auto_all')
186 re_auto_all = re_mark('auto_all')
@@ -50,7 +50,6 b' import subprocess'
50 from subprocess import PIPE
50 from subprocess import PIPE
51 import sys
51 import sys
52 import os
52 import os
53 import time
54 import types
53 import types
55
54
56 try:
55 try:
@@ -69,7 +68,15 b' except ImportError:'
69
68
70 mswindows = (sys.platform == "win32")
69 mswindows = (sys.platform == "win32")
71
70
71 skip = False
72
72 if mswindows:
73 if mswindows:
74 import platform
75 if platform.uname()[3] == '' or platform.uname()[3] > '6.0.6000':
76 # Killable process does not work under vista when starting for
77 # something else than cmd.
78 skip = True
79 else:
73 import winprocess
80 import winprocess
74 else:
81 else:
75 import signal
82 import signal
@@ -78,6 +85,10 b' if not mswindows:'
78 def DoNothing(*args):
85 def DoNothing(*args):
79 pass
86 pass
80
87
88
89 if skip:
90 Popen = subprocess.Popen
91 else:
81 class Popen(subprocess.Popen):
92 class Popen(subprocess.Popen):
82 if not mswindows:
93 if not mswindows:
83 # Override __init__ to set a preexec_fn
94 # Override __init__ to set a preexec_fn
@@ -50,7 +50,7 b' class PipedProcess(Thread):'
50 """
50 """
51 env = os.environ
51 env = os.environ
52 env['TERM'] = 'xterm'
52 env['TERM'] = 'xterm'
53 process = Popen((self.command_string + ' 2>&1', ), shell=True,
53 process = Popen(self.command_string + ' 2>&1', shell=True,
54 env=env,
54 env=env,
55 universal_newlines=True,
55 universal_newlines=True,
56 stdout=PIPE, stdin=PIPE, )
56 stdout=PIPE, stdin=PIPE, )
@@ -14,30 +14,14 b' __docformat__ = "restructuredtext en"'
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17 import uuid
17 from IPython.external import guid
18
18
19 try:
20 from zope.interface import Interface, Attribute, implements, classProvides
21 except ImportError, e:
22 e.message = """%s
23 ________________________________________________________________________________
24 zope.interface is required to run asynchronous frontends.""" % e.message
25 e.args = (e.message, ) + e.args[1:]
26
27 from frontendbase import FrontEndBase, IFrontEnd, IFrontEndFactory
28
29 from IPython.kernel.engineservice import IEngineCore
30 from IPython.kernel.core.history import FrontEndHistory
31
19
32 try:
20 from zope.interface import Interface, Attribute, implements, classProvides
33 from twisted.python.failure import Failure
21 from twisted.python.failure import Failure
34 except ImportError, e:
22 from IPython.frontend.frontendbase import FrontEndBase, IFrontEnd, IFrontEndFactory
35 e.message = """%s
23 from IPython.kernel.core.history import FrontEndHistory
36 ________________________________________________________________________________
24 from IPython.kernel.engineservice import IEngineCore
37 twisted is required to run asynchronous frontends.""" % e.message
38 e.args = (e.message, ) + e.args[1:]
39
40
41
25
42
26
43 class AsyncFrontEndBase(FrontEndBase):
27 class AsyncFrontEndBase(FrontEndBase):
@@ -75,7 +59,7 b' class AsyncFrontEndBase(FrontEndBase):'
75 return Failure(Exception("Block is not compilable"))
59 return Failure(Exception("Block is not compilable"))
76
60
77 if(blockID == None):
61 if(blockID == None):
78 blockID = uuid.uuid4() #random UUID
62 blockID = guid.generate()
79
63
80 d = self.engine.execute(block)
64 d = self.engine.execute(block)
81 d.addCallback(self._add_history, block=block)
65 d.addCallback(self._add_history, block=block)
@@ -26,7 +26,7 b' __docformat__ = "restructuredtext en"'
26
26
27 import sys
27 import sys
28 import objc
28 import objc
29 import uuid
29 from IPython.external import guid
30
30
31 from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\
31 from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\
32 NSLog, NSNotificationCenter, NSMakeRange,\
32 NSLog, NSNotificationCenter, NSMakeRange,\
@@ -361,7 +361,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
361
361
362 def next_block_ID(self):
362 def next_block_ID(self):
363
363
364 return uuid.uuid4()
364 return guid.generate()
365
365
366 def new_cell_block(self):
366 def new_cell_block(self):
367 """A new CellBlock at the end of self.textView.textStorage()"""
367 """A new CellBlock at the end of self.textView.textStorage()"""
@@ -14,14 +14,18 b' __docformat__ = "restructuredtext en"'
14 #---------------------------------------------------------------------------
14 #---------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #---------------------------------------------------------------------------
16 #---------------------------------------------------------------------------
17
18 try:
17 from IPython.kernel.core.interpreter import Interpreter
19 from IPython.kernel.core.interpreter import Interpreter
18 import IPython.kernel.engineservice as es
20 import IPython.kernel.engineservice as es
19 from IPython.testing.util import DeferredTestCase
21 from IPython.testing.util import DeferredTestCase
20 from twisted.internet.defer import succeed
22 from twisted.internet.defer import succeed
21 from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController
23 from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController
22
23 from Foundation import NSMakeRect
24 from Foundation import NSMakeRect
24 from AppKit import NSTextView, NSScrollView
25 from AppKit import NSTextView, NSScrollView
26 except ImportError:
27 import nose
28 raise nose.SkipTest("This test requires zope.interface, Twisted, Foolscap and PyObjC")
25
29
26 class TestIPythonCocoaControler(DeferredTestCase):
30 class TestIPythonCocoaControler(DeferredTestCase):
27 """Tests for IPythonCocoaController"""
31 """Tests for IPythonCocoaController"""
@@ -31,7 +35,6 b' class TestIPythonCocoaControler(DeferredTestCase):'
31 self.engine = es.EngineService()
35 self.engine = es.EngineService()
32 self.engine.startService()
36 self.engine.startService()
33
37
34
35 def tearDown(self):
38 def tearDown(self):
36 self.controller = None
39 self.controller = None
37 self.engine.stopService()
40 self.engine.stopService()
@@ -21,14 +21,16 b' __docformat__ = "restructuredtext en"'
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import string
23 import string
24 import uuid
24 import codeop
25 import _ast
25 from IPython.external import guid
26
26
27 from zopeinterface import Interface, Attribute, implements, classProvides
28
27
28 from IPython.frontend.zopeinterface import (
29 Interface,
30 Attribute,
31 )
29 from IPython.kernel.core.history import FrontEndHistory
32 from IPython.kernel.core.history import FrontEndHistory
30 from IPython.kernel.core.util import Bunch
33 from IPython.kernel.core.util import Bunch
31 from IPython.kernel.engineservice import IEngineCore
32
34
33 ##############################################################################
35 ##############################################################################
34 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
36 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
@@ -131,10 +133,6 b' class IFrontEnd(Interface):'
131
133
132 pass
134 pass
133
135
134 def compile_ast(block):
135 """Compiles block to an _ast.AST"""
136
137 pass
138
136
139 def get_history_previous(current_block):
137 def get_history_previous(current_block):
140 """Returns the block previous in the history. Saves currentBlock if
138 """Returns the block previous in the history. Saves currentBlock if
@@ -217,28 +215,14 b' class FrontEndBase(object):'
217 """
215 """
218
216
219 try:
217 try:
220 ast = self.compile_ast(block)
218 is_complete = codeop.compile_command(block.rstrip() + '\n\n',
219 "<string>", "exec")
221 except:
220 except:
222 return False
221 return False
223
222
224 lines = block.split('\n')
223 lines = block.split('\n')
225 return (len(lines)==1 or str(lines[-1])=='')
224 return ((is_complete is not None)
226
225 and (len(lines)==1 or str(lines[-1])==''))
227
228 def compile_ast(self, block):
229 """Compile block to an AST
230
231 Parameters:
232 block : str
233
234 Result:
235 AST
236
237 Throws:
238 Exception if block cannot be compiled
239 """
240
241 return compile(block, "<string>", "exec", _ast.PyCF_ONLY_AST)
242
226
243
227
244 def execute(self, block, blockID=None):
228 def execute(self, block, blockID=None):
@@ -258,7 +242,7 b' class FrontEndBase(object):'
258 raise Exception("Block is not compilable")
242 raise Exception("Block is not compilable")
259
243
260 if(blockID == None):
244 if(blockID == None):
261 blockID = uuid.uuid4() #random UUID
245 blockID = guid.generate()
262
246
263 try:
247 try:
264 result = self.shell.execute(block)
248 result = self.shell.execute(block)
@@ -20,6 +20,8 b' import re'
20
20
21 import IPython
21 import IPython
22 import sys
22 import sys
23 import codeop
24 import traceback
23
25
24 from frontendbase import FrontEndBase
26 from frontendbase import FrontEndBase
25 from IPython.kernel.core.interpreter import Interpreter
27 from IPython.kernel.core.interpreter import Interpreter
@@ -76,6 +78,11 b' class LineFrontEndBase(FrontEndBase):'
76
78
77 if banner is not None:
79 if banner is not None:
78 self.banner = banner
80 self.banner = banner
81
82 def start(self):
83 """ Put the frontend in a state where it is ready for user
84 interaction.
85 """
79 if self.banner is not None:
86 if self.banner is not None:
80 self.write(self.banner, refresh=False)
87 self.write(self.banner, refresh=False)
81
88
@@ -141,9 +148,18 b' class LineFrontEndBase(FrontEndBase):'
141 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
148 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
142 return False
149 return False
143 else:
150 else:
151 self.capture_output()
152 try:
144 # Add line returns here, to make sure that the statement is
153 # Add line returns here, to make sure that the statement is
145 # complete.
154 # complete.
146 return FrontEndBase.is_complete(self, string.rstrip() + '\n\n')
155 is_complete = codeop.compile_command(string.rstrip() + '\n\n',
156 "<string>", "exec")
157 self.release_output()
158 except Exception, e:
159 # XXX: Hack: return True so that the
160 # code gets executed and the error captured.
161 is_complete = True
162 return is_complete
147
163
148
164
149 def write(self, string, refresh=True):
165 def write(self, string, refresh=True):
@@ -166,6 +182,18 b' class LineFrontEndBase(FrontEndBase):'
166 raw_string = python_string
182 raw_string = python_string
167 # Create a false result, in case there is an exception
183 # Create a false result, in case there is an exception
168 self.last_result = dict(number=self.prompt_number)
184 self.last_result = dict(number=self.prompt_number)
185
186 ## try:
187 ## self.history.input_cache[-1] = raw_string.rstrip()
188 ## result = self.shell.execute(python_string)
189 ## self.last_result = result
190 ## self.render_result(result)
191 ## except:
192 ## self.show_traceback()
193 ## finally:
194 ## self.after_execute()
195
196 try:
169 try:
197 try:
170 self.history.input_cache[-1] = raw_string.rstrip()
198 self.history.input_cache[-1] = raw_string.rstrip()
171 result = self.shell.execute(python_string)
199 result = self.shell.execute(python_string)
@@ -176,12 +204,13 b' class LineFrontEndBase(FrontEndBase):'
176 finally:
204 finally:
177 self.after_execute()
205 self.after_execute()
178
206
207
179 #--------------------------------------------------------------------------
208 #--------------------------------------------------------------------------
180 # LineFrontEndBase interface
209 # LineFrontEndBase interface
181 #--------------------------------------------------------------------------
210 #--------------------------------------------------------------------------
182
211
183 def prefilter_input(self, string):
212 def prefilter_input(self, string):
184 """ Priflter the input to turn it in valid python.
213 """ Prefilter the input to turn it in valid python.
185 """
214 """
186 string = string.replace('\r\n', '\n')
215 string = string.replace('\r\n', '\n')
187 string = string.replace('\t', 4*' ')
216 string = string.replace('\t', 4*' ')
@@ -210,9 +239,12 b' class LineFrontEndBase(FrontEndBase):'
210 line = self.input_buffer
239 line = self.input_buffer
211 new_line, completions = self.complete(line)
240 new_line, completions = self.complete(line)
212 if len(completions)>1:
241 if len(completions)>1:
213 self.write_completion(completions)
242 self.write_completion(completions, new_line=new_line)
243 elif not line == new_line:
214 self.input_buffer = new_line
244 self.input_buffer = new_line
215 if self.debug:
245 if self.debug:
246 print >>sys.__stdout__, 'line', line
247 print >>sys.__stdout__, 'new_line', new_line
216 print >>sys.__stdout__, completions
248 print >>sys.__stdout__, completions
217
249
218
250
@@ -222,10 +254,15 b' class LineFrontEndBase(FrontEndBase):'
222 return 80
254 return 80
223
255
224
256
225 def write_completion(self, possibilities):
257 def write_completion(self, possibilities, new_line=None):
226 """ Write the list of possible completions.
258 """ Write the list of possible completions.
259
260 new_line is the completed input line that should be displayed
261 after the completion are writen. If None, the input_buffer
262 before the completion is used.
227 """
263 """
228 current_buffer = self.input_buffer
264 if new_line is None:
265 new_line = self.input_buffer
229
266
230 self.write('\n')
267 self.write('\n')
231 max_len = len(max(possibilities, key=len)) + 1
268 max_len = len(max(possibilities, key=len)) + 1
@@ -246,7 +283,7 b' class LineFrontEndBase(FrontEndBase):'
246 self.write(''.join(buf))
283 self.write(''.join(buf))
247 self.new_prompt(self.input_prompt_template.substitute(
284 self.new_prompt(self.input_prompt_template.substitute(
248 number=self.last_result['number'] + 1))
285 number=self.last_result['number'] + 1))
249 self.input_buffer = current_buffer
286 self.input_buffer = new_line
250
287
251
288
252 def new_prompt(self, prompt):
289 def new_prompt(self, prompt):
@@ -275,6 +312,8 b' class LineFrontEndBase(FrontEndBase):'
275 else:
312 else:
276 self.input_buffer += self._get_indent_string(
313 self.input_buffer += self._get_indent_string(
277 current_buffer[:-1])
314 current_buffer[:-1])
315 if len(current_buffer.split('\n')) == 2:
316 self.input_buffer += '\t\t'
278 if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
317 if current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
279 self.input_buffer += '\t'
318 self.input_buffer += '\t'
280
319
@@ -24,6 +24,7 b' __docformat__ = "restructuredtext en"'
24 import sys
24 import sys
25
25
26 from linefrontendbase import LineFrontEndBase, common_prefix
26 from linefrontendbase import LineFrontEndBase, common_prefix
27 from frontendbase import FrontEndBase
27
28
28 from IPython.ipmaker import make_IPython
29 from IPython.ipmaker import make_IPython
29 from IPython.ipapi import IPApi
30 from IPython.ipapi import IPApi
@@ -34,6 +35,7 b' from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap'
34 from IPython.genutils import Term
35 from IPython.genutils import Term
35 import pydoc
36 import pydoc
36 import os
37 import os
38 import sys
37
39
38
40
39 def mk_system_call(system_call_function, command):
41 def mk_system_call(system_call_function, command):
@@ -58,6 +60,8 b' class PrefilterFrontEnd(LineFrontEndBase):'
58 completion...
60 completion...
59 """
61 """
60
62
63 debug = False
64
61 def __init__(self, ipython0=None, *args, **kwargs):
65 def __init__(self, ipython0=None, *args, **kwargs):
62 """ Parameters:
66 """ Parameters:
63 -----------
67 -----------
@@ -65,12 +69,24 b' class PrefilterFrontEnd(LineFrontEndBase):'
65 ipython0: an optional ipython0 instance to use for command
69 ipython0: an optional ipython0 instance to use for command
66 prefiltering and completion.
70 prefiltering and completion.
67 """
71 """
72 LineFrontEndBase.__init__(self, *args, **kwargs)
73 self.shell.output_trap = RedirectorOutputTrap(
74 out_callback=self.write,
75 err_callback=self.write,
76 )
77 self.shell.traceback_trap = SyncTracebackTrap(
78 formatters=self.shell.traceback_trap.formatters,
79 )
80
81 # Start the ipython0 instance:
68 self.save_output_hooks()
82 self.save_output_hooks()
69 if ipython0 is None:
83 if ipython0 is None:
70 # Instanciate an IPython0 interpreter to be able to use the
84 # Instanciate an IPython0 interpreter to be able to use the
71 # prefiltering.
85 # prefiltering.
72 # XXX: argv=[] is a bit bold.
86 # XXX: argv=[] is a bit bold.
73 ipython0 = make_IPython(argv=[])
87 ipython0 = make_IPython(argv=[],
88 user_ns=self.shell.user_ns,
89 user_global_ns=self.shell.user_global_ns)
74 self.ipython0 = ipython0
90 self.ipython0 = ipython0
75 # Set the pager:
91 # Set the pager:
76 self.ipython0.set_hook('show_in_pager',
92 self.ipython0.set_hook('show_in_pager',
@@ -86,24 +102,13 b' class PrefilterFrontEnd(LineFrontEndBase):'
86 'ls -CF')
102 'ls -CF')
87 # And now clean up the mess created by ipython0
103 # And now clean up the mess created by ipython0
88 self.release_output()
104 self.release_output()
105
106
89 if not 'banner' in kwargs and self.banner is None:
107 if not 'banner' in kwargs and self.banner is None:
90 kwargs['banner'] = self.ipython0.BANNER + """
108 self.banner = self.ipython0.BANNER + """
91 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
109 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
92
110
93 LineFrontEndBase.__init__(self, *args, **kwargs)
111 self.start()
94 # XXX: Hack: mix the two namespaces
95 self.shell.user_ns.update(self.ipython0.user_ns)
96 self.ipython0.user_ns = self.shell.user_ns
97 self.shell.user_global_ns.update(self.ipython0.user_global_ns)
98 self.ipython0.user_global_ns = self.shell.user_global_ns
99
100 self.shell.output_trap = RedirectorOutputTrap(
101 out_callback=self.write,
102 err_callback=self.write,
103 )
104 self.shell.traceback_trap = SyncTracebackTrap(
105 formatters=self.shell.traceback_trap.formatters,
106 )
107
112
108 #--------------------------------------------------------------------------
113 #--------------------------------------------------------------------------
109 # FrontEndBase interface
114 # FrontEndBase interface
@@ -113,7 +118,7 b' This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""'
113 """ Use ipython0 to capture the last traceback and display it.
118 """ Use ipython0 to capture the last traceback and display it.
114 """
119 """
115 self.capture_output()
120 self.capture_output()
116 self.ipython0.showtraceback()
121 self.ipython0.showtraceback(tb_offset=-1)
117 self.release_output()
122 self.release_output()
118
123
119
124
@@ -164,6 +169,8 b' This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""'
164
169
165
170
166 def complete(self, line):
171 def complete(self, line):
172 # FIXME: This should be factored out in the linefrontendbase
173 # method.
167 word = line.split('\n')[-1].split(' ')[-1]
174 word = line.split('\n')[-1].split(' ')[-1]
168 completions = self.ipython0.complete(word)
175 completions = self.ipython0.complete(word)
169 # FIXME: The proper sort should be done in the complete method.
176 # FIXME: The proper sort should be done in the complete method.
@@ -189,6 +196,20 b' This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""'
189 # capture it.
196 # capture it.
190 self.capture_output()
197 self.capture_output()
191 self.last_result = dict(number=self.prompt_number)
198 self.last_result = dict(number=self.prompt_number)
199
200 ## try:
201 ## for line in input_string.split('\n'):
202 ## filtered_lines.append(
203 ## self.ipython0.prefilter(line, False).rstrip())
204 ## except:
205 ## # XXX: probably not the right thing to do.
206 ## self.ipython0.showsyntaxerror()
207 ## self.after_execute()
208 ## finally:
209 ## self.release_output()
210
211
212 try:
192 try:
213 try:
193 for line in input_string.split('\n'):
214 for line in input_string.split('\n'):
194 filtered_lines.append(
215 filtered_lines.append(
@@ -200,6 +221,8 b' This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""'
200 finally:
221 finally:
201 self.release_output()
222 self.release_output()
202
223
224
225
203 # Clean up the trailing whitespace, to avoid indentation errors
226 # Clean up the trailing whitespace, to avoid indentation errors
204 filtered_string = '\n'.join(filtered_lines)
227 filtered_string = '\n'.join(filtered_lines)
205 return filtered_string
228 return filtered_string
@@ -1,152 +1,32 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2 """
3 """This file contains unittests for the frontendbase module."""
3 Test the basic functionality of frontendbase.
4 """
4
5
5 __docformat__ = "restructuredtext en"
6 __docformat__ = "restructuredtext en"
6
7
7 #---------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
9 #
10 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is
11 # the file COPYING, distributed as part of this software.
12 # in the file COPYING, distributed as part of this software.
12 #---------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
13
14 #---------------------------------------------------------------------------
15 # Imports
16 #---------------------------------------------------------------------------
17
18 import unittest
19 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
20 from IPython.frontend import frontendbase
21 from IPython.kernel.engineservice import EngineService
22
23 class FrontEndCallbackChecker(AsyncFrontEndBase):
24 """FrontEndBase subclass for checking callbacks"""
25 def __init__(self, engine=None, history=None):
26 super(FrontEndCallbackChecker, self).__init__(engine=engine,
27 history=history)
28 self.updateCalled = False
29 self.renderResultCalled = False
30 self.renderErrorCalled = False
31
32 def update_cell_prompt(self, result, blockID=None):
33 self.updateCalled = True
34 return result
35
36 def render_result(self, result):
37 self.renderResultCalled = True
38 return result
39
40
41 def render_error(self, failure):
42 self.renderErrorCalled = True
43 return failure
44
45
46
47
48 class TestAsyncFrontendBase(unittest.TestCase):
49 def setUp(self):
50 """Setup the EngineService and FrontEndBase"""
51
52 self.fb = FrontEndCallbackChecker(engine=EngineService())
53
54
55 def test_implements_IFrontEnd(self):
56 assert(frontendbase.IFrontEnd.implementedBy(
57 AsyncFrontEndBase))
58
59
60 def test_is_complete_returns_False_for_incomplete_block(self):
61 """"""
62
63 block = """def test(a):"""
64
65 assert(self.fb.is_complete(block) == False)
66
67 def test_is_complete_returns_True_for_complete_block(self):
68 """"""
69
70 block = """def test(a): pass"""
71
72 assert(self.fb.is_complete(block))
73
74 block = """a=3"""
75
76 assert(self.fb.is_complete(block))
77
78
14
79 def test_blockID_added_to_result(self):
15 from IPython.frontend.frontendbase import FrontEndBase
80 block = """3+3"""
81
16
82 d = self.fb.execute(block, blockID='TEST_ID')
17 def test_iscomplete():
83
18 """ Check that is_complete works.
84 d.addCallback(self.checkBlockID, expected='TEST_ID')
85
86 def test_blockID_added_to_failure(self):
87 block = "raise Exception()"
88
89 d = self.fb.execute(block,blockID='TEST_ID')
90 d.addErrback(self.checkFailureID, expected='TEST_ID')
91
92 def checkBlockID(self, result, expected=""):
93 assert(result['blockID'] == expected)
94
95
96 def checkFailureID(self, failure, expected=""):
97 assert(failure.blockID == expected)
98
99
100 def test_callbacks_added_to_execute(self):
101 """test that
102 update_cell_prompt
103 render_result
104
105 are added to execute request
106 """
19 """
107
20 f = FrontEndBase()
108 d = self.fb.execute("10+10")
21 assert f.is_complete('(a + a)')
109 d.addCallback(self.checkCallbacks)
22 assert not f.is_complete('(a + a')
110
23 assert f.is_complete('1')
111
24 assert not f.is_complete('1 + ')
112 def checkCallbacks(self, result):
25 assert not f.is_complete('1 + \n\n')
113 assert(self.fb.updateCalled)
26 assert f.is_complete('if True:\n print 1\n')
114 assert(self.fb.renderResultCalled)
27 assert not f.is_complete('if True:\n print 1')
115
28 assert f.is_complete('def f():\n print 1\n')
116
29
117 def test_error_callback_added_to_execute(self):
30 if __name__ == '__main__':
118 """test that render_error called on execution error"""
31 test_iscomplete()
119
120 d = self.fb.execute("raise Exception()")
121 d.addCallback(self.checkRenderError)
122
123 def checkRenderError(self, result):
124 assert(self.fb.renderErrorCalled)
125
126 def test_history_returns_expected_block(self):
127 """Make sure history browsing doesn't fail"""
128
129 blocks = ["a=1","a=2","a=3"]
130 for b in blocks:
131 d = self.fb.execute(b)
132
133 # d is now the deferred for the last executed block
134 d.addCallback(self.historyTests, blocks)
135
136
137 def historyTests(self, result, blocks):
138 """historyTests"""
139
140 assert(len(blocks) >= 3)
141 assert(self.fb.get_history_previous("") == blocks[-2])
142 assert(self.fb.get_history_previous("") == blocks[-3])
143 assert(self.fb.get_history_next() == blocks[-2])
144
145
146 def test_history_returns_none_at_startup(self):
147 """test_history_returns_none_at_startup"""
148
149 assert(self.fb.get_history_previous("")==None)
150 assert(self.fb.get_history_next()==None)
151
152
32
@@ -17,6 +17,8 b' from time import sleep'
17 import sys
17 import sys
18
18
19 from IPython.frontend._process import PipedProcess
19 from IPython.frontend._process import PipedProcess
20 from IPython.testing import decorators as testdec
21
20
22
21 def test_capture_out():
23 def test_capture_out():
22 """ A simple test to see if we can execute a process and get the output.
24 """ A simple test to see if we can execute a process and get the output.
@@ -25,7 +27,8 b' def test_capture_out():'
25 p = PipedProcess('echo 1', out_callback=s.write, )
27 p = PipedProcess('echo 1', out_callback=s.write, )
26 p.start()
28 p.start()
27 p.join()
29 p.join()
28 assert s.getvalue() == '1\n'
30 result = s.getvalue().rstrip()
31 assert result == '1'
29
32
30
33
31 def test_io():
34 def test_io():
@@ -40,7 +43,8 b' def test_io():'
40 sleep(0.1)
43 sleep(0.1)
41 p.process.stdin.write(test_string)
44 p.process.stdin.write(test_string)
42 p.join()
45 p.join()
43 assert s.getvalue() == test_string
46 result = s.getvalue()
47 assert result == test_string
44
48
45
49
46 def test_kill():
50 def test_kill():
@@ -23,6 +23,7 b' import wx'
23 import wx.stc as stc
23 import wx.stc as stc
24
24
25 from wx.py import editwindow
25 from wx.py import editwindow
26 import time
26 import sys
27 import sys
27 LINESEP = '\n'
28 LINESEP = '\n'
28 if sys.platform == 'win32':
29 if sys.platform == 'win32':
@@ -35,7 +36,7 b' import re'
35
36
36 _DEFAULT_SIZE = 10
37 _DEFAULT_SIZE = 10
37 if sys.platform == 'darwin':
38 if sys.platform == 'darwin':
38 _DEFAULT_STYLE = 12
39 _DEFAULT_SIZE = 12
39
40
40 _DEFAULT_STYLE = {
41 _DEFAULT_STYLE = {
41 'stdout' : 'fore:#0000FF',
42 'stdout' : 'fore:#0000FF',
@@ -115,12 +116,15 b' class ConsoleWidget(editwindow.EditWindow):'
115 # The color of the carret (call _apply_style() after setting)
116 # The color of the carret (call _apply_style() after setting)
116 carret_color = 'BLACK'
117 carret_color = 'BLACK'
117
118
119 # Store the last time a refresh was done
120 _last_refresh_time = 0
121
118 #--------------------------------------------------------------------------
122 #--------------------------------------------------------------------------
119 # Public API
123 # Public API
120 #--------------------------------------------------------------------------
124 #--------------------------------------------------------------------------
121
125
122 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
126 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
123 size=wx.DefaultSize, style=0, ):
127 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
124 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
128 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
125 self._configure_scintilla()
129 self._configure_scintilla()
126
130
@@ -168,9 +172,14 b' class ConsoleWidget(editwindow.EditWindow):'
168
172
169 self.GotoPos(self.GetLength())
173 self.GotoPos(self.GetLength())
170 if refresh:
174 if refresh:
171 # Maybe this is faster than wx.Yield()
175 current_time = time.time()
172 self.ProcessEvent(wx.PaintEvent())
176 if current_time - self._last_refresh_time > 0.03:
173 #wx.Yield()
177 if sys.platform == 'win32':
178 wx.SafeYield()
179 else:
180 wx.Yield()
181 # self.ProcessEvent(wx.PaintEvent())
182 self._last_refresh_time = current_time
174
183
175
184
176 def new_prompt(self, prompt):
185 def new_prompt(self, prompt):
@@ -183,7 +192,6 b' class ConsoleWidget(editwindow.EditWindow):'
183 # now we update our cursor giving end of prompt
192 # now we update our cursor giving end of prompt
184 self.current_prompt_pos = self.GetLength()
193 self.current_prompt_pos = self.GetLength()
185 self.current_prompt_line = self.GetCurrentLine()
194 self.current_prompt_line = self.GetCurrentLine()
186 wx.Yield()
187 self.EnsureCaretVisible()
195 self.EnsureCaretVisible()
188
196
189
197
@@ -128,6 +128,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
128 # while it is being swapped
128 # while it is being swapped
129 _out_buffer_lock = Lock()
129 _out_buffer_lock = Lock()
130
130
131 # The different line markers used to higlight the prompts.
131 _markers = dict()
132 _markers = dict()
132
133
133 #--------------------------------------------------------------------------
134 #--------------------------------------------------------------------------
@@ -135,13 +136,17 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
135 #--------------------------------------------------------------------------
136 #--------------------------------------------------------------------------
136
137
137 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
138 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
138 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
139 size=wx.DefaultSize,
140 style=wx.CLIP_CHILDREN|wx.WANTS_CHARS,
139 *args, **kwds):
141 *args, **kwds):
140 """ Create Shell instance.
142 """ Create Shell instance.
141 """
143 """
142 ConsoleWidget.__init__(self, parent, id, pos, size, style)
144 ConsoleWidget.__init__(self, parent, id, pos, size, style)
143 PrefilterFrontEnd.__init__(self, **kwds)
145 PrefilterFrontEnd.__init__(self, **kwds)
144
146
147 # Stick in our own raw_input:
148 self.ipython0.raw_input = self.raw_input
149
145 # Marker for complete buffer.
150 # Marker for complete buffer.
146 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
151 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
147 background=_COMPLETE_BUFFER_BG)
152 background=_COMPLETE_BUFFER_BG)
@@ -164,9 +169,11 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
164 # Inject self in namespace, for debug
169 # Inject self in namespace, for debug
165 if self.debug:
170 if self.debug:
166 self.shell.user_ns['self'] = self
171 self.shell.user_ns['self'] = self
172 # Inject our own raw_input in namespace
173 self.shell.user_ns['raw_input'] = self.raw_input
167
174
168
175
169 def raw_input(self, prompt):
176 def raw_input(self, prompt=''):
170 """ A replacement from python's raw_input.
177 """ A replacement from python's raw_input.
171 """
178 """
172 self.new_prompt(prompt)
179 self.new_prompt(prompt)
@@ -174,15 +181,13 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
174 if hasattr(self, '_cursor'):
181 if hasattr(self, '_cursor'):
175 del self._cursor
182 del self._cursor
176 self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
183 self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
177 self.waiting = True
178 self.__old_on_enter = self._on_enter
184 self.__old_on_enter = self._on_enter
185 event_loop = wx.EventLoop()
179 def my_on_enter():
186 def my_on_enter():
180 self.waiting = False
187 event_loop.Exit()
181 self._on_enter = my_on_enter
188 self._on_enter = my_on_enter
182 # XXX: Busy waiting, ugly.
189 # XXX: Running a separate event_loop. Ugly.
183 while self.waiting:
190 event_loop.Run()
184 wx.Yield()
185 sleep(0.1)
186 self._on_enter = self.__old_on_enter
191 self._on_enter = self.__old_on_enter
187 self._input_state = 'buffering'
192 self._input_state = 'buffering'
188 self._cursor = wx.BusyCursor()
193 self._cursor = wx.BusyCursor()
@@ -191,16 +196,18 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
191
196
192 def system_call(self, command_string):
197 def system_call(self, command_string):
193 self._input_state = 'subprocess'
198 self._input_state = 'subprocess'
199 event_loop = wx.EventLoop()
200 def _end_system_call():
201 self._input_state = 'buffering'
202 self._running_process = False
203 event_loop.Exit()
204
194 self._running_process = PipedProcess(command_string,
205 self._running_process = PipedProcess(command_string,
195 out_callback=self.buffered_write,
206 out_callback=self.buffered_write,
196 end_callback = self._end_system_call)
207 end_callback = _end_system_call)
197 self._running_process.start()
208 self._running_process.start()
198 # XXX: another one of these polling loops to have a blocking
209 # XXX: Running a separate event_loop. Ugly.
199 # call
210 event_loop.Run()
200 wx.Yield()
201 while self._running_process:
202 wx.Yield()
203 sleep(0.1)
204 # Be sure to flush the buffer.
211 # Be sure to flush the buffer.
205 self._buffer_flush(event=None)
212 self._buffer_flush(event=None)
206
213
@@ -226,8 +233,9 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
226 for name in symbol_string.split('.')[1:] + ['__doc__']:
233 for name in symbol_string.split('.')[1:] + ['__doc__']:
227 symbol = getattr(symbol, name)
234 symbol = getattr(symbol, name)
228 self.AutoCompCancel()
235 self.AutoCompCancel()
229 wx.Yield()
236 # Check that the symbol can indeed be converted to a string:
230 self.CallTipShow(self.GetCurrentPos(), symbol)
237 symbol += ''
238 wx.CallAfter(self.CallTipShow, self.GetCurrentPos(), symbol)
231 except:
239 except:
232 # The retrieve symbol couldn't be converted to a string
240 # The retrieve symbol couldn't be converted to a string
233 pass
241 pass
@@ -238,9 +246,9 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
238 true, open the menu.
246 true, open the menu.
239 """
247 """
240 if self.debug:
248 if self.debug:
241 print >>sys.__stdout__, "_popup_completion",
249 print >>sys.__stdout__, "_popup_completion"
242 line = self.input_buffer
250 line = self.input_buffer
243 if (self.AutoCompActive() and not line[-1] == '.') \
251 if (self.AutoCompActive() and line and not line[-1] == '.') \
244 or create==True:
252 or create==True:
245 suggestion, completions = self.complete(line)
253 suggestion, completions = self.complete(line)
246 offset=0
254 offset=0
@@ -284,19 +292,21 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
284 if i in self._markers:
292 if i in self._markers:
285 self.MarkerDeleteHandle(self._markers[i])
293 self.MarkerDeleteHandle(self._markers[i])
286 self._markers[i] = self.MarkerAdd(i, _COMPLETE_BUFFER_MARKER)
294 self._markers[i] = self.MarkerAdd(i, _COMPLETE_BUFFER_MARKER)
287 # Update the display:
295 # Use a callafter to update the display robustly under windows
288 wx.Yield()
296 def callback():
289 self.GotoPos(self.GetLength())
297 self.GotoPos(self.GetLength())
290 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
298 PrefilterFrontEnd.execute(self, python_string,
299 raw_string=raw_string)
300 wx.CallAfter(callback)
291
301
292 def save_output_hooks(self):
302 def save_output_hooks(self):
293 self.__old_raw_input = __builtin__.raw_input
303 self.__old_raw_input = __builtin__.raw_input
294 PrefilterFrontEnd.save_output_hooks(self)
304 PrefilterFrontEnd.save_output_hooks(self)
295
305
296 def capture_output(self):
306 def capture_output(self):
297 __builtin__.raw_input = self.raw_input
298 self.SetLexer(stc.STC_LEX_NULL)
307 self.SetLexer(stc.STC_LEX_NULL)
299 PrefilterFrontEnd.capture_output(self)
308 PrefilterFrontEnd.capture_output(self)
309 __builtin__.raw_input = self.raw_input
300
310
301
311
302 def release_output(self):
312 def release_output(self):
@@ -316,7 +326,19 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
316 def show_traceback(self):
326 def show_traceback(self):
317 start_line = self.GetCurrentLine()
327 start_line = self.GetCurrentLine()
318 PrefilterFrontEnd.show_traceback(self)
328 PrefilterFrontEnd.show_traceback(self)
319 wx.Yield()
329 self.ProcessEvent(wx.PaintEvent())
330 #wx.Yield()
331 for i in range(start_line, self.GetCurrentLine()):
332 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
333
334
335 #--------------------------------------------------------------------------
336 # FrontEndBase interface
337 #--------------------------------------------------------------------------
338
339 def render_error(self, e):
340 start_line = self.GetCurrentLine()
341 self.write('\n' + e + '\n')
320 for i in range(start_line, self.GetCurrentLine()):
342 for i in range(start_line, self.GetCurrentLine()):
321 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
343 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
322
344
@@ -351,6 +373,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
351 if self._input_state == 'subprocess':
373 if self._input_state == 'subprocess':
352 if self.debug:
374 if self.debug:
353 print >>sys.__stderr__, 'Killing running process'
375 print >>sys.__stderr__, 'Killing running process'
376 if hasattr(self._running_process, 'process'):
354 self._running_process.process.kill()
377 self._running_process.process.kill()
355 elif self._input_state == 'buffering':
378 elif self._input_state == 'buffering':
356 if self.debug:
379 if self.debug:
@@ -376,7 +399,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
376 char = '\04'
399 char = '\04'
377 self._running_process.process.stdin.write(char)
400 self._running_process.process.stdin.write(char)
378 self._running_process.process.stdin.flush()
401 self._running_process.process.stdin.flush()
379 elif event.KeyCode in (ord('('), 57):
402 elif event.KeyCode in (ord('('), 57, 53):
380 # Calltips
403 # Calltips
381 event.Skip()
404 event.Skip()
382 self.do_calltip()
405 self.do_calltip()
@@ -410,8 +433,8 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
410 self.input_buffer = new_buffer
433 self.input_buffer = new_buffer
411 # Tab-completion
434 # Tab-completion
412 elif event.KeyCode == ord('\t'):
435 elif event.KeyCode == ord('\t'):
413 last_line = self.input_buffer.split('\n')[-1]
436 current_line, current_line_number = self.CurLine
414 if not re.match(r'^\s*$', last_line):
437 if not re.match(r'^\s*$', current_line):
415 self.complete_current_input()
438 self.complete_current_input()
416 if self.AutoCompActive():
439 if self.AutoCompActive():
417 wx.CallAfter(self._popup_completion, create=True)
440 wx.CallAfter(self._popup_completion, create=True)
@@ -427,7 +450,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
427 if event.KeyCode in (59, ord('.')):
450 if event.KeyCode in (59, ord('.')):
428 # Intercepting '.'
451 # Intercepting '.'
429 event.Skip()
452 event.Skip()
430 self._popup_completion(create=True)
453 wx.CallAfter(self._popup_completion, create=True)
431 else:
454 else:
432 ConsoleWidget._on_key_up(self, event, skip=skip)
455 ConsoleWidget._on_key_up(self, event, skip=skip)
433
456
@@ -456,13 +479,6 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
456 # Private API
479 # Private API
457 #--------------------------------------------------------------------------
480 #--------------------------------------------------------------------------
458
481
459 def _end_system_call(self):
460 """ Called at the end of a system call.
461 """
462 self._input_state = 'buffering'
463 self._running_process = False
464
465
466 def _buffer_flush(self, event):
482 def _buffer_flush(self, event):
467 """ Called by the timer to flush the write buffer.
483 """ Called by the timer to flush the write buffer.
468
484
@@ -16,13 +16,6 b' __docformat__ = "restructuredtext en"'
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18
18
19 #-------------------------------------------------------------------------------
20 # Imports
21 #-------------------------------------------------------------------------------
22 import string
23 import uuid
24 import _ast
25
26 try:
19 try:
27 from zope.interface import Interface, Attribute, implements, classProvides
20 from zope.interface import Interface, Attribute, implements, classProvides
28 except ImportError:
21 except ImportError:
@@ -979,6 +979,38 b' def get_home_dir():'
979 else:
979 else:
980 raise HomeDirError,'support for your operating system not implemented.'
980 raise HomeDirError,'support for your operating system not implemented.'
981
981
982
983 def get_ipython_dir():
984 """Get the IPython directory for this platform and user.
985
986 This uses the logic in `get_home_dir` to find the home directory
987 and the adds either .ipython or _ipython to the end of the path.
988 """
989 if os.name == 'posix':
990 ipdir_def = '.ipython'
991 else:
992 ipdir_def = '_ipython'
993 home_dir = get_home_dir()
994 ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
995 os.path.join(home_dir,ipdir_def)))
996 return ipdir
997
998 def get_security_dir():
999 """Get the IPython security directory.
1000
1001 This directory is the default location for all security related files,
1002 including SSL/TLS certificates and FURL files.
1003
1004 If the directory does not exist, it is created with 0700 permissions.
1005 If it exists, permissions are set to 0700.
1006 """
1007 security_dir = os.path.join(get_ipython_dir(), 'security')
1008 if not os.path.isdir(security_dir):
1009 os.mkdir(security_dir, 0700)
1010 else:
1011 os.chmod(security_dir, 0700)
1012 return security_dir
1013
982 #****************************************************************************
1014 #****************************************************************************
983 # strings and text
1015 # strings and text
984
1016
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -8,6 +8,7 b' import os'
8
8
9 # IPython imports
9 # IPython imports
10 from IPython.genutils import Term, ask_yes_no
10 from IPython.genutils import Term, ask_yes_no
11 import IPython.ipapi
11
12
12 def magic_history(self, parameter_s = ''):
13 def magic_history(self, parameter_s = ''):
13 """Print input history (_i<n> variables), with most recent last.
14 """Print input history (_i<n> variables), with most recent last.
@@ -222,6 +223,7 b' class ShadowHist:'
222 # cmd => idx mapping
223 # cmd => idx mapping
223 self.curidx = 0
224 self.curidx = 0
224 self.db = db
225 self.db = db
226 self.disabled = False
225
227
226 def inc_idx(self):
228 def inc_idx(self):
227 idx = self.db.get('shadowhist_idx', 1)
229 idx = self.db.get('shadowhist_idx', 1)
@@ -229,12 +231,19 b' class ShadowHist:'
229 return idx
231 return idx
230
232
231 def add(self, ent):
233 def add(self, ent):
234 if self.disabled:
235 return
236 try:
232 old = self.db.hget('shadowhist', ent, _sentinel)
237 old = self.db.hget('shadowhist', ent, _sentinel)
233 if old is not _sentinel:
238 if old is not _sentinel:
234 return
239 return
235 newidx = self.inc_idx()
240 newidx = self.inc_idx()
236 #print "new",newidx # dbg
241 #print "new",newidx # dbg
237 self.db.hset('shadowhist',ent, newidx)
242 self.db.hset('shadowhist',ent, newidx)
243 except:
244 IPython.ipapi.get().IP.showtraceback()
245 print "WARNING: disabling shadow history"
246 self.disabled = True
238
247
239 def all(self):
248 def all(self):
240 d = self.db.hdict('shadowhist')
249 d = self.db.hdict('shadowhist')
@@ -25,7 +25,8 b' ip = IPython.ipapi.get()'
25 def calljed(self,filename, linenum):
25 def calljed(self,filename, linenum):
26 "My editor hook calls the jed editor directly."
26 "My editor hook calls the jed editor directly."
27 print "Calling my own editor, jed ..."
27 print "Calling my own editor, jed ..."
28 os.system('jed +%d %s' % (linenum,filename))
28 if os.system('jed +%d %s' % (linenum,filename)) != 0:
29 raise ipapi.TryNext()
29
30
30 ip.set_hook('editor', calljed)
31 ip.set_hook('editor', calljed)
31
32
@@ -84,7 +85,8 b' def editor(self,filename, linenum=None):'
84 editor = '"%s"' % editor
85 editor = '"%s"' % editor
85
86
86 # Call the actual editor
87 # Call the actual editor
87 os.system('%s %s %s' % (editor,linemark,filename))
88 if os.system('%s %s %s' % (editor,linemark,filename)) != 0:
89 raise ipapi.TryNext()
88
90
89 import tempfile
91 import tempfile
90 def fix_error_editor(self,filename,linenum,column,msg):
92 def fix_error_editor(self,filename,linenum,column,msg):
@@ -105,7 +107,8 b' def fix_error_editor(self,filename,linenum,column,msg):'
105 return
107 return
106 t = vim_quickfix_file()
108 t = vim_quickfix_file()
107 try:
109 try:
108 os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name)
110 if os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name):
111 raise ipapi.TryNext()
109 finally:
112 finally:
110 t.close()
113 t.close()
111
114
@@ -1419,8 +1419,12 b' want to merge them back into the new files.""" % locals()'
1419 except TypeError:
1419 except TypeError:
1420 return 0
1420 return 0
1421 # always pass integer line and offset values to editor hook
1421 # always pass integer line and offset values to editor hook
1422 try:
1422 self.hooks.fix_error_editor(e.filename,
1423 self.hooks.fix_error_editor(e.filename,
1423 int0(e.lineno),int0(e.offset),e.msg)
1424 int0(e.lineno),int0(e.offset),e.msg)
1425 except IPython.ipapi.TryNext:
1426 warn('Could not open editor')
1427 return False
1424 return True
1428 return True
1425
1429
1426 def edit_syntax_error(self):
1430 def edit_syntax_error(self):
@@ -1572,6 +1576,11 b' want to merge them back into the new files.""" % locals()'
1572 else:
1576 else:
1573 banner = self.BANNER+self.banner2
1577 banner = self.BANNER+self.banner2
1574
1578
1579 # if you run stuff with -c <cmd>, raw hist is not updated
1580 # ensure that it's in sync
1581 if len(self.input_hist) != len (self.input_hist_raw):
1582 self.input_hist_raw = InputList(self.input_hist)
1583
1575 while 1:
1584 while 1:
1576 try:
1585 try:
1577 self.interact(banner)
1586 self.interact(banner)
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -15,17 +15,15 b' __docformat__ = "restructuredtext en"'
15 # Imports
15 # Imports
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 from os.path import join as pjoin
19
18 from IPython.external.configobj import ConfigObj
20 from IPython.external.configobj import ConfigObj
19 from IPython.config.api import ConfigObjManager
21 from IPython.config.api import ConfigObjManager
20 from IPython.config.cutils import get_ipython_dir
22 from IPython.genutils import get_ipython_dir, get_security_dir
21
23
22 default_kernel_config = ConfigObj()
24 default_kernel_config = ConfigObj()
23
25
24 try:
26 security_dir = get_security_dir()
25 ipython_dir = get_ipython_dir() + '/'
26 except:
27 # This will defaults to the cwd
28 ipython_dir = ''
29
27
30 #-------------------------------------------------------------------------------
28 #-------------------------------------------------------------------------------
31 # Engine Configuration
29 # Engine Configuration
@@ -33,7 +31,7 b' except:'
33
31
34 engine_config = dict(
32 engine_config = dict(
35 logfile = '', # Empty means log to stdout
33 logfile = '', # Empty means log to stdout
36 furl_file = ipython_dir + 'ipcontroller-engine.furl'
34 furl_file = pjoin(security_dir, 'ipcontroller-engine.furl')
37 )
35 )
38
36
39 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
@@ -63,16 +61,17 b' controller_config = dict('
63
61
64 logfile = '', # Empty means log to stdout
62 logfile = '', # Empty means log to stdout
65 import_statement = '',
63 import_statement = '',
64 reuse_furls = False, # If False, old furl files are deleted
66
65
67 engine_tub = dict(
66 engine_tub = dict(
68 ip = '', # Empty string means all interfaces
67 ip = '', # Empty string means all interfaces
69 port = 0, # 0 means pick a port for me
68 port = 0, # 0 means pick a port for me
70 location = '', # Empty string means try to set automatically
69 location = '', # Empty string means try to set automatically
71 secure = True,
70 secure = True,
72 cert_file = ipython_dir + 'ipcontroller-engine.pem',
71 cert_file = pjoin(security_dir, 'ipcontroller-engine.pem'),
73 ),
72 ),
74 engine_fc_interface = 'IPython.kernel.enginefc.IFCControllerBase',
73 engine_fc_interface = 'IPython.kernel.enginefc.IFCControllerBase',
75 engine_furl_file = ipython_dir + 'ipcontroller-engine.furl',
74 engine_furl_file = pjoin(security_dir, 'ipcontroller-engine.furl'),
76
75
77 controller_interfaces = dict(
76 controller_interfaces = dict(
78 # multiengine = dict(
77 # multiengine = dict(
@@ -83,12 +82,12 b' controller_config = dict('
83 task = dict(
82 task = dict(
84 controller_interface = 'IPython.kernel.task.ITaskController',
83 controller_interface = 'IPython.kernel.task.ITaskController',
85 fc_interface = 'IPython.kernel.taskfc.IFCTaskController',
84 fc_interface = 'IPython.kernel.taskfc.IFCTaskController',
86 furl_file = ipython_dir + 'ipcontroller-tc.furl'
85 furl_file = pjoin(security_dir, 'ipcontroller-tc.furl')
87 ),
86 ),
88 multiengine = dict(
87 multiengine = dict(
89 controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
88 controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
90 fc_interface = 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine',
89 fc_interface = 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine',
91 furl_file = ipython_dir + 'ipcontroller-mec.furl'
90 furl_file = pjoin(security_dir, 'ipcontroller-mec.furl')
92 )
91 )
93 ),
92 ),
94
93
@@ -97,7 +96,7 b' controller_config = dict('
97 port = 0, # 0 means pick a port for me
96 port = 0, # 0 means pick a port for me
98 location = '', # Empty string means try to set automatically
97 location = '', # Empty string means try to set automatically
99 secure = True,
98 secure = True,
100 cert_file = ipython_dir + 'ipcontroller-client.pem'
99 cert_file = pjoin(security_dir, 'ipcontroller-client.pem')
101 )
100 )
102 )
101 )
103
102
@@ -108,10 +107,10 b' controller_config = dict('
108 client_config = dict(
107 client_config = dict(
109 client_interfaces = dict(
108 client_interfaces = dict(
110 task = dict(
109 task = dict(
111 furl_file = ipython_dir + 'ipcontroller-tc.furl'
110 furl_file = pjoin(security_dir, 'ipcontroller-tc.furl')
112 ),
111 ),
113 multiengine = dict(
112 multiengine = dict(
114 furl_file = ipython_dir + 'ipcontroller-mec.furl'
113 furl_file = pjoin(security_dir, 'ipcontroller-mec.furl')
115 )
114 )
116 )
115 )
117 )
116 )
@@ -8,8 +8,6 b' which can also be useful as templates for writing new, application-specific'
8 managers.
8 managers.
9 """
9 """
10
10
11 from __future__ import with_statement
12
13 __docformat__ = "restructuredtext en"
11 __docformat__ = "restructuredtext en"
14
12
15 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
@@ -50,7 +50,7 b' from IPython.kernel.engineservice import \\'
50 IEngineSerialized, \
50 IEngineSerialized, \
51 IEngineQueued
51 IEngineQueued
52
52
53 from IPython.config import cutils
53 from IPython.genutils import get_ipython_dir
54 from IPython.kernel import codeutil
54 from IPython.kernel import codeutil
55
55
56 #-------------------------------------------------------------------------------
56 #-------------------------------------------------------------------------------
@@ -170,7 +170,7 b' class ControllerService(object, service.Service):'
170
170
171 def _getEngineInfoLogFile(self):
171 def _getEngineInfoLogFile(self):
172 # Store all logs inside the ipython directory
172 # Store all logs inside the ipython directory
173 ipdir = cutils.get_ipython_dir()
173 ipdir = get_ipython_dir()
174 pjoin = os.path.join
174 pjoin = os.path.join
175 logdir_base = pjoin(ipdir,'log')
175 logdir_base = pjoin(ipdir,'log')
176 if not os.path.isdir(logdir_base):
176 if not os.path.isdir(logdir_base):
@@ -680,6 +680,13 b' class Interpreter(object):'
680 # how trailing whitespace is handled, but this seems to work.
680 # how trailing whitespace is handled, but this seems to work.
681 python = python.strip()
681 python = python.strip()
682
682
683 # The compiler module does not like unicode. We need to convert
684 # it encode it:
685 if isinstance(python, unicode):
686 # Use the utf-8-sig BOM so the compiler detects this a UTF-8
687 # encode string.
688 python = '\xef\xbb\xbf' + python.encode('utf-8')
689
683 # The compiler module will parse the code into an abstract syntax tree.
690 # The compiler module will parse the code into an abstract syntax tree.
684 ast = compiler.parse(python)
691 ast = compiler.parse(python)
685
692
@@ -13,10 +13,17 b' __docformat__ = "restructuredtext en"'
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15
15
16 # Stdlib imports
16 import os
17 import os
17 from cStringIO import StringIO
18 from cStringIO import StringIO
18
19
20 # Our own imports
21 from IPython.testing import decorators as dec
19
22
23 #-----------------------------------------------------------------------------
24 # Test functions
25
26 @dec.skip_win32
20 def test_redirector():
27 def test_redirector():
21 """ Checks that the redirector can be used to do synchronous capture.
28 """ Checks that the redirector can be used to do synchronous capture.
22 """
29 """
@@ -33,9 +40,12 b' def test_redirector():'
33 r.stop()
40 r.stop()
34 raise
41 raise
35 r.stop()
42 r.stop()
36 assert out.getvalue() == "".join("%ic\n%i\n" %(i, i) for i in range(10))
43 result1 = out.getvalue()
44 result2 = "".join("%ic\n%i\n" %(i, i) for i in range(10))
45 assert result1 == result2
37
46
38
47
48 @dec.skip_win32
39 def test_redirector_output_trap():
49 def test_redirector_output_trap():
40 """ This test check not only that the redirector_output_trap does
50 """ This test check not only that the redirector_output_trap does
41 trap the output, but also that it does it in a gready way, that
51 trap the output, but also that it does it in a gready way, that
@@ -54,8 +64,7 b' def test_redirector_output_trap():'
54 trap.unset()
64 trap.unset()
55 raise
65 raise
56 trap.unset()
66 trap.unset()
57 assert out.getvalue() == "".join("%ic\n%ip\n%i\n" %(i, i, i)
67 result1 = out.getvalue()
58 for i in range(10))
68 result2 = "".join("%ic\n%ip\n%i\n" %(i, i, i) for i in range(10))
59
69 assert result1 == result2
60
61
70
@@ -18,7 +18,8 b' __docformat__ = "restructuredtext en"'
18 import os
18 import os
19 import cPickle as pickle
19 import cPickle as pickle
20
20
21 from twisted.python import log
21 from twisted.python import log, failure
22 from twisted.internet import defer
22
23
23 from IPython.kernel.fcutil import find_furl
24 from IPython.kernel.fcutil import find_furl
24 from IPython.kernel.enginefc import IFCEngine
25 from IPython.kernel.enginefc import IFCEngine
@@ -62,13 +63,17 b' class EngineConnector(object):'
62 self.tub.startService()
63 self.tub.startService()
63 self.engine_service = engine_service
64 self.engine_service = engine_service
64 self.engine_reference = IFCEngine(self.engine_service)
65 self.engine_reference = IFCEngine(self.engine_service)
66 try:
65 self.furl = find_furl(furl_or_file)
67 self.furl = find_furl(furl_or_file)
68 except ValueError:
69 return defer.fail(failure.Failure())
70 # return defer.fail(failure.Failure(ValueError('not a valid furl or furl file: %r' % furl_or_file)))
66 d = self.tub.getReference(self.furl)
71 d = self.tub.getReference(self.furl)
67 d.addCallbacks(self._register, self._log_failure)
72 d.addCallbacks(self._register, self._log_failure)
68 return d
73 return d
69
74
70 def _log_failure(self, reason):
75 def _log_failure(self, reason):
71 log.err('engine registration failed:')
76 log.err('EngineConnector: engine registration failed:')
72 log.err(reason)
77 log.err(reason)
73 return reason
78 return reason
74
79
This diff has been collapsed as it changes many lines, (722 lines changed) Show them Hide them
@@ -1,324 +1,486 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 """Start an IPython cluster conveniently, either locally or remotely.
4 """Start an IPython cluster = (controller + engines)."""
5
5
6 Basic usage
6 #-----------------------------------------------------------------------------
7 -----------
8
9 For local operation, the simplest mode of usage is:
10
11 %prog -n N
12
13 where N is the number of engines you want started.
14
15 For remote operation, you must call it with a cluster description file:
16
17 %prog -f clusterfile.py
18
19 The cluster file is a normal Python script which gets run via execfile(). You
20 can have arbitrary logic in it, but all that matters is that at the end of the
21 execution, it declares the variables 'controller', 'engines', and optionally
22 'sshx'. See the accompanying examples for details on what these variables must
23 contain.
24
25
26 Notes
27 -----
28
29 WARNING: this code is still UNFINISHED and EXPERIMENTAL! It is incomplete,
30 some listed options are not really implemented, and all of its interfaces are
31 subject to change.
32
33 When operating over SSH for a remote cluster, this program relies on the
34 existence of a particular script called 'sshx'. This script must live in the
35 target systems where you'll be running your controller and engines, and is
36 needed to configure your PATH and PYTHONPATH variables for further execution of
37 python code at the other end of an SSH connection. The script can be as simple
38 as:
39
40 #!/bin/sh
41 . $HOME/.bashrc
42 "$@"
43
44 which is the default one provided by IPython. You can modify this or provide
45 your own. Since it's quite likely that for different clusters you may need
46 this script to configure things differently or that it may live in different
47 locations, its full path can be set in the same file where you define the
48 cluster setup. IPython's order of evaluation for this variable is the
49 following:
50
51 a) Internal default: 'sshx'. This only works if it is in the default system
52 path which SSH sets up in non-interactive mode.
53
54 b) Environment variable: if $IPYTHON_SSHX is defined, this overrides the
55 internal default.
56
57 c) Variable 'sshx' in the cluster configuration file: finally, this will
58 override the previous two values.
59
60 This code is Unix-only, with precious little hope of any of this ever working
61 under Windows, since we need SSH from the ground up, we background processes,
62 etc. Ports of this functionality to Windows are welcome.
63
64
65 Call summary
66 ------------
67
68 %prog [options]
69 """
70
71 __docformat__ = "restructuredtext en"
72
73 #-------------------------------------------------------------------------------
74 # Copyright (C) 2008 The IPython Development Team
7 # Copyright (C) 2008 The IPython Development Team
75 #
8 #
76 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
77 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
78 #-------------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
79
12
80 #-------------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
81 # Stdlib imports
14 # Imports
82 #-------------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
83
16
84 import os
17 import os
85 import signal
18 import re
86 import sys
19 import sys
87 import time
20 import signal
88
21 pjoin = os.path.join
89 from optparse import OptionParser
90 from subprocess import Popen,call
91
22
92 #---------------------------------------------------------------------------
23 from twisted.internet import reactor, defer
93 # IPython imports
24 from twisted.internet.protocol import ProcessProtocol
94 #---------------------------------------------------------------------------
25 from twisted.python import failure, log
95 from IPython.tools import utils
26 from twisted.internet.error import ProcessDone, ProcessTerminated
96 from IPython.config import cutils
27 from twisted.internet.utils import getProcessOutput
97
28
98 #---------------------------------------------------------------------------
29 from IPython.external import argparse
99 # Normal code begins
30 from IPython.external import Itpl
100 #---------------------------------------------------------------------------
31 from IPython.kernel.twistedutil import gatherBoth
32 from IPython.kernel.util import printer
33 from IPython.genutils import get_ipython_dir, num_cpus
101
34
102 def parse_args():
35 #-----------------------------------------------------------------------------
103 """Parse command line and return opts,args."""
36 # General process handling code
37 #-----------------------------------------------------------------------------
104
38
105 parser = OptionParser(usage=__doc__)
39 def find_exe(cmd):
106 newopt = parser.add_option # shorthand
40 try:
41 import win32api
42 except ImportError:
43 raise ImportError('you need to have pywin32 installed for this to work')
44 else:
45 (path, offest) = win32api.SearchPath(os.environ['PATH'],cmd)
46 return path
107
47
108 newopt("--controller-port", type="int", dest="controllerport",
48 class ProcessStateError(Exception):
109 help="the TCP port the controller is listening on")
49 pass
110
50
111 newopt("--controller-ip", type="string", dest="controllerip",
51 class UnknownStatus(Exception):
112 help="the TCP ip address of the controller")
52 pass
113
53
114 newopt("-n", "--num", type="int", dest="n",default=2,
54 class LauncherProcessProtocol(ProcessProtocol):
115 help="the number of engines to start")
55 """
56 A ProcessProtocol to go with the ProcessLauncher.
57 """
58 def __init__(self, process_launcher):
59 self.process_launcher = process_launcher
60
61 def connectionMade(self):
62 self.process_launcher.fire_start_deferred(self.transport.pid)
63
64 def processEnded(self, status):
65 value = status.value
66 if isinstance(value, ProcessDone):
67 self.process_launcher.fire_stop_deferred(0)
68 elif isinstance(value, ProcessTerminated):
69 self.process_launcher.fire_stop_deferred(
70 {'exit_code':value.exitCode,
71 'signal':value.signal,
72 'status':value.status
73 }
74 )
75 else:
76 raise UnknownStatus("unknown exit status, this is probably a bug in Twisted")
116
77
117 newopt("--engine-port", type="int", dest="engineport",
78 def outReceived(self, data):
118 help="the TCP port the controller will listen on for engine "
79 log.msg(data)
119 "connections")
120
80
121 newopt("--engine-ip", type="string", dest="engineip",
81 def errReceived(self, data):
122 help="the TCP ip address the controller will listen on "
82 log.err(data)
123 "for engine connections")
124
83
125 newopt("--mpi", type="string", dest="mpi",
84 class ProcessLauncher(object):
126 help="use mpi with package: for instance --mpi=mpi4py")
85 """
86 Start and stop an external process in an asynchronous manner.
127
87
128 newopt("-l", "--logfile", type="string", dest="logfile",
88 Currently this uses deferreds to notify other parties of process state
129 help="log file name")
89 changes. This is an awkward design and should be moved to using
90 a formal NotificationCenter.
91 """
92 def __init__(self, cmd_and_args):
93 self.cmd = cmd_and_args[0]
94 self.args = cmd_and_args
95 self._reset()
96
97 def _reset(self):
98 self.process_protocol = None
99 self.pid = None
100 self.start_deferred = None
101 self.stop_deferreds = []
102 self.state = 'before' # before, running, or after
103
104 @property
105 def running(self):
106 if self.state == 'running':
107 return True
108 else:
109 return False
110
111 def fire_start_deferred(self, pid):
112 self.pid = pid
113 self.state = 'running'
114 log.msg('Process %r has started with pid=%i' % (self.args, pid))
115 self.start_deferred.callback(pid)
116
117 def start(self):
118 if self.state == 'before':
119 self.process_protocol = LauncherProcessProtocol(self)
120 self.start_deferred = defer.Deferred()
121 self.process_transport = reactor.spawnProcess(
122 self.process_protocol,
123 self.cmd,
124 self.args,
125 env=os.environ
126 )
127 return self.start_deferred
128 else:
129 s = 'the process has already been started and has state: %r' % \
130 self.state
131 return defer.fail(ProcessStateError(s))
132
133 def get_stop_deferred(self):
134 if self.state == 'running' or self.state == 'before':
135 d = defer.Deferred()
136 self.stop_deferreds.append(d)
137 return d
138 else:
139 s = 'this process is already complete'
140 return defer.fail(ProcessStateError(s))
130
141
131 newopt('-f','--cluster-file',dest='clusterfile',
142 def fire_stop_deferred(self, exit_code):
132 help='file describing a remote cluster')
143 log.msg('Process %r has stopped with %r' % (self.args, exit_code))
144 self.state = 'after'
145 for d in self.stop_deferreds:
146 d.callback(exit_code)
133
147
134 return parser.parse_args()
148 def signal(self, sig):
149 """
150 Send a signal to the process.
135
151
136 def numAlive(controller,engines):
152 The argument sig can be ('KILL','INT', etc.) or any signal number.
137 """Return the number of processes still alive."""
153 """
138 retcodes = [controller.poll()] + \
154 if self.state == 'running':
139 [e.poll() for e in engines]
155 self.process_transport.signalProcess(sig)
140 return retcodes.count(None)
141
156
142 stop = lambda pid: os.kill(pid,signal.SIGINT)
157 # def __del__(self):
143 kill = lambda pid: os.kill(pid,signal.SIGTERM)
158 # self.signal('KILL')
144
159
145 def cleanup(clean,controller,engines):
160 def interrupt_then_kill(self, delay=1.0):
146 """Stop the controller and engines with the given cleanup method."""
161 self.signal('INT')
162 reactor.callLater(delay, self.signal, 'KILL')
147
163
148 for e in engines:
149 if e.poll() is None:
150 print 'Stopping engine, pid',e.pid
151 clean(e.pid)
152 if controller.poll() is None:
153 print 'Stopping controller, pid',controller.pid
154 clean(controller.pid)
155
164
165 #-----------------------------------------------------------------------------
166 # Code for launching controller and engines
167 #-----------------------------------------------------------------------------
156
168
157 def ensureDir(path):
158 """Ensure a directory exists or raise an exception."""
159 if not os.path.isdir(path):
160 os.makedirs(path)
161
169
170 class ControllerLauncher(ProcessLauncher):
162
171
163 def startMsg(control_host,control_port=10105):
172 def __init__(self, extra_args=None):
164 """Print a startup message"""
173 if sys.platform == 'win32':
165 print
174 args = [find_exe('ipcontroller.bat')]
166 print 'Your cluster is up and running.'
175 else:
167 print
176 args = ['ipcontroller']
168 print 'For interactive use, you can make a MultiEngineClient with:'
177 self.extra_args = extra_args
169 print
178 if extra_args is not None:
170 print 'from IPython.kernel import client'
179 args.extend(extra_args)
171 print "mec = client.MultiEngineClient()"
172 print
173 print 'You can then cleanly stop the cluster from IPython using:'
174 print
175 print 'mec.kill(controller=True)'
176 print
177
180
181 ProcessLauncher.__init__(self, args)
178
182
179 def clusterLocal(opt,arg):
180 """Start a cluster on the local machine."""
181
183
182 # Store all logs inside the ipython directory
184 class EngineLauncher(ProcessLauncher):
183 ipdir = cutils.get_ipython_dir()
184 pjoin = os.path.join
185
185
186 logfile = opt.logfile
186 def __init__(self, extra_args=None):
187 if logfile is None:
187 if sys.platform == 'win32':
188 logdir_base = pjoin(ipdir,'log')
188 args = [find_exe('ipengine.bat')]
189 ensureDir(logdir_base)
190 logfile = pjoin(logdir_base,'ipcluster-')
191
192 print 'Starting controller:',
193 controller = Popen(['ipcontroller','--logfile',logfile,'-x','-y'])
194 print 'Controller PID:',controller.pid
195
196 print 'Starting engines: ',
197 time.sleep(5)
198
199 englogfile = '%s%s-' % (logfile,controller.pid)
200 mpi = opt.mpi
201 if mpi: # start with mpi - killing the engines with sigterm will not work if you do this
202 engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi',
203 mpi, '--logfile',englogfile])]
204 # engines = [Popen(['mpirun', '-np', str(opt.n), 'ipengine', '--mpi', mpi])]
205 else: # do what we would normally do
206 engines = [ Popen(['ipengine','--logfile',englogfile])
207 for i in range(opt.n) ]
208 eids = [e.pid for e in engines]
209 print 'Engines PIDs: ',eids
210 print 'Log files: %s*' % englogfile
211
212 proc_ids = eids + [controller.pid]
213 procs = engines + [controller]
214
215 grpid = os.getpgrp()
216 try:
217 startMsg('127.0.0.1')
218 print 'You can also hit Ctrl-C to stop it, or use from the cmd line:'
219 print
220 print 'kill -INT',grpid
221 print
222 try:
223 while True:
224 time.sleep(5)
225 except:
226 pass
227 finally:
228 print 'Stopping cluster. Cleaning up...'
229 cleanup(stop,controller,engines)
230 for i in range(4):
231 time.sleep(i+2)
232 nZombies = numAlive(controller,engines)
233 if nZombies== 0:
234 print 'OK: All processes cleaned up.'
235 break
236 print 'Trying again, %d processes did not stop...' % nZombies
237 cleanup(kill,controller,engines)
238 if numAlive(controller,engines) == 0:
239 print 'OK: All processes cleaned up.'
240 break
241 else:
189 else:
242 print '*'*75
190 args = ['ipengine']
243 print 'ERROR: could not kill some processes, try to do it',
191 self.extra_args = extra_args
244 print 'manually.'
192 if extra_args is not None:
245 zombies = []
193 args.extend(extra_args)
246 if controller.returncode is None:
194
247 print 'Controller is alive: pid =',controller.pid
195 ProcessLauncher.__init__(self, args)
248 zombies.append(controller.pid)
196
249 liveEngines = [ e for e in engines if e.returncode is None ]
197
250 for e in liveEngines:
198 class LocalEngineSet(object):
251 print 'Engine is alive: pid =',e.pid
199
252 zombies.append(e.pid)
200 def __init__(self, extra_args=None):
253 print
201 self.extra_args = extra_args
254 print 'Zombie summary:',' '.join(map(str,zombies))
202 self.launchers = []
255
203
256 def clusterRemote(opt,arg):
204 def start(self, n):
257 """Start a remote cluster over SSH"""
205 dlist = []
258
206 for i in range(n):
259 # Load the remote cluster configuration
207 el = EngineLauncher(extra_args=self.extra_args)
260 clConfig = {}
208 d = el.start()
261 execfile(opt.clusterfile,clConfig)
209 self.launchers.append(el)
262 contConfig = clConfig['controller']
210 dlist.append(d)
263 engConfig = clConfig['engines']
211 dfinal = gatherBoth(dlist, consumeErrors=True)
264 # Determine where to find sshx:
212 dfinal.addCallback(self._handle_start)
265 sshx = clConfig.get('sshx',os.environ.get('IPYTHON_SSHX','sshx'))
213 return dfinal
266
214
267 # Store all logs inside the ipython directory
215 def _handle_start(self, r):
268 ipdir = cutils.get_ipython_dir()
216 log.msg('Engines started with pids: %r' % r)
269 pjoin = os.path.join
217 return r
270
218
271 logfile = opt.logfile
219 def _handle_stop(self, r):
272 if logfile is None:
220 log.msg('Engines received signal: %r' % r)
273 logdir_base = pjoin(ipdir,'log')
221 return r
274 ensureDir(logdir_base)
222
275 logfile = pjoin(logdir_base,'ipcluster')
223 def signal(self, sig):
276
224 dlist = []
277 # Append this script's PID to the logfile name always
225 for el in self.launchers:
278 logfile = '%s-%s' % (logfile,os.getpid())
226 d = el.get_stop_deferred()
279
227 dlist.append(d)
280 print 'Starting controller:'
228 el.signal(sig)
281 # Controller data:
229 dfinal = gatherBoth(dlist, consumeErrors=True)
282 xsys = os.system
230 dfinal.addCallback(self._handle_stop)
283
231 return dfinal
284 contHost = contConfig['host']
232
285 contLog = '%s-con-%s-' % (logfile,contHost)
233 def interrupt_then_kill(self, delay=1.0):
286 cmd = "ssh %s '%s' 'ipcontroller --logfile %s' &" % \
234 dlist = []
287 (contHost,sshx,contLog)
235 for el in self.launchers:
288 #print 'cmd:<%s>' % cmd # dbg
236 d = el.get_stop_deferred()
289 xsys(cmd)
237 dlist.append(d)
290 time.sleep(2)
238 el.interrupt_then_kill(delay)
291
239 dfinal = gatherBoth(dlist, consumeErrors=True)
292 print 'Starting engines: '
240 dfinal.addCallback(self._handle_stop)
293 for engineHost,engineData in engConfig.iteritems():
241 return dfinal
294 if isinstance(engineData,int):
242
295 numEngines = engineData
243
244 class BatchEngineSet(object):
245
246 # Subclasses must fill these in. See PBSEngineSet
247 submit_command = ''
248 delete_command = ''
249 job_id_regexp = ''
250
251 def __init__(self, template_file, **kwargs):
252 self.template_file = template_file
253 self.context = {}
254 self.context.update(kwargs)
255 self.batch_file = self.template_file+'-run'
256
257 def parse_job_id(self, output):
258 m = re.match(self.job_id_regexp, output)
259 if m is not None:
260 job_id = m.group()
296 else:
261 else:
297 raise NotImplementedError('port configuration not finished for engines')
262 raise Exception("job id couldn't be determined: %s" % output)
298
263 self.job_id = job_id
299 print 'Sarting %d engines on %s' % (numEngines,engineHost)
264 log.msg('Job started with job id: %r' % job_id)
300 engLog = '%s-eng-%s-' % (logfile,engineHost)
265 return job_id
301 for i in range(numEngines):
266
302 cmd = "ssh %s '%s' 'ipengine --controller-ip %s --logfile %s' &" % \
267 def write_batch_script(self, n):
303 (engineHost,sshx,contHost,engLog)
268 self.context['n'] = n
304 #print 'cmd:<%s>' % cmd # dbg
269 template = open(self.template_file, 'r').read()
305 xsys(cmd)
270 log.msg('Using template for batch script: %s' % self.template_file)
306 # Wait after each host a little bit
271 script_as_string = Itpl.itplns(template, self.context)
307 time.sleep(1)
272 log.msg('Writing instantiated batch script: %s' % self.batch_file)
308
273 f = open(self.batch_file,'w')
309 startMsg(contConfig['host'])
274 f.write(script_as_string)
275 f.close()
276
277 def handle_error(self, f):
278 f.printTraceback()
279 f.raiseException()
280
281 def start(self, n):
282 self.write_batch_script(n)
283 d = getProcessOutput(self.submit_command,
284 [self.batch_file],env=os.environ)
285 d.addCallback(self.parse_job_id)
286 d.addErrback(self.handle_error)
287 return d
288
289 def kill(self):
290 d = getProcessOutput(self.delete_command,
291 [self.job_id],env=os.environ)
292 return d
293
294 class PBSEngineSet(BatchEngineSet):
295
296 submit_command = 'qsub'
297 delete_command = 'qdel'
298 job_id_regexp = '\d+'
299
300 def __init__(self, template_file, **kwargs):
301 BatchEngineSet.__init__(self, template_file, **kwargs)
302
303
304 #-----------------------------------------------------------------------------
305 # Main functions for the different types of clusters
306 #-----------------------------------------------------------------------------
307
308 # TODO:
309 # The logic in these codes should be moved into classes like LocalCluster
310 # MpirunCluster, PBSCluster, etc. This would remove alot of the duplications.
311 # The main functions should then just parse the command line arguments, create
312 # the appropriate class and call a 'start' method.
313
314 def main_local(args):
315 cont_args = []
316 cont_args.append('--logfile=%s' % pjoin(args.logdir,'ipcontroller'))
317 if args.x:
318 cont_args.append('-x')
319 if args.y:
320 cont_args.append('-y')
321 cl = ControllerLauncher(extra_args=cont_args)
322 dstart = cl.start()
323 def start_engines(cont_pid):
324 engine_args = []
325 engine_args.append('--logfile=%s' % \
326 pjoin(args.logdir,'ipengine%s-' % cont_pid))
327 eset = LocalEngineSet(extra_args=engine_args)
328 def shutdown(signum, frame):
329 log.msg('Stopping local cluster')
330 # We are still playing with the times here, but these seem
331 # to be reliable in allowing everything to exit cleanly.
332 eset.interrupt_then_kill(0.5)
333 cl.interrupt_then_kill(0.5)
334 reactor.callLater(1.0, reactor.stop)
335 signal.signal(signal.SIGINT,shutdown)
336 d = eset.start(args.n)
337 return d
338 def delay_start(cont_pid):
339 # This is needed because the controller doesn't start listening
340 # right when it starts and the controller needs to write
341 # furl files for the engine to pick up
342 reactor.callLater(1.0, start_engines, cont_pid)
343 dstart.addCallback(delay_start)
344 dstart.addErrback(lambda f: f.raiseException())
345
346 def main_mpirun(args):
347 cont_args = []
348 cont_args.append('--logfile=%s' % pjoin(args.logdir,'ipcontroller'))
349 if args.x:
350 cont_args.append('-x')
351 if args.y:
352 cont_args.append('-y')
353 cl = ControllerLauncher(extra_args=cont_args)
354 dstart = cl.start()
355 def start_engines(cont_pid):
356 raw_args = ['mpirun']
357 raw_args.extend(['-n',str(args.n)])
358 raw_args.append('ipengine')
359 raw_args.append('-l')
360 raw_args.append(pjoin(args.logdir,'ipengine%s-' % cont_pid))
361 if args.mpi:
362 raw_args.append('--mpi=%s' % args.mpi)
363 eset = ProcessLauncher(raw_args)
364 def shutdown(signum, frame):
365 log.msg('Stopping local cluster')
366 # We are still playing with the times here, but these seem
367 # to be reliable in allowing everything to exit cleanly.
368 eset.interrupt_then_kill(1.0)
369 cl.interrupt_then_kill(1.0)
370 reactor.callLater(2.0, reactor.stop)
371 signal.signal(signal.SIGINT,shutdown)
372 d = eset.start()
373 return d
374 def delay_start(cont_pid):
375 # This is needed because the controller doesn't start listening
376 # right when it starts and the controller needs to write
377 # furl files for the engine to pick up
378 reactor.callLater(1.0, start_engines, cont_pid)
379 dstart.addCallback(delay_start)
380 dstart.addErrback(lambda f: f.raiseException())
381
382 def main_pbs(args):
383 cont_args = []
384 cont_args.append('--logfile=%s' % pjoin(args.logdir,'ipcontroller'))
385 if args.x:
386 cont_args.append('-x')
387 if args.y:
388 cont_args.append('-y')
389 cl = ControllerLauncher(extra_args=cont_args)
390 dstart = cl.start()
391 def start_engines(r):
392 pbs_set = PBSEngineSet(args.pbsscript)
393 def shutdown(signum, frame):
394 log.msg('Stopping pbs cluster')
395 d = pbs_set.kill()
396 d.addBoth(lambda _: cl.interrupt_then_kill(1.0))
397 d.addBoth(lambda _: reactor.callLater(2.0, reactor.stop))
398 signal.signal(signal.SIGINT,shutdown)
399 d = pbs_set.start(args.n)
400 return d
401 dstart.addCallback(start_engines)
402 dstart.addErrback(lambda f: f.raiseException())
403
404
405 def get_args():
406 base_parser = argparse.ArgumentParser(add_help=False)
407 base_parser.add_argument(
408 '-x',
409 action='store_true',
410 dest='x',
411 help='turn off client security'
412 )
413 base_parser.add_argument(
414 '-y',
415 action='store_true',
416 dest='y',
417 help='turn off engine security'
418 )
419 base_parser.add_argument(
420 "--logdir",
421 type=str,
422 dest="logdir",
423 help="directory to put log files (default=$IPYTHONDIR/log)",
424 default=pjoin(get_ipython_dir(),'log')
425 )
426 base_parser.add_argument(
427 "-n",
428 "--num",
429 type=int,
430 dest="n",
431 default=2,
432 help="the number of engines to start"
433 )
434
435 parser = argparse.ArgumentParser(
436 description='IPython cluster startup. This starts a controller and\
437 engines using various approaches. THIS IS A TECHNOLOGY PREVIEW AND\
438 THE API WILL CHANGE SIGNIFICANTLY BEFORE THE FINAL RELEASE.'
439 )
440 subparsers = parser.add_subparsers(
441 help='available cluster types. For help, do "ipcluster TYPE --help"')
442
443 parser_local = subparsers.add_parser(
444 'local',
445 help='run a local cluster',
446 parents=[base_parser]
447 )
448 parser_local.set_defaults(func=main_local)
449
450 parser_mpirun = subparsers.add_parser(
451 'mpirun',
452 help='run a cluster using mpirun',
453 parents=[base_parser]
454 )
455 parser_mpirun.add_argument(
456 "--mpi",
457 type=str,
458 dest="mpi", # Don't put a default here to allow no MPI support
459 help="how to call MPI_Init (default=mpi4py)"
460 )
461 parser_mpirun.set_defaults(func=main_mpirun)
462
463 parser_pbs = subparsers.add_parser(
464 'pbs',
465 help='run a pbs cluster',
466 parents=[base_parser]
467 )
468 parser_pbs.add_argument(
469 '--pbs-script',
470 type=str,
471 dest='pbsscript',
472 help='PBS script template',
473 default='pbs.template'
474 )
475 parser_pbs.set_defaults(func=main_pbs)
476 args = parser.parse_args()
477 return args
310
478
311 def main():
479 def main():
312 """Main driver for the two big options: local or remote cluster."""
480 args = get_args()
313
481 reactor.callWhenRunning(args.func, args)
314 opt,arg = parse_args()
482 log.startLogging(sys.stdout)
315
483 reactor.run()
316 clusterfile = opt.clusterfile
317 if clusterfile:
318 clusterRemote(opt,arg)
319 else:
320 clusterLocal(opt,arg)
321
322
484
323 if __name__=='__main__':
485 if __name__ == '__main__':
324 main()
486 main()
@@ -64,7 +64,10 b' def make_tub(ip, port, secure, cert_file):'
64 if have_crypto:
64 if have_crypto:
65 tub = Tub(certFile=cert_file)
65 tub = Tub(certFile=cert_file)
66 else:
66 else:
67 raise SecurityError("OpenSSL is not available, so we can't run in secure mode, aborting")
67 raise SecurityError("""
68 OpenSSL/pyOpenSSL is not available, so we can't run in secure mode.
69 Try running without security using 'ipcontroller -xy'.
70 """)
68 else:
71 else:
69 tub = UnauthenticatedTub()
72 tub = UnauthenticatedTub()
70
73
@@ -202,6 +205,17 b' def start_controller():'
202 except:
205 except:
203 log.msg("Error running import_statement: %s" % cis)
206 log.msg("Error running import_statement: %s" % cis)
204
207
208 # Delete old furl files unless the reuse_furls is set
209 reuse = config['controller']['reuse_furls']
210 if not reuse:
211 paths = (config['controller']['engine_furl_file'],
212 config['controller']['controller_interfaces']['task']['furl_file'],
213 config['controller']['controller_interfaces']['multiengine']['furl_file']
214 )
215 for p in paths:
216 if os.path.isfile(p):
217 os.remove(p)
218
205 # Create the service hierarchy
219 # Create the service hierarchy
206 main_service = service.MultiService()
220 main_service = service.MultiService()
207 # The controller service
221 # The controller service
@@ -316,6 +330,12 b' def init_config():'
316 dest="ipythondir",
330 dest="ipythondir",
317 help="look for config files and profiles in this directory"
331 help="look for config files and profiles in this directory"
318 )
332 )
333 parser.add_option(
334 "-r",
335 action="store_true",
336 dest="reuse_furls",
337 help="try to reuse all furl files"
338 )
319
339
320 (options, args) = parser.parse_args()
340 (options, args) = parser.parse_args()
321
341
@@ -349,6 +369,8 b' def init_config():'
349 config['controller']['engine_tub']['cert_file'] = options.engine_cert_file
369 config['controller']['engine_tub']['cert_file'] = options.engine_cert_file
350 if options.engine_furl_file is not None:
370 if options.engine_furl_file is not None:
351 config['controller']['engine_furl_file'] = options.engine_furl_file
371 config['controller']['engine_furl_file'] = options.engine_furl_file
372 if options.reuse_furls is not None:
373 config['controller']['reuse_furls'] = options.reuse_furls
352
374
353 if options.logfile is not None:
375 if options.logfile is not None:
354 config['controller']['logfile'] = options.logfile
376 config['controller']['logfile'] = options.logfile
@@ -91,7 +91,7 b' def start_engine():'
91 try:
91 try:
92 engine_service.execute(shell_import_statement)
92 engine_service.execute(shell_import_statement)
93 except:
93 except:
94 log.msg("Error running import_statement: %s" % sis)
94 log.msg("Error running import_statement: %s" % shell_import_statement)
95
95
96 # Create the service hierarchy
96 # Create the service hierarchy
97 main_service = service.MultiService()
97 main_service = service.MultiService()
@@ -105,8 +105,13 b' def start_engine():'
105 # register_engine to tell the controller we are ready to do work
105 # register_engine to tell the controller we are ready to do work
106 engine_connector = EngineConnector(tub_service)
106 engine_connector = EngineConnector(tub_service)
107 furl_file = kernel_config['engine']['furl_file']
107 furl_file = kernel_config['engine']['furl_file']
108 log.msg("Using furl file: %s" % furl_file)
108 d = engine_connector.connect_to_controller(engine_service, furl_file)
109 d = engine_connector.connect_to_controller(engine_service, furl_file)
109 d.addErrback(lambda _: reactor.stop())
110 def handle_error(f):
111 log.err(f)
112 if reactor.running:
113 reactor.stop()
114 d.addErrback(handle_error)
110
115
111 reactor.run()
116 reactor.run()
112
117
@@ -245,7 +245,7 b' class IEngineSerializedTestCase(object):'
245 self.assert_(es.IEngineSerialized.providedBy(self.engine))
245 self.assert_(es.IEngineSerialized.providedBy(self.engine))
246
246
247 def testIEngineSerializedInterfaceMethods(self):
247 def testIEngineSerializedInterfaceMethods(self):
248 """Does self.engine have the methods and attributes in IEngireCore."""
248 """Does self.engine have the methods and attributes in IEngineCore."""
249 for m in list(es.IEngineSerialized):
249 for m in list(es.IEngineSerialized):
250 self.assert_(hasattr(self.engine, m))
250 self.assert_(hasattr(self.engine, m))
251
251
@@ -288,7 +288,7 b' class IEngineQueuedTestCase(object):'
288 self.assert_(es.IEngineQueued.providedBy(self.engine))
288 self.assert_(es.IEngineQueued.providedBy(self.engine))
289
289
290 def testIEngineQueuedInterfaceMethods(self):
290 def testIEngineQueuedInterfaceMethods(self):
291 """Does self.engine have the methods and attributes in IEngireQueued."""
291 """Does self.engine have the methods and attributes in IEngineQueued."""
292 for m in list(es.IEngineQueued):
292 for m in list(es.IEngineQueued):
293 self.assert_(hasattr(self.engine, m))
293 self.assert_(hasattr(self.engine, m))
294
294
@@ -326,7 +326,7 b' class IEnginePropertiesTestCase(object):'
326 self.assert_(es.IEngineProperties.providedBy(self.engine))
326 self.assert_(es.IEngineProperties.providedBy(self.engine))
327
327
328 def testIEnginePropertiesInterfaceMethods(self):
328 def testIEnginePropertiesInterfaceMethods(self):
329 """Does self.engine have the methods and attributes in IEngireProperties."""
329 """Does self.engine have the methods and attributes in IEngineProperties."""
330 for m in list(es.IEngineProperties):
330 for m in list(es.IEngineProperties):
331 self.assert_(hasattr(self.engine, m))
331 self.assert_(hasattr(self.engine, m))
332
332
@@ -20,7 +20,6 b' from twisted.internet import defer'
20 from IPython.kernel import engineservice as es
20 from IPython.kernel import engineservice as es
21 from IPython.kernel import multiengine as me
21 from IPython.kernel import multiengine as me
22 from IPython.kernel import newserialized
22 from IPython.kernel import newserialized
23 from IPython.kernel.error import NotDefined
24 from IPython.testing import util
23 from IPython.testing import util
25 from IPython.testing.parametric import parametric, Parametric
24 from IPython.testing.parametric import parametric, Parametric
26 from IPython.kernel import newserialized
25 from IPython.kernel import newserialized
@@ -1,4 +1,6 b''
1 from __future__ import with_statement
1 #from __future__ import with_statement
2
3 # XXX This file is currently disabled to preserve 2.4 compatibility.
2
4
3 #def test_simple():
5 #def test_simple():
4 if 0:
6 if 0:
@@ -25,17 +27,17 b' if 0:'
25
27
26 mec.pushAll()
28 mec.pushAll()
27
29
28 with parallel as pr:
30 ## with parallel as pr:
29 # A comment
31 ## # A comment
30 remote() # this means the code below only runs remotely
32 ## remote() # this means the code below only runs remotely
31 print 'Hello remote world'
33 ## print 'Hello remote world'
32 x = range(10)
34 ## x = range(10)
33 # Comments are OK
35 ## # Comments are OK
34 # Even misindented.
36 ## # Even misindented.
35 y = x+1
37 ## y = x+1
36
38
37
39
38 with pfor('i',sequence) as pr:
40 ## with pfor('i',sequence) as pr:
39 print x[i]
41 ## print x[i]
40
42
41 print pr.x + pr.y
43 print pr.x + pr.y
@@ -30,8 +30,9 b' try:'
30 from controllertest import IControllerCoreTestCase
30 from controllertest import IControllerCoreTestCase
31 from IPython.testing.util import DeferredTestCase
31 from IPython.testing.util import DeferredTestCase
32 except ImportError:
32 except ImportError:
33 pass
33 import nose
34 else:
34 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
35
35 class BasicControllerServiceTest(DeferredTestCase,
36 class BasicControllerServiceTest(DeferredTestCase,
36 IControllerCoreTestCase):
37 IControllerCoreTestCase):
37
38
@@ -37,9 +37,10 b' try:'
37 IEngineSerializedTestCase, \
37 IEngineSerializedTestCase, \
38 IEngineQueuedTestCase
38 IEngineQueuedTestCase
39 except ImportError:
39 except ImportError:
40 print "we got an error!!!"
40 import nose
41 raise
41 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
42 else:
42
43
43 class EngineFCTest(DeferredTestCase,
44 class EngineFCTest(DeferredTestCase,
44 IEngineCoreTestCase,
45 IEngineCoreTestCase,
45 IEngineSerializedTestCase,
46 IEngineSerializedTestCase,
@@ -35,8 +35,10 b' try:'
35 IEngineQueuedTestCase, \
35 IEngineQueuedTestCase, \
36 IEnginePropertiesTestCase
36 IEnginePropertiesTestCase
37 except ImportError:
37 except ImportError:
38 pass
38 import nose
39 else:
39 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
40
41
40 class BasicEngineServiceTest(DeferredTestCase,
42 class BasicEngineServiceTest(DeferredTestCase,
41 IEngineCoreTestCase,
43 IEngineCoreTestCase,
42 IEngineSerializedTestCase,
44 IEngineSerializedTestCase,
@@ -23,8 +23,10 b' try:'
23 from IPython.kernel.tests.multienginetest import (IMultiEngineTestCase,
23 from IPython.kernel.tests.multienginetest import (IMultiEngineTestCase,
24 ISynchronousMultiEngineTestCase)
24 ISynchronousMultiEngineTestCase)
25 except ImportError:
25 except ImportError:
26 pass
26 import nose
27 else:
27 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
28
29
28 class BasicMultiEngineTestCase(DeferredTestCase, IMultiEngineTestCase):
30 class BasicMultiEngineTestCase(DeferredTestCase, IMultiEngineTestCase):
29
31
30 def setUp(self):
32 def setUp(self):
@@ -30,8 +30,8 b' try:'
30 from IPython.kernel.error import CompositeError
30 from IPython.kernel.error import CompositeError
31 from IPython.kernel.util import printer
31 from IPython.kernel.util import printer
32 except ImportError:
32 except ImportError:
33 pass
33 import nose
34 else:
34 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
35
35
36 def _raise_it(f):
36 def _raise_it(f):
37 try:
37 try:
@@ -28,8 +28,9 b' try:'
28 SerializeIt, \
28 SerializeIt, \
29 UnSerializeIt
29 UnSerializeIt
30 except ImportError:
30 except ImportError:
31 pass
31 import nose
32 else:
32 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
33
33 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
34 # Tests
35 # Tests
35 #-------------------------------------------------------------------------------
36 #-------------------------------------------------------------------------------
@@ -99,4 +100,3 b' else:'
99 self.assert_(a.shape == final.shape)
100 self.assert_(a.shape == final.shape)
100
101
101
102
102 No newline at end of file
@@ -25,8 +25,8 b' try:'
25 from IPython.kernel import error
25 from IPython.kernel import error
26 from IPython.kernel.util import printer
26 from IPython.kernel.util import printer
27 except ImportError:
27 except ImportError:
28 pass
28 import nose
29 else:
29 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
30
30
31 class Foo(object):
31 class Foo(object):
32
32
@@ -26,8 +26,9 b' try:'
26 from IPython.testing.util import DeferredTestCase
26 from IPython.testing.util import DeferredTestCase
27 from IPython.kernel.tests.tasktest import ITaskControllerTestCase
27 from IPython.kernel.tests.tasktest import ITaskControllerTestCase
28 except ImportError:
28 except ImportError:
29 pass
29 import nose
30 else:
30 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
31
31 #-------------------------------------------------------------------------------
32 #-------------------------------------------------------------------------------
32 # Tests
33 # Tests
33 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
@@ -33,8 +33,9 b' try:'
33 from IPython.kernel.error import CompositeError
33 from IPython.kernel.error import CompositeError
34 from IPython.kernel.parallelfunction import ParallelFunction
34 from IPython.kernel.parallelfunction import ParallelFunction
35 except ImportError:
35 except ImportError:
36 pass
36 import nose
37 else:
37 raise nose.SkipTest("This test requires zope.interface, Twisted and Foolscap")
38
38
39
39 #-------------------------------------------------------------------------------
40 #-------------------------------------------------------------------------------
40 # Tests
41 # Tests
@@ -8,6 +8,10 b' the decorator, in order to preserve metadata such as function name,'
8 setup and teardown functions and so on - see nose.tools for more
8 setup and teardown functions and so on - see nose.tools for more
9 information.
9 information.
10
10
11 This module provides a set of useful decorators meant to be ready to use in
12 your own tests. See the bottom of the file for the ready-made ones, and if you
13 find yourself writing a new one that may be of generic use, add it here.
14
11 NOTE: This file contains IPython-specific decorators and imports the
15 NOTE: This file contains IPython-specific decorators and imports the
12 numpy.testing.decorators file, which we've copied verbatim. Any of our own
16 numpy.testing.decorators file, which we've copied verbatim. Any of our own
13 code will be added at the bottom if we end up extending this.
17 code will be added at the bottom if we end up extending this.
@@ -15,6 +19,7 b' code will be added at the bottom if we end up extending this.'
15
19
16 # Stdlib imports
20 # Stdlib imports
17 import inspect
21 import inspect
22 import sys
18
23
19 # Third-party imports
24 # Third-party imports
20
25
@@ -120,16 +125,36 b" skip_doctest = make_label_dec('skip_doctest',"
120 omit from testing, while preserving the docstring for introspection, help,
125 omit from testing, while preserving the docstring for introspection, help,
121 etc.""")
126 etc.""")
122
127
128 def skip(msg=''):
129 """Decorator - mark a test function for skipping from test suite.
130
131 This function *is* already a decorator, it is not a factory like
132 make_label_dec or some of those in decorators_numpy.
133
134 :Parameters:
123
135
124 def skip(func):
136 func : function
125 """Decorator - mark a test function for skipping from test suite."""
137 Test function to be skipped
138
139 msg : string
140 Optional message to be added.
141 """
126
142
127 import nose
143 import nose
128
144
145 def inner(func):
146
129 def wrapper(*a,**k):
147 def wrapper(*a,**k):
130 raise nose.SkipTest("Skipping test for function: %s" %
148 if msg: out = '\n'+msg
131 func.__name__)
149 else: out = ''
150 raise nose.SkipTest("Skipping test for function: %s%s" %
151 (func.__name__,out))
132
152
133 return apply_wrapper(wrapper,func)
153 return apply_wrapper(wrapper,func)
134
154
155 return inner
135
156
157 # Decorators to skip certain tests on specific platforms.
158 skip_win32 = skipif(sys.platform=='win32',"This test does not run under Windows")
159 skip_linux = skipif(sys.platform=='linux2',"This test does not run under Linux")
160 skip_osx = skipif(sys.platform=='darwin',"This test does not run under OSX")
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -1,6 +1,5 b''
1 # Set this prefix to where you want to install the plugin
1 # Set this prefix to where you want to install the plugin
2 PREFIX=~/usr/local
2 PREFIX=/usr/local
3 PREFIX=~/tmp/local
4
3
5 NOSE0=nosetests -vs --with-doctest --doctest-tests --detailed-errors
4 NOSE0=nosetests -vs --with-doctest --doctest-tests --detailed-errors
6 NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt \
5 NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt \
@@ -658,6 +658,24 b' class ExtensionDoctest(doctests.Doctest):'
658
658
659 def options(self, parser, env=os.environ):
659 def options(self, parser, env=os.environ):
660 Plugin.options(self, parser, env)
660 Plugin.options(self, parser, env)
661 parser.add_option('--doctest-tests', action='store_true',
662 dest='doctest_tests',
663 default=env.get('NOSE_DOCTEST_TESTS',True),
664 help="Also look for doctests in test modules. "
665 "Note that classes, methods and functions should "
666 "have either doctests or non-doctest tests, "
667 "not both. [NOSE_DOCTEST_TESTS]")
668 parser.add_option('--doctest-extension', action="append",
669 dest="doctestExtension",
670 help="Also look for doctests in files with "
671 "this extension [NOSE_DOCTEST_EXTENSION]")
672 # Set the default as a list, if given in env; otherwise
673 # an additional value set on the command line will cause
674 # an error.
675 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
676 if env_setting is not None:
677 parser.set_defaults(doctestExtension=tolist(env_setting))
678
661
679
662 def configure(self, options, config):
680 def configure(self, options, config):
663 Plugin.configure(self, options, config)
681 Plugin.configure(self, options, config)
@@ -743,16 +761,19 b' class ExtensionDoctest(doctests.Doctest):'
743 Modified version that accepts extension modules as valid containers for
761 Modified version that accepts extension modules as valid containers for
744 doctests.
762 doctests.
745 """
763 """
746 #print 'Filename:',filename # dbg
764 print 'Filename:',filename # dbg
747
765
748 # XXX - temporarily hardcoded list, will move to driver later
766 # XXX - temporarily hardcoded list, will move to driver later
749 exclude = ['IPython/external/',
767 exclude = ['IPython/external/',
750 'IPython/Extensions/ipy_',
751 'IPython/platutils_win32',
768 'IPython/platutils_win32',
752 'IPython/frontend/cocoa',
769 'IPython/frontend/cocoa',
753 'IPython_doctest_plugin',
770 'IPython_doctest_plugin',
754 'IPython/Gnuplot',
771 'IPython/Gnuplot',
755 'IPython/Extensions/PhysicalQIn']
772 'IPython/Extensions/ipy_',
773 'IPython/Extensions/PhysicalQIn',
774 'IPython/Extensions/scitedirector',
775 'IPython/testing/plugin',
776 ]
756
777
757 for fex in exclude:
778 for fex in exclude:
758 if fex in filename: # substring
779 if fex in filename: # substring
@@ -782,3 +803,4 b' class IPythonDoctest(ExtensionDoctest):'
782 self.checker = IPDoctestOutputChecker()
803 self.checker = IPDoctestOutputChecker()
783 self.globs = None
804 self.globs = None
784 self.extraglobs = None
805 self.extraglobs = None
806
@@ -1,147 +1,19 b''
1 """Some simple tests for the plugin while running scripts.
2 """
1 # Module imports
3 # Module imports
2 # Std lib
4 # Std lib
3 import inspect
5 import inspect
4
6
5 # Third party
6
7 # Our own
7 # Our own
8 from IPython.testing import decorators as dec
8 from IPython.testing import decorators as dec
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Utilities
12
13 # Note: copied from OInspect, kept here so the testing stuff doesn't create
14 # circular dependencies and is easier to reuse.
15 def getargspec(obj):
16 """Get the names and default values of a function's arguments.
17
18 A tuple of four things is returned: (args, varargs, varkw, defaults).
19 'args' is a list of the argument names (it may contain nested lists).
20 'varargs' and 'varkw' are the names of the * and ** arguments or None.
21 'defaults' is an n-tuple of the default values of the last n arguments.
22
23 Modified version of inspect.getargspec from the Python Standard
24 Library."""
25
26 if inspect.isfunction(obj):
27 func_obj = obj
28 elif inspect.ismethod(obj):
29 func_obj = obj.im_func
30 else:
31 raise TypeError, 'arg is not a Python function'
32 args, varargs, varkw = inspect.getargs(func_obj.func_code)
33 return args, varargs, varkw, func_obj.func_defaults
34
35 #-----------------------------------------------------------------------------
36 # Testing functions
11 # Testing functions
37
12
38 def test_trivial():
13 def test_trivial():
39 """A trivial passing test."""
14 """A trivial passing test."""
40 pass
15 pass
41
16
42
43 @dec.skip
44 def test_deliberately_broken():
45 """A deliberately broken test - we want to skip this one."""
46 1/0
47
48
49 # Verify that we can correctly skip the doctest for a function at will, but
50 # that the docstring itself is NOT destroyed by the decorator.
51 @dec.skip_doctest
52 def doctest_bad(x,y=1,**k):
53 """A function whose doctest we need to skip.
54
55 >>> 1+1
56 3
57 """
58 print 'x:',x
59 print 'y:',y
60 print 'k:',k
61
62
63 def call_doctest_bad():
64 """Check that we can still call the decorated functions.
65
66 >>> doctest_bad(3,y=4)
67 x: 3
68 y: 4
69 k: {}
70 """
71 pass
72
73
74 # Doctest skipping should work for class methods too
75 class foo(object):
76 """Foo
77
78 Example:
79
80 >>> 1+1
81 2
82 """
83
84 @dec.skip_doctest
85 def __init__(self,x):
86 """Make a foo.
87
88 Example:
89
90 >>> f = foo(3)
91 junk
92 """
93 print 'Making a foo.'
94 self.x = x
95
96 @dec.skip_doctest
97 def bar(self,y):
98 """Example:
99
100 >>> f = foo(3)
101 >>> f.bar(0)
102 boom!
103 >>> 1/0
104 bam!
105 """
106 return 1/y
107
108 def baz(self,y):
109 """Example:
110
111 >>> f = foo(3)
112 Making a foo.
113 >>> f.baz(3)
114 True
115 """
116 return self.x==y
117
118
119 def test_skip_dt_decorator():
120 """Doctest-skipping decorator should preserve the docstring.
121 """
122 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
123 check = """A function whose doctest we need to skip.
124
125 >>> 1+1
126 3
127 """
128 # Fetch the docstring from doctest_bad after decoration.
129 val = doctest_bad.__doc__
130
131 assert check==val,"doctest_bad docstrings don't match"
132
133
134 def test_skip_dt_decorator2():
135 """Doctest-skipping decorator should preserve function signature.
136 """
137 # Hardcoded correct answer
138 dtargs = (['x', 'y'], None, 'k', (1,))
139 # Introspect out the value
140 dtargsr = getargspec(doctest_bad)
141 assert dtargsr==dtargs, \
142 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
143
144
145 def doctest_run():
17 def doctest_run():
146 """Test running a trivial script.
18 """Test running a trivial script.
147
19
@@ -149,7 +21,6 b' def doctest_run():'
149 x is: 1
21 x is: 1
150 """
22 """
151
23
152 #@dec.skip_doctest
153 def doctest_runvars():
24 def doctest_runvars():
154 """Test that variables defined in scripts get loaded correcly via %run.
25 """Test that variables defined in scripts get loaded correcly via %run.
155
26
@@ -9,6 +9,7 b' Utilities for testing code.'
9 # testing machinery from snakeoil that were good have already been merged into
9 # testing machinery from snakeoil that were good have already been merged into
10 # the nose plugin, so this can be taken away soon. Leave a warning for now,
10 # the nose plugin, so this can be taken away soon. Leave a warning for now,
11 # we'll remove it in a later release (around 0.10 or so).
11 # we'll remove it in a later release (around 0.10 or so).
12
12 from warnings import warn
13 from warnings import warn
13 warn('This will be removed soon. Use IPython.testing.util instead',
14 warn('This will be removed soon. Use IPython.testing.util instead',
14 DeprecationWarning)
15 DeprecationWarning)
@@ -446,6 +446,7 b' class ListTB(TBTools):'
446 Also lifted nearly verbatim from traceback.py
446 Also lifted nearly verbatim from traceback.py
447 """
447 """
448
448
449 have_filedata = False
449 Colors = self.Colors
450 Colors = self.Colors
450 list = []
451 list = []
451 try:
452 try:
@@ -459,8 +460,9 b' class ListTB(TBTools):'
459 try:
460 try:
460 msg, (filename, lineno, offset, line) = value
461 msg, (filename, lineno, offset, line) = value
461 except:
462 except:
462 pass
463 have_filedata = False
463 else:
464 else:
465 have_filedata = True
464 #print 'filename is',filename # dbg
466 #print 'filename is',filename # dbg
465 if not filename: filename = "<string>"
467 if not filename: filename = "<string>"
466 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
468 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
@@ -492,6 +494,7 b' class ListTB(TBTools):'
492 list.append('%s\n' % str(stype))
494 list.append('%s\n' % str(stype))
493
495
494 # vds:>>
496 # vds:>>
497 if have_filedata:
495 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
498 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
496 # vds:<<
499 # vds:<<
497
500
@@ -809,10 +812,10 b' class VerboseTB(TBTools):'
809
812
810 # vds: >>
813 # vds: >>
811 if records:
814 if records:
812 frame, file, lnum, func, lines, index = records[-1]
815 filepath, lnum = records[-1][1:3]
813 #print "file:", str(file), "linenb", str(lnum)
816 #print "file:", str(file), "linenb", str(lnum) # dbg
814 file = abspath(file)
817 filepath = os.path.abspath(filepath)
815 __IPYTHON__.hooks.synchronize_with_editor(file, lnum, 0)
818 __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0)
816 # vds: <<
819 # vds: <<
817
820
818 # return all our info assembled as a single string
821 # return all our info assembled as a single string
@@ -1,7 +1,6 b''
1 include README_Windows.txt
2 include win32_manual_post_install.py
3 include ipython.py
1 include ipython.py
4 include setupbase.py
2 include setupbase.py
3 include setupegg.py
5
4
6 graft scripts
5 graft scripts
7
6
@@ -30,3 +29,4 b' global-exclude *.pyc'
30 global-exclude .dircopy.log
29 global-exclude .dircopy.log
31 global-exclude .svn
30 global-exclude .svn
32 global-exclude .bzr
31 global-exclude .bzr
32 global-exclude .hgignore
@@ -1,11 +1,11 b''
1 ===============
1 ==============
2 IPython1 README
2 IPython README
3 ===============
3 ==============
4
5 .. contents::
6
4
7 Overview
5 Overview
8 ========
6 ========
9
7
10 Welcome to IPython. New users should consult our documentation, which can be found
8 Welcome to IPython. Our documentation can be found in the docs/source
11 in the docs/source subdirectory.
9 subdirectory. We also have ``.html`` and ``.pdf`` versions of this
10 documentation available on the IPython `website <http://ipython.scipy.org>`_.
11
@@ -28,17 +28,16 b' help:'
28 @echo "dist all, and then puts the results in dist/"
28 @echo "dist all, and then puts the results in dist/"
29
29
30 clean:
30 clean:
31 -rm -rf build/*
31 -rm -rf build/* dist/*
32
32
33 pdf: latex
33 pdf: latex
34 cd build/latex && make all-pdf
34 cd build/latex && make all-pdf
35
35
36 all: html pdf
36 all: html pdf
37
37
38 dist: all
38 dist: clean all
39 mkdir -p dist
39 mkdir -p dist
40 -rm -rf dist/*
40 ln build/latex/ipython.pdf dist/
41 ln build/latex/IPython.pdf dist/
42 cp -al build/html dist/
41 cp -al build/html dist/
43 @echo "Build finished. Final docs are in dist/"
42 @echo "Build finished. Final docs are in dist/"
44
43
@@ -40,3 +40,4 b' def main():'
40
40
41 if __name__ == '__main__':
41 if __name__ == '__main__':
42 main()
42 main()
43
@@ -45,7 +45,10 b' def mergesort(list_of_lists, key=None):'
45 for i, itr in enumerate(iter(pl) for pl in list_of_lists):
45 for i, itr in enumerate(iter(pl) for pl in list_of_lists):
46 try:
46 try:
47 item = itr.next()
47 item = itr.next()
48 toadd = (key(item), i, item, itr) if key else (item, i, itr)
48 if key:
49 toadd = (key(item), i, item, itr)
50 else:
51 toadd = (item, i, itr)
49 heap.append(toadd)
52 heap.append(toadd)
50 except StopIteration:
53 except StopIteration:
51 pass
54 pass
@@ -53,5 +53,5 b" if __name__ == '__main__':"
53 %timeit -n1 -r1 parallelDiffs(rc, nmats, matsize)
53 %timeit -n1 -r1 parallelDiffs(rc, nmats, matsize)
54
54
55 # Uncomment these to plot the histogram
55 # Uncomment these to plot the histogram
56 import pylab
56 # import pylab
57 pylab.hist(parallelDiffs(rc,matsize,matsize))
57 # pylab.hist(parallelDiffs(rc,matsize,matsize))
@@ -5,6 +5,89 b" What's new"
5 ==========
5 ==========
6
6
7 .. contents::
7 .. contents::
8 ..
9 1 Release 0.9.1
10 2 Release 0.9
11 2.1 New features
12 2.2 Bug fixes
13 2.3 Backwards incompatible changes
14 2.4 Changes merged in from IPython1
15 2.4.1 New features
16 2.4.2 Bug fixes
17 2.4.3 Backwards incompatible changes
18 3 Release 0.8.4
19 4 Release 0.8.3
20 5 Release 0.8.2
21 6 Older releases
22 ..
23
24 Release dev
25 ===========
26
27 New features
28 ------------
29
30 * The wonderful TextMate editor can now be used with %edit on OS X. Thanks
31 to Matt Foster for this patch.
32
33 * Fully refactored :command:`ipcluster` command line program for starting
34 IPython clusters. This new version is a complete rewrite and 1) is fully
35 cross platform (we now use Twisted's process management), 2) has much
36 improved performance, 3) uses subcommands for different types of clusters,
37 4) uses argparse for parsing command line options, 5) has better support
38 for starting clusters using :command:`mpirun`, 6) has experimental support
39 for starting engines using PBS. However, this new version of ipcluster
40 should be considered a technology preview. We plan on changing the API
41 in significant ways before it is final.
42
43 * The :mod:`argparse` module has been added to :mod:`IPython.external`.
44
45 * Fully description of the security model added to the docs.
46
47 * cd completer: show bookmarks if no other completions are available.
48
49 * sh profile: easy way to give 'title' to prompt: assign to variable
50 '_prompt_title'. It looks like this::
51
52 [~]|1> _prompt_title = 'sudo!'
53 sudo![~]|2>
54
55 * %edit: If you do '%edit pasted_block', pasted_block
56 variable gets updated with new data (so repeated
57 editing makes sense)
58
59 Bug fixes
60 ---------
61
62 * The ipengine and ipcontroller scripts now handle missing furl files
63 more gracefully by giving better error messages.
64
65 * %rehashx: Aliases no longer contain dots. python3.0 binary
66 will create alias python30. Fixes:
67 #259716 "commands with dots in them don't work"
68
69 * %cpaste: %cpaste -r repeats the last pasted block.
70 The block is assigned to pasted_block even if code
71 raises exception.
72
73 Backwards incompatible changes
74 ------------------------------
75
76 * The controller now has a ``-r`` flag that needs to be used if you want to
77 reuse existing furl files. Otherwise they are deleted (the default).
78
79 * Remove ipy_leo.py. "easy_install ipython-extension" to get it.
80 (done to decouple it from ipython release cycle)
81
82
83
84 Release 0.9.1
85 =============
86
87 This release was quickly made to restore compatibility with Python 2.4, which
88 version 0.9 accidentally broke. No new features were introduced, other than
89 some additional testing support for internal use.
90
8
91
9 Release 0.9
92 Release 0.9
10 ===========
93 ===========
@@ -12,89 +95,170 b' Release 0.9'
12 New features
95 New features
13 ------------
96 ------------
14
97
98 * All furl files and security certificates are now put in a read-only
99 directory named ~./ipython/security.
100
101 * A single function :func:`get_ipython_dir`, in :mod:`IPython.genutils` that
102 determines the user's IPython directory in a robust manner.
103
104 * Laurent's WX application has been given a top-level script called
105 ipython-wx, and it has received numerous fixes. We expect this code to be
106 architecturally better integrated with Gael's WX 'ipython widget' over the
107 next few releases.
108
109 * The Editor synchronization work by Vivian De Smedt has been merged in. This
110 code adds a number of new editor hooks to synchronize with editors under
111 Windows.
112
113 * A new, still experimental but highly functional, WX shell by Gael Varoquaux.
114 This work was sponsored by Enthought, and while it's still very new, it is
115 based on a more cleanly organized arhictecture of the various IPython
116 components. We will continue to develop this over the next few releases as a
117 model for GUI components that use IPython.
118
119 * Another GUI frontend, Cocoa based (Cocoa is the OSX native GUI framework),
120 authored by Barry Wark. Currently the WX and the Cocoa ones have slightly
121 different internal organizations, but the whole team is working on finding
122 what the right abstraction points are for a unified codebase.
123
124 * As part of the frontend work, Barry Wark also implemented an experimental
125 event notification system that various ipython components can use. In the
126 next release the implications and use patterns of this system regarding the
127 various GUI options will be worked out.
128
129 * IPython finally has a full test system, that can test docstrings with
130 IPython-specific functionality. There are still a few pieces missing for it
131 to be widely accessible to all users (so they can run the test suite at any
132 time and report problems), but it now works for the developers. We are
133 working hard on continuing to improve it, as this was probably IPython's
134 major Achilles heel (the lack of proper test coverage made it effectively
135 impossible to do large-scale refactoring). The full test suite can now
136 be run using the :command:`iptest` command line program.
137
15 * The notion of a task has been completely reworked. An `ITask` interface has
138 * The notion of a task has been completely reworked. An `ITask` interface has
16 been created. This interface defines the methods that tasks need to implement.
139 been created. This interface defines the methods that tasks need to
17 These methods are now responsible for things like submitting tasks and processing
140 implement. These methods are now responsible for things like submitting
18 results. There are two basic task types: :class:`IPython.kernel.task.StringTask`
141 tasks and processing results. There are two basic task types:
19 (this is the old `Task` object, but renamed) and the new
142 :class:`IPython.kernel.task.StringTask` (this is the old `Task` object, but
20 :class:`IPython.kernel.task.MapTask`, which is based on a function.
143 renamed) and the new :class:`IPython.kernel.task.MapTask`, which is based on
144 a function.
145
21 * A new interface, :class:`IPython.kernel.mapper.IMapper` has been defined to
146 * A new interface, :class:`IPython.kernel.mapper.IMapper` has been defined to
22 standardize the idea of a `map` method. This interface has a single
147 standardize the idea of a `map` method. This interface has a single `map`
23 `map` method that has the same syntax as the built-in `map`. We have also defined
148 method that has the same syntax as the built-in `map`. We have also defined
24 a `mapper` factory interface that creates objects that implement
149 a `mapper` factory interface that creates objects that implement
25 :class:`IPython.kernel.mapper.IMapper` for different controllers. Both
150 :class:`IPython.kernel.mapper.IMapper` for different controllers. Both the
26 the multiengine and task controller now have mapping capabilties.
151 multiengine and task controller now have mapping capabilties.
27 * The parallel function capabilities have been reworks. The major changes are that
152
28 i) there is now an `@parallel` magic that creates parallel functions, ii)
153 * The parallel function capabilities have been reworks. The major changes are
29 the syntax for mulitple variable follows that of `map`, iii) both the
154 that i) there is now an `@parallel` magic that creates parallel functions,
155 ii) the syntax for mulitple variable follows that of `map`, iii) both the
30 multiengine and task controller now have a parallel function implementation.
156 multiengine and task controller now have a parallel function implementation.
31 * All of the parallel computing capabilities from `ipython1-dev` have been merged into
157
32 IPython proper. This resulted in the following new subpackages:
158 * All of the parallel computing capabilities from `ipython1-dev` have been
159 merged into IPython proper. This resulted in the following new subpackages:
33 :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`IPython.config`,
160 :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`IPython.config`,
34 :mod:`IPython.tools` and :mod:`IPython.testing`.
161 :mod:`IPython.tools` and :mod:`IPython.testing`.
35 * As part of merging in the `ipython1-dev` stuff, the `setup.py` script and friends
162
36 have been completely refactored. Now we are checking for dependencies using
163 * As part of merging in the `ipython1-dev` stuff, the `setup.py` script and
37 the approach that matplotlib uses.
164 friends have been completely refactored. Now we are checking for
38 * The documentation has been completely reorganized to accept the documentation
165 dependencies using the approach that matplotlib uses.
39 from `ipython1-dev`.
166
167 * The documentation has been completely reorganized to accept the
168 documentation from `ipython1-dev`.
169
40 * We have switched to using Foolscap for all of our network protocols in
170 * We have switched to using Foolscap for all of our network protocols in
41 :mod:`IPython.kernel`. This gives us secure connections that are both encrypted
171 :mod:`IPython.kernel`. This gives us secure connections that are both
42 and authenticated.
172 encrypted and authenticated.
173
43 * We have a brand new `COPYING.txt` files that describes the IPython license
174 * We have a brand new `COPYING.txt` files that describes the IPython license
44 and copyright. The biggest change is that we are putting "The IPython
175 and copyright. The biggest change is that we are putting "The IPython
45 Development Team" as the copyright holder. We give more details about exactly
176 Development Team" as the copyright holder. We give more details about
46 what this means in this file. All developer should read this and use the new
177 exactly what this means in this file. All developer should read this and use
47 banner in all IPython source code files.
178 the new banner in all IPython source code files.
179
48 * sh profile: ./foo runs foo as system command, no need to do !./foo anymore
180 * sh profile: ./foo runs foo as system command, no need to do !./foo anymore
49 * String lists now support 'sort(field, nums = True)' method (to easily
181
50 sort system command output). Try it with 'a = !ls -l ; a.sort(1, nums=1)'
182 * String lists now support ``sort(field, nums = True)`` method (to easily sort
183 system command output). Try it with ``a = !ls -l ; a.sort(1, nums=1)``.
184
51 * '%cpaste foo' now assigns the pasted block as string list, instead of string
185 * '%cpaste foo' now assigns the pasted block as string list, instead of string
52 * The ipcluster script now run by default with no security. This is done because
186
53 the main usage of the script is for starting things on localhost. Eventually
187 * The ipcluster script now run by default with no security. This is done
54 when ipcluster is able to start things on other hosts, we will put security
188 because the main usage of the script is for starting things on localhost.
55 back.
189 Eventually when ipcluster is able to start things on other hosts, we will put
190 security back.
191
56 * 'cd --foo' searches directory history for string foo, and jumps to that dir.
192 * 'cd --foo' searches directory history for string foo, and jumps to that dir.
57 Last part of dir name is checked first. If no matches for that are found,
193 Last part of dir name is checked first. If no matches for that are found,
58 look at the whole path.
194 look at the whole path.
59
195
196
60 Bug fixes
197 Bug fixes
61 ---------
198 ---------
62
199
63 * The colors escapes in the multiengine client are now turned off on win32 as they
200 * The Windows installer has been fixed. Now all IPython scripts have ``.bat``
64 don't print correctly.
201 versions created. Also, the Start Menu shortcuts have been updated.
65 * The :mod:`IPython.kernel.scripts.ipengine` script was exec'ing mpi_import_statement
202
66 incorrectly, which was leading the engine to crash when mpi was enabled.
203 * The colors escapes in the multiengine client are now turned off on win32 as
67 * A few subpackages has missing `__init__.py` files.
204 they don't print correctly.
68 * The documentation is only created is Sphinx is found. Previously, the `setup.py`
205
69 script would fail if it was missing.
206 * The :mod:`IPython.kernel.scripts.ipengine` script was exec'ing
70 * Greedy 'cd' completion has been disabled again (it was enabled in 0.8.4)
207 mpi_import_statement incorrectly, which was leading the engine to crash when
208 mpi was enabled.
209
210 * A few subpackages had missing ``__init__.py`` files.
211
212 * The documentation is only created if Sphinx is found. Previously, the
213 ``setup.py`` script would fail if it was missing.
214
215 * Greedy ``cd`` completion has been disabled again (it was enabled in 0.8.4) as
216 it caused problems on certain platforms.
71
217
72
218
73 Backwards incompatible changes
219 Backwards incompatible changes
74 ------------------------------
220 ------------------------------
75
221
222 * The ``clusterfile`` options of the :command:`ipcluster` command has been
223 removed as it was not working and it will be replaced soon by something much
224 more robust.
225
226 * The :mod:`IPython.kernel` configuration now properly find the user's
227 IPython directory.
228
229 * In ipapi, the :func:`make_user_ns` function has been replaced with
230 :func:`make_user_namespaces`, to support dict subclasses in namespace
231 creation.
232
76 * :class:`IPython.kernel.client.Task` has been renamed
233 * :class:`IPython.kernel.client.Task` has been renamed
77 :class:`IPython.kernel.client.StringTask` to make way for new task types.
234 :class:`IPython.kernel.client.StringTask` to make way for new task types.
235
78 * The keyword argument `style` has been renamed `dist` in `scatter`, `gather`
236 * The keyword argument `style` has been renamed `dist` in `scatter`, `gather`
79 and `map`.
237 and `map`.
238
80 * Renamed the values that the rename `dist` keyword argument can have from
239 * Renamed the values that the rename `dist` keyword argument can have from
81 `'basic'` to `'b'`.
240 `'basic'` to `'b'`.
241
82 * IPython has a larger set of dependencies if you want all of its capabilities.
242 * IPython has a larger set of dependencies if you want all of its capabilities.
83 See the `setup.py` script for details.
243 See the `setup.py` script for details.
244
84 * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and
245 * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and
85 :class:`IPython.kernel.client.TaskClient` no longer take the (ip,port) tuple.
246 :class:`IPython.kernel.client.TaskClient` no longer take the (ip,port) tuple.
86 Instead they take the filename of a file that contains the FURL for that
247 Instead they take the filename of a file that contains the FURL for that
87 client. If the FURL file is in your IPYTHONDIR, it will be found automatically
248 client. If the FURL file is in your IPYTHONDIR, it will be found automatically
88 and the constructor can be left empty.
249 and the constructor can be left empty.
250
89 * The asynchronous clients in :mod:`IPython.kernel.asyncclient` are now created
251 * The asynchronous clients in :mod:`IPython.kernel.asyncclient` are now created
90 using the factory functions :func:`get_multiengine_client` and
252 using the factory functions :func:`get_multiengine_client` and
91 :func:`get_task_client`. These return a `Deferred` to the actual client.
253 :func:`get_task_client`. These return a `Deferred` to the actual client.
254
92 * The command line options to `ipcontroller` and `ipengine` have changed to
255 * The command line options to `ipcontroller` and `ipengine` have changed to
93 reflect the new Foolscap network protocol and the FURL files. Please see the
256 reflect the new Foolscap network protocol and the FURL files. Please see the
94 help for these scripts for details.
257 help for these scripts for details.
95 * The configuration files for the kernel have changed because of the Foolscap stuff.
258
96 If you were using custom config files before, you should delete them and regenerate
259 * The configuration files for the kernel have changed because of the Foolscap
97 new ones.
260 stuff. If you were using custom config files before, you should delete them
261 and regenerate new ones.
98
262
99 Changes merged in from IPython1
263 Changes merged in from IPython1
100 -------------------------------
264 -------------------------------
@@ -102,41 +266,56 b' Changes merged in from IPython1'
102 New features
266 New features
103 ............
267 ............
104
268
105 * Much improved ``setup.py`` and ``setupegg.py`` scripts. Because Twisted
269 * Much improved ``setup.py`` and ``setupegg.py`` scripts. Because Twisted and
106 and zope.interface are now easy installable, we can declare them as dependencies
270 zope.interface are now easy installable, we can declare them as dependencies
107 in our setupegg.py script.
271 in our setupegg.py script.
272
108 * IPython is now compatible with Twisted 2.5.0 and 8.x.
273 * IPython is now compatible with Twisted 2.5.0 and 8.x.
274
109 * Added a new example of how to use :mod:`ipython1.kernel.asynclient`.
275 * Added a new example of how to use :mod:`ipython1.kernel.asynclient`.
276
110 * Initial draft of a process daemon in :mod:`ipython1.daemon`. This has not
277 * Initial draft of a process daemon in :mod:`ipython1.daemon`. This has not
111 been merged into IPython and is still in `ipython1-dev`.
278 been merged into IPython and is still in `ipython1-dev`.
279
112 * The ``TaskController`` now has methods for getting the queue status.
280 * The ``TaskController`` now has methods for getting the queue status.
281
113 * The ``TaskResult`` objects not have information about how long the task
282 * The ``TaskResult`` objects not have information about how long the task
114 took to run.
283 took to run.
284
115 * We are attaching additional attributes to exceptions ``(_ipython_*)`` that
285 * We are attaching additional attributes to exceptions ``(_ipython_*)`` that
116 we use to carry additional info around.
286 we use to carry additional info around.
287
117 * New top-level module :mod:`asyncclient` that has asynchronous versions (that
288 * New top-level module :mod:`asyncclient` that has asynchronous versions (that
118 return deferreds) of the client classes. This is designed to users who want
289 return deferreds) of the client classes. This is designed to users who want
119 to run their own Twisted reactor
290 to run their own Twisted reactor.
291
120 * All the clients in :mod:`client` are now based on Twisted. This is done by
292 * All the clients in :mod:`client` are now based on Twisted. This is done by
121 running the Twisted reactor in a separate thread and using the
293 running the Twisted reactor in a separate thread and using the
122 :func:`blockingCallFromThread` function that is in recent versions of Twisted.
294 :func:`blockingCallFromThread` function that is in recent versions of Twisted.
295
123 * Functions can now be pushed/pulled to/from engines using
296 * Functions can now be pushed/pulled to/from engines using
124 :meth:`MultiEngineClient.push_function` and :meth:`MultiEngineClient.pull_function`.
297 :meth:`MultiEngineClient.push_function` and
298 :meth:`MultiEngineClient.pull_function`.
299
125 * Gather/scatter are now implemented in the client to reduce the work load
300 * Gather/scatter are now implemented in the client to reduce the work load
126 of the controller and improve performance.
301 of the controller and improve performance.
302
127 * Complete rewrite of the IPython docuementation. All of the documentation
303 * Complete rewrite of the IPython docuementation. All of the documentation
128 from the IPython website has been moved into docs/source as restructured
304 from the IPython website has been moved into docs/source as restructured
129 text documents. PDF and HTML documentation are being generated using
305 text documents. PDF and HTML documentation are being generated using
130 Sphinx.
306 Sphinx.
307
131 * New developer oriented documentation: development guidelines and roadmap.
308 * New developer oriented documentation: development guidelines and roadmap.
132 * Traditional ``ChangeLog`` has been changed to a more useful ``changes.txt`` file
309
133 that is organized by release and is meant to provide something more relevant
310 * Traditional ``ChangeLog`` has been changed to a more useful ``changes.txt``
134 for users.
311 file that is organized by release and is meant to provide something more
312 relevant for users.
135
313
136 Bug fixes
314 Bug fixes
137 .........
315 .........
138
316
139 * Created a proper ``MANIFEST.in`` file to create source distributions.
317 * Created a proper ``MANIFEST.in`` file to create source distributions.
318
140 * Fixed a bug in the ``MultiEngine`` interface. Previously, multi-engine
319 * Fixed a bug in the ``MultiEngine`` interface. Previously, multi-engine
141 actions were being collected with a :class:`DeferredList` with
320 actions were being collected with a :class:`DeferredList` with
142 ``fireononeerrback=1``. This meant that methods were returning
321 ``fireononeerrback=1``. This meant that methods were returning
@@ -154,36 +333,41 b' Backwards incompatible changes'
154 * All names have been renamed to conform to the lowercase_with_underscore
333 * All names have been renamed to conform to the lowercase_with_underscore
155 convention. This will require users to change references to all names like
334 convention. This will require users to change references to all names like
156 ``queueStatus`` to ``queue_status``.
335 ``queueStatus`` to ``queue_status``.
336
157 * Previously, methods like :meth:`MultiEngineClient.push` and
337 * Previously, methods like :meth:`MultiEngineClient.push` and
158 :meth:`MultiEngineClient.push` used ``*args`` and ``**kwargs``. This was
338 :meth:`MultiEngineClient.push` used ``*args`` and ``**kwargs``. This was
159 becoming a problem as we weren't able to introduce new keyword arguments into
339 becoming a problem as we weren't able to introduce new keyword arguments into
160 the API. Now these methods simple take a dict or sequence. This has also allowed
340 the API. Now these methods simple take a dict or sequence. This has also
161 us to get rid of the ``*All`` methods like :meth:`pushAll` and :meth:`pullAll`.
341 allowed us to get rid of the ``*All`` methods like :meth:`pushAll` and
162 These things are now handled with the ``targets`` keyword argument that defaults
342 :meth:`pullAll`. These things are now handled with the ``targets`` keyword
163 to ``'all'``.
343 argument that defaults to ``'all'``.
344
164 * The :attr:`MultiEngineClient.magicTargets` has been renamed to
345 * The :attr:`MultiEngineClient.magicTargets` has been renamed to
165 :attr:`MultiEngineClient.targets`.
346 :attr:`MultiEngineClient.targets`.
166 * All methods in the MultiEngine interface now accept the optional keyword argument
347
167 ``block``.
348 * All methods in the MultiEngine interface now accept the optional keyword
349 argument ``block``.
350
168 * Renamed :class:`RemoteController` to :class:`MultiEngineClient` and
351 * Renamed :class:`RemoteController` to :class:`MultiEngineClient` and
169 :class:`TaskController` to :class:`TaskClient`.
352 :class:`TaskController` to :class:`TaskClient`.
353
170 * Renamed the top-level module from :mod:`api` to :mod:`client`.
354 * Renamed the top-level module from :mod:`api` to :mod:`client`.
171 * Most methods in the multiengine interface now raise a :exc:`CompositeError` exception
355
172 that wraps the user's exceptions, rather than just raising the raw user's exception.
356 * Most methods in the multiengine interface now raise a :exc:`CompositeError`
357 exception that wraps the user's exceptions, rather than just raising the raw
358 user's exception.
359
173 * Changed the ``setupNS`` and ``resultNames`` in the ``Task`` class to ``push``
360 * Changed the ``setupNS`` and ``resultNames`` in the ``Task`` class to ``push``
174 and ``pull``.
361 and ``pull``.
175
362
363
176 Release 0.8.4
364 Release 0.8.4
177 =============
365 =============
178
366
179 Someone needs to describe what went into 0.8.4.
367 This was a quick release to fix an unfortunate bug that slipped into the 0.8.3
368 release. The ``--twisted`` option was disabled, as it turned out to be broken
369 across several platforms.
180
370
181 Release 0.8.2
182 =============
183
184 * %pushd/%popd behave differently; now "pushd /foo" pushes CURRENT directory
185 and jumps to /foo. The current behaviour is closer to the documented
186 behaviour, and should not trip anyone.
187
371
188 Release 0.8.3
372 Release 0.8.3
189 =============
373 =============
@@ -192,9 +376,18 b' Release 0.8.3'
192 it by passing -pydb command line argument to IPython. Note that setting
376 it by passing -pydb command line argument to IPython. Note that setting
193 it in config file won't work.
377 it in config file won't work.
194
378
379
380 Release 0.8.2
381 =============
382
383 * %pushd/%popd behave differently; now "pushd /foo" pushes CURRENT directory
384 and jumps to /foo. The current behaviour is closer to the documented
385 behaviour, and should not trip anyone.
386
387
195 Older releases
388 Older releases
196 ==============
389 ==============
197
390
198 Changes in earlier releases of IPython are described in the older file ``ChangeLog``.
391 Changes in earlier releases of IPython are described in the older file
199 Please refer to this document for details.
392 ``ChangeLog``. Please refer to this document for details.
200
393
@@ -1,7 +1,11 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 #
2 #
3 # IPython documentation build configuration file, created by
3 # IPython documentation build configuration file.
4 # sphinx-quickstart on Thu May 8 16:45:02 2008.
4
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
7 # needed, generate a scratch one and merge by hand any new fields needed.
8
5 #
9 #
6 # 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.
7 #
11 #
@@ -16,14 +20,26 b' import sys, os'
16 # 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
17 # 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
18 # absolute, like shown here.
22 # absolute, like shown here.
19 #sys.path.append(os.path.abspath('some/directory'))
23 sys.path.append(os.path.abspath('../sphinxext'))
24
25 # Import support for ipython console session syntax highlighting (lives
26 # in the sphinxext directory defined above)
27 import ipython_console_highlighting
28
29 # We load the ipython release info into a dict by explicit execution
30 iprelease = {}
31 execfile('../../IPython/Release.py',iprelease)
20
32
21 # General configuration
33 # General configuration
22 # ---------------------
34 # ---------------------
23
35
24 # 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
25 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
37 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
26 #extensions = []
38 extensions = ['sphinx.ext.autodoc',
39 'inheritance_diagram', 'only_directives',
40 'ipython_console_highlighting',
41 # 'plot_directive', # disabled for now, needs matplotlib
42 ]
27
43
28 # Add any paths that contain templates here, relative to this directory.
44 # Add any paths that contain templates here, relative to this directory.
29 templates_path = ['_templates']
45 templates_path = ['_templates']
@@ -41,10 +57,11 b" copyright = '2008, The IPython Development Team'"
41 # The default replacements for |version| and |release|, also used in various
57 # The default replacements for |version| and |release|, also used in various
42 # other places throughout the built documents.
58 # other places throughout the built documents.
43 #
59 #
44 # The short X.Y version.
45 version = '0.9'
46 # The full version, including alpha/beta/rc tags.
60 # The full version, including alpha/beta/rc tags.
47 release = '0.9.beta1'
61 release = iprelease['version']
62 # The short X.Y version.
63 version = '.'.join(release.split('.',2)[:2])
64
48
65
49 # There are two options for replacing |today|: either, you set today to some
66 # There are two options for replacing |today|: either, you set today to some
50 # non-false value, then it is used:
67 # non-false value, then it is used:
@@ -57,7 +74,7 b" today_fmt = '%B %d, %Y'"
57
74
58 # List of directories, relative to source directories, that shouldn't be searched
75 # List of directories, relative to source directories, that shouldn't be searched
59 # for source files.
76 # for source files.
60 #exclude_dirs = []
77 exclude_dirs = ['attic']
61
78
62 # If true, '()' will be appended to :func: etc. cross-reference text.
79 # If true, '()' will be appended to :func: etc. cross-reference text.
63 #add_function_parentheses = True
80 #add_function_parentheses = True
@@ -125,7 +142,7 b" html_last_updated_fmt = '%b %d, %Y'"
125 #html_file_suffix = ''
142 #html_file_suffix = ''
126
143
127 # Output file base name for HTML help builder.
144 # Output file base name for HTML help builder.
128 htmlhelp_basename = 'IPythondoc'
145 htmlhelp_basename = 'ipythondoc'
129
146
130
147
131 # Options for LaTeX output
148 # Options for LaTeX output
@@ -140,11 +157,8 b" latex_font_size = '11pt'"
140 # Grouping the document tree into LaTeX files. List of tuples
157 # Grouping the document tree into LaTeX files. List of tuples
141 # (source start file, target name, title, author, document class [howto/manual]).
158 # (source start file, target name, title, author, document class [howto/manual]).
142
159
143 latex_documents = [ ('index', 'IPython.tex', 'IPython Documentation',
160 latex_documents = [ ('index', 'ipython.tex', 'IPython Documentation',
144 ur"""Brian Granger, Fernando Pérez and Ville Vainio\\
161 ur"""The IPython Development Team""",
145 \ \\
146 With contributions from:\\
147 Benjamin Ragan-Kelley.""",
148 'manual'),
162 'manual'),
149 ]
163 ]
150
164
@@ -164,3 +178,10 b" latex_documents = [ ('index', 'IPython.tex', 'IPython Documentation',"
164
178
165 # If false, no module index is generated.
179 # If false, no module index is generated.
166 #latex_use_modindex = True
180 #latex_use_modindex = True
181
182
183 # Cleanup
184 # -------
185 # delete release info to avoid pickling errors from sphinx
186
187 del iprelease
@@ -18,6 +18,8 b' time. A hybrid approach of specifying a few options in ipythonrc and'
18 doing the more advanced configuration in ipy_user_conf.py is also
18 doing the more advanced configuration in ipy_user_conf.py is also
19 possible.
19 possible.
20
20
21 .. _ipythonrc:
22
21 The ipythonrc approach
23 The ipythonrc approach
22 ======================
24 ======================
23
25
@@ -36,11 +38,11 b' fairly primitive). Note that these are not python files, and this is'
36 deliberate, because it allows us to do some things which would be quite
38 deliberate, because it allows us to do some things which would be quite
37 tricky to implement if they were normal python files.
39 tricky to implement if they were normal python files.
38
40
39 First, an rcfile can contain permanent default values for almost all
41 First, an rcfile can contain permanent default values for almost all command
40 command line options (except things like -help or -Version). Sec
42 line options (except things like -help or -Version). :ref:`This section
41 `command line options`_ contains a description of all command-line
43 <command_line_options>` contains a description of all command-line
42 options. However, values you explicitly specify at the command line
44 options. However, values you explicitly specify at the command line override
43 override the values defined in the rcfile.
45 the values defined in the rcfile.
44
46
45 Besides command line option values, the rcfile can specify values for
47 Besides command line option values, the rcfile can specify values for
46 certain extra special options which are not available at the command
48 certain extra special options which are not available at the command
@@ -266,13 +268,13 b' which look like this::'
266 IPython profiles
268 IPython profiles
267 ================
269 ================
268
270
269 As we already mentioned, IPython supports the -profile command-line
271 As we already mentioned, IPython supports the -profile command-line option (see
270 option (see sec. `command line options`_). A profile is nothing more
272 :ref:`here <command_line_options>`). A profile is nothing more than a
271 than a particular configuration file like your basic ipythonrc one,
273 particular configuration file like your basic ipythonrc one, but with
272 but with particular customizations for a specific purpose. When you
274 particular customizations for a specific purpose. When you start IPython with
273 start IPython with 'ipython -profile <name>', it assumes that in your
275 'ipython -profile <name>', it assumes that in your IPYTHONDIR there is a file
274 IPYTHONDIR there is a file called ipythonrc-<name> or
276 called ipythonrc-<name> or ipy_profile_<name>.py, and loads it instead of the
275 ipy_profile_<name>.py, and loads it instead of the normal ipythonrc.
277 normal ipythonrc.
276
278
277 This system allows you to maintain multiple configurations which load
279 This system allows you to maintain multiple configurations which load
278 modules, set options, define functions, etc. suitable for different
280 modules, set options, define functions, etc. suitable for different
@@ -3,7 +3,7 b' Configuration and customization'
3 ===============================
3 ===============================
4
4
5 .. toctree::
5 .. toctree::
6 :maxdepth: 1
6 :maxdepth: 2
7
7
8 initial_config.txt
8 initial_config.txt
9 customization.txt
9 customization.txt
@@ -11,28 +11,27 b' in a directory named by default $HOME/.ipython. You can change this by'
11 defining the environment variable IPYTHONDIR, or at runtime with the
11 defining the environment variable IPYTHONDIR, or at runtime with the
12 command line option -ipythondir.
12 command line option -ipythondir.
13
13
14 If all goes well, the first time you run IPython it should
14 If all goes well, the first time you run IPython it should automatically create
15 automatically create a user copy of the config directory for you,
15 a user copy of the config directory for you, based on its builtin defaults. You
16 based on its builtin defaults. You can look at the files it creates to
16 can look at the files it creates to learn more about configuring the
17 learn more about configuring the system. The main file you will modify
17 system. The main file you will modify to configure IPython's behavior is called
18 to configure IPython's behavior is called ipythonrc (with a .ini
18 ipythonrc (with a .ini extension under Windows), included for reference
19 extension under Windows), included for reference in `ipythonrc`_
19 :ref:`here <ipythonrc>`. This file is very commented and has many variables you
20 section. This file is very commented and has many variables you can
20 can change to suit your taste, you can find more details :ref:`here
21 change to suit your taste, you can find more details in
21 <customization>`. Here we discuss the basic things you will want to make sure
22 Sec. customization_. Here we discuss the basic things you will want to
22 things are working properly from the beginning.
23 make sure things are working properly from the beginning.
24
23
25
24
26 .. _Accessing help:
25 .. _accessing_help:
27
26
28 Access to the Python help system
27 Access to the Python help system
29 ================================
28 ================================
30
29
31 This is true for Python in general (not just for IPython): you should
30 This is true for Python in general (not just for IPython): you should have an
32 have an environment variable called PYTHONDOCS pointing to the directory
31 environment variable called PYTHONDOCS pointing to the directory where your
33 where your HTML Python documentation lives. In my system it's
32 HTML Python documentation lives. In my system it's
34 /usr/share/doc/python-docs-2.3.4/html, check your local details or ask
33 :file:`/usr/share/doc/python-doc/html`, check your local details or ask your
35 your systems administrator.
34 systems administrator.
36
35
37 This is the directory which holds the HTML version of the Python
36 This is the directory which holds the HTML version of the Python
38 manuals. Unfortunately it seems that different Linux distributions
37 manuals. Unfortunately it seems that different Linux distributions
@@ -40,8 +39,9 b' package these files differently, so you may have to look around a bit.'
40 Below I show the contents of this directory on my system for reference::
39 Below I show the contents of this directory on my system for reference::
41
40
42 [html]> ls
41 [html]> ls
43 about.dat acks.html dist/ ext/ index.html lib/ modindex.html
42 about.html dist/ icons/ lib/ python2.5.devhelp.gz whatsnew/
44 stdabout.dat tut/ about.html api/ doc/ icons/ inst/ mac/ ref/ style.css
43 acks.html doc/ index.html mac/ ref/
44 api/ ext/ inst/ modindex.html tut/
45
45
46 You should really make sure this variable is correctly set so that
46 You should really make sure this variable is correctly set so that
47 Python's pydoc-based help system works. It is a powerful and convenient
47 Python's pydoc-based help system works. It is a powerful and convenient
@@ -108,6 +108,8 b' The following terminals seem to handle the color sequences fine:'
108 support under cygwin, please post to the IPython mailing list so
108 support under cygwin, please post to the IPython mailing list so
109 this issue can be resolved for all users.
109 this issue can be resolved for all users.
110
110
111 .. _pyreadline: https://code.launchpad.net/pyreadline
112
111 These have shown problems:
113 These have shown problems:
112
114
113 * Windows command prompt in WinXP/2k logged into a Linux machine via
115 * Windows command prompt in WinXP/2k logged into a Linux machine via
@@ -157,13 +159,12 b' $HOME/.ipython/ipythonrc and set the colors option to the desired value.'
157 Object details (types, docstrings, source code, etc.)
159 Object details (types, docstrings, source code, etc.)
158 =====================================================
160 =====================================================
159
161
160 IPython has a set of special functions for studying the objects you
162 IPython has a set of special functions for studying the objects you are working
161 are working with, discussed in detail in Sec. `dynamic object
163 with, discussed in detail :ref:`here <dynamic_object_info>`. But this system
162 information`_. But this system relies on passing information which is
164 relies on passing information which is longer than your screen through a data
163 longer than your screen through a data pager, such as the common Unix
165 pager, such as the common Unix less and more programs. In order to be able to
164 less and more programs. In order to be able to see this information in
166 see this information in color, your pager needs to be properly configured. I
165 color, your pager needs to be properly configured. I strongly
167 strongly recommend using less instead of more, as it seems that more simply can
166 recommend using less instead of more, as it seems that more simply can
167 not understand colored text correctly.
168 not understand colored text correctly.
168
169
169 In order to configure less as your default pager, do the following:
170 In order to configure less as your default pager, do the following:
@@ -4,24 +4,39 b''
4 Credits
4 Credits
5 =======
5 =======
6
6
7 IPython is mainly developed by Fernando Pérez
7 IPython is led by Fernando Pérez.
8 <Fernando.Perez@colorado.edu>, but the project was born from mixing in
9 Fernando's code with the IPP project by Janko Hauser
10 <jhauser-AT-zscout.de> and LazyPython by Nathan Gray
11 <n8gray-AT-caltech.edu>. For all IPython-related requests, please
12 contact Fernando.
13
8
14 As of early 2006, the following developers have joined the core team:
9 As of this writing, the following developers have joined the core team:
15
10
16 * [Robert Kern] <rkern-AT-enthought.com>: co-mentored the 2005
11 * [Robert Kern] <rkern-AT-enthought.com>: co-mentored the 2005
17 Google Summer of Code project to develop python interactive
12 Google Summer of Code project to develop python interactive
18 notebooks (XML documents) and graphical interface. This project
13 notebooks (XML documents) and graphical interface. This project
19 was awarded to the students Tzanko Matev <tsanko-AT-gmail.com> and
14 was awarded to the students Tzanko Matev <tsanko-AT-gmail.com> and
20 Toni Alatalo <antont-AT-an.org>
15 Toni Alatalo <antont-AT-an.org>.
21 * [Brian Granger] <bgranger-AT-scu.edu>: extending IPython to allow
16
17 * [Brian Granger] <ellisonbg-AT-gmail.com>: extending IPython to allow
22 support for interactive parallel computing.
18 support for interactive parallel computing.
23 * [Ville Vainio] <vivainio-AT-gmail.com>: Ville is the new
19
24 maintainer for the main trunk of IPython after version 0.7.1.
20 * [Benjamin (Min) Ragan-Kelley]: key work on IPython's parallel
21 computing infrastructure.
22
23 * [Ville Vainio] <vivainio-AT-gmail.com>: Ville has made many improvements
24 to the core of IPython and was the maintainer of the main IPython
25 trunk from version 0.7.1 to 0.8.4.
26
27 * [Gael Varoquaux] <gael.varoquaux-AT-normalesup.org>: work on the merged
28 architecture for the interpreter as of version 0.9, implementing a new WX GUI
29 based on this system.
30
31 * [Barry Wark] <barrywark-AT-gmail.com>: implementing a new Cocoa GUI, as well
32 as work on the new interpreter architecture and Twisted support.
33
34 * [Laurent Dufrechou] <laurent.dufrechou-AT-gmail.com>: development of the WX
35 GUI support.
36
37 * [Jörgen Stenarson] <jorgen.stenarson-AT-bostream.nu>: maintainer of the
38 PyReadline project, necessary for IPython under windows.
39
25
40
26 The IPython project is also very grateful to:
41 The IPython project is also very grateful to:
27
42
@@ -50,9 +65,12 b" an O'Reilly Python editor. His Oct/11/2001 article about IPP and"
50 LazyPython, was what got this project started. You can read it at:
65 LazyPython, was what got this project started. You can read it at:
51 http://www.onlamp.com/pub/a/python/2001/10/11/pythonnews.html.
66 http://www.onlamp.com/pub/a/python/2001/10/11/pythonnews.html.
52
67
53 And last but not least, all the kind IPython users who have emailed new
68 And last but not least, all the kind IPython users who have emailed new code,
54 code, bug reports, fixes, comments and ideas. A brief list follows,
69 bug reports, fixes, comments and ideas. A brief list follows, please let us
55 please let me know if I have ommitted your name by accident:
70 know if we have ommitted your name by accident:
71
72 * Dan Milstein <danmil-AT-comcast.net>. A bold refactoring of the
73 core prefilter stuff in the IPython interpreter.
56
74
57 * [Jack Moffit] <jack-AT-xiph.org> Bug fixes, including the infamous
75 * [Jack Moffit] <jack-AT-xiph.org> Bug fixes, including the infamous
58 color problem. This bug alone caused many lost hours and
76 color problem. This bug alone caused many lost hours and
@@ -60,80 +78,130 b' please let me know if I have ommitted your name by accident:'
60 fan of Ogg & friends, now I have one more reason to like these folks.
78 fan of Ogg & friends, now I have one more reason to like these folks.
61 Jack is also contributing with Debian packaging and many other
79 Jack is also contributing with Debian packaging and many other
62 things.
80 things.
81
63 * [Alexander Schmolck] <a.schmolck-AT-gmx.net> Emacs work, bug
82 * [Alexander Schmolck] <a.schmolck-AT-gmx.net> Emacs work, bug
64 reports, bug fixes, ideas, lots more. The ipython.el mode for
83 reports, bug fixes, ideas, lots more. The ipython.el mode for
65 (X)Emacs is Alex's code, providing full support for IPython under
84 (X)Emacs is Alex's code, providing full support for IPython under
66 (X)Emacs.
85 (X)Emacs.
86
67 * [Andrea Riciputi] <andrea.riciputi-AT-libero.it> Mac OSX
87 * [Andrea Riciputi] <andrea.riciputi-AT-libero.it> Mac OSX
68 information, Fink package management.
88 information, Fink package management.
89
69 * [Gary Bishop] <gb-AT-cs.unc.edu> Bug reports, and patches to work
90 * [Gary Bishop] <gb-AT-cs.unc.edu> Bug reports, and patches to work
70 around the exception handling idiosyncracies of WxPython. Readline
91 around the exception handling idiosyncracies of WxPython. Readline
71 and color support for Windows.
92 and color support for Windows.
93
72 * [Jeffrey Collins] <Jeff.Collins-AT-vexcel.com> Bug reports. Much
94 * [Jeffrey Collins] <Jeff.Collins-AT-vexcel.com> Bug reports. Much
73 improved readline support, including fixes for Python 2.3.
95 improved readline support, including fixes for Python 2.3.
96
74 * [Dryice Liu] <dryice-AT-liu.com.cn> FreeBSD port.
97 * [Dryice Liu] <dryice-AT-liu.com.cn> FreeBSD port.
98
75 * [Mike Heeter] <korora-AT-SDF.LONESTAR.ORG>
99 * [Mike Heeter] <korora-AT-SDF.LONESTAR.ORG>
100
76 * [Christopher Hart] <hart-AT-caltech.edu> PDB integration.
101 * [Christopher Hart] <hart-AT-caltech.edu> PDB integration.
102
77 * [Milan Zamazal] <pdm-AT-zamazal.org> Emacs info.
103 * [Milan Zamazal] <pdm-AT-zamazal.org> Emacs info.
104
78 * [Philip Hisley] <compsys-AT-starpower.net>
105 * [Philip Hisley] <compsys-AT-starpower.net>
106
79 * [Holger Krekel] <pyth-AT-devel.trillke.net> Tab completion, lots
107 * [Holger Krekel] <pyth-AT-devel.trillke.net> Tab completion, lots
80 more.
108 more.
109
81 * [Robin Siebler] <robinsiebler-AT-starband.net>
110 * [Robin Siebler] <robinsiebler-AT-starband.net>
111
82 * [Ralf Ahlbrink] <ralf_ahlbrink-AT-web.de>
112 * [Ralf Ahlbrink] <ralf_ahlbrink-AT-web.de>
113
83 * [Thorsten Kampe] <thorsten-AT-thorstenkampe.de>
114 * [Thorsten Kampe] <thorsten-AT-thorstenkampe.de>
115
84 * [Fredrik Kant] <fredrik.kant-AT-front.com> Windows setup.
116 * [Fredrik Kant] <fredrik.kant-AT-front.com> Windows setup.
117
85 * [Syver Enstad] <syver-en-AT-online.no> Windows setup.
118 * [Syver Enstad] <syver-en-AT-online.no> Windows setup.
119
86 * [Richard] <rxe-AT-renre-europe.com> Global embedding.
120 * [Richard] <rxe-AT-renre-europe.com> Global embedding.
121
87 * [Hayden Callow] <h.callow-AT-elec.canterbury.ac.nz> Gnuplot.py 1.6
122 * [Hayden Callow] <h.callow-AT-elec.canterbury.ac.nz> Gnuplot.py 1.6
88 compatibility.
123 compatibility.
124
89 * [Leonardo Santagada] <retype-AT-terra.com.br> Fixes for Windows
125 * [Leonardo Santagada] <retype-AT-terra.com.br> Fixes for Windows
90 installation.
126 installation.
127
91 * [Christopher Armstrong] <radix-AT-twistedmatrix.com> Bugfixes.
128 * [Christopher Armstrong] <radix-AT-twistedmatrix.com> Bugfixes.
129
92 * [Francois Pinard] <pinard-AT-iro.umontreal.ca> Code and
130 * [Francois Pinard] <pinard-AT-iro.umontreal.ca> Code and
93 documentation fixes.
131 documentation fixes.
132
94 * [Cory Dodt] <cdodt-AT-fcoe.k12.ca.us> Bug reports and Windows
133 * [Cory Dodt] <cdodt-AT-fcoe.k12.ca.us> Bug reports and Windows
95 ideas. Patches for Windows installer.
134 ideas. Patches for Windows installer.
135
96 * [Olivier Aubert] <oaubert-AT-bat710.univ-lyon1.fr> New magics.
136 * [Olivier Aubert] <oaubert-AT-bat710.univ-lyon1.fr> New magics.
137
97 * [King C. Shu] <kingshu-AT-myrealbox.com> Autoindent patch.
138 * [King C. Shu] <kingshu-AT-myrealbox.com> Autoindent patch.
139
98 * [Chris Drexler] <chris-AT-ac-drexler.de> Readline packages for
140 * [Chris Drexler] <chris-AT-ac-drexler.de> Readline packages for
99 Win32/CygWin.
141 Win32/CygWin.
142
100 * [Gustavo Cordova Avila] <gcordova-AT-sismex.com> EvalDict code for
143 * [Gustavo Cordova Avila] <gcordova-AT-sismex.com> EvalDict code for
101 nice, lightweight string interpolation.
144 nice, lightweight string interpolation.
145
102 * [Kasper Souren] <Kasper.Souren-AT-ircam.fr> Bug reports, ideas.
146 * [Kasper Souren] <Kasper.Souren-AT-ircam.fr> Bug reports, ideas.
147
103 * [Gever Tulley] <gever-AT-helium.com> Code contributions.
148 * [Gever Tulley] <gever-AT-helium.com> Code contributions.
149
104 * [Ralf Schmitt] <ralf-AT-brainbot.com> Bug reports & fixes.
150 * [Ralf Schmitt] <ralf-AT-brainbot.com> Bug reports & fixes.
151
105 * [Oliver Sander] <osander-AT-gmx.de> Bug reports.
152 * [Oliver Sander] <osander-AT-gmx.de> Bug reports.
153
106 * [Rod Holland] <rhh-AT-structurelabs.com> Bug reports and fixes to
154 * [Rod Holland] <rhh-AT-structurelabs.com> Bug reports and fixes to
107 logging module.
155 logging module.
156
108 * [Daniel 'Dang' Griffith] <pythondev-dang-AT-lazytwinacres.net>
157 * [Daniel 'Dang' Griffith] <pythondev-dang-AT-lazytwinacres.net>
109 Fixes, enhancement suggestions for system shell use.
158 Fixes, enhancement suggestions for system shell use.
159
110 * [Viktor Ransmayr] <viktor.ransmayr-AT-t-online.de> Tests and
160 * [Viktor Ransmayr] <viktor.ransmayr-AT-t-online.de> Tests and
111 reports on Windows installation issues. Contributed a true Windows
161 reports on Windows installation issues. Contributed a true Windows
112 binary installer.
162 binary installer.
163
113 * [Mike Salib] <msalib-AT-mit.edu> Help fixing a subtle bug related
164 * [Mike Salib] <msalib-AT-mit.edu> Help fixing a subtle bug related
114 to traceback printing.
165 to traceback printing.
166
115 * [W.J. van der Laan] <gnufnork-AT-hetdigitalegat.nl> Bash-like
167 * [W.J. van der Laan] <gnufnork-AT-hetdigitalegat.nl> Bash-like
116 prompt specials.
168 prompt specials.
169
117 * [Antoon Pardon] <Antoon.Pardon-AT-rece.vub.ac.be> Critical fix for
170 * [Antoon Pardon] <Antoon.Pardon-AT-rece.vub.ac.be> Critical fix for
118 the multithreaded IPython.
171 the multithreaded IPython.
172
119 * [John Hunter] <jdhunter-AT-nitace.bsd.uchicago.edu> Matplotlib
173 * [John Hunter] <jdhunter-AT-nitace.bsd.uchicago.edu> Matplotlib
120 author, helped with all the development of support for matplotlib
174 author, helped with all the development of support for matplotlib
121 in IPyhton, including making necessary changes to matplotlib itself.
175 in IPyhton, including making necessary changes to matplotlib itself.
176
122 * [Matthew Arnison] <maffew-AT-cat.org.au> Bug reports, '%run -d' idea.
177 * [Matthew Arnison] <maffew-AT-cat.org.au> Bug reports, '%run -d' idea.
178
123 * [Prabhu Ramachandran] <prabhu_r-AT-users.sourceforge.net> Help
179 * [Prabhu Ramachandran] <prabhu_r-AT-users.sourceforge.net> Help
124 with (X)Emacs support, threading patches, ideas...
180 with (X)Emacs support, threading patches, ideas...
181
125 * [Norbert Tretkowski] <tretkowski-AT-inittab.de> help with Debian
182 * [Norbert Tretkowski] <tretkowski-AT-inittab.de> help with Debian
126 packaging and distribution.
183 packaging and distribution.
184
127 * [George Sakkis] <gsakkis-AT-eden.rutgers.edu> New matcher for
185 * [George Sakkis] <gsakkis-AT-eden.rutgers.edu> New matcher for
128 tab-completing named arguments of user-defined functions.
186 tab-completing named arguments of user-defined functions.
187
129 * [Jörgen Stenarson] <jorgen.stenarson-AT-bostream.nu> Wildcard
188 * [Jörgen Stenarson] <jorgen.stenarson-AT-bostream.nu> Wildcard
130 support implementation for searching namespaces.
189 support implementation for searching namespaces.
190
131 * [Vivian De Smedt] <vivian-AT-vdesmedt.com> Debugger enhancements,
191 * [Vivian De Smedt] <vivian-AT-vdesmedt.com> Debugger enhancements,
132 so that when pdb is activated from within IPython, coloring, tab
192 so that when pdb is activated from within IPython, coloring, tab
133 completion and other features continue to work seamlessly.
193 completion and other features continue to work seamlessly.
194
134 * [Scott Tsai] <scottt958-AT-yahoo.com.tw> Support for automatic
195 * [Scott Tsai] <scottt958-AT-yahoo.com.tw> Support for automatic
135 editor invocation on syntax errors (see
196 editor invocation on syntax errors (see
136 http://www.scipy.net/roundup/ipython/issue36).
197 http://www.scipy.net/roundup/ipython/issue36).
198
137 * [Alexander Belchenko] <bialix-AT-ukr.net> Improvements for win32
199 * [Alexander Belchenko] <bialix-AT-ukr.net> Improvements for win32
138 paging system.
200 paging system.
201
139 * [Will Maier] <willmaier-AT-ml1.net> Official OpenBSD port.
202 * [Will Maier] <willmaier-AT-ml1.net> Official OpenBSD port.
203
204 * [Ondrej Certik] <ondrej-AT-certik.cz>: set up the IPython docs to use the new
205 Sphinx system used by Python, Matplotlib and many more projects.
206
207 * [Stefan van der Walt] <stefan-AT-sun.ac.za>: support for the new config system.
@@ -1,191 +1,142 b''
1 .. _development:
1 .. _development:
2
2
3 ==================================
3 ==============================
4 IPython development guidelines
4 IPython development guidelines
5 ==================================
5 ==============================
6
7 .. contents::
8
6
9
7
10 Overview
8 Overview
11 ========
9 ========
12
10
13 IPython is the next generation of IPython. It is named such for two reasons:
11 This document describes IPython from the perspective of developers. Most
14
12 importantly, it gives information for people who want to contribute to the
15 - Eventually, IPython will become IPython version 1.0.
13 development of IPython. So if you want to help out, read on!
16 - This new code base needs to be able to co-exist with the existing IPython until
17 it is a full replacement for it. Thus we needed a different name. We couldn't
18 use ``ipython`` (lowercase) as some files systems are case insensitive.
19
20 There are two, no three, main goals of the IPython effort:
21
22 1. Clean up the existing codebase and write lots of tests.
23 2. Separate the core functionality of IPython from the terminal to enable IPython
24 to be used from within a variety of GUI applications.
25 3. Implement a system for interactive parallel computing.
26
27 While the third goal may seem a bit unrelated to the main focus of IPython, it turns
28 out that the technologies required for this goal are nearly identical with those
29 required for goal two. This is the main reason the interactive parallel computing
30 capabilities are being put into IPython proper. Currently the third of these goals is
31 furthest along.
32
33 This document describes IPython from the perspective of developers.
34
35
36 Project organization
37 ====================
38
14
39 Subpackages
15 How to contribute to IPython
40 -----------
16 ============================
41
17
42 IPython is organized into semi self-contained subpackages. Each of the subpackages will have its own:
18 IPython development is done using Bazaar [Bazaar]_ and Launchpad [Launchpad]_.
19 This makes it easy for people to contribute to the development of IPython.
20 Here is a sketch of how to get going.
43
21
44 - **Dependencies**. One of the most important things to keep in mind in
22 Install Bazaar and create a Launchpad account
45 partitioning code amongst subpackages, is that they should be used to cleanly
23 ---------------------------------------------
46 encapsulate dependencies.
47 - **Tests**. Each subpackage shoud have its own ``tests`` subdirectory that
48 contains all of the tests for that package. For information about writing tests
49 for IPython, see the `Testing System`_ section of this document.
50 - **Configuration**. Each subpackage should have its own ``config`` subdirectory
51 that contains the configuration information for the components of the
52 subpackage. For information about how the IPython configuration system
53 works, see the `Configuration System`_ section of this document.
54 - **Scripts**. Each subpackage should have its own ``scripts`` subdirectory that
55 contains all of the command line scripts associated with the subpackage.
56
24
57 Installation and dependencies
25 First make sure you have installed Bazaar (see their `website
58 -----------------------------
26 <http://bazaar-vcs.org/>`_). To see that Bazaar is installed and knows about
27 you, try the following::
59
28
60 IPython will not use `setuptools`_ for installation. Instead, we will use standard
29 $ bzr whoami
61 ``setup.py`` scripts that use `distutils`_. While there are a number a extremely nice
30 Joe Coder <jcoder@gmail.com>
62 features that `setuptools`_ has (like namespace packages), the current implementation
63 of `setuptools`_ has performance problems, particularly on shared file systems. In
64 particular, when Python packages are installed on NSF file systems, import times
65 become much too long (up towards 10 seconds).
66
31
67 Because IPython is being used extensively in the context of high performance
32 This should display your name and email. Next, you will want to create an
68 computing, where performance is critical but shared file systems are common, we feel
33 account on the `Launchpad website <http://www.launchpad.net>`_ and setup your
69 these performance hits are not acceptable. Thus, until the performance problems
34 ssh keys. For more information of setting up your ssh keys, see `this link
70 associated with `setuptools`_ are addressed, we will stick with plain `distutils`_. We
35 <https://help.launchpad.net/YourAccount/CreatingAnSSHKeyPair>`_.
71 are hopeful that these problems will be addressed and that we will eventually begin
72 using `setuptools`_. Because of this, we are trying to organize IPython in a way that
73 will make the eventual transition to `setuptools`_ as painless as possible.
74
36
75 Because we will be using `distutils`_, there will be no method for automatically installing dependencies. Instead, we are following the approach of `Matplotlib`_ which can be summarized as follows:
37 Get the main IPython branch from Launchpad
38 ------------------------------------------
76
39
77 - Distinguish between required and optional dependencies. However, the required
40 Now, you can get a copy of the main IPython development branch (we call this
78 dependencies for IPython should be only the Python standard library.
41 the "trunk")::
79 - Upon installation check to see which optional dependencies are present and tell
80 the user which parts of IPython need which optional dependencies.
81
42
82 It is absolutely critical that each subpackage of IPython has a clearly specified set
43 $ bzr branch lp:ipython
83 of dependencies and that dependencies are not carelessly inherited from other IPython
84 subpackages. Furthermore, tests that have certain dependencies should not fail if
85 those dependencies are not present. Instead they should be skipped and print a
86 message.
87
88 .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
89 .. _distutils: http://docs.python.org/lib/module-distutils.html
90 .. _Matplotlib: http://matplotlib.sourceforge.net/
91
92 Specific subpackages
93 --------------------
94
95 ``core``
96 This is the core functionality of IPython that is independent of the
97 terminal, network and GUIs. Most of the code that is in the current
98 IPython trunk will be refactored, cleaned up and moved here.
99
100 ``kernel``
101 The enables the IPython core to be expose to a the network. This is
102 also where all of the parallel computing capabilities are to be found.
103
104 ``config``
105 The configuration package used by IPython.
106
44
107 ``frontends``
45 Create a working branch
108 The various frontends for IPython. A frontend is the end-user application
46 -----------------------
109 that exposes the capabilities of IPython to the user. The most basic frontend
110 will simply be a terminal based application that looks just like today 's
111 IPython. Other frontends will likely be more powerful and based on GUI toolkits.
112
47
113 ``notebook``
48 When working on IPython, you won't actually make edits directly to the
114 An application that allows users to work with IPython notebooks.
49 :file:`lp:ipython` branch. Instead, you will create a separate branch for your
115
50 changes. For now, let's assume you want to do your work in a branch named
116 ``tools``
51 "ipython-mybranch". Create this branch by doing::
117 This is where general utilities go.
118
52
53 $ bzr branch ipython ipython-mybranch
119
54
120 Version control
55 When you actually create a branch, you will want to give it a name that
121 ===============
56 reflects the nature of the work that you will be doing in it, like
122
57 "install-docs-update".
123 In the past, IPython development has been done using `Subversion`__. Recently, we made the transition to using `Bazaar`__ and `Launchpad`__. This makes it much easier for people
124 to contribute code to IPython. Here is a sketch of how to use Bazaar for IPython
125 development. First, you should install Bazaar. After you have done that, make
126 sure that it is working by getting the latest main branch of IPython::
127
58
128 $ bzr branch lp:ipython
59 Make edits in your working branch
60 ---------------------------------
129
61
130 Now you can create a new branch for you to do your work in::
62 Now you are ready to actually make edits in your :file:`ipython-mybranch`
63 branch. Before doing this, it is helpful to install this branch so you can
64 test your changes as you work. This is easiest if you have setuptools
65 installed. Then, just do::
131
66
132 $ bzr branch ipython ipython-mybranch
67 $ cd ipython-mybranch
68 $ python setupegg.py develop
133
69
134 The typical work cycle in this branch will be to make changes in `ipython-mybranch`
70 Now, make some changes. After a while, you will want to commit your changes.
135 and then commit those changes using the commit command::
71 This let's Bazaar know that you like the changes you have made and gives you
72 an opportunity to keep a nice record of what you have done. This looks like
73 this::
136
74
137 $ ...do work in ipython-mybranch...
75 $ ...do work in ipython-mybranch...
138 $ bzr ci -m "the commit message goes here"
76 $ bzr commit -m "the commit message goes here"
139
77
140 Please note that since we now don't use an old-style linear ChangeLog
78 Please note that since we now don't use an old-style linear ChangeLog (that
141 (that tends to cause problems with distributed version control
79 tends to cause problems with distributed version control systems), you should
142 systems), you should ensure that your log messages are reasonably
80 ensure that your log messages are reasonably detailed. Use a docstring-like
143 detailed. Use a docstring-like approach in the commit messages
81 approach in the commit messages (including the second line being left
144 (including the second line being left *blank*)::
82 *blank*)::
145
83
146 Single line summary of changes being committed.
84 Single line summary of changes being committed.
147
85
148 - more details when warranted ...
86 * more details when warranted ...
149 - including crediting outside contributors if they sent the
87 * including crediting outside contributors if they sent the
150 code/bug/idea!
88 code/bug/idea!
151
89
152 If we couple this with a policy of making single commits for each
90 As you work, you will repeat this edit/commit cycle many times. If you work on
153 reasonably atomic change, the bzr log should give an excellent view of
91 your branch for a long time, you will also want to get the latest changes from
154 the project, and the `--short` log option becomes a nice summary.
92 the :file:`lp:ipython` branch. This can be done with the following sequence of
93 commands::
155
94
156 While working with this branch, it is a good idea to merge in changes that have been
95 $ ls
157 made upstream in the parent branch. This can be done by doing::
96 ipython
97 ipython-mybranch
158
98
99 $ cd ipython
159 $ bzr pull
100 $ bzr pull
101 $ cd ../ipython-mybranch
102 $ bzr merge ../ipython
103 $ bzr commit -m "Merging changes from trunk"
160
104
161 If this command shows that the branches have diverged, then you should do a merge
105 Along the way, you should also run the IPython test suite. You can do this using the :command:`iptest` command::
162 instead::
163
106
164 $ bzr merge lp:ipython
107 $ cd
108 $ iptest
165
109
166 If you want others to be able to see your branch, you can create an account with
110 The :command:`iptest` command will also pick up and run any tests you have written.
167 launchpad and push the branch to your own workspace::
168
111
169 $ bzr push bzr+ssh://<me>@bazaar.launchpad.net/~<me>/+junk/ipython-mybranch
112 Post your branch and request a code review
113 ------------------------------------------
170
114
171 Finally, once the work in your branch is done, you can merge your changes back into
115 Once you are done with your edits, you should post your branch on Launchpad so
172 the `ipython` branch by using merge::
116 that other IPython developers can review the changes and help you merge your
117 changes into the main development branch. To post your branch on Launchpad,
118 do::
173
119
174 $ cd ipython
120 $ cd ipython-mybranch
175 $ merge ../ipython-mybranch
121 $ bzr push lp:~yourusername/ipython/ipython-mybranch
176 [resolve any conflicts]
177 $ bzr ci -m "Fixing that bug"
178 $ bzr push
179
122
180 But this will require you to have write permissions to the `ipython` branch. It you don't
123 Then, go to the `IPython Launchpad site <www.launchpad.net/ipython>`_, and you
181 you can tell one of the IPython devs about your branch and they can do the merge for you.
124 should see your branch under the "Code" tab. If you click on your branch, you
125 can provide a short description of the branch as well as mark its status. Most
126 importantly, you should click the link that reads "Propose for merging into
127 another branch". What does this do?
182
128
183 More information about Bazaar workflows can be found `here`__.
129 This let's the other IPython developers know that your branch is ready to be
130 reviewed and merged into the main development branch. During this review
131 process, other developers will give you feedback and help you get your code
132 ready to be merged. What types of things will we be looking for:
184
133
185 .. __: http://subversion.tigris.org/
134 * All code is documented.
186 .. __: http://bazaar-vcs.org/
135 * All code has tests.
187 .. __: http://www.launchpad.net/ipython
136 * The entire IPython test suite passes.
188 .. __: http://doc.bazaar-vcs.org/bzr.dev/en/user-guide/index.html
137
138 Once your changes have been reviewed and approved, someone will merge them
139 into the main development branch.
189
140
190 Documentation
141 Documentation
191 =============
142 =============
@@ -193,38 +144,32 b' Documentation'
193 Standalone documentation
144 Standalone documentation
194 ------------------------
145 ------------------------
195
146
196 All standalone documentation should be written in plain text (``.txt``) files using
147 All standalone documentation should be written in plain text (``.txt``) files
197 `reStructuredText`_ for markup and formatting. All such documentation should be placed
148 using reStructuredText [reStructuredText]_ for markup and formatting. All such
198 in the top level directory ``docs`` of the IPython source tree. Or, when appropriate,
149 documentation should be placed in directory :file:`docs/source` of the IPython
199 a suitably named subdirectory should be used. The documentation in this location will
150 source tree. The documentation in this location will serve as the main source
200 serve as the main source for IPython documentation and all existing documentation
151 for IPython documentation and all existing documentation should be converted
201 should be converted to this format.
152 to this format.
202
153
203 In the future, the text files in the ``docs`` directory will be used to generate all
154 To build the final documentation, we use Sphinx [Sphinx]_. Once you have Sphinx installed, you can build the html docs yourself by doing::
204 forms of documentation for IPython. This include documentation on the IPython website
205 as well as *pdf* documentation.
206
155
207 .. _reStructuredText: http://docutils.sourceforge.net/rst.html
156 $ cd ipython-mybranch/docs
157 $ make html
208
158
209 Docstring format
159 Docstring format
210 ----------------
160 ----------------
211
161
212 Good docstrings are very important. All new code will use `Epydoc`_ for generating API
162 Good docstrings are very important. All new code should have docstrings that
213 docs, so we will follow the `Epydoc`_ conventions. More specifically, we will use
163 are formatted using reStructuredText for markup and formatting, since it is
214 `reStructuredText`_ for markup and formatting, since it is understood by a wide
164 understood by a wide variety of tools. Details about using reStructuredText
215 variety of tools. This means that if in the future we have any reason to change from
165 for docstrings can be found `here
216 `Epydoc`_ to something else, we'll have fewer transition pains.
217
218 Details about using `reStructuredText`_ for docstrings can be found `here
219 <http://epydoc.sourceforge.net/manual-othermarkup.html>`_.
166 <http://epydoc.sourceforge.net/manual-othermarkup.html>`_.
220
167
221 .. _Epydoc: http://epydoc.sourceforge.net/
222
223 Additional PEPs of interest regarding documentation of code:
168 Additional PEPs of interest regarding documentation of code:
224
169
225 - `Docstring Conventions <http://www.python.org/peps/pep-0257.html>`_
170 * `Docstring Conventions <http://www.python.org/peps/pep-0257.html>`_
226 - `Docstring Processing System Framework <http://www.python.org/peps/pep-0256.html>`_
171 * `Docstring Processing System Framework <http://www.python.org/peps/pep-0256.html>`_
227 - `Docutils Design Specification <http://www.python.org/peps/pep-0258.html>`_
172 * `Docutils Design Specification <http://www.python.org/peps/pep-0258.html>`_
228
173
229
174
230 Coding conventions
175 Coding conventions
@@ -233,128 +178,133 b' Coding conventions'
233 General
178 General
234 -------
179 -------
235
180
236 In general, we'll try to follow the standard Python style conventions as described here:
181 In general, we'll try to follow the standard Python style conventions as
182 described here:
237
183
238 - `Style Guide for Python Code <http://www.python.org/peps/pep-0008.html>`_
184 * `Style Guide for Python Code <http://www.python.org/peps/pep-0008.html>`_
239
185
240
186
241 Other comments:
187 Other comments:
242
188
243 - In a large file, top level classes and functions should be
189 * In a large file, top level classes and functions should be
244 separated by 2-3 lines to make it easier to separate them visually.
190 separated by 2-3 lines to make it easier to separate them visually.
245 - Use 4 spaces for indentation.
191 * Use 4 spaces for indentation.
246 - Keep the ordering of methods the same in classes that have the same
192 * Keep the ordering of methods the same in classes that have the same
247 methods. This is particularly true for classes that implement
193 methods. This is particularly true for classes that implement an interface.
248 similar interfaces and for interfaces that are similar.
249
194
250 Naming conventions
195 Naming conventions
251 ------------------
196 ------------------
252
197
253 In terms of naming conventions, we'll follow the guidelines from the `Style Guide for
198 In terms of naming conventions, we'll follow the guidelines from the `Style
254 Python Code`_.
199 Guide for Python Code`_.
255
200
256 For all new IPython code (and much existing code is being refactored), we'll use:
201 For all new IPython code (and much existing code is being refactored), we'll use:
257
202
258 - All ``lowercase`` module names.
203 * All ``lowercase`` module names.
259
204
260 - ``CamelCase`` for class names.
205 * ``CamelCase`` for class names.
261
206
262 - ``lowercase_with_underscores`` for methods, functions, variables and attributes.
207 * ``lowercase_with_underscores`` for methods, functions, variables and
208 attributes.
263
209
264 This may be confusing as most of the existing IPython codebase uses a different convention (``lowerCamelCase`` for methods and attributes). Slowly, we will move IPython over to the new
210 There are, however, some important exceptions to these rules. In some cases,
265 convention, providing shadow names for backward compatibility in public interfaces.
211 IPython code will interface with packages (Twisted, Wx, Qt) that use other
212 conventions. At some level this makes it impossible to adhere to our own
213 standards at all times. In particular, when subclassing classes that use other
214 naming conventions, you must follow their naming conventions. To deal with
215 cases like this, we propose the following policy:
266
216
267 There are, however, some important exceptions to these rules. In some cases, IPython
217 * If you are subclassing a class that uses different conventions, use its
268 code will interface with packages (Twisted, Wx, Qt) that use other conventions. At some level this makes it impossible to adhere to our own standards at all times. In particular, when subclassing classes that use other naming conventions, you must follow their naming conventions. To deal with cases like this, we propose the following policy:
269
270 - If you are subclassing a class that uses different conventions, use its
271 naming conventions throughout your subclass. Thus, if you are creating a
218 naming conventions throughout your subclass. Thus, if you are creating a
272 Twisted Protocol class, used Twisted's ``namingSchemeForMethodsAndAttributes.``
219 Twisted Protocol class, used Twisted's
220 ``namingSchemeForMethodsAndAttributes.``
273
221
274 - All IPython's official interfaces should use our conventions. In some cases
222 * All IPython's official interfaces should use our conventions. In some cases
275 this will mean that you need to provide shadow names (first implement ``fooBar``
223 this will mean that you need to provide shadow names (first implement
276 and then ``foo_bar = fooBar``). We want to avoid this at all costs, but it
224 ``fooBar`` and then ``foo_bar = fooBar``). We want to avoid this at all
277 will probably be necessary at times. But, please use this sparingly!
225 costs, but it will probably be necessary at times. But, please use this
226 sparingly!
278
227
279 Implementation-specific *private* methods will use ``_single_underscore_prefix``.
228 Implementation-specific *private* methods will use
280 Names with a leading double underscore will *only* be used in special cases, as they
229 ``_single_underscore_prefix``. Names with a leading double underscore will
281 makes subclassing difficult (such names are not easily seen by child classes).
230 *only* be used in special cases, as they makes subclassing difficult (such
231 names are not easily seen by child classes).
282
232
283 Occasionally some run-in lowercase names are used, but mostly for very short names or
233 Occasionally some run-in lowercase names are used, but mostly for very short
284 where we are implementing methods very similar to existing ones in a base class (like
234 names or where we are implementing methods very similar to existing ones in a
285 ``runlines()`` where ``runsource()`` and ``runcode()`` had established precedent).
235 base class (like ``runlines()`` where ``runsource()`` and ``runcode()`` had
236 established precedent).
286
237
287 The old IPython codebase has a big mix of classes and modules prefixed with an
238 The old IPython codebase has a big mix of classes and modules prefixed with an
288 explicit ``IP``. In Python this is mostly unnecessary, redundant and frowned upon, as
239 explicit ``IP``. In Python this is mostly unnecessary, redundant and frowned
289 namespaces offer cleaner prefixing. The only case where this approach is justified is
240 upon, as namespaces offer cleaner prefixing. The only case where this approach
290 for classes which are expected to be imported into external namespaces and a very
241 is justified is for classes which are expected to be imported into external
291 generic name (like Shell) is too likely to clash with something else. We'll need to
242 namespaces and a very generic name (like Shell) is too likely to clash with
292 revisit this issue as we clean up and refactor the code, but in general we should
243 something else. We'll need to revisit this issue as we clean up and refactor
293 remove as many unnecessary ``IP``/``ip`` prefixes as possible. However, if a prefix
244 the code, but in general we should remove as many unnecessary ``IP``/``ip``
294 seems absolutely necessary the more specific ``IPY`` or ``ipy`` are preferred.
245 prefixes as possible. However, if a prefix seems absolutely necessary the more
246 specific ``IPY`` or ``ipy`` are preferred.
295
247
296 .. _devel_testing:
248 .. _devel_testing:
297
249
298 Testing system
250 Testing system
299 ==============
251 ==============
300
252
301 It is extremely important that all code contributed to IPython has tests. Tests should
253 It is extremely important that all code contributed to IPython has tests.
302 be written as unittests, doctests or as entities that the `Nose`_ testing package will
254 Tests should be written as unittests, doctests or as entities that the Nose
303 find. Regardless of how the tests are written, we will use `Nose`_ for discovering and
255 [Nose]_ testing package will find. Regardless of how the tests are written, we
304 running the tests. `Nose`_ will be required to run the IPython test suite, but will
256 will use Nose for discovering and running the tests. Nose will be required to
305 not be required to simply use IPython.
257 run the IPython test suite, but will not be required to simply use IPython.
306
307 .. _Nose: http://code.google.com/p/python-nose/
308
258
309 Tests of `Twisted`__ using code should be written by subclassing the ``TestCase`` class
259 Tests of Twisted using code need to follow two additional guidelines:
310 that comes with ``twisted.trial.unittest``. When this is done, `Nose`_ will be able to
311 run the tests and the twisted reactor will be handled correctly.
312
260
313 .. __: http://www.twistedmatrix.com
261 1. Twisted using tests should be written by subclassing the :class:`TestCase`
262 class that comes with :mod:`twisted.trial.unittest`.
314
263
315 Each subpackage in IPython should have its own ``tests`` directory that contains all
264 2. All :class:`Deferred` instances that are created in the test must be
316 of the tests for that subpackage. This allows each subpackage to be self-contained. If
265 properly chained and the final one *must* be the return value of the test
317 a subpackage has any dependencies beyond the Python standard library, the tests for
266 method.
318 that subpackage should be skipped if the dependencies are not found. This is very
319 important so users don't get tests failing simply because they don't have dependencies.
320
267
321 We also need to look into use Noses ability to tag tests to allow a more modular
268 When these two things are done, Nose will be able to run the tests and the
322 approach of running tests.
269 twisted reactor will be handled correctly.
323
324 .. _devel_config:
325
270
326 Configuration system
271 Each subpackage in IPython should have its own :file:`tests` directory that
327 ====================
272 contains all of the tests for that subpackage. This allows each subpackage to
273 be self-contained. If a subpackage has any dependencies beyond the Python
274 standard library, the tests for that subpackage should be skipped if the
275 dependencies are not found. This is very important so users don't get tests
276 failing simply because they don't have dependencies.
328
277
329 IPython uses `.ini`_ files for configuration purposes. This represents a huge
278 To run the IPython test suite, use the :command:`iptest` command that is installed with IPython::
330 improvement over the configuration system used in IPython. IPython works with these
331 files using the `ConfigObj`_ package, which IPython includes as
332 ``ipython1/external/configobj.py``.
333
279
334 Currently, we are using raw `ConfigObj`_ objects themselves. Each subpackage of IPython
280 $ iptest
335 should contain a ``config`` subdirectory that contains all of the configuration
336 information for the subpackage. To see how configuration information is defined (along
337 with defaults) see at the examples in ``ipython1/kernel/config`` and
338 ``ipython1/core/config``. Likewise, to see how the configuration information is used,
339 see examples in ``ipython1/kernel/scripts/ipengine.py``.
340
341 Eventually, we will add a new layer on top of the raw `ConfigObj`_ objects. We are
342 calling this new layer, ``tconfig``, as it will use a `Traits`_-like validation model.
343 We won't actually use `Traits`_, but will implement something similar in pure Python.
344 But, even in this new system, we will still use `ConfigObj`_ and `.ini`_ files
345 underneath the hood. Talk to Fernando if you are interested in working on this part of
346 IPython. The current prototype of ``tconfig`` is located in the IPython sandbox.
347
348 .. _.ini: http://docs.python.org/lib/module-ConfigParser.html
349 .. _ConfigObj: http://www.voidspace.org.uk/python/configobj.html
350 .. _Traits: http://code.enthought.com/traits/
351
281
282 This command runs Nose with the proper options and extensions.
352
283
284 .. _devel_config:
353
285
286 Release checklist
287 =================
354
288
289 Most of the release process is automated by the :file:`release` script in the
290 :file:`tools` directory. This is just a handy reminder for the release manager.
355
291
292 #. Run the release script, which makes the tar.gz, eggs and Win32 .exe
293 installer. It posts them to the site and registers the release with PyPI.
356
294
295 #. Updating the website with announcements and links to the updated
296 changes.txt in html form. Remember to put a short note both on the news
297 page of the site and on Launcphad.
357
298
299 #. Drafting a short release announcement with i) highlights and ii) a link to
300 the html changes.txt.
358
301
302 #. Make sure that the released version of the docs is live on the site.
359
303
304 #. Celebrate!
360
305
306 .. [Bazaar] Bazaar. http://bazaar-vcs.org/
307 .. [Launchpad] Launchpad. http://www.launchpad.net/ipython
308 .. [reStructuredText] reStructuredText. http://docutils.sourceforge.net/rst.html
309 .. [Sphinx] Sphinx. http://sphinx.pocoo.org/
310 .. [Nose] Nose: a discovery based unittest extension. http://code.google.com/p/python-nose/
@@ -7,3 +7,5 b' Development'
7
7
8 development.txt
8 development.txt
9 roadmap.txt
9 roadmap.txt
10 notification_blueprint.txt
11 config_blueprint.txt
@@ -1,4 +1,4 b''
1 .. Notification:
1 .. _notification:
2
2
3 ==========================================
3 ==========================================
4 IPython.kernel.core.notification blueprint
4 IPython.kernel.core.notification blueprint
@@ -6,41 +6,77 b' IPython.kernel.core.notification blueprint'
6
6
7 Overview
7 Overview
8 ========
8 ========
9 The :mod:`IPython.kernel.core.notification` module will provide a simple implementation of a notification center and support for the observer pattern within the :mod:`IPython.kernel.core`. The main intended use case is to provide notification of Interpreter events to an observing frontend during the execution of a single block of code.
9
10 The :mod:`IPython.kernel.core.notification` module will provide a simple
11 implementation of a notification center and support for the observer pattern
12 within the :mod:`IPython.kernel.core`. The main intended use case is to
13 provide notification of Interpreter events to an observing frontend during the
14 execution of a single block of code.
10
15
11 Functional Requirements
16 Functional Requirements
12 =======================
17 =======================
18
13 The notification center must:
19 The notification center must:
20
14 * Provide synchronous notification of events to all registered observers.
21 * Provide synchronous notification of events to all registered observers.
15 * Provide typed or labeled notification types
22
16 * Allow observers to register callbacks for individual or all notification types
23 * Provide typed or labeled notification types.
17 * Allow observers to register callbacks for events from individual or all notifying objects
24
18 * Notification to the observer consists of the notification type, notifying object and user-supplied extra information [implementation: as keyword parameters to the registered callback]
25 * Allow observers to register callbacks for individual or all notification
26 types.
27
28 * Allow observers to register callbacks for events from individual or all
29 notifying objects.
30
31 * Notification to the observer consists of the notification type, notifying
32 object and user-supplied extra information [implementation: as keyword
33 parameters to the registered callback].
34
19 * Perform as O(1) in the case of no registered observers.
35 * Perform as O(1) in the case of no registered observers.
36
20 * Permit out-of-process or cross-network extension.
37 * Permit out-of-process or cross-network extension.
21
38
22 What's not included
39 What's not included
23 ==============================================================
40 ===================
41
24 As written, the :mod:`IPython.kernel.core.notificaiton` module does not:
42 As written, the :mod:`IPython.kernel.core.notificaiton` module does not:
25 * Provide out-of-process or network notifications [these should be handled by a separate, Twisted aware module in :mod:`IPython.kernel`].
43
26 * Provide zope.interface-style interfaces for the notification system [these should also be provided by the :mod:`IPython.kernel` module]
44 * Provide out-of-process or network notifications (these should be handled by
45 a separate, Twisted aware module in :mod:`IPython.kernel`).
46
47 * Provide zope.interface-style interfaces for the notification system (these
48 should also be provided by the :mod:`IPython.kernel` module).
27
49
28 Use Cases
50 Use Cases
29 =========
51 =========
52
30 The following use cases describe the main intended uses of the notificaiton module and illustrate the main success scenario for each use case:
53 The following use cases describe the main intended uses of the notificaiton module and illustrate the main success scenario for each use case:
31
54
32 1. Dwight Schroot is writing a frontend for the IPython project. His frontend is stuck in the stone age and must communicate synchronously with an IPython.kernel.core.Interpreter instance. Because code is executed in blocks by the Interpreter, Dwight's UI freezes every time he executes a long block of code. To keep track of the progress of his long running block, Dwight adds the following code to his frontend's set-up code::
55 1. Dwight Schroot is writing a frontend for the IPython project. His frontend is stuck in the stone age and must communicate synchronously with an IPython.kernel.core.Interpreter instance. Because code is executed in blocks by the Interpreter, Dwight's UI freezes every time he executes a long block of code. To keep track of the progress of his long running block, Dwight adds the following code to his frontend's set-up code::
56
33 from IPython.kernel.core.notification import NotificationCenter
57 from IPython.kernel.core.notification import NotificationCenter
34 center = NotificationCenter.sharedNotificationCenter
58 center = NotificationCenter.sharedNotificationCenter
35 center.registerObserver(self, type=IPython.kernel.core.Interpreter.STDOUT_NOTIFICATION_TYPE, notifying_object=self.interpreter, callback=self.stdout_notification)
59 center.registerObserver(self, type=IPython.kernel.core.Interpreter.STDOUT_NOTIFICATION_TYPE, notifying_object=self.interpreter, callback=self.stdout_notification)
36
60
37 and elsewhere in his front end::
61 and elsewhere in his front end::
62
38 def stdout_notification(self, type, notifying_object, out_string=None):
63 def stdout_notification(self, type, notifying_object, out_string=None):
39 self.writeStdOut(out_string)
64 self.writeStdOut(out_string)
40
65
41 If everything works, the Interpreter will (according to its published API) fire a notification via the :data:`IPython.kernel.core.notification.sharedCenter` of type :const:`STD_OUT_NOTIFICATION_TYPE` before writing anything to stdout [it's up to the Intereter implementation to figure out when to do this]. The notificaiton center will then call the registered callbacks for that event type (in this case, Dwight's frontend's stdout_notification method). Again, according to its API, the Interpreter provides an additional keyword argument when firing the notificaiton of out_string, a copy of the string it will write to stdout.
66 If everything works, the Interpreter will (according to its published API)
67 fire a notification via the
68 :data:`IPython.kernel.core.notification.sharedCenter` of type
69 :const:`STD_OUT_NOTIFICATION_TYPE` before writing anything to stdout [it's up
70 to the Intereter implementation to figure out when to do this]. The
71 notificaiton center will then call the registered callbacks for that event
72 type (in this case, Dwight's frontend's stdout_notification method). Again,
73 according to its API, the Interpreter provides an additional keyword argument
74 when firing the notificaiton of out_string, a copy of the string it will write
75 to stdout.
42
76
43 Like magic, Dwight's frontend is able to provide output, even during long-running calculations. Now if Jim could just convince Dwight to use Twisted...
77 Like magic, Dwight's frontend is able to provide output, even during
78 long-running calculations. Now if Jim could just convince Dwight to use
79 Twisted...
44
80
45 2. Boss Hog is writing a frontend for the IPython project. Because Boss Hog is stuck in the stone age, his frontend will be written in a new Fortran-like dialect of python and will run only from the command line. Because he doesn't need any fancy notification system and is used to worrying about every cycle on his rat-wheel powered mini, Boss Hog is adamant that the new notification system not produce any performance penalty. As they say in Hazard county, there's no such thing as a free lunch. If he wanted zero overhead, he should have kept using IPython 0.8. Instead, those tricky Duke boys slide in a suped-up bridge-out jumpin' awkwardly confederate-lovin' notification module that imparts only a constant (and small) performance penalty when the Interpreter (or any other object) fires an event for which there are no registered observers. Of course, the same notificaiton-enabled Interpreter can then be used in frontends that require notifications, thus saving the IPython project from a nasty civil war.
81 2. Boss Hog is writing a frontend for the IPython project. Because Boss Hog is stuck in the stone age, his frontend will be written in a new Fortran-like dialect of python and will run only from the command line. Because he doesn't need any fancy notification system and is used to worrying about every cycle on his rat-wheel powered mini, Boss Hog is adamant that the new notification system not produce any performance penalty. As they say in Hazard county, there's no such thing as a free lunch. If he wanted zero overhead, he should have kept using IPython 0.8. Instead, those tricky Duke boys slide in a suped-up bridge-out jumpin' awkwardly confederate-lovin' notification module that imparts only a constant (and small) performance penalty when the Interpreter (or any other object) fires an event for which there are no registered observers. Of course, the same notificaiton-enabled Interpreter can then be used in frontends that require notifications, thus saving the IPython project from a nasty civil war.
46
82
@@ -4,93 +4,78 b''
4 Development roadmap
4 Development roadmap
5 ===================
5 ===================
6
6
7 .. contents::
8
9 IPython is an ambitious project that is still under heavy development. However, we want IPython to become useful to as many people as possible, as quickly as possible. To help us accomplish this, we are laying out a roadmap of where we are headed and what needs to happen to get there. Hopefully, this will help the IPython developers figure out the best things to work on for each upcoming release.
7 IPython is an ambitious project that is still under heavy development. However, we want IPython to become useful to as many people as possible, as quickly as possible. To help us accomplish this, we are laying out a roadmap of where we are headed and what needs to happen to get there. Hopefully, this will help the IPython developers figure out the best things to work on for each upcoming release.
10
8
11 Speaking of releases, we are going to begin releasing a new version of IPython every four weeks. We are hoping that a regular release schedule, along with a clear roadmap of where we are headed will propel the project forward.
9 Work targeted to particular releases
12
10 ====================================
13 Where are we headed
14 ===================
15
11
16 Our goal with IPython is simple: to provide a *powerful*, *robust* and *easy to use* framework for parallel computing. While there are other secondary goals you will hear us talking about at various times, this is the primary goal of IPython that frames the roadmap.
12 Release 0.10
17
13 ------------
18 Steps along the way
19 ===================
20
14
21 Here we describe the various things that we need to work on to accomplish this goal.
15 * Initial refactor of :command:`ipcluster`.
22
16
23 Setting up for regular release schedule
17 * Better TextMate integration.
24 ---------------------------------------
25
18
26 We would like to begin to release IPython regularly (probably a 4 week release cycle). To get ready for this, we need to revisit the development guidelines and put in information about releasing IPython.
19 * Merge in the daemon branch.
27
20
28 Process startup and management
21 Release 0.11
29 ------------------------------
22 ------------
30
23
31 IPython is implemented using a distributed set of processes that communicate using TCP/IP network channels. Currently, users have to start each of the various processes separately using command line scripts. This is both difficult and error prone. Furthermore, there are a number of things that often need to be managed once the processes have been started, such as the sending of signals and the shutting down and cleaning up of processes.
24 * Refactor the configuration system and command line options for
25 :command:`ipengine` and :command:`ipcontroller`. This will include the
26 creation of cluster directories that encapsulate all the configuration
27 files, log files and security related files for a particular cluster.
32
28
33 We need to build a system that makes it trivial for users to start and manage IPython processes. This system should have the following properties:
29 * Refactor :command:`ipcluster` to support the new configuration system.
34
30
35 * It should possible to do everything through an extremely simple API that users
31 * Refactor the daemon stuff to support the new configuration system.
36 can call from their own Python script. No shell commands should be needed.
37 * This simple API should be configured using standard .ini files.
38 * The system should make it possible to start processes using a number of different
39 approaches: SSH, PBS/Torque, Xgrid, Windows Server, mpirun, etc.
40 * The controller and engine processes should each have a daemon for monitoring,
41 signaling and clean up.
42 * The system should be secure.
43 * The system should work under all the major operating systems, including
44 Windows.
45
32
46 Initial work has begun on the daemon infrastructure, and some of the needed logic is contained in the ipcluster script.
33 * Merge back in the core of the notebook.
47
34
48 Ease of use/high-level approaches to parallelism
35 Release 0.12
49 ------------------------------------------------
36 ------------
50
37
51 While our current API for clients is well designed, we can still do a lot better in designing a user-facing API that is super simple. The main goal here is that it should take *almost no extra code* for users to get their code running in parallel. For this to be possible, we need to tie into Python's standard idioms that enable efficient coding. The biggest ones we are looking at are using context managers (i.e., Python 2.5's ``with`` statement) and decorators. Initial work on this front has begun, but more work is needed.
38 * Fully integrate process startup with the daemons for full process
39 management.
52
40
53 We also need to think about new models for expressing parallelism. This is fun work as most of the foundation has already been established.
41 * Make the capabilites of :command:`ipcluster` available from simple Python
42 classes.
54
43
55 Security
44 Major areas of work
56 --------
45 ===================
57
46
58 Currently, IPython has no built in security or security model. Because we would like IPython to be usable on public computer systems and over wide area networks, we need to come up with a robust solution for security. Here are some of the specific things that need to be included:
47 Refactoring the main IPython core
48 ---------------------------------
59
49
60 * User authentication between all processes (engines, controller and clients).
50 Process management for :mod:`IPython.kernel`
61 * Optional TSL/SSL based encryption of all communication channels.
51 --------------------------------------------
62 * A good way of picking network ports so multiple users on the same system can
63 run their own controller and engines without interfering with those of others.
64 * A clear model for security that enables users to evaluate the security risks
65 associated with using IPython in various manners.
66
52
67 For the implementation of this, we plan on using Twisted's support for SSL and authentication. One things that we really should look at is the `Foolscap`_ network protocol, which provides many of these things out of the box.
53 Configuration system
54 --------------------
68
55
69 .. _Foolscap: http://foolscap.lothar.com/trac
56 Performance problems
57 --------------------
70
58
71 The security work needs to be done in conjunction with other network protocol stuff.
59 Currently, we have a number of performance issues that are waiting to bite users:
72
60
73 Latent performance issues
61 * The controller stores a large amount of state in Python dictionaries. Under
74 -------------------------
62 heavy usage, these dicts with get very large, causing memory usage problems.
63 We need to develop more scalable solutions to this problem, such as using a
64 sqlite database to store this state. This will also help the controller to
65 be more fault tolerant.
75
66
76 Currently, we have a number of performance issues that are waiting to bite users:
67 * We currently don't have a good way of handling large objects in the
68 controller. The biggest problem is that because we don't have any way of
69 streaming objects, we get lots of temporary copies in the low-level buffers.
70 We need to implement a better serialization approach and true streaming
71 support.
77
72
78 * The controller store a large amount of state in Python dictionaries. Under heavy
79 usage, these dicts with get very large, causing memory usage problems. We need to
80 develop more scalable solutions to this problem, such as using a sqlite database
81 to store this state. This will also help the controller to be more fault tolerant.
82 * Currently, the client to controller connections are done through XML-RPC using
83 HTTP 1.0. This is very inefficient as XML-RPC is a very verbose protocol and
84 each request must be handled with a new connection. We need to move these network
85 connections over to PB or Foolscap.
86 * We currently don't have a good way of handling large objects in the controller.
87 The biggest problem is that because we don't have any way of streaming objects,
88 we get lots of temporary copies in the low-level buffers. We need to implement
89 a better serialization approach and true streaming support.
90 * The controller currently unpickles and repickles objects. We need to use the
73 * The controller currently unpickles and repickles objects. We need to use the
91 [push|pull]_serialized methods instead.
74 [push|pull]_serialized methods instead.
92 * Currently the controller is a bottleneck. We need the ability to scale the
75
93 controller by aggregating multiple controllers into one effective controller.
76 * Currently the controller is a bottleneck. The best approach for this is to
77 separate the controller itself into multiple processes, one for the core
78 controller and one each for the controller interfaces.
94
79
95
80
96
81
@@ -17,8 +17,11 b' Yes and no. When converting a serial code to run in parallel, there often many'
17 difficulty questions that need to be answered, such as:
17 difficulty questions that need to be answered, such as:
18
18
19 * How should data be decomposed onto the set of processors?
19 * How should data be decomposed onto the set of processors?
20
20 * What are the data movement patterns?
21 * What are the data movement patterns?
22
21 * Can the algorithm be structured to minimize data movement?
23 * Can the algorithm be structured to minimize data movement?
24
22 * Is dynamic load balancing important?
25 * Is dynamic load balancing important?
23
26
24 We can't answer such questions for you. This is the hard (but fun) work of parallel
27 We can't answer such questions for you. This is the hard (but fun) work of parallel
@@ -28,9 +31,7 b' resulting parallel code interactively.'
28
31
29 With that said, if your problem is trivial to parallelize, IPython has a number of
32 With that said, if your problem is trivial to parallelize, IPython has a number of
30 different interfaces that will enable you to parallelize things is almost no time at
33 different interfaces that will enable you to parallelize things is almost no time at
31 all. A good place to start is the ``map`` method of our `multiengine interface`_.
34 all. A good place to start is the ``map`` method of our :class:`MultiEngineClient`.
32
33 .. _multiengine interface: ./parallel_multiengine
34
35
35 What is the best way to use MPI from Python?
36 What is the best way to use MPI from Python?
36 --------------------------------------------
37 --------------------------------------------
@@ -44,21 +45,28 b' Some of the unique characteristic of IPython are:'
44 parallel computation in such a way that new models of parallel computing
45 parallel computation in such a way that new models of parallel computing
45 can be explored quickly and easily. If you don't like the models we
46 can be explored quickly and easily. If you don't like the models we
46 provide, you can simply create your own using the capabilities we provide.
47 provide, you can simply create your own using the capabilities we provide.
48
47 * IPython is asynchronous from the ground up (we use `Twisted`_).
49 * IPython is asynchronous from the ground up (we use `Twisted`_).
50
48 * IPython's architecture is designed to avoid subtle problems
51 * IPython's architecture is designed to avoid subtle problems
49 that emerge because of Python's global interpreter lock (GIL).
52 that emerge because of Python's global interpreter lock (GIL).
50 * While IPython'1 architecture is designed to support a wide range
53
54 * While IPython's architecture is designed to support a wide range
51 of novel parallel computing models, it is fully interoperable with
55 of novel parallel computing models, it is fully interoperable with
52 traditional MPI applications.
56 traditional MPI applications.
57
53 * IPython has been used and tested extensively on modern supercomputers.
58 * IPython has been used and tested extensively on modern supercomputers.
59
54 * IPython's networking layers are completely modular. Thus, is
60 * IPython's networking layers are completely modular. Thus, is
55 straightforward to replace our existing network protocols with
61 straightforward to replace our existing network protocols with
56 high performance alternatives (ones based upon Myranet/Infiniband).
62 high performance alternatives (ones based upon Myranet/Infiniband).
63
57 * IPython is designed from the ground up to support collaborative
64 * IPython is designed from the ground up to support collaborative
58 parallel computing. This enables multiple users to actively develop
65 parallel computing. This enables multiple users to actively develop
59 and run the *same* parallel computation.
66 and run the *same* parallel computation.
67
60 * Interactivity is a central goal for us. While IPython does not have
68 * Interactivity is a central goal for us. While IPython does not have
61 to be used interactivly, is can be.
69 to be used interactivly, it can be.
62
70
63 .. _Twisted: http://www.twistedmatrix.com
71 .. _Twisted: http://www.twistedmatrix.com
64
72
@@ -72,11 +80,15 b' is structured in this way, you really should think about alternative ways of'
72 handling the data movement. Here are some ideas:
80 handling the data movement. Here are some ideas:
73
81
74 1. Have the engines write data to files on the locals disks of the engines.
82 1. Have the engines write data to files on the locals disks of the engines.
83
75 2. Have the engines write data to files on a file system that is shared by
84 2. Have the engines write data to files on a file system that is shared by
76 the engines.
85 the engines.
86
77 3. Have the engines write data to a database that is shared by the engines.
87 3. Have the engines write data to a database that is shared by the engines.
88
78 4. Simply keep data in the persistent memory of the engines and move the
89 4. Simply keep data in the persistent memory of the engines and move the
79 computation to the data (rather than the data to the computation).
90 computation to the data (rather than the data to the computation).
91
80 5. See if you can pass data directly between engines using MPI.
92 5. See if you can pass data directly between engines using MPI.
81
93
82 Isn't Python slow to be used for high-performance parallel computing?
94 Isn't Python slow to be used for high-performance parallel computing?
@@ -7,19 +7,22 b' History'
7 Origins
7 Origins
8 =======
8 =======
9
9
10 The current IPython system grew out of the following three projects:
10 IPython was starting in 2001 by Fernando Perez. IPython as we know it
11 today grew out of the following three projects:
11
12
12 * [ipython] by Fernando Pérez. I was working on adding
13 * ipython by Fernando Pérez. I was working on adding
13 Mathematica-type prompts and a flexible configuration system
14 Mathematica-type prompts and a flexible configuration system
14 (something better than $PYTHONSTARTUP) to the standard Python
15 (something better than $PYTHONSTARTUP) to the standard Python
15 interactive interpreter.
16 interactive interpreter.
16 * [IPP] by Janko Hauser. Very well organized, great usability. Had
17 * IPP by Janko Hauser. Very well organized, great usability. Had
17 an old help system. IPP was used as the 'container' code into
18 an old help system. IPP was used as the 'container' code into
18 which I added the functionality from ipython and LazyPython.
19 which I added the functionality from ipython and LazyPython.
19 * [LazyPython] by Nathan Gray. Simple but very powerful. The quick
20 * LazyPython by Nathan Gray. Simple but very powerful. The quick
20 syntax (auto parens, auto quotes) and verbose/colored tracebacks
21 syntax (auto parens, auto quotes) and verbose/colored tracebacks
21 were all taken from here.
22 were all taken from here.
22
23
24 Here is how Fernando describes it:
25
23 When I found out about IPP and LazyPython I tried to join all three
26 When I found out about IPP and LazyPython I tried to join all three
24 into a unified system. I thought this could provide a very nice
27 into a unified system. I thought this could provide a very nice
25 working environment, both for regular programming and scientific
28 working environment, both for regular programming and scientific
@@ -28,29 +31,8 b' prompt history and great object introspection and help facilities. I'
28 think it worked reasonably well, though it was a lot more work than I
31 think it worked reasonably well, though it was a lot more work than I
29 had initially planned.
32 had initially planned.
30
33
34 Today and how we got here
35 =========================
31
36
32 Current status
37 This needs to be filled in.
33 ==============
34
35 The above listed features work, and quite well for the most part. But
36 until a major internal restructuring is done (see below), only bug
37 fixing will be done, no other features will be added (unless very minor
38 and well localized in the cleaner parts of the code).
39
40 IPython consists of some 18000 lines of pure python code, of which
41 roughly two thirds is reasonably clean. The rest is, messy code which
42 needs a massive restructuring before any further major work is done.
43 Even the messy code is fairly well documented though, and most of the
44 problems in the (non-existent) class design are well pointed to by a
45 PyChecker run. So the rewriting work isn't that bad, it will just be
46 time-consuming.
47
48
49 Future
50 ------
51
38
52 See the separate new_design document for details. Ultimately, I would
53 like to see IPython become part of the standard Python distribution as a
54 'big brother with batteries' to the standard Python interactive
55 interpreter. But that will never happen with the current state of the
56 code, so all contributions are welcome. No newline at end of file
@@ -2,11 +2,15 b''
2 IPython Documentation
2 IPython Documentation
3 =====================
3 =====================
4
4
5 Contents
5 .. htmlonly::
6 ========
6
7 :Release: |release|
8 :Date: |today|
9
10 Contents:
7
11
8 .. toctree::
12 .. toctree::
9 :maxdepth: 1
13 :maxdepth: 2
10
14
11 overview.txt
15 overview.txt
12 install/index.txt
16 install/index.txt
@@ -20,9 +24,7 b' Contents'
20 license_and_copyright.txt
24 license_and_copyright.txt
21 credits.txt
25 credits.txt
22
26
23 Indices and tables
27 .. htmlonly::
24 ==================
25
26 * :ref:`genindex`
28 * :ref:`genindex`
27 * :ref:`modindex`
29 * :ref:`modindex`
28 * :ref:`search`
30 * :ref:`search`
@@ -7,5 +7,4 b' Installation'
7 .. toctree::
7 .. toctree::
8 :maxdepth: 2
8 :maxdepth: 2
9
9
10 basic.txt
10 install.txt
11 advanced.txt
@@ -3,7 +3,7 b' Using IPython for interactive work'
3 ==================================
3 ==================================
4
4
5 .. toctree::
5 .. toctree::
6 :maxdepth: 1
6 :maxdepth: 2
7
7
8 tutorial.txt
8 tutorial.txt
9 reference.txt
9 reference.txt
@@ -1,14 +1,8 b''
1 .. IPython documentation master file, created by sphinx-quickstart.py on Mon Mar 24 17:01:34 2008.
2 You can adapt this file completely to your liking, but it should at least
3 contain the root 'toctree' directive.
4
5 =================
1 =================
6 IPython reference
2 IPython reference
7 =================
3 =================
8
4
9 .. contents::
5 .. _command_line_options:
10
11 .. _Command line options:
12
6
13 Command-line usage
7 Command-line usage
14 ==================
8 ==================
@@ -288,12 +282,13 b' All options with a [no] prepended can be specified in negated form'
288 recursive inclusions.
282 recursive inclusions.
289
283
290 -prompt_in1, pi1 <string>
284 -prompt_in1, pi1 <string>
291 Specify the string used for input prompts. Note that if you
285
292 are using numbered prompts, the number is represented with a
286 Specify the string used for input prompts. Note that if you are using
293 '\#' in the string. Don't forget to quote strings with spaces
287 numbered prompts, the number is represented with a '\#' in the
294 embedded in them. Default: 'In [\#]:'. Sec. Prompts_
288 string. Don't forget to quote strings with spaces embedded in
295 discusses in detail all the available escapes to customize
289 them. Default: 'In [\#]:'. The :ref:`prompts section <prompts>`
296 your prompts.
290 discusses in detail all the available escapes to customize your
291 prompts.
297
292
298 -prompt_in2, pi2 <string>
293 -prompt_in2, pi2 <string>
299 Similar to the previous option, but used for the continuation
294 Similar to the previous option, but used for the continuation
@@ -2077,13 +2072,14 b' customizations.'
2077 Access to the standard Python help
2072 Access to the standard Python help
2078 ----------------------------------
2073 ----------------------------------
2079
2074
2080 As of Python 2.1, a help system is available with access to object
2075 As of Python 2.1, a help system is available with access to object docstrings
2081 docstrings and the Python manuals. Simply type 'help' (no quotes) to
2076 and the Python manuals. Simply type 'help' (no quotes) to access it. You can
2082 access it. You can also type help(object) to obtain information about a
2077 also type help(object) to obtain information about a given object, and
2083 given object, and help('keyword') for information on a keyword. As noted
2078 help('keyword') for information on a keyword. As noted :ref:`here
2084 in sec. `accessing help`_, you need to properly configure
2079 <accessing_help>`, you need to properly configure your environment variable
2085 your environment variable PYTHONDOCS for this feature to work correctly.
2080 PYTHONDOCS for this feature to work correctly.
2086
2081
2082 .. _dynamic_object_info:
2087
2083
2088 Dynamic object information
2084 Dynamic object information
2089 --------------------------
2085 --------------------------
@@ -2126,7 +2122,7 b' are not really defined as separate identifiers. Try for example typing'
2126 {}.get? or after doing import os, type os.path.abspath??.
2122 {}.get? or after doing import os, type os.path.abspath??.
2127
2123
2128
2124
2129 .. _Readline:
2125 .. _readline:
2130
2126
2131 Readline-based features
2127 Readline-based features
2132 -----------------------
2128 -----------------------
@@ -2240,10 +2236,9 b' explanation in your ipythonrc file.'
2240 Session logging and restoring
2236 Session logging and restoring
2241 -----------------------------
2237 -----------------------------
2242
2238
2243 You can log all input from a session either by starting IPython with
2239 You can log all input from a session either by starting IPython with the
2244 the command line switches -log or -logfile (see sec. `command line
2240 command line switches -log or -logfile (see :ref:`here <command_line_options>`)
2245 options`_) or by activating the logging at any moment with the magic
2241 or by activating the logging at any moment with the magic function %logstart.
2246 function %logstart.
2247
2242
2248 Log files can later be reloaded with the -logplay option and IPython
2243 Log files can later be reloaded with the -logplay option and IPython
2249 will attempt to 'replay' the log by executing all the lines in it, thus
2244 will attempt to 'replay' the log by executing all the lines in it, thus
@@ -2279,6 +2274,8 b' resume logging to a file which had previously been started with'
2279 %logstart. They will fail (with an explanation) if you try to use them
2274 %logstart. They will fail (with an explanation) if you try to use them
2280 before logging has been started.
2275 before logging has been started.
2281
2276
2277 .. _system_shell_access:
2278
2282 System shell access
2279 System shell access
2283 -------------------
2280 -------------------
2284
2281
@@ -2389,14 +2386,16 b" These features are basically a terminal version of Ka-Ping Yee's cgitb"
2389 module, now part of the standard Python library.
2386 module, now part of the standard Python library.
2390
2387
2391
2388
2392 .. _Input caching:
2389 .. _input_caching:
2393
2390
2394 Input caching system
2391 Input caching system
2395 --------------------
2392 --------------------
2396
2393
2397 IPython offers numbered prompts (In/Out) with input and output caching.
2394 IPython offers numbered prompts (In/Out) with input and output caching
2398 All input is saved and can be retrieved as variables (besides the usual
2395 (also referred to as 'input history'). All input is saved and can be
2399 arrow key recall).
2396 retrieved as variables (besides the usual arrow key recall), in
2397 addition to the %rep magic command that brings a history entry
2398 up for editing on the next command line.
2400
2399
2401 The following GLOBAL variables always exist (so don't overwrite them!):
2400 The following GLOBAL variables always exist (so don't overwrite them!):
2402 _i: stores previous input. _ii: next previous. _iii: next-next previous.
2401 _i: stores previous input. _ii: next previous. _iii: next-next previous.
@@ -2429,7 +2428,43 b' sec. 6.2 <#sec:magic> for more details on the macro system.'
2429 A history function %hist allows you to see any part of your input
2428 A history function %hist allows you to see any part of your input
2430 history by printing a range of the _i variables.
2429 history by printing a range of the _i variables.
2431
2430
2432 .. _Output caching:
2431 You can also search ('grep') through your history by typing
2432 '%hist -g somestring'. This also searches through the so called *shadow history*,
2433 which remembers all the commands (apart from multiline code blocks)
2434 you have ever entered. Handy for searching for svn/bzr URL's, IP adrresses
2435 etc. You can bring shadow history entries listed by '%hist -g' up for editing
2436 (or re-execution by just pressing ENTER) with %rep command. Shadow history
2437 entries are not available as _iNUMBER variables, and they are identified by
2438 the '0' prefix in %hist -g output. That is, history entry 12 is a normal
2439 history entry, but 0231 is a shadow history entry.
2440
2441 Shadow history was added because the readline history is inherently very
2442 unsafe - if you have multiple IPython sessions open, the last session
2443 to close will overwrite the history of previountly closed session. Likewise,
2444 if a crash occurs, history is never saved, whereas shadow history entries
2445 are added after entering every command (so a command executed
2446 in another IPython session is immediately available in other IPython
2447 sessions that are open).
2448
2449 To conserve space, a command can exist in shadow history only once - it doesn't
2450 make sense to store a common line like "cd .." a thousand times. The idea is
2451 mainly to provide a reliable place where valuable, hard-to-remember commands can
2452 always be retrieved, as opposed to providing an exact sequence of commands
2453 you have entered in actual order.
2454
2455 Because shadow history has all the commands you have ever executed,
2456 time taken by %hist -g will increase oven time. If it ever starts to take
2457 too long (or it ends up containing sensitive information like passwords),
2458 clear the shadow history by `%clear shadow_nuke`.
2459
2460 Time taken to add entries to shadow history should be negligible, but
2461 in any case, if you start noticing performance degradation after using
2462 IPython for a long time (or running a script that floods the shadow history!),
2463 you can 'compress' the shadow history by executing
2464 `%clear shadow_compress`. In practice, this should never be necessary
2465 in normal use.
2466
2467 .. _output_caching:
2433
2468
2434 Output caching system
2469 Output caching system
2435 ---------------------
2470 ---------------------
@@ -2472,7 +2507,7 b' Directory history'
2472
2507
2473 Your history of visited directories is kept in the global list _dh, and
2508 Your history of visited directories is kept in the global list _dh, and
2474 the magic %cd command can be used to go to any entry in that list. The
2509 the magic %cd command can be used to go to any entry in that list. The
2475 %dhist command allows you to view this history. do ``cd -<TAB`` to
2510 %dhist command allows you to view this history. Do ``cd -<TAB`` to
2476 conventiently view the directory history.
2511 conventiently view the directory history.
2477
2512
2478
2513
@@ -3034,7 +3069,7 b' which is being shared by the interactive IPython loop and your GUI'
3034 thread, you should really handle it with thread locking and
3069 thread, you should really handle it with thread locking and
3035 syncrhonization properties. The Python documentation discusses these.
3070 syncrhonization properties. The Python documentation discusses these.
3036
3071
3037 .. _Interactive demos:
3072 .. _interactive_demos:
3038
3073
3039 Interactive demos with IPython
3074 Interactive demos with IPython
3040 ==============================
3075 ==============================
@@ -3143,21 +3178,17 b' toolkits, including Tk, GTK and WXPython. It also provides a number of'
3143 commands useful for scientific computing, all with a syntax compatible
3178 commands useful for scientific computing, all with a syntax compatible
3144 with that of the popular Matlab program.
3179 with that of the popular Matlab program.
3145
3180
3146 IPython accepts the special option -pylab (Sec. `Command line
3181 IPython accepts the special option -pylab (see :ref:`here
3147 options`_). This configures it to support matplotlib, honoring the
3182 <command_line_options>`). This configures it to support matplotlib, honoring
3148 settings in the .matplotlibrc file. IPython will detect the user's
3183 the settings in the .matplotlibrc file. IPython will detect the user's choice
3149 choice of matplotlib GUI backend, and automatically select the proper
3184 of matplotlib GUI backend, and automatically select the proper threading model
3150 threading model to prevent blocking. It also sets matplotlib in
3185 to prevent blocking. It also sets matplotlib in interactive mode and modifies
3151 interactive mode and modifies %run slightly, so that any
3186 %run slightly, so that any matplotlib-based script can be executed using %run
3152 matplotlib-based script can be executed using %run and the final
3187 and the final show() command does not block the interactive shell.
3153 show() command does not block the interactive shell.
3188
3154
3189 The -pylab option must be given first in order for IPython to configure its
3155 The -pylab option must be given first in order for IPython to
3190 threading mode. However, you can still issue other options afterwards. This
3156 configure its threading mode. However, you can still issue other
3191 allows you to have a matplotlib-based environment customized with additional
3157 options afterwards. This allows you to have a matplotlib-based
3192 modules using the standard IPython profile mechanism (see :ref:`here
3158 environment customized with additional modules using the standard
3193 <profiles>`): ``ipython -pylab -p myprofile`` will load the profile defined in
3159 IPython profile mechanism (Sec. Profiles_): ''ipython -pylab -p
3194 ipythonrc-myprofile after configuring matplotlib.
3160 myprofile'' will load the profile defined in ipythonrc-myprofile after
3161 configuring matplotlib.
3162
3163
@@ -4,8 +4,6 b''
4 Quick IPython tutorial
4 Quick IPython tutorial
5 ======================
5 ======================
6
6
7 .. contents::
8
9 IPython can be used as an improved replacement for the Python prompt,
7 IPython can be used as an improved replacement for the Python prompt,
10 and for that you don't really need to read any more of this manual. But
8 and for that you don't really need to read any more of this manual. But
11 in this section we'll try to summarize a few tips on how to make the
9 in this section we'll try to summarize a few tips on how to make the
@@ -24,11 +22,11 b' Tab completion'
24 --------------
22 --------------
25
23
26 TAB-completion, especially for attributes, is a convenient way to explore the
24 TAB-completion, especially for attributes, is a convenient way to explore the
27 structure of any object you're dealing with. Simply type object_name.<TAB>
25 structure of any object you're dealing with. Simply type object_name.<TAB> and
28 and a list of the object's attributes will be printed (see readline_ for
26 a list of the object's attributes will be printed (see :ref:`the readline
29 more). Tab completion also works on file and directory names, which combined
27 section <readline>` for more). Tab completion also works on file and directory
30 with IPython's alias system allows you to do from within IPython many of the
28 names, which combined with IPython's alias system allows you to do from within
31 things you normally would need the system shell for.
29 IPython many of the things you normally would need the system shell for.
32
30
33 Explore your objects
31 Explore your objects
34 --------------------
32 --------------------
@@ -39,18 +37,18 b' constructor details for classes. The magic commands %pdoc, %pdef, %psource'
39 and %pfile will respectively print the docstring, function definition line,
37 and %pfile will respectively print the docstring, function definition line,
40 full source code and the complete file for any object (when they can be
38 full source code and the complete file for any object (when they can be
41 found). If automagic is on (it is by default), you don't need to type the '%'
39 found). If automagic is on (it is by default), you don't need to type the '%'
42 explicitly. See sec. `dynamic object information`_ for more.
40 explicitly. See :ref:`this section <dynamic_object_info>` for more.
43
41
44 The `%run` magic command
42 The `%run` magic command
45 ------------------------
43 ------------------------
46
44
47 The %run magic command allows you to run any python script and load all of
45 The %run magic command allows you to run any python script and load all of its
48 its data directly into the interactive namespace. Since the file is re-read
46 data directly into the interactive namespace. Since the file is re-read from
49 from disk each time, changes you make to it are reflected immediately (in
47 disk each time, changes you make to it are reflected immediately (in contrast
50 contrast to the behavior of import). I rarely use import for code I am
48 to the behavior of import). I rarely use import for code I am testing, relying
51 testing, relying on %run instead. See magic_ section for more on this and
49 on %run instead. See :ref:`this section <magic>` for more on this and other
52 other magic commands, or type the name of any magic command and ? to get
50 magic commands, or type the name of any magic command and ? to get details on
53 details on it. See also sec. dreload_ for a recursive reload command. %run
51 it. See also :ref:`this section <dreload>` for a recursive reload command. %run
54 also has special flags for timing the execution of your scripts (-t) and for
52 also has special flags for timing the execution of your scripts (-t) and for
55 executing them under the control of either Python's pdb debugger (-d) or
53 executing them under the control of either Python's pdb debugger (-d) or
56 profiler (-p). With all of these, %run can be used as the main tool for
54 profiler (-p). With all of these, %run can be used as the main tool for
@@ -60,21 +58,21 b' choice.'
60 Debug a Python script
58 Debug a Python script
61 ---------------------
59 ---------------------
62
60
63 Use the Python debugger, pdb. The %pdb command allows you to toggle on and
61 Use the Python debugger, pdb. The %pdb command allows you to toggle on and off
64 off the automatic invocation of an IPython-enhanced pdb debugger (with
62 the automatic invocation of an IPython-enhanced pdb debugger (with coloring,
65 coloring, tab completion and more) at any uncaught exception. The advantage
63 tab completion and more) at any uncaught exception. The advantage of this is
66 of this is that pdb starts inside the function where the exception occurred,
64 that pdb starts inside the function where the exception occurred, with all data
67 with all data still available. You can print variables, see code, execute
65 still available. You can print variables, see code, execute statements and even
68 statements and even walk up and down the call stack to track down the true
66 walk up and down the call stack to track down the true source of the problem
69 source of the problem (which often is many layers in the stack above where
67 (which often is many layers in the stack above where the exception gets
70 the exception gets triggered). Running programs with %run and pdb active can
68 triggered). Running programs with %run and pdb active can be an efficient to
71 be an efficient to develop and debug code, in many cases eliminating the need
69 develop and debug code, in many cases eliminating the need for print statements
72 for print statements or external debugging tools. I often simply put a 1/0 in
70 or external debugging tools. I often simply put a 1/0 in a place where I want
73 a place where I want to take a look so that pdb gets called, quickly view
71 to take a look so that pdb gets called, quickly view whatever variables I need
74 whatever variables I need to or test various pieces of code and then remove
72 to or test various pieces of code and then remove the 1/0. Note also that '%run
75 the 1/0. Note also that '%run -d' activates pdb and automatically sets
73 -d' activates pdb and automatically sets initial breakpoints for you to step
76 initial breakpoints for you to step through your code, watch variables, etc.
74 through your code, watch variables, etc. The :ref:`output caching section
77 See Sec. `Output caching`_ for details.
75 <output_caching>` has more details.
78
76
79 Use the output cache
77 Use the output cache
80 --------------------
78 --------------------
@@ -84,7 +82,8 b' and variables named _1, _2, etc. alias them. For example, the result of input'
84 line 4 is available either as Out[4] or as _4. Additionally, three variables
82 line 4 is available either as Out[4] or as _4. Additionally, three variables
85 named _, __ and ___ are always kept updated with the for the last three
83 named _, __ and ___ are always kept updated with the for the last three
86 results. This allows you to recall any previous result and further use it for
84 results. This allows you to recall any previous result and further use it for
87 new calculations. See Sec. `Output caching`_ for more.
85 new calculations. See :ref:`the output caching section <output_caching>` for
86 more.
88
87
89 Suppress output
88 Suppress output
90 ---------------
89 ---------------
@@ -102,7 +101,7 b' A similar system exists for caching input. All input is stored in a global'
102 list called In , so you can re-execute lines 22 through 28 plus line 34 by
101 list called In , so you can re-execute lines 22 through 28 plus line 34 by
103 typing 'exec In[22:29]+In[34]' (using Python slicing notation). If you need
102 typing 'exec In[22:29]+In[34]' (using Python slicing notation). If you need
104 to execute the same set of lines often, you can assign them to a macro with
103 to execute the same set of lines often, you can assign them to a macro with
105 the %macro function. See sec. `Input caching`_ for more.
104 the %macro function. See :ref:`here <input_caching>` for more.
106
105
107 Use your input history
106 Use your input history
108 ----------------------
107 ----------------------
@@ -134,17 +133,18 b' into Python variables.'
134 Use Python variables when calling the shell
133 Use Python variables when calling the shell
135 -------------------------------------------
134 -------------------------------------------
136
135
137 Expand python variables when calling the shell (either via '!' and '!!' or
136 Expand python variables when calling the shell (either via '!' and '!!' or via
138 via aliases) by prepending a $ in front of them. You can also expand complete
137 aliases) by prepending a $ in front of them. You can also expand complete
139 python expressions. See `System shell access`_ for more.
138 python expressions. See :ref:`our shell section <system_shell_access>` for
139 more details.
140
140
141 Use profiles
141 Use profiles
142 ------------
142 ------------
143
143
144 Use profiles to maintain different configurations (modules to load, function
144 Use profiles to maintain different configurations (modules to load, function
145 definitions, option settings) for particular tasks. You can then have
145 definitions, option settings) for particular tasks. You can then have
146 customized versions of IPython for specific purposes. See sec. profiles_ for
146 customized versions of IPython for specific purposes. :ref:`This section
147 more.
147 <profiles>` has more details.
148
148
149
149
150 Embed IPython in your programs
150 Embed IPython in your programs
@@ -152,7 +152,7 b' Embed IPython in your programs'
152
152
153 A few lines of code are enough to load a complete IPython inside your own
153 A few lines of code are enough to load a complete IPython inside your own
154 programs, giving you the ability to work with your data interactively after
154 programs, giving you the ability to work with your data interactively after
155 automatic processing has been completed. See sec. embedding_ for more.
155 automatic processing has been completed. See :ref:`here <embedding>` for more.
156
156
157 Use the Python profiler
157 Use the Python profiler
158 -----------------------
158 -----------------------
@@ -166,8 +166,8 b' Use IPython to present interactive demos'
166 ----------------------------------------
166 ----------------------------------------
167
167
168 Use the IPython.demo.Demo class to load any Python script as an interactive
168 Use the IPython.demo.Demo class to load any Python script as an interactive
169 demo. With a minimal amount of simple markup, you can control the execution
169 demo. With a minimal amount of simple markup, you can control the execution of
170 of the script, stopping as needed. See sec. `interactive demos`_ for more.
170 the script, stopping as needed. See :ref:`here <interactive_demos>` for more.
171
171
172 Run doctests
172 Run doctests
173 ------------
173 ------------
@@ -1,61 +1,91 b''
1 .. _license:
1 .. _license:
2
2
3 =============================
3 =====================
4 License and Copyright
4 License and Copyright
5 =============================
5 =====================
6
6
7 This files needs to be updated to reflect what the new COPYING.txt files says about our license and copyright!
7 License
8 =======
8
9
9 IPython is released under the terms of the BSD license, whose general
10 IPython is licensed under the terms of the new or revised BSD license, as follows::
10 form can be found at: http://www.opensource.org/licenses/bsd-license.php. The full text of the
11 IPython license is reproduced below::
12
11
13 IPython is released under a BSD-type license.
12 Copyright (c) 2008, IPython Development Team
14
15 Copyright (c) 2001, 2002, 2003, 2004 Fernando Perez
16 <fperez@colorado.edu>.
17
18 Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and
19 Nathaniel Gray <n8gray@caltech.edu>.
20
13
21 All rights reserved.
14 All rights reserved.
22
15
23 Redistribution and use in source and binary forms, with or without
16 Redistribution and use in source and binary forms, with or without
24 modification, are permitted provided that the following conditions
17 modification, are permitted provided that the following conditions are
25 are met:
18 met:
26
19
27 a. Redistributions of source code must retain the above copyright
20 Redistributions of source code must retain the above copyright notice,
28 notice, this list of conditions and the following disclaimer.
21 this list of conditions and the following disclaimer.
29
22
30 b. Redistributions in binary form must reproduce the above copyright
23 Redistributions in binary form must reproduce the above copyright notice,
31 notice, this list of conditions and the following disclaimer in the
24 this list of conditions and the following disclaimer in the documentation
32 documentation and/or other materials provided with the distribution.
25 and/or other materials provided with the distribution.
33
26
34 c. Neither the name of the copyright holders nor the names of any
27 Neither the name of the IPython Development Team nor the names of its
35 contributors to this software may be used to endorse or promote
28 contributors may be used to endorse or promote products derived from this
36 products derived from this software without specific prior written
29 software without specific prior written permission.
37 permission.
30
38
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
39 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
40 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
34 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
35 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
43 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
36 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
44 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
37 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
45 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
46 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
47 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
48 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
41 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42
50 POSSIBILITY OF SUCH DAMAGE.
43 About the IPython Development Team
51
44 ==================================
52 Individual authors are the holders of the copyright for their code and
45
53 are listed in each file.
46 Fernando Perez began IPython in 2001 based on code from Janko Hauser
47 <jhauser@zscout.de> and Nathaniel Gray <n8gray@caltech.edu>. Fernando is still
48 the project lead.
49
50 The IPython Development Team is the set of all contributors to the IPython
51 project. This includes all of the IPython subprojects. Here is a list of the
52 currently active contributors:
53
54 * Matthieu Brucher
55 * Ondrej Certik
56 * Laurent Dufrechou
57 * Robert Kern
58 * Brian E. Granger
59 * Fernando Perez (project leader)
60 * Benjamin Ragan-Kelley
61 * Ville M. Vainio
62 * Gael Varoququx
63 * Stefan van der Walt
64 * Tech-X Corporation
65 * Barry Wark
66
67 If your name is missing, please add it.
68
69 Our Copyright Policy
70 ====================
71
72 IPython uses a shared copyright model. Each contributor maintains copyright
73 over their contributions to IPython. But, it is important to note that these
74 contributions are typically only changes to the repositories. Thus, the
75 IPython source code, in its entirety is not the copyright of any single person
76 or institution. Instead, it is the collective copyright of the entire IPython
77 Development Team. If individual contributors want to maintain a record of what
78 changes/contributions they have specific copyright on, they should indicate
79 their copyright in the commit message of the change, when they commit the
80 change to one of the IPython repositories.
81
82 Miscellaneous
83 =============
54
84
55 Some files (DPyGetOpt.py, for example) may be licensed under different
85 Some files (DPyGetOpt.py, for example) may be licensed under different
56 conditions. Ultimately each file indicates clearly the conditions under
86 conditions. Ultimately each file indicates clearly the conditions under which
57 which its author/authors have decided to publish the code.
87 its author/authors have decided to publish the code.
58
88
59 Versions of IPython up to and including 0.6.3 were released under the
89 Versions of IPython up to and including 0.6.3 were released under the GNU
60 GNU Lesser General Public License (LGPL), available at
90 Lesser General Public License (LGPL), available at
61 http://www.gnu.org/copyleft/lesser.html. No newline at end of file
91 http://www.gnu.org/copyleft/lesser.html.
@@ -14,7 +14,7 b' However, the interpreter supplied with the standard Python distribution'
14 is somewhat limited for extended interactive use.
14 is somewhat limited for extended interactive use.
15
15
16 The goal of IPython is to create a comprehensive environment for
16 The goal of IPython is to create a comprehensive environment for
17 interactive and exploratory computing. To support, this goal, IPython
17 interactive and exploratory computing. To support this goal, IPython
18 has two main components:
18 has two main components:
19
19
20 * An enhanced interactive Python shell.
20 * An enhanced interactive Python shell.
@@ -25,7 +25,8 b' All of IPython is open source (released under the revised BSD license).'
25 Enhanced interactive Python shell
25 Enhanced interactive Python shell
26 =================================
26 =================================
27
27
28 IPython's interactive shell (`ipython`), has the following goals:
28 IPython's interactive shell (:command:`ipython`), has the following goals,
29 amongst others:
29
30
30 1. Provide an interactive shell superior to Python's default. IPython
31 1. Provide an interactive shell superior to Python's default. IPython
31 has many features for object introspection, system shell access,
32 has many features for object introspection, system shell access,
@@ -33,17 +34,21 b" IPython's interactive shell (`ipython`), has the following goals:"
33 working interactively. It tries to be a very efficient environment
34 working interactively. It tries to be a very efficient environment
34 both for Python code development and for exploration of problems
35 both for Python code development and for exploration of problems
35 using Python objects (in situations like data analysis).
36 using Python objects (in situations like data analysis).
37
36 2. Serve as an embeddable, ready to use interpreter for your own
38 2. Serve as an embeddable, ready to use interpreter for your own
37 programs. IPython can be started with a single call from inside
39 programs. IPython can be started with a single call from inside
38 another program, providing access to the current namespace. This
40 another program, providing access to the current namespace. This
39 can be very useful both for debugging purposes and for situations
41 can be very useful both for debugging purposes and for situations
40 where a blend of batch-processing and interactive exploration are
42 where a blend of batch-processing and interactive exploration are
41 needed.
43 needed. New in the 0.9 version of IPython is a reusable wxPython
44 based IPython widget.
45
42 3. Offer a flexible framework which can be used as the base
46 3. Offer a flexible framework which can be used as the base
43 environment for other systems with Python as the underlying
47 environment for other systems with Python as the underlying
44 language. Specifically scientific environments like Mathematica,
48 language. Specifically scientific environments like Mathematica,
45 IDL and Matlab inspired its design, but similar ideas can be
49 IDL and Matlab inspired its design, but similar ideas can be
46 useful in many fields.
50 useful in many fields.
51
47 4. Allow interactive testing of threaded graphical toolkits. IPython
52 4. Allow interactive testing of threaded graphical toolkits. IPython
48 has support for interactive, non-blocking control of GTK, Qt and
53 has support for interactive, non-blocking control of GTK, Qt and
49 WX applications via special threading flags. The normal Python
54 WX applications via special threading flags. The normal Python
@@ -56,74 +61,95 b' Main features of the interactive shell'
56 definition prototypes, source code, source files and other details
61 definition prototypes, source code, source files and other details
57 of any object accessible to the interpreter with a single
62 of any object accessible to the interpreter with a single
58 keystroke (:samp:`?`, and using :samp:`??` provides additional detail).
63 keystroke (:samp:`?`, and using :samp:`??` provides additional detail).
64
59 * Searching through modules and namespaces with :samp:`*` wildcards, both
65 * Searching through modules and namespaces with :samp:`*` wildcards, both
60 when using the :samp:`?` system and via the :samp:`%psearch` command.
66 when using the :samp:`?` system and via the :samp:`%psearch` command.
67
61 * Completion in the local namespace, by typing :kbd:`TAB` at the prompt.
68 * Completion in the local namespace, by typing :kbd:`TAB` at the prompt.
62 This works for keywords, modules, methods, variables and files in the
69 This works for keywords, modules, methods, variables and files in the
63 current directory. This is supported via the readline library, and
70 current directory. This is supported via the readline library, and
64 full access to configuring readline's behavior is provided.
71 full access to configuring readline's behavior is provided.
65 Custom completers can be implemented easily for different purposes
72 Custom completers can be implemented easily for different purposes
66 (system commands, magic arguments etc.)
73 (system commands, magic arguments etc.)
74
67 * Numbered input/output prompts with command history (persistent
75 * Numbered input/output prompts with command history (persistent
68 across sessions and tied to each profile), full searching in this
76 across sessions and tied to each profile), full searching in this
69 history and caching of all input and output.
77 history and caching of all input and output.
78
70 * User-extensible 'magic' commands. A set of commands prefixed with
79 * User-extensible 'magic' commands. A set of commands prefixed with
71 :samp:`%` is available for controlling IPython itself and provides
80 :samp:`%` is available for controlling IPython itself and provides
72 directory control, namespace information and many aliases to
81 directory control, namespace information and many aliases to
73 common system shell commands.
82 common system shell commands.
83
74 * Alias facility for defining your own system aliases.
84 * Alias facility for defining your own system aliases.
85
75 * Complete system shell access. Lines starting with :samp:`!` are passed
86 * Complete system shell access. Lines starting with :samp:`!` are passed
76 directly to the system shell, and using :samp:`!!` or :samp:`var = !cmd`
87 directly to the system shell, and using :samp:`!!` or :samp:`var = !cmd`
77 captures shell output into python variables for further use.
88 captures shell output into python variables for further use.
89
78 * Background execution of Python commands in a separate thread.
90 * Background execution of Python commands in a separate thread.
79 IPython has an internal job manager called jobs, and a
91 IPython has an internal job manager called jobs, and a
80 conveninence backgrounding magic function called :samp:`%bg`.
92 convenience backgrounding magic function called :samp:`%bg`.
93
81 * The ability to expand python variables when calling the system
94 * The ability to expand python variables when calling the system
82 shell. In a shell command, any python variable prefixed with :samp:`$` is
95 shell. In a shell command, any python variable prefixed with :samp:`$` is
83 expanded. A double :samp:`$$` allows passing a literal :samp:`$` to the shell (for
96 expanded. A double :samp:`$$` allows passing a literal :samp:`$` to the shell (for
84 access to shell and environment variables like :envvar:`PATH`).
97 access to shell and environment variables like :envvar:`PATH`).
98
85 * Filesystem navigation, via a magic :samp:`%cd` command, along with a
99 * Filesystem navigation, via a magic :samp:`%cd` command, along with a
86 persistent bookmark system (using :samp:`%bookmark`) for fast access to
100 persistent bookmark system (using :samp:`%bookmark`) for fast access to
87 frequently visited directories.
101 frequently visited directories.
102
88 * A lightweight persistence framework via the :samp:`%store` command, which
103 * A lightweight persistence framework via the :samp:`%store` command, which
89 allows you to save arbitrary Python variables. These get restored
104 allows you to save arbitrary Python variables. These get restored
90 automatically when your session restarts.
105 automatically when your session restarts.
106
91 * Automatic indentation (optional) of code as you type (through the
107 * Automatic indentation (optional) of code as you type (through the
92 readline library).
108 readline library).
109
93 * Macro system for quickly re-executing multiple lines of previous
110 * Macro system for quickly re-executing multiple lines of previous
94 input with a single name. Macros can be stored persistently via
111 input with a single name. Macros can be stored persistently via
95 :samp:`%store` and edited via :samp:`%edit`.
112 :samp:`%store` and edited via :samp:`%edit`.
113
96 * Session logging (you can then later use these logs as code in your
114 * Session logging (you can then later use these logs as code in your
97 programs). Logs can optionally timestamp all input, and also store
115 programs). Logs can optionally timestamp all input, and also store
98 session output (marked as comments, so the log remains valid
116 session output (marked as comments, so the log remains valid
99 Python source code).
117 Python source code).
118
100 * Session restoring: logs can be replayed to restore a previous
119 * Session restoring: logs can be replayed to restore a previous
101 session to the state where you left it.
120 session to the state where you left it.
121
102 * Verbose and colored exception traceback printouts. Easier to parse
122 * Verbose and colored exception traceback printouts. Easier to parse
103 visually, and in verbose mode they produce a lot of useful
123 visually, and in verbose mode they produce a lot of useful
104 debugging information (basically a terminal version of the cgitb
124 debugging information (basically a terminal version of the cgitb
105 module).
125 module).
126
106 * Auto-parentheses: callable objects can be executed without
127 * Auto-parentheses: callable objects can be executed without
107 parentheses: :samp:`sin 3` is automatically converted to :samp:`sin(3)`.
128 parentheses: :samp:`sin 3` is automatically converted to :samp:`sin(3)`.
129
108 * Auto-quoting: using :samp:`,`, or :samp:`;` as the first character forces
130 * Auto-quoting: using :samp:`,`, or :samp:`;` as the first character forces
109 auto-quoting of the rest of the line: :samp:`,my_function a b` becomes
131 auto-quoting of the rest of the line: :samp:`,my_function a b` becomes
110 automatically :samp:`my_function("a","b")`, while :samp:`;my_function a b`
132 automatically :samp:`my_function("a","b")`, while :samp:`;my_function a b`
111 becomes :samp:`my_function("a b")`.
133 becomes :samp:`my_function("a b")`.
134
112 * Extensible input syntax. You can define filters that pre-process
135 * Extensible input syntax. You can define filters that pre-process
113 user input to simplify input in special situations. This allows
136 user input to simplify input in special situations. This allows
114 for example pasting multi-line code fragments which start with
137 for example pasting multi-line code fragments which start with
115 :samp:`>>>` or :samp:`...` such as those from other python sessions or the
138 :samp:`>>>` or :samp:`...` such as those from other python sessions or the
116 standard Python documentation.
139 standard Python documentation.
140
117 * Flexible configuration system. It uses a configuration file which
141 * Flexible configuration system. It uses a configuration file which
118 allows permanent setting of all command-line options, module
142 allows permanent setting of all command-line options, module
119 loading, code and file execution. The system allows recursive file
143 loading, code and file execution. The system allows recursive file
120 inclusion, so you can have a base file with defaults and layers
144 inclusion, so you can have a base file with defaults and layers
121 which load other customizations for particular projects.
145 which load other customizations for particular projects.
146
122 * Embeddable. You can call IPython as a python shell inside your own
147 * Embeddable. You can call IPython as a python shell inside your own
123 python programs. This can be used both for debugging code or for
148 python programs. This can be used both for debugging code or for
124 providing interactive abilities to your programs with knowledge
149 providing interactive abilities to your programs with knowledge
125 about the local namespaces (very useful in debugging and data
150 about the local namespaces (very useful in debugging and data
126 analysis situations).
151 analysis situations).
152
127 * Easy debugger access. You can set IPython to call up an enhanced
153 * Easy debugger access. You can set IPython to call up an enhanced
128 version of the Python debugger (pdb) every time there is an
154 version of the Python debugger (pdb) every time there is an
129 uncaught exception. This drops you inside the code which triggered
155 uncaught exception. This drops you inside the code which triggered
@@ -135,11 +161,13 b' Main features of the interactive shell'
135 tab-completion and traceback coloring support. For even easier
161 tab-completion and traceback coloring support. For even easier
136 debugger access, try :samp:`%debug` after seeing an exception. winpdb is
162 debugger access, try :samp:`%debug` after seeing an exception. winpdb is
137 also supported, see ipy_winpdb extension.
163 also supported, see ipy_winpdb extension.
164
138 * Profiler support. You can run single statements (similar to
165 * Profiler support. You can run single statements (similar to
139 :samp:`profile.run()`) or complete programs under the profiler's control.
166 :samp:`profile.run()`) or complete programs under the profiler's control.
140 While this is possible with standard cProfile or profile modules,
167 While this is possible with standard cProfile or profile modules,
141 IPython wraps this functionality with magic commands (see :samp:`%prun`
168 IPython wraps this functionality with magic commands (see :samp:`%prun`
142 and :samp:`%run -p`) convenient for rapid interactive work.
169 and :samp:`%run -p`) convenient for rapid interactive work.
170
143 * Doctest support. The special :samp:`%doctest_mode` command toggles a mode
171 * Doctest support. The special :samp:`%doctest_mode` command toggles a mode
144 that allows you to paste existing doctests (with leading :samp:`>>>`
172 that allows you to paste existing doctests (with leading :samp:`>>>`
145 prompts and whitespace) and uses doctest-compatible prompts and
173 prompts and whitespace) and uses doctest-compatible prompts and
@@ -153,6 +181,37 b' architecture within IPython that allows such hardware to be used quickly and eas'
153 from Python. Moreover, this architecture is designed to support interactive and
181 from Python. Moreover, this architecture is designed to support interactive and
154 collaborative parallel computing.
182 collaborative parallel computing.
155
183
184 The main features of this system are:
185
186 * Quickly parallelize Python code from an interactive Python/IPython session.
187
188 * A flexible and dynamic process model that be deployed on anything from
189 multicore workstations to supercomputers.
190
191 * An architecture that supports many different styles of parallelism, from
192 message passing to task farming. And all of these styles can be handled
193 interactively.
194
195 * Both blocking and fully asynchronous interfaces.
196
197 * High level APIs that enable many things to be parallelized in a few lines
198 of code.
199
200 * Write parallel code that will run unchanged on everything from multicore
201 workstations to supercomputers.
202
203 * Full integration with Message Passing libraries (MPI).
204
205 * Capabilities based security model with full encryption of network connections.
206
207 * Share live parallel jobs with other users securely. We call this collaborative
208 parallel computing.
209
210 * Dynamically load balanced task farming system.
211
212 * Robust error handling. Python exceptions raised in parallel execution are
213 gathered and presented to the top-level code.
214
156 For more information, see our :ref:`overview <parallel_index>` of using IPython for
215 For more information, see our :ref:`overview <parallel_index>` of using IPython for
157 parallel computing.
216 parallel computing.
158
217
@@ -1,17 +1,16 b''
1 .. _parallel_index:
1 .. _parallel_index:
2
2
3 ====================================
3 ====================================
4 Using IPython for Parallel computing
4 Using IPython for parallel computing
5 ====================================
5 ====================================
6
6
7 User Documentation
8 ==================
9
10 .. toctree::
7 .. toctree::
11 :maxdepth: 2
8 :maxdepth: 2
12
9
13 parallel_intro.txt
10 parallel_intro.txt
11 parallel_process.txt
14 parallel_multiengine.txt
12 parallel_multiengine.txt
15 parallel_task.txt
13 parallel_task.txt
16 parallel_mpi.txt
14 parallel_mpi.txt
15 parallel_security.txt
17
16
@@ -1,23 +1,20 b''
1 .. _ip1par:
1 .. _ip1par:
2
2
3 ======================================
3 ============================
4 Using IPython for parallel computing
4 Overview and getting started
5 ======================================
5 ============================
6
7 .. contents::
8
6
9 Introduction
7 Introduction
10 ============
8 ============
11
9
12 This file gives an overview of IPython. IPython has a sophisticated and
10 This section gives an overview of IPython's sophisticated and powerful
13 powerful architecture for parallel and distributed computing. This
11 architecture for parallel and distributed computing. This architecture
14 architecture abstracts out parallelism in a very general way, which
12 abstracts out parallelism in a very general way, which enables IPython to
15 enables IPython to support many different styles of parallelism
13 support many different styles of parallelism including:
16 including:
17
14
18 * Single program, multiple data (SPMD) parallelism.
15 * Single program, multiple data (SPMD) parallelism.
19 * Multiple program, multiple data (MPMD) parallelism.
16 * Multiple program, multiple data (MPMD) parallelism.
20 * Message passing using ``MPI``.
17 * Message passing using MPI.
21 * Task farming.
18 * Task farming.
22 * Data parallel.
19 * Data parallel.
23 * Combinations of these approaches.
20 * Combinations of these approaches.
@@ -30,18 +27,24 b' the ``I`` in IPython. The following are some example usage cases for IPython:'
30 * Quickly parallelize algorithms that are embarrassingly parallel
27 * Quickly parallelize algorithms that are embarrassingly parallel
31 using a number of simple approaches. Many simple things can be
28 using a number of simple approaches. Many simple things can be
32 parallelized interactively in one or two lines of code.
29 parallelized interactively in one or two lines of code.
30
33 * Steer traditional MPI applications on a supercomputer from an
31 * Steer traditional MPI applications on a supercomputer from an
34 IPython session on your laptop.
32 IPython session on your laptop.
33
35 * Analyze and visualize large datasets (that could be remote and/or
34 * Analyze and visualize large datasets (that could be remote and/or
36 distributed) interactively using IPython and tools like
35 distributed) interactively using IPython and tools like
37 matplotlib/TVTK.
36 matplotlib/TVTK.
37
38 * Develop, test and debug new parallel algorithms
38 * Develop, test and debug new parallel algorithms
39 (that may use MPI) interactively.
39 (that may use MPI) interactively.
40
40 * Tie together multiple MPI jobs running on different systems into
41 * Tie together multiple MPI jobs running on different systems into
41 one giant distributed and parallel system.
42 one giant distributed and parallel system.
43
42 * Start a parallel job on your cluster and then have a remote
44 * Start a parallel job on your cluster and then have a remote
43 collaborator connect to it and pull back data into their
45 collaborator connect to it and pull back data into their
44 local IPython session for plotting and analysis.
46 local IPython session for plotting and analysis.
47
45 * Run a set of tasks on a set of CPUs using dynamic load balancing.
48 * Run a set of tasks on a set of CPUs using dynamic load balancing.
46
49
47 Architecture overview
50 Architecture overview
@@ -51,7 +54,12 b' The IPython architecture consists of three components:'
51
54
52 * The IPython engine.
55 * The IPython engine.
53 * The IPython controller.
56 * The IPython controller.
54 * Various controller Clients.
57 * Various controller clients.
58
59 These components live in the :mod:`IPython.kernel` package and are
60 installed with IPython. They do, however, have additional dependencies
61 that must be installed. For more information, see our
62 :ref:`installation documentation <install_index>`.
55
63
56 IPython engine
64 IPython engine
57 ---------------
65 ---------------
@@ -75,16 +83,21 b' IPython engines can connect. For each connected engine, the controller'
75 manages a queue. All actions that can be performed on the engine go
83 manages a queue. All actions that can be performed on the engine go
76 through this queue. While the engines themselves block when user code is
84 through this queue. While the engines themselves block when user code is
77 run, the controller hides that from the user to provide a fully
85 run, the controller hides that from the user to provide a fully
78 asynchronous interface to a set of engines. Because the controller
86 asynchronous interface to a set of engines.
79 listens on a network port for engines to connect to it, it must be
87
80 started before any engines are started.
88 .. note::
89
90 Because the controller listens on a network port for engines to
91 connect to it, it must be started *before* any engines are started.
81
92
82 The controller also provides a single point of contact for users who wish
93 The controller also provides a single point of contact for users who wish
83 to utilize the engines connected to the controller. There are different
94 to utilize the engines connected to the controller. There are different
84 ways of working with a controller. In IPython these ways correspond to different interfaces that the controller is adapted to. Currently we have two default interfaces to the controller:
95 ways of working with a controller. In IPython these ways correspond to different interfaces that the controller is adapted to. Currently we have two default interfaces to the controller:
85
96
86 * The MultiEngine interface.
97 * The MultiEngine interface, which provides the simplest possible way of
87 * The Task interface.
98 working with engines interactively.
99 * The Task interface, which provides presents the engines as a load balanced
100 task farming system.
88
101
89 Advanced users can easily add new custom interfaces to enable other
102 Advanced users can easily add new custom interfaces to enable other
90 styles of parallelism.
103 styles of parallelism.
@@ -100,126 +113,58 b' Controller clients'
100
113
101 For each controller interface, there is a corresponding client. These
114 For each controller interface, there is a corresponding client. These
102 clients allow users to interact with a set of engines through the
115 clients allow users to interact with a set of engines through the
103 interface.
116 interface. Here are the two default clients:
117
118 * The :class:`MultiEngineClient` class.
119 * The :class:`TaskClient` class.
104
120
105 Security
121 Security
106 --------
122 --------
107
123
108 By default (as long as `pyOpenSSL` is installed) all network connections between the controller and engines and the controller and clients are secure. What does this mean? First of all, all of the connections will be encrypted using SSL. Second, the connections are authenticated. We handle authentication in a `capabilities`__ based security model. In this model, a "capability (known in some systems as a key) is a communicable, unforgeable token of authority". Put simply, a capability is like a key to your house. If you have the key to your house, you can get in, if not you can't.
124 By default (as long as `pyOpenSSL` is installed) all network connections between the controller and engines and the controller and clients are secure. What does this mean? First of all, all of the connections will be encrypted using SSL. Second, the connections are authenticated. We handle authentication in a capability based security model [Capability]_. In this model, a "capability (known in some systems as a key) is a communicable, unforgeable token of authority". Put simply, a capability is like a key to your house. If you have the key to your house, you can get in. If not, you can't.
109
110 .. __: http://en.wikipedia.org/wiki/Capability-based_security
111
112 In our architecture, the controller is the only process that listens on network ports, and is thus responsible to creating these keys. In IPython, these keys are known as Foolscap URLs, or FURLs, because of the underlying network protocol we are using. As a user, you don't need to know anything about the details of these FURLs, other than that when the controller starts, it saves a set of FURLs to files named something.furl. The default location of these files is your ~./ipython directory.
113
114 To connect and authenticate to the controller an engine or client simply needs to present an appropriate furl (that was originally created by the controller) to the controller. Thus, the .furl files need to be copied to a location where the clients and engines can find them. Typically, this is the ~./ipython directory on the host where the client/engine is running (which could be a different host than the controller). Once the .furl files are copied over, everything should work fine.
115
116 Getting Started
117 ===============
118
119 To use IPython for parallel computing, you need to start one instance of
120 the controller and one or more instances of the engine. The controller
121 and each engine can run on different machines or on the same machine.
122 Because of this, there are many different possibilities for setting up
123 the IP addresses and ports used by the various processes.
124
125 Starting the controller and engine on your local machine
126 --------------------------------------------------------
127
128 This is the simplest configuration that can be used and is useful for
129 testing the system and on machines that have multiple cores and/or
130 multple CPUs. The easiest way of doing this is using the ``ipcluster``
131 command::
132
133 $ ipcluster -n 4
134
135 This will start an IPython controller and then 4 engines that connect to
136 the controller. Lastly, the script will print out the Python commands
137 that you can use to connect to the controller. It is that easy.
138
125
139 Underneath the hood, the ``ipcluster`` script uses two other top-level
126 In our architecture, the controller is the only process that listens on network ports, and is thus responsible to creating these keys. In IPython, these keys are known as Foolscap URLs, or FURLs, because of the underlying network protocol we are using. As a user, you don't need to know anything about the details of these FURLs, other than that when the controller starts, it saves a set of FURLs to files named :file:`something.furl`. The default location of these files is the :file:`~./ipython/security` directory.
140 scripts that you can also use yourself. These scripts are
141 ``ipcontroller``, which starts the controller and ``ipengine`` which
142 starts one engine. To use these scripts to start things on your local
143 machine, do the following.
144
127
145 First start the controller::
128 To connect and authenticate to the controller an engine or client simply needs to present an appropriate FURL (that was originally created by the controller) to the controller. Thus, the FURL files need to be copied to a location where the clients and engines can find them. Typically, this is the :file:`~./ipython/security` directory on the host where the client/engine is running (which could be a different host than the controller). Once the FURL files are copied over, everything should work fine.
146
129
147 $ ipcontroller &
130 Currently, there are three FURL files that the controller creates:
148
131
149 Next, start however many instances of the engine you want using (repeatedly) the command::
132 ipcontroller-engine.furl
133 This FURL file is the key that gives an engine the ability to connect
134 to a controller.
150
135
151 $ ipengine &
136 ipcontroller-tc.furl
137 This FURL file is the key that a :class:`TaskClient` must use to
138 connect to the task interface of a controller.
152
139
153 .. warning::
140 ipcontroller-mec.furl
141 This FURL file is the key that a :class:`MultiEngineClient` must use
142 to connect to the multiengine interface of a controller.
154
143
155 The order of the above operations is very important. You *must*
144 More details of how these FURL files are used are given below.
156 start the controller before the engines, since the engines connect
157 to the controller as they get started.
158
145
159 On some platforms you may need to give these commands in the form
146 A detailed description of the security model and its implementation in IPython
160 ``(ipcontroller &)`` and ``(ipengine &)`` for them to work properly. The
147 can be found :ref:`here <parallelsecurity>`.
161 engines should start and automatically connect to the controller on the
162 default ports, which are chosen for this type of setup. You are now ready
163 to use the controller and engines from IPython.
164
148
165 Starting the controller and engines on different machines
149 Getting Started
166 ---------------------------------------------------------
150 ===============
167
168 This section needs to be updated to reflect the new Foolscap capabilities based
169 model.
170
171 Using ``ipcluster`` with ``ssh``
172 --------------------------------
173
174 The ``ipcluster`` command can also start a controller and engines using
175 ``ssh``. We need more documentation on this, but for now here is any
176 example startup script::
177
178 controller = dict(host='myhost',
179 engine_port=None, # default is 10105
180 control_port=None,
181 )
182
183 # keys are hostnames, values are the number of engine on that host
184 engines = dict(node1=2,
185 node2=2,
186 node3=2,
187 node3=2,
188 )
189
190 Starting engines using ``mpirun``
191 ---------------------------------
192
193 The IPython engines can be started using ``mpirun``/``mpiexec``, even if
194 the engines don't call MPI_Init() or use the MPI API in any way. This is
195 supported on modern MPI implementations like `Open MPI`_.. This provides
196 an really nice way of starting a bunch of engine. On a system with MPI
197 installed you can do::
198
199 mpirun -n 4 ipengine --controller-port=10000 --controller-ip=host0
200
201 .. _Open MPI: http://www.open-mpi.org/
202
203 More details on using MPI with IPython can be found :ref:`here <parallelmpi>`.
204
151
205 Log files
152 To use IPython for parallel computing, you need to start one instance of
206 ---------
153 the controller and one or more instances of the engine. Initially, it is best to simply start a controller and engines on a single host using the :command:`ipcluster` command. To start a controller and 4 engines on you localhost, just do::
207
154
208 All of the components of IPython have log files associated with them.
155 $ ipcluster local -n 4
209 These log files can be extremely useful in debugging problems with
210 IPython and can be found in the directory ``~/.ipython/log``. Sending
211 the log files to us will often help us to debug any problems.
212
156
213 Next Steps
157 More details about starting the IPython controller and engines can be found :ref:`here <parallel_process>`
214 ==========
215
158
216 Once you have started the IPython controller and one or more engines, you
159 Once you have started the IPython controller and one or more engines, you
217 are ready to use the engines to do somnething useful. To make sure
160 are ready to use the engines to do something useful. To make sure
218 everything is working correctly, try the following commands::
161 everything is working correctly, try the following commands:
162
163 .. sourcecode:: ipython
219
164
220 In [1]: from IPython.kernel import client
165 In [1]: from IPython.kernel import client
221
166
222 In [2]: mec = client.MultiEngineClient() # This looks for .furl files in ~./ipython
167 In [2]: mec = client.MultiEngineClient()
223
168
224 In [4]: mec.get_ids()
169 In [4]: mec.get_ids()
225 Out[4]: [0, 1, 2, 3]
170 Out[4]: [0, 1, 2, 3]
@@ -239,4 +184,22 b' everything is working correctly, try the following commands::'
239 [3] In [1]: print "Hello World"
184 [3] In [1]: print "Hello World"
240 [3] Out[1]: Hello World
185 [3] Out[1]: Hello World
241
186
242 If this works, you are ready to learn more about the :ref:`MultiEngine <parallelmultiengine>` and :ref:`Task <paralleltask>` interfaces to the controller.
187 Remember, a client also needs to present a FURL file to the controller. How does this happen? When a multiengine client is created with no arguments, the client tries to find the corresponding FURL file in the local :file:`~./ipython/security` directory. If it finds it, you are set. If you have put the FURL file in a different location or it has a different name, create the client like this::
188
189 mec = client.MultiEngineClient('/path/to/my/ipcontroller-mec.furl')
190
191 Same thing hold true of creating a task client::
192
193 tc = client.TaskClient('/path/to/my/ipcontroller-tc.furl')
194
195 You are now ready to learn more about the :ref:`MultiEngine <parallelmultiengine>` and :ref:`Task <paralleltask>` interfaces to the controller.
196
197 .. note::
198
199 Don't forget that the engine, multiengine client and task client all have
200 *different* furl files. You must move *each* of these around to an
201 appropriate location so that the engines and clients can use them to
202 connect to the controller.
203
204 .. [Capability] Capability-based security, http://en.wikipedia.org/wiki/Capability-based_security
205
@@ -4,19 +4,154 b''
4 Using MPI with IPython
4 Using MPI with IPython
5 =======================
5 =======================
6
6
7 The simplest way of getting started with MPI is to install an MPI implementation
7 Often, a parallel algorithm will require moving data between the engines. One way of accomplishing this is by doing a pull and then a push using the multiengine client. However, this will be slow as all the data has to go through the controller to the client and then back through the controller, to its final destination.
8 (we recommend `Open MPI`_) and `mpi4py`_ and then start the engines using the
9 ``mpirun`` command::
10
8
11 mpirun -n 4 ipengine --mpi=mpi4py
9 A much better way of moving data between engines is to use a message passing library, such as the Message Passing Interface (MPI) [MPI]_. IPython's parallel computing architecture has been designed from the ground up to integrate with MPI. This document describes how to use MPI with IPython.
12
10
13 This will automatically import `mpi4py`_ and make sure that `MPI_Init` is called
11 Additional installation requirements
14 at the right time. We also have built in support for `PyTrilinos`_, which can be
12 ====================================
15 used (assuming `PyTrilinos`_ is installed) by starting the engines with::
13
14 If you want to use MPI with IPython, you will need to install:
15
16 * A standard MPI implementation such as OpenMPI [OpenMPI]_ or MPICH.
17 * The mpi4py [mpi4py]_ package.
18
19 .. note::
20
21 The mpi4py package is not a strict requirement. However, you need to
22 have *some* way of calling MPI from Python. You also need some way of
23 making sure that :func:`MPI_Init` is called when the IPython engines start
24 up. There are a number of ways of doing this and a good number of
25 associated subtleties. We highly recommend just using mpi4py as it
26 takes care of most of these problems. If you want to do something
27 different, let us know and we can help you get started.
28
29 Starting the engines with MPI enabled
30 =====================================
31
32 To use code that calls MPI, there are typically two things that MPI requires.
33
34 1. The process that wants to call MPI must be started using
35 :command:`mpirun` or a batch system (like PBS) that has MPI support.
36 2. Once the process starts, it must call :func:`MPI_Init`.
37
38 There are a couple of ways that you can start the IPython engines and get these things to happen.
39
40 Automatic starting using :command:`mpirun` and :command:`ipcluster`
41 -------------------------------------------------------------------
42
43 The easiest approach is to use the `mpirun` mode of :command:`ipcluster`, which will first start a controller and then a set of engines using :command:`mpirun`::
44
45 $ ipcluster mpirun -n 4
46
47 This approach is best as interrupting :command:`ipcluster` will automatically
48 stop and clean up the controller and engines.
49
50 Manual starting using :command:`mpirun`
51 ---------------------------------------
52
53 If you want to start the IPython engines using the :command:`mpirun`, just do::
54
55 $ mpirun -n 4 ipengine --mpi=mpi4py
56
57 This requires that you already have a controller running and that the FURL
58 files for the engines are in place. We also have built in support for
59 PyTrilinos [PyTrilinos]_, which can be used (assuming is installed) by
60 starting the engines with::
16
61
17 mpirun -n 4 ipengine --mpi=pytrilinos
62 mpirun -n 4 ipengine --mpi=pytrilinos
18
63
19 .. _MPI: http://www-unix.mcs.anl.gov/mpi/
64 Automatic starting using PBS and :command:`ipcluster`
20 .. _mpi4py: http://mpi4py.scipy.org/
65 -----------------------------------------------------
21 .. _Open MPI: http://www.open-mpi.org/
66
22 .. _PyTrilinos: http://trilinos.sandia.gov/packages/pytrilinos/ No newline at end of file
67 The :command:`ipcluster` command also has built-in integration with PBS. For more information on this approach, see our documentation on :ref:`ipcluster <parallel_process>`.
68
69 Actually using MPI
70 ==================
71
72 Once the engines are running with MPI enabled, you are ready to go. You can now call any code that uses MPI in the IPython engines. And, all of this can be done interactively. Here we show a simple example that uses mpi4py [mpi4py]_.
73
74 First, lets define a simply function that uses MPI to calculate the sum of a distributed array. Save the following text in a file called :file:`psum.py`:
75
76 .. sourcecode:: python
77
78 from mpi4py import MPI
79 import numpy as np
80
81 def psum(a):
82 s = np.sum(a)
83 return MPI.COMM_WORLD.Allreduce(s,MPI.SUM)
84
85 Now, start an IPython cluster in the same directory as :file:`psum.py`::
86
87 $ ipcluster mpirun -n 4
88
89 Finally, connect to the cluster and use this function interactively. In this case, we create a random array on each engine and sum up all the random arrays using our :func:`psum` function:
90
91 .. sourcecode:: ipython
92
93 In [1]: from IPython.kernel import client
94
95 In [2]: mec = client.MultiEngineClient()
96
97 In [3]: mec.activate()
98
99 In [4]: px import numpy as np
100 Parallel execution on engines: all
101 Out[4]:
102 <Results List>
103 [0] In [13]: import numpy as np
104 [1] In [13]: import numpy as np
105 [2] In [13]: import numpy as np
106 [3] In [13]: import numpy as np
107
108 In [6]: px a = np.random.rand(100)
109 Parallel execution on engines: all
110 Out[6]:
111 <Results List>
112 [0] In [15]: a = np.random.rand(100)
113 [1] In [15]: a = np.random.rand(100)
114 [2] In [15]: a = np.random.rand(100)
115 [3] In [15]: a = np.random.rand(100)
116
117 In [7]: px from psum import psum
118 Parallel execution on engines: all
119 Out[7]:
120 <Results List>
121 [0] In [16]: from psum import psum
122 [1] In [16]: from psum import psum
123 [2] In [16]: from psum import psum
124 [3] In [16]: from psum import psum
125
126 In [8]: px s = psum(a)
127 Parallel execution on engines: all
128 Out[8]:
129 <Results List>
130 [0] In [17]: s = psum(a)
131 [1] In [17]: s = psum(a)
132 [2] In [17]: s = psum(a)
133 [3] In [17]: s = psum(a)
134
135 In [9]: px print s
136 Parallel execution on engines: all
137 Out[9]:
138 <Results List>
139 [0] In [18]: print s
140 [0] Out[18]: 187.451545803
141
142 [1] In [18]: print s
143 [1] Out[18]: 187.451545803
144
145 [2] In [18]: print s
146 [2] Out[18]: 187.451545803
147
148 [3] In [18]: print s
149 [3] Out[18]: 187.451545803
150
151 Any Python code that makes calls to MPI can be used in this manner, including
152 compiled C, C++ and Fortran libraries that have been exposed to Python.
153
154 .. [MPI] Message Passing Interface. http://www-unix.mcs.anl.gov/mpi/
155 .. [mpi4py] MPI for Python. mpi4py: http://mpi4py.scipy.org/
156 .. [OpenMPI] Open MPI. http://www.open-mpi.org/
157 .. [PyTrilinos] PyTrilinos. http://trilinos.sandia.gov/packages/pytrilinos/ No newline at end of file
@@ -1,58 +1,126 b''
1 .. _parallelmultiengine:
1 .. _parallelmultiengine:
2
2
3 =================================
3 ===============================
4 IPython's MultiEngine interface
4 IPython's multiengine interface
5 =================================
5 ===============================
6
6
7 .. contents::
7 The multiengine interface represents one possible way of working with a set of
8
8 IPython engines. The basic idea behind the multiengine interface is that the
9 The MultiEngine interface represents one possible way of working with a
9 capabilities of each engine are directly and explicitly exposed to the user.
10 set of IPython engines. The basic idea behind the MultiEngine interface is
10 Thus, in the multiengine interface, each engine is given an id that is used to
11 that the capabilities of each engine are explicitly exposed to the user.
11 identify the engine and give it work to do. This interface is very intuitive
12 Thus, in the MultiEngine interface, each engine is given an id that is
12 and is designed with interactive usage in mind, and is thus the best place for
13 used to identify the engine and give it work to do. This interface is very
13 new users of IPython to begin.
14 intuitive and is designed with interactive usage in mind, and is thus the
15 best place for new users of IPython to begin.
16
14
17 Starting the IPython controller and engines
15 Starting the IPython controller and engines
18 ===========================================
16 ===========================================
19
17
20 To follow along with this tutorial, you will need to start the IPython
18 To follow along with this tutorial, you will need to start the IPython
21 controller and four IPython engines. The simplest way of doing this is to
19 controller and four IPython engines. The simplest way of doing this is to use
22 use the ``ipcluster`` command::
20 the :command:`ipcluster` command::
23
21
24 $ ipcluster -n 4
22 $ ipcluster local -n 4
25
23
26 For more detailed information about starting the controller and engines, see our :ref:`introduction <ip1par>` to using IPython for parallel computing.
24 For more detailed information about starting the controller and engines, see
25 our :ref:`introduction <ip1par>` to using IPython for parallel computing.
27
26
28 Creating a ``MultiEngineClient`` instance
27 Creating a ``MultiEngineClient`` instance
29 =========================================
28 =========================================
30
29
31 The first step is to import the IPython ``client`` module and then create a ``MultiEngineClient`` instance::
30 The first step is to import the IPython :mod:`IPython.kernel.client` module
31 and then create a :class:`MultiEngineClient` instance:
32
33 .. sourcecode:: ipython
32
34
33 In [1]: from IPython.kernel import client
35 In [1]: from IPython.kernel import client
34
36
35 In [2]: mec = client.MultiEngineClient()
37 In [2]: mec = client.MultiEngineClient()
36
38
37 To make sure there are engines connected to the controller, use can get a list of engine ids::
39 This form assumes that the :file:`ipcontroller-mec.furl` is in the
40 :file:`~./ipython/security` directory on the client's host. If not, the
41 location of the FURL file must be given as an argument to the
42 constructor:
43
44 .. sourcecode:: ipython
45
46 In [2]: mec = client.MultiEngineClient('/path/to/my/ipcontroller-mec.furl')
47
48 To make sure there are engines connected to the controller, use can get a list
49 of engine ids:
50
51 .. sourcecode:: ipython
38
52
39 In [3]: mec.get_ids()
53 In [3]: mec.get_ids()
40 Out[3]: [0, 1, 2, 3]
54 Out[3]: [0, 1, 2, 3]
41
55
42 Here we see that there are four engines ready to do work for us.
56 Here we see that there are four engines ready to do work for us.
43
57
58 Quick and easy parallelism
59 ==========================
60
61 In many cases, you simply want to apply a Python function to a sequence of objects, but *in parallel*. The multiengine interface provides two simple ways of accomplishing this: a parallel version of :func:`map` and ``@parallel`` function decorator.
62
63 Parallel map
64 ------------
65
66 Python's builtin :func:`map` functions allows a function to be applied to a
67 sequence element-by-element. This type of code is typically trivial to
68 parallelize. In fact, the multiengine interface in IPython already has a
69 parallel version of :meth:`map` that works just like its serial counterpart:
70
71 .. sourcecode:: ipython
72
73 In [63]: serial_result = map(lambda x:x**10, range(32))
74
75 In [64]: parallel_result = mec.map(lambda x:x**10, range(32))
76
77 In [65]: serial_result==parallel_result
78 Out[65]: True
79
80 .. note::
81
82 The multiengine interface version of :meth:`map` does not do any load
83 balancing. For a load balanced version, see the task interface.
84
85 .. seealso::
86
87 The :meth:`map` method has a number of options that can be controlled by
88 the :meth:`mapper` method. See its docstring for more information.
89
90 Parallel function decorator
91 ---------------------------
92
93 Parallel functions are just like normal function, but they can be called on sequences and *in parallel*. The multiengine interface provides a decorator that turns any Python function into a parallel function:
94
95 .. sourcecode:: ipython
96
97 In [10]: @mec.parallel()
98 ....: def f(x):
99 ....: return 10.0*x**4
100 ....:
101
102 In [11]: f(range(32)) # this is done in parallel
103 Out[11]:
104 [0.0,10.0,160.0,...]
105
106 See the docstring for the :meth:`parallel` decorator for options.
107
44 Running Python commands
108 Running Python commands
45 =======================
109 =======================
46
110
47 The most basic type of operation that can be performed on the engines is to execute Python code. Executing Python code can be done in blocking or non-blocking mode (blocking is default) using the ``execute`` method.
111 The most basic type of operation that can be performed on the engines is to
112 execute Python code. Executing Python code can be done in blocking or
113 non-blocking mode (blocking is default) using the :meth:`execute` method.
48
114
49 Blocking execution
115 Blocking execution
50 ------------------
116 ------------------
51
117
52 In blocking mode, the ``MultiEngineClient`` object (called ``mec`` in
118 In blocking mode, the :class:`MultiEngineClient` object (called ``mec`` in
53 these examples) submits the command to the controller, which places the
119 these examples) submits the command to the controller, which places the
54 command in the engines' queues for execution. The ``execute`` call then
120 command in the engines' queues for execution. The :meth:`execute` call then
55 blocks until the engines are done executing the command::
121 blocks until the engines are done executing the command:
122
123 .. sourcecode:: ipython
56
124
57 # The default is to run on all engines
125 # The default is to run on all engines
58 In [4]: mec.execute('a=5')
126 In [4]: mec.execute('a=5')
@@ -71,7 +139,10 b' blocks until the engines are done executing the command::'
71 [2] In [2]: b=10
139 [2] In [2]: b=10
72 [3] In [2]: b=10
140 [3] In [2]: b=10
73
141
74 Python commands can be executed on specific engines by calling execute using the ``targets`` keyword argument::
142 Python commands can be executed on specific engines by calling execute using
143 the ``targets`` keyword argument:
144
145 .. sourcecode:: ipython
75
146
76 In [6]: mec.execute('c=a+b',targets=[0,2])
147 In [6]: mec.execute('c=a+b',targets=[0,2])
77 Out[6]:
148 Out[6]:
@@ -102,7 +173,11 b' Python commands can be executed on specific engines by calling execute using the'
102 [3] In [4]: print c
173 [3] In [4]: print c
103 [3] Out[4]: -5
174 [3] Out[4]: -5
104
175
105 This example also shows one of the most important things about the IPython engines: they have a persistent user namespaces. The ``execute`` method returns a Python ``dict`` that contains useful information::
176 This example also shows one of the most important things about the IPython
177 engines: they have a persistent user namespaces. The :meth:`execute` method
178 returns a Python ``dict`` that contains useful information:
179
180 .. sourcecode:: ipython
106
181
107 In [9]: result_dict = mec.execute('d=10; print d')
182 In [9]: result_dict = mec.execute('d=10; print d')
108
183
@@ -118,10 +193,14 b' This example also shows one of the most important things about the IPython engin'
118 Non-blocking execution
193 Non-blocking execution
119 ----------------------
194 ----------------------
120
195
121 In non-blocking mode, ``execute`` submits the command to be executed and then returns a
196 In non-blocking mode, :meth:`execute` submits the command to be executed and
122 ``PendingResult`` object immediately. The ``PendingResult`` object gives you a way of getting a
197 then returns a :class:`PendingResult` object immediately. The
123 result at a later time through its ``get_result`` method or ``r`` attribute. This allows you to
198 :class:`PendingResult` object gives you a way of getting a result at a later
124 quickly submit long running commands without blocking your local Python/IPython session::
199 time through its :meth:`get_result` method or :attr:`r` attribute. This allows
200 you to quickly submit long running commands without blocking your local
201 Python/IPython session:
202
203 .. sourcecode:: ipython
125
204
126 # In blocking mode
205 # In blocking mode
127 In [6]: mec.execute('import time')
206 In [6]: mec.execute('import time')
@@ -159,7 +238,12 b' quickly submit long running commands without blocking your local Python/IPython '
159 [2] In [3]: time.sleep(10)
238 [2] In [3]: time.sleep(10)
160 [3] In [3]: time.sleep(10)
239 [3] In [3]: time.sleep(10)
161
240
162 Often, it is desirable to wait until a set of ``PendingResult`` objects are done. For this, there is a the method ``barrier``. This method takes a tuple of ``PendingResult`` objects and blocks until all of the associated results are ready::
241 Often, it is desirable to wait until a set of :class:`PendingResult` objects
242 are done. For this, there is a the method :meth:`barrier`. This method takes a
243 tuple of :class:`PendingResult` objects and blocks until all of the associated
244 results are ready:
245
246 .. sourcecode:: ipython
163
247
164 In [72]: mec.block=False
248 In [72]: mec.block=False
165
249
@@ -182,16 +266,20 b' Often, it is desirable to wait until a set of ``PendingResult`` objects are done'
182 The ``block`` and ``targets`` keyword arguments and attributes
266 The ``block`` and ``targets`` keyword arguments and attributes
183 --------------------------------------------------------------
267 --------------------------------------------------------------
184
268
185 Most commands in the multiengine interface (like ``execute``) accept ``block`` and ``targets``
269 Most methods in the multiengine interface (like :meth:`execute`) accept
186 as keyword arguments. As we have seen above, these keyword arguments control the blocking mode
270 ``block`` and ``targets`` as keyword arguments. As we have seen above, these
187 and which engines the command is applied to. The ``MultiEngineClient`` class also has ``block``
271 keyword arguments control the blocking mode and which engines the command is
188 and ``targets`` attributes that control the default behavior when the keyword arguments are not
272 applied to. The :class:`MultiEngineClient` class also has :attr:`block` and
189 provided. Thus the following logic is used for ``block`` and ``targets``:
273 :attr:`targets` attributes that control the default behavior when the keyword
274 arguments are not provided. Thus the following logic is used for :attr:`block`
275 and :attr:`targets`:
190
276
191 * If no keyword argument is provided, the instance attributes are used.
277 * If no keyword argument is provided, the instance attributes are used.
192 * Keyword argument, if provided override the instance attributes.
278 * Keyword argument, if provided override the instance attributes.
193
279
194 The following examples demonstrate how to use the instance attributes::
280 The following examples demonstrate how to use the instance attributes:
281
282 .. sourcecode:: ipython
195
283
196 In [16]: mec.targets = [0,2]
284 In [16]: mec.targets = [0,2]
197
285
@@ -225,14 +313,21 b' The following examples demonstrate how to use the instance attributes::'
225 [3] In [6]: b=10; print b
313 [3] In [6]: b=10; print b
226 [3] Out[6]: 10
314 [3] Out[6]: 10
227
315
228 The ``block`` and ``targets`` instance attributes also determine the behavior of the parallel
316 The :attr:`block` and :attr:`targets` instance attributes also determine the
229 magic commands...
317 behavior of the parallel magic commands.
230
318
231
319
232 Parallel magic commands
320 Parallel magic commands
233 -----------------------
321 -----------------------
234
322
235 We provide a few IPython magic commands (``%px``, ``%autopx`` and ``%result``) that make it more pleasant to execute Python commands on the engines interactively. These are simply shortcuts to ``execute`` and ``get_result``. The ``%px`` magic executes a single Python command on the engines specified by the `magicTargets``targets` attribute of the ``MultiEngineClient`` instance (by default this is 'all')::
323 We provide a few IPython magic commands (``%px``, ``%autopx`` and ``%result``)
324 that make it more pleasant to execute Python commands on the engines
325 interactively. These are simply shortcuts to :meth:`execute` and
326 :meth:`get_result`. The ``%px`` magic executes a single Python command on the
327 engines specified by the :attr:`targets` attribute of the
328 :class:`MultiEngineClient` instance (by default this is ``'all'``):
329
330 .. sourcecode:: ipython
236
331
237 # Make this MultiEngineClient active for parallel magic commands
332 # Make this MultiEngineClient active for parallel magic commands
238 In [23]: mec.activate()
333 In [23]: mec.activate()
@@ -277,7 +372,11 b' We provide a few IPython magic commands (``%px``, ``%autopx`` and ``%result``) t'
277 [3] In [9]: print numpy.linalg.eigvals(a)
372 [3] In [9]: print numpy.linalg.eigvals(a)
278 [3] Out[9]: [ 0.83664764 -0.25602658]
373 [3] Out[9]: [ 0.83664764 -0.25602658]
279
374
280 The ``%result`` magic gets and prints the stdin/stdout/stderr of the last command executed on each engine. It is simply a shortcut to the ``get_result`` method::
375 The ``%result`` magic gets and prints the stdin/stdout/stderr of the last
376 command executed on each engine. It is simply a shortcut to the
377 :meth:`get_result` method:
378
379 .. sourcecode:: ipython
281
380
282 In [29]: %result
381 In [29]: %result
283 Out[29]:
382 Out[29]:
@@ -294,7 +393,10 b' The ``%result`` magic gets and prints the stdin/stdout/stderr of the last comman'
294 [3] In [9]: print numpy.linalg.eigvals(a)
393 [3] In [9]: print numpy.linalg.eigvals(a)
295 [3] Out[9]: [ 0.83664764 -0.25602658]
394 [3] Out[9]: [ 0.83664764 -0.25602658]
296
395
297 The ``%autopx`` magic switches to a mode where everything you type is executed on the engines given by the ``targets`` attribute::
396 The ``%autopx`` magic switches to a mode where everything you type is executed
397 on the engines given by the :attr:`targets` attribute:
398
399 .. sourcecode:: ipython
298
400
299 In [30]: mec.block=False
401 In [30]: mec.block=False
300
402
@@ -335,51 +437,21 b' The ``%autopx`` magic switches to a mode where everything you type is executed o'
335 [3] In [12]: print "Average max eigenvalue is: ", sum(max_evals)/len(max_evals)
437 [3] In [12]: print "Average max eigenvalue is: ", sum(max_evals)/len(max_evals)
336 [3] Out[12]: Average max eigenvalue is: 10.1158837784
438 [3] Out[12]: Average max eigenvalue is: 10.1158837784
337
439
338 Using the ``with`` statement of Python 2.5
339 ------------------------------------------
340
341 Python 2.5 introduced the ``with`` statement. The ``MultiEngineClient`` can be used with the ``with`` statement to execute a block of code on the engines indicated by the ``targets`` attribute::
342
343 In [3]: with mec:
344 ...: client.remote() # Required so the following code is not run locally
345 ...: a = 10
346 ...: b = 30
347 ...: c = a+b
348 ...:
349 ...:
350
351 In [4]: mec.get_result()
352 Out[4]:
353 <Results List>
354 [0] In [1]: a = 10
355 b = 30
356 c = a+b
357
358 [1] In [1]: a = 10
359 b = 30
360 c = a+b
361
440
362 [2] In [1]: a = 10
441 Moving Python objects around
363 b = 30
442 ============================
364 c = a+b
365
443
366 [3] In [1]: a = 10
444 In addition to executing code on engines, you can transfer Python objects to
367 b = 30
445 and from your IPython session and the engines. In IPython, these operations
368 c = a+b
446 are called :meth:`push` (sending an object to the engines) and :meth:`pull`
369
447 (getting an object from the engines).
370 This is basically another way of calling execute, but one with allows you to avoid writing code in strings. When used in this way, the attributes ``targets`` and ``block`` are used to control how the code is executed. For now, if you run code in non-blocking mode you won't have access to the ``PendingResult``.
371
372 Moving Python object around
373 ===========================
374
375 In addition to executing code on engines, you can transfer Python objects to and from your
376 IPython session and the engines. In IPython, these operations are called ``push`` (sending an
377 object to the engines) and ``pull`` (getting an object from the engines).
378
448
379 Basic push and pull
449 Basic push and pull
380 -------------------
450 -------------------
381
451
382 Here are some examples of how you use ``push`` and ``pull``::
452 Here are some examples of how you use :meth:`push` and :meth:`pull`:
453
454 .. sourcecode:: ipython
383
455
384 In [38]: mec.push(dict(a=1.03234,b=3453))
456 In [38]: mec.push(dict(a=1.03234,b=3453))
385 Out[38]: [None, None, None, None]
457 Out[38]: [None, None, None, None]
@@ -415,7 +487,10 b' Here are some examples of how you use ``push`` and ``pull``::'
415 [3] In [13]: print c
487 [3] In [13]: print c
416 [3] Out[13]: speed
488 [3] Out[13]: speed
417
489
418 In non-blocking mode ``push`` and ``pull`` also return ``PendingResult`` objects::
490 In non-blocking mode :meth:`push` and :meth:`pull` also return
491 :class:`PendingResult` objects:
492
493 .. sourcecode:: ipython
419
494
420 In [47]: mec.block=False
495 In [47]: mec.block=False
421
496
@@ -428,7 +503,12 b' In non-blocking mode ``push`` and ``pull`` also return ``PendingResult`` objects'
428 Push and pull for functions
503 Push and pull for functions
429 ---------------------------
504 ---------------------------
430
505
431 Functions can also be pushed and pulled using ``push_function`` and ``pull_function``::
506 Functions can also be pushed and pulled using :meth:`push_function` and
507 :meth:`pull_function`:
508
509 .. sourcecode:: ipython
510
511 In [52]: mec.block=True
432
512
433 In [53]: def f(x):
513 In [53]: def f(x):
434 ....: return 2.0*x**4
514 ....: return 2.0*x**4
@@ -466,7 +546,12 b' Functions can also be pushed and pulled using ``push_function`` and ``pull_funct'
466 Dictionary interface
546 Dictionary interface
467 --------------------
547 --------------------
468
548
469 As a shorthand to ``push`` and ``pull``, the ``MultiEngineClient`` class implements some of the Python dictionary interface. This make the remote namespaces of the engines appear as a local dictionary. Underneath, this uses ``push`` and ``pull``::
549 As a shorthand to :meth:`push` and :meth:`pull`, the
550 :class:`MultiEngineClient` class implements some of the Python dictionary
551 interface. This make the remote namespaces of the engines appear as a local
552 dictionary. Underneath, this uses :meth:`push` and :meth:`pull`:
553
554 .. sourcecode:: ipython
470
555
471 In [50]: mec.block=True
556 In [50]: mec.block=True
472
557
@@ -478,11 +563,15 b' As a shorthand to ``push`` and ``pull``, the ``MultiEngineClient`` class impleme'
478 Scatter and gather
563 Scatter and gather
479 ------------------
564 ------------------
480
565
481 Sometimes it is useful to partition a sequence and push the partitions to different engines. In
566 Sometimes it is useful to partition a sequence and push the partitions to
482 MPI language, this is know as scatter/gather and we follow that terminology. However, it is
567 different engines. In MPI language, this is know as scatter/gather and we
483 important to remember that in IPython ``scatter`` is from the interactive IPython session to
568 follow that terminology. However, it is important to remember that in
484 the engines and ``gather`` is from the engines back to the interactive IPython session. For
569 IPython's :class:`MultiEngineClient` class, :meth:`scatter` is from the
485 scatter/gather operations between engines, MPI should be used::
570 interactive IPython session to the engines and :meth:`gather` is from the
571 engines back to the interactive IPython session. For scatter/gather operations
572 between engines, MPI should be used:
573
574 .. sourcecode:: ipython
486
575
487 In [58]: mec.scatter('a',range(16))
576 In [58]: mec.scatter('a',range(16))
488 Out[58]: [None, None, None, None]
577 Out[58]: [None, None, None, None]
@@ -510,24 +599,14 b' scatter/gather operations between engines, MPI should be used::'
510 Other things to look at
599 Other things to look at
511 =======================
600 =======================
512
601
513 Parallel map
514 ------------
515
516 Python's builtin ``map`` functions allows a function to be applied to a sequence element-by-element. This type of code is typically trivial to parallelize. In fact, the MultiEngine interface in IPython already has a parallel version of ``map`` that works just like its serial counterpart::
517
518 In [63]: serial_result = map(lambda x:x**10, range(32))
519
520 In [64]: parallel_result = mec.map(lambda x:x**10, range(32))
521
522 In [65]: serial_result==parallel_result
523 Out[65]: True
524
525 As you would expect, the parallel version of ``map`` is also influenced by the ``block`` and ``targets`` keyword arguments and attributes.
526
527 How to do parallel list comprehensions
602 How to do parallel list comprehensions
528 --------------------------------------
603 --------------------------------------
529
604
530 In many cases list comprehensions are nicer than using the map function. While we don't have fully parallel list comprehensions, it is simple to get the basic effect using ``scatter`` and ``gather``::
605 In many cases list comprehensions are nicer than using the map function. While
606 we don't have fully parallel list comprehensions, it is simple to get the
607 basic effect using :meth:`scatter` and :meth:`gather`:
608
609 .. sourcecode:: ipython
531
610
532 In [66]: mec.scatter('x',range(64))
611 In [66]: mec.scatter('x',range(64))
533 Out[66]: [None, None, None, None]
612 Out[66]: [None, None, None, None]
@@ -547,10 +626,18 b' In many cases list comprehensions are nicer than using the map function. While '
547 In [69]: print y
626 In [69]: print y
548 [0, 1, 1024, 59049, 1048576, 9765625, 60466176, 282475249, 1073741824,...]
627 [0, 1, 1024, 59049, 1048576, 9765625, 60466176, 282475249, 1073741824,...]
549
628
550 Parallel Exceptions
629 Parallel exceptions
551 -------------------
630 -------------------
552
631
553 In the MultiEngine interface, parallel commands can raise Python exceptions, just like serial commands. But, it is a little subtle, because a single parallel command can actually raise multiple exceptions (one for each engine the command was run on). To express this idea, the MultiEngine interface has a ``CompositeError`` exception class that will be raised in most cases. The ``CompositeError`` class is a special type of exception that wraps one or more other types of exceptions. Here is how it works::
632 In the multiengine interface, parallel commands can raise Python exceptions,
633 just like serial commands. But, it is a little subtle, because a single
634 parallel command can actually raise multiple exceptions (one for each engine
635 the command was run on). To express this idea, the MultiEngine interface has a
636 :exc:`CompositeError` exception class that will be raised in most cases. The
637 :exc:`CompositeError` class is a special type of exception that wraps one or
638 more other types of exceptions. Here is how it works:
639
640 .. sourcecode:: ipython
554
641
555 In [76]: mec.block=True
642 In [76]: mec.block=True
556
643
@@ -580,7 +667,9 b' In the MultiEngine interface, parallel commands can raise Python exceptions, jus'
580 [2:execute]: ZeroDivisionError: integer division or modulo by zero
667 [2:execute]: ZeroDivisionError: integer division or modulo by zero
581 [3:execute]: ZeroDivisionError: integer division or modulo by zero
668 [3:execute]: ZeroDivisionError: integer division or modulo by zero
582
669
583 Notice how the error message printed when ``CompositeError`` is raised has information about the individual exceptions that were raised on each engine. If you want, you can even raise one of these original exceptions::
670 Notice how the error message printed when :exc:`CompositeError` is raised has information about the individual exceptions that were raised on each engine. If you want, you can even raise one of these original exceptions:
671
672 .. sourcecode:: ipython
584
673
585 In [80]: try:
674 In [80]: try:
586 ....: mec.execute('1/0')
675 ....: mec.execute('1/0')
@@ -602,7 +691,11 b' Notice how the error message printed when ``CompositeError`` is raised has infor'
602
691
603 ZeroDivisionError: integer division or modulo by zero
692 ZeroDivisionError: integer division or modulo by zero
604
693
605 If you are working in IPython, you can simple type ``%debug`` after one of these ``CompositeError`` is raised, and inspect the exception instance::
694 If you are working in IPython, you can simple type ``%debug`` after one of
695 these :exc:`CompositeError` exceptions is raised, and inspect the exception
696 instance:
697
698 .. sourcecode:: ipython
606
699
607 In [81]: mec.execute('1/0')
700 In [81]: mec.execute('1/0')
608 ---------------------------------------------------------------------------
701 ---------------------------------------------------------------------------
@@ -679,7 +772,14 b' If you are working in IPython, you can simple type ``%debug`` after one of these'
679
772
680 ZeroDivisionError: integer division or modulo by zero
773 ZeroDivisionError: integer division or modulo by zero
681
774
682 All of this same error handling magic even works in non-blocking mode::
775 .. note::
776
777 The above example appears to be broken right now because of a change in
778 how we are using Twisted.
779
780 All of this same error handling magic even works in non-blocking mode:
781
782 .. sourcecode:: ipython
683
783
684 In [83]: mec.block=False
784 In [83]: mec.block=False
685
785
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from IPython/config/config.py to sandbox/config.py
NO CONTENT: file renamed from IPython/config/config.py to sandbox/config.py
1 NO CONTENT: file renamed from IPython/config/tests/sample_config.py to sandbox/sample_config.py
NO CONTENT: file renamed from IPython/config/tests/sample_config.py to sandbox/sample_config.py
1 NO CONTENT: file renamed from IPython/config/tests/test_config.py to sandbox/test_config.py
NO CONTENT: file renamed from IPython/config/tests/test_config.py to sandbox/test_config.py
1 NO CONTENT: file renamed from IPython/config/traitlets.py to sandbox/traitlets.py
NO CONTENT: file renamed from IPython/config/traitlets.py to sandbox/traitlets.py
1 NO CONTENT: modified file chmod 100644 => 100755, file renamed from scripts/wxIpython to scripts/ipython-wx
NO CONTENT: modified file chmod 100644 => 100755, file renamed from scripts/wxIpython to scripts/ipython-wx
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (660 lines changed) Show them Hide them
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now