##// END OF EJS Templates
First draft of refactored Component->Configurable.
Brian Granger -
Show More

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

@@ -0,0 +1,136 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 A base class for objects that are configurable.
5
6 Authors:
7
8 * Brian Granger
9 * Fernando Perez
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2010 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22
23 from copy import deepcopy
24 import datetime
25 from weakref import WeakValueDictionary
26
27 from IPython.utils.importstring import import_item
28 from loader import Config
29 from IPython.utils.traitlets import HasTraits, Instance
30
31
32 #-----------------------------------------------------------------------------
33 # Helper classes for Configurables
34 #-----------------------------------------------------------------------------
35
36
37 class ConfigurableError(Exception):
38 pass
39
40
41 #-----------------------------------------------------------------------------
42 # Configurable implementation
43 #-----------------------------------------------------------------------------
44
45
46 class Configurable(HasTraits):
47
48 config = Instance(Config,(),{})
49 created = None
50
51 def __init__(self, config=None):
52 """Create a conigurable given a config config.
53
54 Parameters
55 ----------
56 config : Config
57 If this is empty, default values are used. If config is a
58 :class:`Config` instance, it will be used to configure the
59 instance.
60
61 Notes
62 -----
63 Subclasses of Configurable must call the :meth:`__init__` method of
64 :class:`Configurable` *before* doing anything else and using
65 :func:`super`::
66
67 class MyConfigurable(Configurable):
68 def __init__(self, config=None):
69 super(MyConfigurable, self).__init__(config)
70 # Then any other code you need to finish initialization.
71
72 This ensures that instances will be configured properly.
73 """
74 super(Configurable, self).__init__()
75 if config is not None:
76 # We used to deepcopy, but for now we are trying to just save
77 # by reference. This *could* have side effects as all components
78 # will share config. In fact, I did find such a side effect in
79 # _config_changed below. If a config attribute value was a mutable type
80 # all instances of a component were getting the same copy, effectively
81 # making that a class attribute.
82 # self.config = deepcopy(config)
83 self.config = config
84 self.created = datetime.datetime.now()
85
86 #-------------------------------------------------------------------------
87 # Static trait notifiations
88 #-------------------------------------------------------------------------
89
90 def _config_changed(self, name, old, new):
91 """Update all the class traits having ``config=True`` as metadata.
92
93 For any class trait with a ``config`` metadata attribute that is
94 ``True``, we update the trait with the value of the corresponding
95 config entry.
96 """
97 # Get all traits with a config metadata entry that is True
98 traits = self.traits(config=True)
99
100 # We auto-load config section for this class as well as any parent
101 # classes that are Configurable subclasses. This starts with Configurable
102 # and works down the mro loading the config for each section.
103 section_names = [cls.__name__ for cls in \
104 reversed(self.__class__.__mro__) if
105 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
106
107 for sname in section_names:
108 # Don't do a blind getattr as that would cause the config to
109 # dynamically create the section with name self.__class__.__name__.
110 if new._has_section(sname):
111 my_config = new[sname]
112 for k, v in traits.items():
113 # Don't allow traitlets with config=True to start with
114 # uppercase. Otherwise, they are confused with Config
115 # subsections. But, developers shouldn't have uppercase
116 # attributes anyways! (PEP 6)
117 if k[0].upper()==k[0] and not k.startswith('_'):
118 raise ConfigurableError('Configurable traitlets with '
119 'config=True must start with a lowercase so they are '
120 'not confused with Config subsections: %s.%s' % \
121 (self.__class__.__name__, k))
122 try:
123 # Here we grab the value from the config
124 # If k has the naming convention of a config
125 # section, it will be auto created.
126 config_value = my_config[k]
127 except KeyError:
128 pass
129 else:
130 # print "Setting %s.%s from %s.%s=%r" % \
131 # (self.__class__.__name__,k,sname,k,config_value)
132 # We have to do a deepcopy here if we don't deepcopy the entire
133 # config object. If we don't, a mutable config_value will be
134 # shared by all instances, effectively making it a class attribute.
135 setattr(self, k, deepcopy(config_value))
136
@@ -0,0 +1,95 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 Tests for IPython.config.configurable
5
6 Authors:
7
8 * Brian Granger
9 * Fernando Perez (design help)
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2010 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22
23 from unittest import TestCase
24
25 from IPython.config.configurable import Configurable, ConfigurableError
26 from IPython.utils.traitlets import (
27 TraitError, Int, Float, Str
28 )
29 from IPython.config.loader import Config
30
31
32 #-----------------------------------------------------------------------------
33 # Test cases
34 #-----------------------------------------------------------------------------
35
36
37 class TestConfigurableConfig(TestCase):
38
39 def test_default(self):
40 c1 = Configurable()
41 c2 = Configurable(config=c1.config)
42 c3 = Configurable(config=c2.config)
43 self.assertEquals(c1.config, c2.config)
44 self.assertEquals(c2.config, c3.config)
45
46 def test_custom(self):
47 config = Config()
48 config.foo = 'foo'
49 config.bar = 'bar'
50 c1 = Configurable(config=config)
51 c2 = Configurable(c1.config)
52 c3 = Configurable(c2.config)
53 self.assertEquals(c1.config, config)
54 self.assertEquals(c2.config, config)
55 self.assertEquals(c3.config, config)
56 # Test that copies are not made
57 self.assert_(c1.config is config)
58 self.assert_(c2.config is config)
59 self.assert_(c3.config is config)
60 self.assert_(c1.config is c2.config)
61 self.assert_(c2.config is c3.config)
62
63 def test_inheritance(self):
64 class MyConfigurable(Configurable):
65 a = Int(1, config=True)
66 b = Float(1.0, config=True)
67 c = Str('no config')
68 config = Config()
69 config.MyConfigurable.a = 2
70 config.MyConfigurable.b = 2.0
71 c1 = MyConfigurable(config=config)
72 c2 = MyConfigurable(c1.config)
73 self.assertEquals(c1.a, config.MyConfigurable.a)
74 self.assertEquals(c1.b, config.MyConfigurable.b)
75 self.assertEquals(c2.a, config.MyConfigurable.a)
76 self.assertEquals(c2.b, config.MyConfigurable.b)
77
78 def test_parent(self):
79 class Foo(Configurable):
80 a = Int(0, config=True)
81 b = Str('nope', config=True)
82 class Bar(Foo):
83 b = Str('gotit', config=False)
84 c = Float(config=True)
85 config = Config()
86 config.Foo.a = 10
87 config.Foo.b = "wow"
88 config.Bar.b = 'later'
89 config.Bar.c = 100.0
90 f = Foo(config=config)
91 b = Bar(f.config)
92 self.assertEquals(f.a, 10)
93 self.assertEquals(f.b, 'wow')
94 self.assertEquals(b.b, 'gotit')
95 self.assertEquals(b.c, 100.0)
@@ -0,0 +1,124 b''
1 # encoding: utf-8
2 """A class for managing IPython extensions.
3
4 Authors:
5
6 * Brian Granger
7 """
8
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
17 # Imports
18 #-----------------------------------------------------------------------------
19
20 import os
21 import sys
22
23 from IPython.config.configurable import Configurable
24 from IPython.utils.traitlets import Instance
25
26 #-----------------------------------------------------------------------------
27 # Main class
28 #-----------------------------------------------------------------------------
29
30 class ExtensionManager(Configurable):
31
32 shell = Instance('IPython.core.iplib.InteractiveShell')
33
34 def __init__(self, shell, config=None):
35 super(ExtensionManager, self).__init__(config=config)
36 self.shell = shell
37 self.shell.on_trait_change(
38 self._on_ipython_dir_changed, 'ipython_dir'
39 )
40
41 def __del__(self):
42 self.shell.on_trait_change(
43 self._on_ipython_dir_changed, 'ipython_dir', remove=True
44 )
45
46 @property
47 def ipython_extension_dir(self):
48 return os.path.join(self.shell.ipython_dir, u'extensions')
49
50 def _on_ipython_dir_changed(self):
51 if not os.path.isdir(self.ipython_extension_dir):
52 os.makedirs(self.ipython_extension_dir, mode = 0777)
53
54 def load_extension(self, module_str):
55 """Load an IPython extension by its module name.
56
57 An IPython extension is an importable Python module that has
58 a function with the signature::
59
60 def load_ipython_extension(ipython):
61 # Do things with ipython
62
63 This function is called after your extension is imported and the
64 currently active :class:`InteractiveShell` instance is passed as
65 the only argument. You can do anything you want with IPython at
66 that point, including defining new magic and aliases, adding new
67 components, etc.
68
69 The :func:`load_ipython_extension` will be called again is you
70 load or reload the extension again. It is up to the extension
71 author to add code to manage that.
72
73 You can put your extension modules anywhere you want, as long as
74 they can be imported by Python's standard import mechanism. However,
75 to make it easy to write extensions, you can also put your extensions
76 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
77 is added to ``sys.path`` automatically.
78
79 If :func:`load_ipython_extension` returns anything, this function
80 will return that object.
81 """
82 from IPython.utils.syspathcontext import prepended_to_syspath
83
84 if module_str not in sys.modules:
85 with prepended_to_syspath(self.ipython_extension_dir):
86 __import__(module_str)
87 mod = sys.modules[module_str]
88 return self._call_load_ipython_extension(mod)
89
90 def unload_extension(self, module_str):
91 """Unload an IPython extension by its module name.
92
93 This function looks up the extension's name in ``sys.modules`` and
94 simply calls ``mod.unload_ipython_extension(self)``.
95 """
96 if module_str in sys.modules:
97 mod = sys.modules[module_str]
98 self._call_unload_ipython_extension(mod)
99
100 def reload_extension(self, module_str):
101 """Reload an IPython extension by calling reload.
102
103 If the module has not been loaded before,
104 :meth:`InteractiveShell.load_extension` is called. Otherwise
105 :func:`reload` is called and then the :func:`load_ipython_extension`
106 function of the module, if it exists is called.
107 """
108 from IPython.utils.syspathcontext import prepended_to_syspath
109
110 with prepended_to_syspath(self.ipython_extension_dir):
111 if module_str in sys.modules:
112 mod = sys.modules[module_str]
113 reload(mod)
114 self._call_load_ipython_extension(mod)
115 else:
116 self.load_extension(module_str)
117
118 def _call_load_ipython_extension(self, mod):
119 if hasattr(mod, 'load_ipython_extension'):
120 return mod.load_ipython_extension(self.shell)
121
122 def _call_unload_ipython_extension(self, mod):
123 if hasattr(mod, 'unload_ipython_extension'):
124 return mod.unload_ipython_extension(self.shell) No newline at end of file
@@ -1,262 +1,259 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 IPython's alias component
4 System command aliases.
5
5
6 Authors:
6 Authors:
7
7
8 * Fernando Perez
8 * Brian Granger
9 * Brian Granger
9 """
10 """
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2009 The IPython Development Team
13 # Copyright (C) 2008-2009 The IPython Development Team
13 #
14 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17
18
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19 # Imports
20 # Imports
20 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
21
22
22 import __builtin__
23 import __builtin__
23 import keyword
24 import keyword
24 import os
25 import os
25 import re
26 import re
26 import sys
27 import sys
27
28
28 from IPython.core.component import Component
29 from IPython.config.configurable import Configurable
29 from IPython.core.splitinput import split_user_input
30 from IPython.core.splitinput import split_user_input
30
31
31 from IPython.utils.traitlets import List
32 from IPython.utils.traitlets import List, Instance
32 from IPython.utils.autoattr import auto_attr
33 from IPython.utils.autoattr import auto_attr
33 from IPython.utils.warn import warn, error
34 from IPython.utils.warn import warn, error
34
35
35 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
36 # Utilities
37 # Utilities
37 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
38
39
39 # This is used as the pattern for calls to split_user_input.
40 # This is used as the pattern for calls to split_user_input.
40 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
41 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
41
42
42 def default_aliases():
43 def default_aliases():
43 # Make some aliases automatically
44 # Make some aliases automatically
44 # Prepare list of shell aliases to auto-define
45 # Prepare list of shell aliases to auto-define
45 if os.name == 'posix':
46 if os.name == 'posix':
46 default_aliases = ('mkdir mkdir', 'rmdir rmdir',
47 default_aliases = ('mkdir mkdir', 'rmdir rmdir',
47 'mv mv -i','rm rm -i','cp cp -i',
48 'mv mv -i','rm rm -i','cp cp -i',
48 'cat cat','less less','clear clear',
49 'cat cat','less less','clear clear',
49 # a better ls
50 # a better ls
50 'ls ls -F',
51 'ls ls -F',
51 # long ls
52 # long ls
52 'll ls -lF')
53 'll ls -lF')
53 # Extra ls aliases with color, which need special treatment on BSD
54 # Extra ls aliases with color, which need special treatment on BSD
54 # variants
55 # variants
55 ls_extra = ( # color ls
56 ls_extra = ( # color ls
56 'lc ls -F -o --color',
57 'lc ls -F -o --color',
57 # ls normal files only
58 # ls normal files only
58 'lf ls -F -o --color %l | grep ^-',
59 'lf ls -F -o --color %l | grep ^-',
59 # ls symbolic links
60 # ls symbolic links
60 'lk ls -F -o --color %l | grep ^l',
61 'lk ls -F -o --color %l | grep ^l',
61 # directories or links to directories,
62 # directories or links to directories,
62 'ldir ls -F -o --color %l | grep /$',
63 'ldir ls -F -o --color %l | grep /$',
63 # things which are executable
64 # things which are executable
64 'lx ls -F -o --color %l | grep ^-..x',
65 'lx ls -F -o --color %l | grep ^-..x',
65 )
66 )
66 # The BSDs don't ship GNU ls, so they don't understand the
67 # The BSDs don't ship GNU ls, so they don't understand the
67 # --color switch out of the box
68 # --color switch out of the box
68 if 'bsd' in sys.platform:
69 if 'bsd' in sys.platform:
69 ls_extra = ( # ls normal files only
70 ls_extra = ( # ls normal files only
70 'lf ls -lF | grep ^-',
71 'lf ls -lF | grep ^-',
71 # ls symbolic links
72 # ls symbolic links
72 'lk ls -lF | grep ^l',
73 'lk ls -lF | grep ^l',
73 # directories or links to directories,
74 # directories or links to directories,
74 'ldir ls -lF | grep /$',
75 'ldir ls -lF | grep /$',
75 # things which are executable
76 # things which are executable
76 'lx ls -lF | grep ^-..x',
77 'lx ls -lF | grep ^-..x',
77 )
78 )
78 default_aliases = default_aliases + ls_extra
79 default_aliases = default_aliases + ls_extra
79 elif os.name in ['nt','dos']:
80 elif os.name in ['nt','dos']:
80 default_aliases = ('ls dir /on',
81 default_aliases = ('ls dir /on',
81 'ddir dir /ad /on', 'ldir dir /ad /on',
82 'ddir dir /ad /on', 'ldir dir /ad /on',
82 'mkdir mkdir','rmdir rmdir','echo echo',
83 'mkdir mkdir','rmdir rmdir','echo echo',
83 'ren ren','cls cls','copy copy')
84 'ren ren','cls cls','copy copy')
84 else:
85 else:
85 default_aliases = ()
86 default_aliases = ()
86 return [s.split(None,1) for s in default_aliases]
87 return [s.split(None,1) for s in default_aliases]
87
88
88
89
89 class AliasError(Exception):
90 class AliasError(Exception):
90 pass
91 pass
91
92
92
93
93 class InvalidAliasError(AliasError):
94 class InvalidAliasError(AliasError):
94 pass
95 pass
95
96
96
97
97 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
98 # Main AliasManager class
99 # Main AliasManager class
99 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
100
101
101
102
102 class AliasManager(Component):
103 class AliasManager(Configurable):
103
104
104 default_aliases = List(default_aliases(), config=True)
105 default_aliases = List(default_aliases(), config=True)
105 user_aliases = List(default_value=[], config=True)
106 user_aliases = List(default_value=[], config=True)
107 shell = Instance('IPython.core.iplib.InteractiveShell')
106
108
107 def __init__(self, parent, config=None):
109 def __init__(self, shell, config=None):
108 super(AliasManager, self).__init__(parent, config=config)
110 super(AliasManager, self).__init__(config=config)
109 self.alias_table = {}
111 self.alias_table = {}
110 self.exclude_aliases()
112 self.exclude_aliases()
111 self.init_aliases()
113 self.init_aliases()
112
114 self.shell = shell
113 @auto_attr
114 def shell(self):
115 return Component.get_instances(
116 root=self.root,
117 klass='IPython.core.iplib.InteractiveShell')[0]
118
115
119 def __contains__(self, name):
116 def __contains__(self, name):
120 if name in self.alias_table:
117 if name in self.alias_table:
121 return True
118 return True
122 else:
119 else:
123 return False
120 return False
124
121
125 @property
122 @property
126 def aliases(self):
123 def aliases(self):
127 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
124 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
128
125
129 def exclude_aliases(self):
126 def exclude_aliases(self):
130 # set of things NOT to alias (keywords, builtins and some magics)
127 # set of things NOT to alias (keywords, builtins and some magics)
131 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
128 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
132 no_alias.update(set(keyword.kwlist))
129 no_alias.update(set(keyword.kwlist))
133 no_alias.update(set(__builtin__.__dict__.keys()))
130 no_alias.update(set(__builtin__.__dict__.keys()))
134 self.no_alias = no_alias
131 self.no_alias = no_alias
135
132
136 def init_aliases(self):
133 def init_aliases(self):
137 # Load default aliases
134 # Load default aliases
138 for name, cmd in self.default_aliases:
135 for name, cmd in self.default_aliases:
139 self.soft_define_alias(name, cmd)
136 self.soft_define_alias(name, cmd)
140
137
141 # Load user aliases
138 # Load user aliases
142 for name, cmd in self.user_aliases:
139 for name, cmd in self.user_aliases:
143 self.soft_define_alias(name, cmd)
140 self.soft_define_alias(name, cmd)
144
141
145 def clear_aliases(self):
142 def clear_aliases(self):
146 self.alias_table.clear()
143 self.alias_table.clear()
147
144
148 def soft_define_alias(self, name, cmd):
145 def soft_define_alias(self, name, cmd):
149 """Define an alias, but don't raise on an AliasError."""
146 """Define an alias, but don't raise on an AliasError."""
150 try:
147 try:
151 self.define_alias(name, cmd)
148 self.define_alias(name, cmd)
152 except AliasError, e:
149 except AliasError, e:
153 error("Invalid alias: %s" % e)
150 error("Invalid alias: %s" % e)
154
151
155 def define_alias(self, name, cmd):
152 def define_alias(self, name, cmd):
156 """Define a new alias after validating it.
153 """Define a new alias after validating it.
157
154
158 This will raise an :exc:`AliasError` if there are validation
155 This will raise an :exc:`AliasError` if there are validation
159 problems.
156 problems.
160 """
157 """
161 nargs = self.validate_alias(name, cmd)
158 nargs = self.validate_alias(name, cmd)
162 self.alias_table[name] = (nargs, cmd)
159 self.alias_table[name] = (nargs, cmd)
163
160
164 def undefine_alias(self, name):
161 def undefine_alias(self, name):
165 if self.alias_table.has_key(name):
162 if self.alias_table.has_key(name):
166 del self.alias_table[name]
163 del self.alias_table[name]
167
164
168 def validate_alias(self, name, cmd):
165 def validate_alias(self, name, cmd):
169 """Validate an alias and return the its number of arguments."""
166 """Validate an alias and return the its number of arguments."""
170 if name in self.no_alias:
167 if name in self.no_alias:
171 raise InvalidAliasError("The name %s can't be aliased "
168 raise InvalidAliasError("The name %s can't be aliased "
172 "because it is a keyword or builtin." % name)
169 "because it is a keyword or builtin." % name)
173 if not (isinstance(cmd, basestring)):
170 if not (isinstance(cmd, basestring)):
174 raise InvalidAliasError("An alias command must be a string, "
171 raise InvalidAliasError("An alias command must be a string, "
175 "got: %r" % name)
172 "got: %r" % name)
176 nargs = cmd.count('%s')
173 nargs = cmd.count('%s')
177 if nargs>0 and cmd.find('%l')>=0:
174 if nargs>0 and cmd.find('%l')>=0:
178 raise InvalidAliasError('The %s and %l specifiers are mutually '
175 raise InvalidAliasError('The %s and %l specifiers are mutually '
179 'exclusive in alias definitions.')
176 'exclusive in alias definitions.')
180 return nargs
177 return nargs
181
178
182 def call_alias(self, alias, rest=''):
179 def call_alias(self, alias, rest=''):
183 """Call an alias given its name and the rest of the line."""
180 """Call an alias given its name and the rest of the line."""
184 cmd = self.transform_alias(alias, rest)
181 cmd = self.transform_alias(alias, rest)
185 try:
182 try:
186 self.shell.system(cmd)
183 self.shell.system(cmd)
187 except:
184 except:
188 self.shell.showtraceback()
185 self.shell.showtraceback()
189
186
190 def transform_alias(self, alias,rest=''):
187 def transform_alias(self, alias,rest=''):
191 """Transform alias to system command string."""
188 """Transform alias to system command string."""
192 nargs, cmd = self.alias_table[alias]
189 nargs, cmd = self.alias_table[alias]
193
190
194 if ' ' in cmd and os.path.isfile(cmd):
191 if ' ' in cmd and os.path.isfile(cmd):
195 cmd = '"%s"' % cmd
192 cmd = '"%s"' % cmd
196
193
197 # Expand the %l special to be the user's input line
194 # Expand the %l special to be the user's input line
198 if cmd.find('%l') >= 0:
195 if cmd.find('%l') >= 0:
199 cmd = cmd.replace('%l', rest)
196 cmd = cmd.replace('%l', rest)
200 rest = ''
197 rest = ''
201 if nargs==0:
198 if nargs==0:
202 # Simple, argument-less aliases
199 # Simple, argument-less aliases
203 cmd = '%s %s' % (cmd, rest)
200 cmd = '%s %s' % (cmd, rest)
204 else:
201 else:
205 # Handle aliases with positional arguments
202 # Handle aliases with positional arguments
206 args = rest.split(None, nargs)
203 args = rest.split(None, nargs)
207 if len(args) < nargs:
204 if len(args) < nargs:
208 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
205 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
209 (alias, nargs, len(args)))
206 (alias, nargs, len(args)))
210 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
207 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
211 return cmd
208 return cmd
212
209
213 def expand_alias(self, line):
210 def expand_alias(self, line):
214 """ Expand an alias in the command line
211 """ Expand an alias in the command line
215
212
216 Returns the provided command line, possibly with the first word
213 Returns the provided command line, possibly with the first word
217 (command) translated according to alias expansion rules.
214 (command) translated according to alias expansion rules.
218
215
219 [ipython]|16> _ip.expand_aliases("np myfile.txt")
216 [ipython]|16> _ip.expand_aliases("np myfile.txt")
220 <16> 'q:/opt/np/notepad++.exe myfile.txt'
217 <16> 'q:/opt/np/notepad++.exe myfile.txt'
221 """
218 """
222
219
223 pre,fn,rest = split_user_input(line)
220 pre,fn,rest = split_user_input(line)
224 res = pre + self.expand_aliases(fn, rest)
221 res = pre + self.expand_aliases(fn, rest)
225 return res
222 return res
226
223
227 def expand_aliases(self, fn, rest):
224 def expand_aliases(self, fn, rest):
228 """Expand multiple levels of aliases:
225 """Expand multiple levels of aliases:
229
226
230 if:
227 if:
231
228
232 alias foo bar /tmp
229 alias foo bar /tmp
233 alias baz foo
230 alias baz foo
234
231
235 then:
232 then:
236
233
237 baz huhhahhei -> bar /tmp huhhahhei
234 baz huhhahhei -> bar /tmp huhhahhei
238
235
239 """
236 """
240 line = fn + " " + rest
237 line = fn + " " + rest
241
238
242 done = set()
239 done = set()
243 while 1:
240 while 1:
244 pre,fn,rest = split_user_input(line, shell_line_split)
241 pre,fn,rest = split_user_input(line, shell_line_split)
245 if fn in self.alias_table:
242 if fn in self.alias_table:
246 if fn in done:
243 if fn in done:
247 warn("Cyclic alias definition, repeated '%s'" % fn)
244 warn("Cyclic alias definition, repeated '%s'" % fn)
248 return ""
245 return ""
249 done.add(fn)
246 done.add(fn)
250
247
251 l2 = self.transform_alias(fn, rest)
248 l2 = self.transform_alias(fn, rest)
252 if l2 == line:
249 if l2 == line:
253 break
250 break
254 # ls -> ls -F should not recurse forever
251 # ls -> ls -F should not recurse forever
255 if l2.split(None,1)[0] == line.split(None,1)[0]:
252 if l2.split(None,1)[0] == line.split(None,1)[0]:
256 line = l2
253 line = l2
257 break
254 break
258 line=l2
255 line=l2
259 else:
256 else:
260 break
257 break
261
258
262 return line
259 return line
@@ -1,453 +1,453 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for IPython.
3 An application for IPython.
4
4
5 All top-level applications should use the classes in this module for
5 All top-level applications should use the classes in this module for
6 handling configuration and creating componenets.
6 handling configuration and creating componenets.
7
7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 object and then create the components, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10
10
11 Authors:
11 Authors:
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15
15
16 Notes
16 Notes
17 -----
17 -----
18 """
18 """
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Copyright (C) 2008-2009 The IPython Development Team
21 # Copyright (C) 2008-2009 The IPython Development Team
22 #
22 #
23 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Imports
28 # Imports
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 import logging
31 import logging
32 import os
32 import os
33 import sys
33 import sys
34
34
35 from IPython.core import release, crashhandler
35 from IPython.core import release, crashhandler
36 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
36 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
37 from IPython.config.loader import (
37 from IPython.config.loader import (
38 PyFileConfigLoader,
38 PyFileConfigLoader,
39 ArgParseConfigLoader,
39 ArgParseConfigLoader,
40 Config,
40 Config,
41 )
41 )
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Classes and functions
44 # Classes and functions
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 class ApplicationError(Exception):
47 class ApplicationError(Exception):
48 pass
48 pass
49
49
50
50
51 class BaseAppConfigLoader(ArgParseConfigLoader):
51 class BaseAppConfigLoader(ArgParseConfigLoader):
52 """Default command line options for IPython based applications."""
52 """Default command line options for IPython based applications."""
53
53
54 def _add_ipython_dir(self, parser):
54 def _add_ipython_dir(self, parser):
55 """Add the --ipython-dir option to the parser."""
55 """Add the --ipython-dir option to the parser."""
56 paa = parser.add_argument
56 paa = parser.add_argument
57 paa('--ipython-dir',
57 paa('--ipython-dir',
58 dest='Global.ipython_dir',type=unicode,
58 dest='Global.ipython_dir',type=unicode,
59 help=
59 help=
60 """Set to override default location of the IPython directory
60 """Set to override default location of the IPython directory
61 IPYTHON_DIR, stored as Global.ipython_dir. This can also be
61 IPYTHON_DIR, stored as Global.ipython_dir. This can also be
62 specified through the environment variable IPYTHON_DIR.""",
62 specified through the environment variable IPYTHON_DIR.""",
63 metavar='Global.ipython_dir')
63 metavar='Global.ipython_dir')
64
64
65 def _add_log_level(self, parser):
65 def _add_log_level(self, parser):
66 """Add the --log-level option to the parser."""
66 """Add the --log-level option to the parser."""
67 paa = parser.add_argument
67 paa = parser.add_argument
68 paa('--log-level',
68 paa('--log-level',
69 dest="Global.log_level",type=int,
69 dest="Global.log_level",type=int,
70 help='Set the log level (0,10,20,30,40,50). Default is 30.',
70 help='Set the log level (0,10,20,30,40,50). Default is 30.',
71 metavar='Global.log_level')
71 metavar='Global.log_level')
72
72
73 def _add_arguments(self):
73 def _add_arguments(self):
74 self._add_ipython_dir(self.parser)
74 self._add_ipython_dir(self.parser)
75 self._add_log_level(self.parser)
75 self._add_log_level(self.parser)
76
76
77
77
78 class Application(object):
78 class Application(object):
79 """Load a config, construct components and set them running.
79 """Load a config, construct configurables and set them running.
80
80
81 The configuration of an application can be done via three different Config
81 The configuration of an application can be done via three different Config
82 objects, which are loaded and ultimately merged into a single one used
82 objects, which are loaded and ultimately merged into a single one used
83 from that point on by the app. These are:
83 from that point on by the app. These are:
84
84
85 1. default_config: internal defaults, implemented in code.
85 1. default_config: internal defaults, implemented in code.
86 2. file_config: read from the filesystem.
86 2. file_config: read from the filesystem.
87 3. command_line_config: read from the system's command line flags.
87 3. command_line_config: read from the system's command line flags.
88
88
89 During initialization, 3 is actually read before 2, since at the
89 During initialization, 3 is actually read before 2, since at the
90 command-line one may override the location of the file to be read. But the
90 command-line one may override the location of the file to be read. But the
91 above is the order in which the merge is made.
91 above is the order in which the merge is made.
92 """
92 """
93
93
94 name = u'ipython'
94 name = u'ipython'
95 description = 'IPython: an enhanced interactive Python shell.'
95 description = 'IPython: an enhanced interactive Python shell.'
96 #: Usage message printed by argparse. If None, auto-generate
96 #: Usage message printed by argparse. If None, auto-generate
97 usage = None
97 usage = None
98 #: The command line config loader. Subclass of ArgParseConfigLoader.
98 #: The command line config loader. Subclass of ArgParseConfigLoader.
99 command_line_loader = BaseAppConfigLoader
99 command_line_loader = BaseAppConfigLoader
100 #: The name of the config file to load, determined at runtime
100 #: The name of the config file to load, determined at runtime
101 config_file_name = None
101 config_file_name = None
102 #: The name of the default config file. Track separately from the actual
102 #: The name of the default config file. Track separately from the actual
103 #: name because some logic happens only if we aren't using the default.
103 #: name because some logic happens only if we aren't using the default.
104 default_config_file_name = u'ipython_config.py'
104 default_config_file_name = u'ipython_config.py'
105 default_log_level = logging.WARN
105 default_log_level = logging.WARN
106 #: Set by --profile option
106 #: Set by --profile option
107 profile_name = None
107 profile_name = None
108 #: User's ipython directory, typically ~/.ipython/
108 #: User's ipython directory, typically ~/.ipython/
109 ipython_dir = None
109 ipython_dir = None
110 #: Internal defaults, implemented in code.
110 #: Internal defaults, implemented in code.
111 default_config = None
111 default_config = None
112 #: Read from the filesystem.
112 #: Read from the filesystem.
113 file_config = None
113 file_config = None
114 #: Read from the system's command line flags.
114 #: Read from the system's command line flags.
115 command_line_config = None
115 command_line_config = None
116 #: The final config that will be passed to the component.
116 #: The final config that will be passed to the main object.
117 master_config = None
117 master_config = None
118 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
118 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
119 argv = None
119 argv = None
120 #: extra arguments computed by the command-line loader
120 #: extra arguments computed by the command-line loader
121 extra_args = None
121 extra_args = None
122 #: The class to use as the crash handler.
122 #: The class to use as the crash handler.
123 crash_handler_class = crashhandler.CrashHandler
123 crash_handler_class = crashhandler.CrashHandler
124
124
125 # Private attributes
125 # Private attributes
126 _exiting = False
126 _exiting = False
127 _initialized = False
127 _initialized = False
128
128
129 def __init__(self, argv=None):
129 def __init__(self, argv=None):
130 self.argv = sys.argv[1:] if argv is None else argv
130 self.argv = sys.argv[1:] if argv is None else argv
131 self.init_logger()
131 self.init_logger()
132
132
133 def init_logger(self):
133 def init_logger(self):
134 self.log = logging.getLogger(self.__class__.__name__)
134 self.log = logging.getLogger(self.__class__.__name__)
135 # This is used as the default until the command line arguments are read.
135 # This is used as the default until the command line arguments are read.
136 self.log.setLevel(self.default_log_level)
136 self.log.setLevel(self.default_log_level)
137 self._log_handler = logging.StreamHandler()
137 self._log_handler = logging.StreamHandler()
138 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
138 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
139 self._log_handler.setFormatter(self._log_formatter)
139 self._log_handler.setFormatter(self._log_formatter)
140 self.log.addHandler(self._log_handler)
140 self.log.addHandler(self._log_handler)
141
141
142 def _set_log_level(self, level):
142 def _set_log_level(self, level):
143 self.log.setLevel(level)
143 self.log.setLevel(level)
144
144
145 def _get_log_level(self):
145 def _get_log_level(self):
146 return self.log.level
146 return self.log.level
147
147
148 log_level = property(_get_log_level, _set_log_level)
148 log_level = property(_get_log_level, _set_log_level)
149
149
150 def initialize(self):
150 def initialize(self):
151 """Initialize the application.
151 """Initialize the application.
152
152
153 Loads all configuration information and sets all application state, but
153 Loads all configuration information and sets all application state, but
154 does not start any relevant processing (typically some kind of event
154 does not start any relevant processing (typically some kind of event
155 loop).
155 loop).
156
156
157 Once this method has been called, the application is flagged as
157 Once this method has been called, the application is flagged as
158 initialized and the method becomes a no-op."""
158 initialized and the method becomes a no-op."""
159
159
160 if self._initialized:
160 if self._initialized:
161 return
161 return
162
162
163 # The first part is protected with an 'attempt' wrapper, that will log
163 # The first part is protected with an 'attempt' wrapper, that will log
164 # failures with the basic system traceback machinery. Once our crash
164 # failures with the basic system traceback machinery. Once our crash
165 # handler is in place, we can let any subsequent exception propagate,
165 # handler is in place, we can let any subsequent exception propagate,
166 # as our handler will log it with much better detail than the default.
166 # as our handler will log it with much better detail than the default.
167 self.attempt(self.create_crash_handler)
167 self.attempt(self.create_crash_handler)
168
168
169 # Configuration phase
169 # Configuration phase
170 # Default config (internally hardwired in application code)
170 # Default config (internally hardwired in application code)
171 self.create_default_config()
171 self.create_default_config()
172 self.log_default_config()
172 self.log_default_config()
173 self.set_default_config_log_level()
173 self.set_default_config_log_level()
174
174
175 # Command-line config
175 # Command-line config
176 self.pre_load_command_line_config()
176 self.pre_load_command_line_config()
177 self.load_command_line_config()
177 self.load_command_line_config()
178 self.set_command_line_config_log_level()
178 self.set_command_line_config_log_level()
179 self.post_load_command_line_config()
179 self.post_load_command_line_config()
180 self.log_command_line_config()
180 self.log_command_line_config()
181
181
182 # Find resources needed for filesystem access, using information from
182 # Find resources needed for filesystem access, using information from
183 # the above two
183 # the above two
184 self.find_ipython_dir()
184 self.find_ipython_dir()
185 self.find_resources()
185 self.find_resources()
186 self.find_config_file_name()
186 self.find_config_file_name()
187 self.find_config_file_paths()
187 self.find_config_file_paths()
188
188
189 # File-based config
189 # File-based config
190 self.pre_load_file_config()
190 self.pre_load_file_config()
191 self.load_file_config()
191 self.load_file_config()
192 self.set_file_config_log_level()
192 self.set_file_config_log_level()
193 self.post_load_file_config()
193 self.post_load_file_config()
194 self.log_file_config()
194 self.log_file_config()
195
195
196 # Merge all config objects into a single one the app can then use
196 # Merge all config objects into a single one the app can then use
197 self.merge_configs()
197 self.merge_configs()
198 self.log_master_config()
198 self.log_master_config()
199
199
200 # Construction phase
200 # Construction phase
201 self.pre_construct()
201 self.pre_construct()
202 self.construct()
202 self.construct()
203 self.post_construct()
203 self.post_construct()
204
204
205 # Done, flag as such and
205 # Done, flag as such and
206 self._initialized = True
206 self._initialized = True
207
207
208 def start(self):
208 def start(self):
209 """Start the application."""
209 """Start the application."""
210 self.initialize()
210 self.initialize()
211 self.start_app()
211 self.start_app()
212
212
213 #-------------------------------------------------------------------------
213 #-------------------------------------------------------------------------
214 # Various stages of Application creation
214 # Various stages of Application creation
215 #-------------------------------------------------------------------------
215 #-------------------------------------------------------------------------
216
216
217 def create_crash_handler(self):
217 def create_crash_handler(self):
218 """Create a crash handler, typically setting sys.excepthook to it."""
218 """Create a crash handler, typically setting sys.excepthook to it."""
219 self.crash_handler = self.crash_handler_class(self)
219 self.crash_handler = self.crash_handler_class(self)
220 sys.excepthook = self.crash_handler
220 sys.excepthook = self.crash_handler
221
221
222 def create_default_config(self):
222 def create_default_config(self):
223 """Create defaults that can't be set elsewhere.
223 """Create defaults that can't be set elsewhere.
224
224
225 For the most part, we try to set default in the class attributes
225 For the most part, we try to set default in the class attributes
226 of Components. But, defaults the top-level Application (which is
226 of Configurables. But, defaults the top-level Application (which is
227 not a HasTraits or Component) are not set in this way. Instead
227 not a HasTraits or Configurables) are not set in this way. Instead
228 we set them here. The Global section is for variables like this that
228 we set them here. The Global section is for variables like this that
229 don't belong to a particular component.
229 don't belong to a particular configurable.
230 """
230 """
231 c = Config()
231 c = Config()
232 c.Global.ipython_dir = get_ipython_dir()
232 c.Global.ipython_dir = get_ipython_dir()
233 c.Global.log_level = self.log_level
233 c.Global.log_level = self.log_level
234 self.default_config = c
234 self.default_config = c
235
235
236 def log_default_config(self):
236 def log_default_config(self):
237 self.log.debug('Default config loaded:')
237 self.log.debug('Default config loaded:')
238 self.log.debug(repr(self.default_config))
238 self.log.debug(repr(self.default_config))
239
239
240 def set_default_config_log_level(self):
240 def set_default_config_log_level(self):
241 try:
241 try:
242 self.log_level = self.default_config.Global.log_level
242 self.log_level = self.default_config.Global.log_level
243 except AttributeError:
243 except AttributeError:
244 # Fallback to the default_log_level class attribute
244 # Fallback to the default_log_level class attribute
245 pass
245 pass
246
246
247 def create_command_line_config(self):
247 def create_command_line_config(self):
248 """Create and return a command line config loader."""
248 """Create and return a command line config loader."""
249 return self.command_line_loader(
249 return self.command_line_loader(
250 self.argv,
250 self.argv,
251 description=self.description,
251 description=self.description,
252 version=release.version,
252 version=release.version,
253 usage=self.usage
253 usage=self.usage
254 )
254 )
255
255
256 def pre_load_command_line_config(self):
256 def pre_load_command_line_config(self):
257 """Do actions just before loading the command line config."""
257 """Do actions just before loading the command line config."""
258 pass
258 pass
259
259
260 def load_command_line_config(self):
260 def load_command_line_config(self):
261 """Load the command line config."""
261 """Load the command line config."""
262 loader = self.create_command_line_config()
262 loader = self.create_command_line_config()
263 self.command_line_config = loader.load_config()
263 self.command_line_config = loader.load_config()
264 self.extra_args = loader.get_extra_args()
264 self.extra_args = loader.get_extra_args()
265
265
266 def set_command_line_config_log_level(self):
266 def set_command_line_config_log_level(self):
267 try:
267 try:
268 self.log_level = self.command_line_config.Global.log_level
268 self.log_level = self.command_line_config.Global.log_level
269 except AttributeError:
269 except AttributeError:
270 pass
270 pass
271
271
272 def post_load_command_line_config(self):
272 def post_load_command_line_config(self):
273 """Do actions just after loading the command line config."""
273 """Do actions just after loading the command line config."""
274 pass
274 pass
275
275
276 def log_command_line_config(self):
276 def log_command_line_config(self):
277 self.log.debug("Command line config loaded:")
277 self.log.debug("Command line config loaded:")
278 self.log.debug(repr(self.command_line_config))
278 self.log.debug(repr(self.command_line_config))
279
279
280 def find_ipython_dir(self):
280 def find_ipython_dir(self):
281 """Set the IPython directory.
281 """Set the IPython directory.
282
282
283 This sets ``self.ipython_dir``, but the actual value that is passed to
283 This sets ``self.ipython_dir``, but the actual value that is passed to
284 the application is kept in either ``self.default_config`` or
284 the application is kept in either ``self.default_config`` or
285 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
285 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
286 ``sys.path`` so config files there can be referenced by other config
286 ``sys.path`` so config files there can be referenced by other config
287 files.
287 files.
288 """
288 """
289
289
290 try:
290 try:
291 self.ipython_dir = self.command_line_config.Global.ipython_dir
291 self.ipython_dir = self.command_line_config.Global.ipython_dir
292 except AttributeError:
292 except AttributeError:
293 self.ipython_dir = self.default_config.Global.ipython_dir
293 self.ipython_dir = self.default_config.Global.ipython_dir
294 sys.path.append(os.path.abspath(self.ipython_dir))
294 sys.path.append(os.path.abspath(self.ipython_dir))
295 if not os.path.isdir(self.ipython_dir):
295 if not os.path.isdir(self.ipython_dir):
296 os.makedirs(self.ipython_dir, mode=0777)
296 os.makedirs(self.ipython_dir, mode=0777)
297 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
297 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
298
298
299 def find_resources(self):
299 def find_resources(self):
300 """Find other resources that need to be in place.
300 """Find other resources that need to be in place.
301
301
302 Things like cluster directories need to be in place to find the
302 Things like cluster directories need to be in place to find the
303 config file. These happen right after the IPython directory has
303 config file. These happen right after the IPython directory has
304 been set.
304 been set.
305 """
305 """
306 pass
306 pass
307
307
308 def find_config_file_name(self):
308 def find_config_file_name(self):
309 """Find the config file name for this application.
309 """Find the config file name for this application.
310
310
311 This must set ``self.config_file_name`` to the filename of the
311 This must set ``self.config_file_name`` to the filename of the
312 config file to use (just the filename). The search paths for the
312 config file to use (just the filename). The search paths for the
313 config file are set in :meth:`find_config_file_paths` and then passed
313 config file are set in :meth:`find_config_file_paths` and then passed
314 to the config file loader where they are resolved to an absolute path.
314 to the config file loader where they are resolved to an absolute path.
315
315
316 If a profile has been set at the command line, this will resolve it.
316 If a profile has been set at the command line, this will resolve it.
317 """
317 """
318 try:
318 try:
319 self.config_file_name = self.command_line_config.Global.config_file
319 self.config_file_name = self.command_line_config.Global.config_file
320 except AttributeError:
320 except AttributeError:
321 pass
321 pass
322 else:
322 else:
323 return
323 return
324
324
325 try:
325 try:
326 self.profile_name = self.command_line_config.Global.profile
326 self.profile_name = self.command_line_config.Global.profile
327 except AttributeError:
327 except AttributeError:
328 # Just use the default as there is no profile
328 # Just use the default as there is no profile
329 self.config_file_name = self.default_config_file_name
329 self.config_file_name = self.default_config_file_name
330 else:
330 else:
331 # Use the default config file name and profile name if set
331 # Use the default config file name and profile name if set
332 # to determine the used config file name.
332 # to determine the used config file name.
333 name_parts = self.default_config_file_name.split('.')
333 name_parts = self.default_config_file_name.split('.')
334 name_parts.insert(1, u'_' + self.profile_name + u'.')
334 name_parts.insert(1, u'_' + self.profile_name + u'.')
335 self.config_file_name = ''.join(name_parts)
335 self.config_file_name = ''.join(name_parts)
336
336
337 def find_config_file_paths(self):
337 def find_config_file_paths(self):
338 """Set the search paths for resolving the config file.
338 """Set the search paths for resolving the config file.
339
339
340 This must set ``self.config_file_paths`` to a sequence of search
340 This must set ``self.config_file_paths`` to a sequence of search
341 paths to pass to the config file loader.
341 paths to pass to the config file loader.
342 """
342 """
343 # Include our own profiles directory last, so that users can still find
343 # Include our own profiles directory last, so that users can still find
344 # our shipped copies of builtin profiles even if they don't have them
344 # our shipped copies of builtin profiles even if they don't have them
345 # in their local ipython directory.
345 # in their local ipython directory.
346 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
346 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
347 self.config_file_paths = (os.getcwd(), self.ipython_dir, prof_dir)
347 self.config_file_paths = (os.getcwd(), self.ipython_dir, prof_dir)
348
348
349 def pre_load_file_config(self):
349 def pre_load_file_config(self):
350 """Do actions before the config file is loaded."""
350 """Do actions before the config file is loaded."""
351 pass
351 pass
352
352
353 def load_file_config(self):
353 def load_file_config(self):
354 """Load the config file.
354 """Load the config file.
355
355
356 This tries to load the config file from disk. If successful, the
356 This tries to load the config file from disk. If successful, the
357 ``CONFIG_FILE`` config variable is set to the resolved config file
357 ``CONFIG_FILE`` config variable is set to the resolved config file
358 location. If not successful, an empty config is used.
358 location. If not successful, an empty config is used.
359 """
359 """
360 self.log.debug("Attempting to load config file: %s" %
360 self.log.debug("Attempting to load config file: %s" %
361 self.config_file_name)
361 self.config_file_name)
362 loader = PyFileConfigLoader(self.config_file_name,
362 loader = PyFileConfigLoader(self.config_file_name,
363 path=self.config_file_paths)
363 path=self.config_file_paths)
364 try:
364 try:
365 self.file_config = loader.load_config()
365 self.file_config = loader.load_config()
366 self.file_config.Global.config_file = loader.full_filename
366 self.file_config.Global.config_file = loader.full_filename
367 except IOError:
367 except IOError:
368 # Only warn if the default config file was NOT being used.
368 # Only warn if the default config file was NOT being used.
369 if not self.config_file_name==self.default_config_file_name:
369 if not self.config_file_name==self.default_config_file_name:
370 self.log.warn("Config file not found, skipping: %s" %
370 self.log.warn("Config file not found, skipping: %s" %
371 self.config_file_name, exc_info=True)
371 self.config_file_name, exc_info=True)
372 self.file_config = Config()
372 self.file_config = Config()
373 except:
373 except:
374 self.log.warn("Error loading config file: %s" %
374 self.log.warn("Error loading config file: %s" %
375 self.config_file_name, exc_info=True)
375 self.config_file_name, exc_info=True)
376 self.file_config = Config()
376 self.file_config = Config()
377
377
378 def set_file_config_log_level(self):
378 def set_file_config_log_level(self):
379 # We need to keeep self.log_level updated. But we only use the value
379 # We need to keeep self.log_level updated. But we only use the value
380 # of the file_config if a value was not specified at the command
380 # of the file_config if a value was not specified at the command
381 # line, because the command line overrides everything.
381 # line, because the command line overrides everything.
382 if not hasattr(self.command_line_config.Global, 'log_level'):
382 if not hasattr(self.command_line_config.Global, 'log_level'):
383 try:
383 try:
384 self.log_level = self.file_config.Global.log_level
384 self.log_level = self.file_config.Global.log_level
385 except AttributeError:
385 except AttributeError:
386 pass # Use existing value
386 pass # Use existing value
387
387
388 def post_load_file_config(self):
388 def post_load_file_config(self):
389 """Do actions after the config file is loaded."""
389 """Do actions after the config file is loaded."""
390 pass
390 pass
391
391
392 def log_file_config(self):
392 def log_file_config(self):
393 if hasattr(self.file_config.Global, 'config_file'):
393 if hasattr(self.file_config.Global, 'config_file'):
394 self.log.debug("Config file loaded: %s" %
394 self.log.debug("Config file loaded: %s" %
395 self.file_config.Global.config_file)
395 self.file_config.Global.config_file)
396 self.log.debug(repr(self.file_config))
396 self.log.debug(repr(self.file_config))
397
397
398 def merge_configs(self):
398 def merge_configs(self):
399 """Merge the default, command line and file config objects."""
399 """Merge the default, command line and file config objects."""
400 config = Config()
400 config = Config()
401 config._merge(self.default_config)
401 config._merge(self.default_config)
402 config._merge(self.file_config)
402 config._merge(self.file_config)
403 config._merge(self.command_line_config)
403 config._merge(self.command_line_config)
404
404
405 # XXX fperez - propose to Brian we rename master_config to simply
405 # XXX fperez - propose to Brian we rename master_config to simply
406 # config, I think this is going to be heavily used in examples and
406 # config, I think this is going to be heavily used in examples and
407 # application code and the name is shorter/easier to find/remember.
407 # application code and the name is shorter/easier to find/remember.
408 # For now, just alias it...
408 # For now, just alias it...
409 self.master_config = config
409 self.master_config = config
410 self.config = config
410 self.config = config
411
411
412 def log_master_config(self):
412 def log_master_config(self):
413 self.log.debug("Master config created:")
413 self.log.debug("Master config created:")
414 self.log.debug(repr(self.master_config))
414 self.log.debug(repr(self.master_config))
415
415
416 def pre_construct(self):
416 def pre_construct(self):
417 """Do actions after the config has been built, but before construct."""
417 """Do actions after the config has been built, but before construct."""
418 pass
418 pass
419
419
420 def construct(self):
420 def construct(self):
421 """Construct the main components that make up this app."""
421 """Construct the main objects that make up this app."""
422 self.log.debug("Constructing components for application")
422 self.log.debug("Constructing main objects for application")
423
423
424 def post_construct(self):
424 def post_construct(self):
425 """Do actions after construct, but before starting the app."""
425 """Do actions after construct, but before starting the app."""
426 pass
426 pass
427
427
428 def start_app(self):
428 def start_app(self):
429 """Actually start the app."""
429 """Actually start the app."""
430 self.log.debug("Starting application")
430 self.log.debug("Starting application")
431
431
432 #-------------------------------------------------------------------------
432 #-------------------------------------------------------------------------
433 # Utility methods
433 # Utility methods
434 #-------------------------------------------------------------------------
434 #-------------------------------------------------------------------------
435
435
436 def exit(self, exit_status=0):
436 def exit(self, exit_status=0):
437 if self._exiting:
437 if self._exiting:
438 pass
438 pass
439 else:
439 else:
440 self.log.debug("Exiting application: %s" % self.name)
440 self.log.debug("Exiting application: %s" % self.name)
441 self._exiting = True
441 self._exiting = True
442 sys.exit(exit_status)
442 sys.exit(exit_status)
443
443
444 def attempt(self, func):
444 def attempt(self, func):
445 try:
445 try:
446 func()
446 func()
447 except SystemExit:
447 except SystemExit:
448 raise
448 raise
449 except:
449 except:
450 self.log.critical("Aborting application: %s" % self.name,
450 self.log.critical("Aborting application: %s" % self.name,
451 exc_info=True)
451 exc_info=True)
452 self.exit(0)
452 self.exit(0)
453
453
@@ -1,118 +1,115 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A context manager for managing things injected into :mod:`__builtin__`.
4 A context manager for managing things injected into :mod:`__builtin__`.
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2009 The IPython Development Team
12 # Copyright (C) 2008-2009 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import __builtin__
22 import __builtin__
23
23
24 from IPython.core.component import Component
24 from IPython.config.configurable import Configurable
25 from IPython.core.quitter import Quitter
25 from IPython.core.quitter import Quitter
26
26
27 from IPython.utils.autoattr import auto_attr
27 from IPython.utils.traitlets import Instance
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Classes and functions
30 # Classes and functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33
33
34 class __BuiltinUndefined(object): pass
34 class __BuiltinUndefined(object): pass
35 BuiltinUndefined = __BuiltinUndefined()
35 BuiltinUndefined = __BuiltinUndefined()
36
36
37
37
38 class BuiltinTrap(Component):
38 class BuiltinTrap(Configurable):
39
39
40 def __init__(self, parent):
40 shell = Instance('IPython.core.iplib.InteractiveShell')
41 super(BuiltinTrap, self).__init__(parent, None, None)
41
42 def __init__(self, shell):
43 super(BuiltinTrap, self).__init__(None)
42 self._orig_builtins = {}
44 self._orig_builtins = {}
43 # We define this to track if a single BuiltinTrap is nested.
45 # We define this to track if a single BuiltinTrap is nested.
44 # Only turn off the trap when the outermost call to __exit__ is made.
46 # Only turn off the trap when the outermost call to __exit__ is made.
45 self._nested_level = 0
47 self._nested_level = 0
46
48 self.shell = shell
47 @auto_attr
48 def shell(self):
49 return Component.get_instances(
50 root=self.root,
51 klass='IPython.core.iplib.InteractiveShell')[0]
52
49
53 def __enter__(self):
50 def __enter__(self):
54 if self._nested_level == 0:
51 if self._nested_level == 0:
55 self.set()
52 self.set()
56 self._nested_level += 1
53 self._nested_level += 1
57 # I return self, so callers can use add_builtin in a with clause.
54 # I return self, so callers can use add_builtin in a with clause.
58 return self
55 return self
59
56
60 def __exit__(self, type, value, traceback):
57 def __exit__(self, type, value, traceback):
61 if self._nested_level == 1:
58 if self._nested_level == 1:
62 self.unset()
59 self.unset()
63 self._nested_level -= 1
60 self._nested_level -= 1
64 # Returning False will cause exceptions to propagate
61 # Returning False will cause exceptions to propagate
65 return False
62 return False
66
63
67 def add_builtin(self, key, value):
64 def add_builtin(self, key, value):
68 """Add a builtin and save the original."""
65 """Add a builtin and save the original."""
69 orig = __builtin__.__dict__.get(key, BuiltinUndefined)
66 orig = __builtin__.__dict__.get(key, BuiltinUndefined)
70 self._orig_builtins[key] = orig
67 self._orig_builtins[key] = orig
71 __builtin__.__dict__[key] = value
68 __builtin__.__dict__[key] = value
72
69
73 def remove_builtin(self, key):
70 def remove_builtin(self, key):
74 """Remove an added builtin and re-set the original."""
71 """Remove an added builtin and re-set the original."""
75 try:
72 try:
76 orig = self._orig_builtins.pop(key)
73 orig = self._orig_builtins.pop(key)
77 except KeyError:
74 except KeyError:
78 pass
75 pass
79 else:
76 else:
80 if orig is BuiltinUndefined:
77 if orig is BuiltinUndefined:
81 del __builtin__.__dict__[key]
78 del __builtin__.__dict__[key]
82 else:
79 else:
83 __builtin__.__dict__[key] = orig
80 __builtin__.__dict__[key] = orig
84
81
85 def set(self):
82 def set(self):
86 """Store ipython references in the __builtin__ namespace."""
83 """Store ipython references in the __builtin__ namespace."""
87 self.add_builtin('exit', Quitter(self.shell, 'exit'))
84 self.add_builtin('exit', Quitter(self.shell, 'exit'))
88 self.add_builtin('quit', Quitter(self.shell, 'quit'))
85 self.add_builtin('quit', Quitter(self.shell, 'quit'))
89 self.add_builtin('get_ipython', self.shell.get_ipython)
86 self.add_builtin('get_ipython', self.shell.get_ipython)
90
87
91 # Recursive reload function
88 # Recursive reload function
92 try:
89 try:
93 from IPython.lib import deepreload
90 from IPython.lib import deepreload
94 if self.shell.deep_reload:
91 if self.shell.deep_reload:
95 self.add_builtin('reload', deepreload.reload)
92 self.add_builtin('reload', deepreload.reload)
96 else:
93 else:
97 self.add_builtin('dreload', deepreload.reload)
94 self.add_builtin('dreload', deepreload.reload)
98 del deepreload
95 del deepreload
99 except ImportError:
96 except ImportError:
100 pass
97 pass
101
98
102 # Keep in the builtins a flag for when IPython is active. We set it
99 # Keep in the builtins a flag for when IPython is active. We set it
103 # with setdefault so that multiple nested IPythons don't clobber one
100 # with setdefault so that multiple nested IPythons don't clobber one
104 # another. Each will increase its value by one upon being activated,
101 # another. Each will increase its value by one upon being activated,
105 # which also gives us a way to determine the nesting level.
102 # which also gives us a way to determine the nesting level.
106 __builtin__.__dict__.setdefault('__IPYTHON__active',0)
103 __builtin__.__dict__.setdefault('__IPYTHON__active',0)
107
104
108 def unset(self):
105 def unset(self):
109 """Remove any builtins which might have been added by add_builtins, or
106 """Remove any builtins which might have been added by add_builtins, or
110 restore overwritten ones to their previous values."""
107 restore overwritten ones to their previous values."""
111 for key in self._orig_builtins.keys():
108 for key in self._orig_builtins.keys():
112 self.remove_builtin(key)
109 self.remove_builtin(key)
113 self._orig_builtins.clear()
110 self._orig_builtins.clear()
114 self._builtins_added = False
111 self._builtins_added = False
115 try:
112 try:
116 del __builtin__.__dict__['__IPYTHON__active']
113 del __builtin__.__dict__['__IPYTHON__active']
117 except KeyError:
114 except KeyError:
118 pass
115 pass
@@ -1,75 +1,69 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A context manager for handling sys.displayhook.
4 A context manager for handling sys.displayhook.
5
5
6 Authors:
6 Authors:
7
7
8 * Robert Kern
8 * Robert Kern
9 * Brian Granger
9 * Brian Granger
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2009 The IPython Development Team
13 # Copyright (C) 2008-2009 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
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 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import sys
23 import sys
24
24
25 from IPython.core.component import Component
25 from IPython.config.configurable import Configurable
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Classes and functions
28 # Classes and functions
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31
31
32 class DisplayTrap(Component):
32 class DisplayTrap(Configurable):
33 """Object to manage sys.displayhook.
33 """Object to manage sys.displayhook.
34
34
35 This came from IPython.core.kernel.display_hook, but is simplified
35 This came from IPython.core.kernel.display_hook, but is simplified
36 (no callbacks or formatters) until more of the core is refactored.
36 (no callbacks or formatters) until more of the core is refactored.
37 """
37 """
38
38
39 def __init__(self, parent, hook):
39 def __init__(self, hook):
40 super(DisplayTrap, self).__init__(parent, None, None)
40 super(DisplayTrap, self).__init__(None)
41 self.hook = hook
41 self.hook = hook
42 self.old_hook = None
42 self.old_hook = None
43 # We define this to track if a single BuiltinTrap is nested.
43 # We define this to track if a single BuiltinTrap is nested.
44 # Only turn off the trap when the outermost call to __exit__ is made.
44 # Only turn off the trap when the outermost call to __exit__ is made.
45 self._nested_level = 0
45 self._nested_level = 0
46
46
47 # @auto_attr
48 # def shell(self):
49 # return Component.get_instances(
50 # root=self.root,
51 # klass='IPython.core.iplib.InteractiveShell')[0]
52
53 def __enter__(self):
47 def __enter__(self):
54 if self._nested_level == 0:
48 if self._nested_level == 0:
55 self.set()
49 self.set()
56 self._nested_level += 1
50 self._nested_level += 1
57 return self
51 return self
58
52
59 def __exit__(self, type, value, traceback):
53 def __exit__(self, type, value, traceback):
60 if self._nested_level == 1:
54 if self._nested_level == 1:
61 self.unset()
55 self.unset()
62 self._nested_level -= 1
56 self._nested_level -= 1
63 # Returning False will cause exceptions to propagate
57 # Returning False will cause exceptions to propagate
64 return False
58 return False
65
59
66 def set(self):
60 def set(self):
67 """Set the hook."""
61 """Set the hook."""
68 if sys.displayhook is not self.hook:
62 if sys.displayhook is not self.hook:
69 self.old_hook = sys.displayhook
63 self.old_hook = sys.displayhook
70 sys.displayhook = self.hook
64 sys.displayhook = self.hook
71
65
72 def unset(self):
66 def unset(self):
73 """Unset the hook."""
67 """Unset the hook."""
74 sys.displayhook = self.old_hook
68 sys.displayhook = self.old_hook
75
69
@@ -1,36 +1,30 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 This module is *completely* deprecated and should no longer be used for
4 This module is *completely* deprecated and should no longer be used for
5 any purpose. Currently, we have a few parts of the core that have
5 any purpose. Currently, we have a few parts of the core that have
6 not been componentized and thus, still rely on this module. When everything
6 not been componentized and thus, still rely on this module. When everything
7 has been made into a component, this module will be sent to deathrow.
7 has been made into a component, this module will be sent to deathrow.
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2009 The IPython Development Team
11 # Copyright (C) 2008-2009 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Classes and functions
22 # Classes and functions
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25
25
26 def get():
26 def get():
27 """Get the most recently created InteractiveShell instance."""
27 """Get the global InteractiveShell instance."""
28 from IPython.core.iplib import InteractiveShell
28 from IPython.core.iplib import InteractiveShell
29 insts = InteractiveShell.get_instances()
29 return InteractiveShell.instance()
30 if len(insts)==0:
30
31 return None
32 most_recent = insts[0]
33 for inst in insts[1:]:
34 if inst.created > most_recent.created:
35 most_recent = inst
36 return most_recent
@@ -1,665 +1,665 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6
6
7 Authors
7 Authors
8 -------
8 -------
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 """
12 """
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2008-2010 The IPython Development Team
15 # Copyright (C) 2008-2010 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 from __future__ import absolute_import
25 from __future__ import absolute_import
26
26
27 import logging
27 import logging
28 import os
28 import os
29 import sys
29 import sys
30
30
31 from IPython.core import release
31 from IPython.core import release
32 from IPython.core.crashhandler import CrashHandler
32 from IPython.core.crashhandler import CrashHandler
33 from IPython.core.application import Application, BaseAppConfigLoader
33 from IPython.core.application import Application, BaseAppConfigLoader
34 from IPython.core.iplib import InteractiveShell
34 from IPython.core.iplib import InteractiveShell
35 from IPython.config.loader import (
35 from IPython.config.loader import (
36 Config,
36 Config,
37 PyFileConfigLoader
37 PyFileConfigLoader
38 )
38 )
39 from IPython.lib import inputhook
39 from IPython.lib import inputhook
40 from IPython.utils.path import filefind, get_ipython_dir
40 from IPython.utils.path import filefind, get_ipython_dir
41 from . import usage
41 from . import usage
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Globals, utilities and helpers
44 # Globals, utilities and helpers
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 #: The default config file name for this application.
47 #: The default config file name for this application.
48 default_config_file_name = u'ipython_config.py'
48 default_config_file_name = u'ipython_config.py'
49
49
50
50
51 class IPAppConfigLoader(BaseAppConfigLoader):
51 class IPAppConfigLoader(BaseAppConfigLoader):
52
52
53 def _add_arguments(self):
53 def _add_arguments(self):
54 super(IPAppConfigLoader, self)._add_arguments()
54 super(IPAppConfigLoader, self)._add_arguments()
55 paa = self.parser.add_argument
55 paa = self.parser.add_argument
56 paa('-p',
56 paa('-p',
57 '--profile', dest='Global.profile', type=unicode,
57 '--profile', dest='Global.profile', type=unicode,
58 help=
58 help=
59 """The string name of the ipython profile to be used. Assume that your
59 """The string name of the ipython profile to be used. Assume that your
60 config file is ipython_config-<name>.py (looks in current dir first,
60 config file is ipython_config-<name>.py (looks in current dir first,
61 then in IPYTHON_DIR). This is a quick way to keep and load multiple
61 then in IPYTHON_DIR). This is a quick way to keep and load multiple
62 config files for different tasks, especially if include your basic one
62 config files for different tasks, especially if include your basic one
63 in your more specialized ones. You can keep a basic
63 in your more specialized ones. You can keep a basic
64 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
64 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
65 include this one and load extra things for particular tasks.""",
65 include this one and load extra things for particular tasks.""",
66 metavar='Global.profile')
66 metavar='Global.profile')
67 paa('--config-file',
67 paa('--config-file',
68 dest='Global.config_file', type=unicode,
68 dest='Global.config_file', type=unicode,
69 help=
69 help=
70 """Set the config file name to override default. Normally IPython
70 """Set the config file name to override default. Normally IPython
71 loads ipython_config.py (from current directory) or
71 loads ipython_config.py (from current directory) or
72 IPYTHON_DIR/ipython_config.py. If the loading of your config file
72 IPYTHON_DIR/ipython_config.py. If the loading of your config file
73 fails, IPython starts with a bare bones configuration (no modules
73 fails, IPython starts with a bare bones configuration (no modules
74 loaded at all).""",
74 loaded at all).""",
75 metavar='Global.config_file')
75 metavar='Global.config_file')
76 paa('--autocall',
76 paa('--autocall',
77 dest='InteractiveShell.autocall', type=int,
77 dest='InteractiveShell.autocall', type=int,
78 help=
78 help=
79 """Make IPython automatically call any callable object even if you
79 """Make IPython automatically call any callable object even if you
80 didn't type explicit parentheses. For example, 'str 43' becomes
80 didn't type explicit parentheses. For example, 'str 43' becomes
81 'str(43)' automatically. The value can be '0' to disable the feature,
81 'str(43)' automatically. The value can be '0' to disable the feature,
82 '1' for 'smart' autocall, where it is not applied if there are no more
82 '1' for 'smart' autocall, where it is not applied if there are no more
83 arguments on the line, and '2' for 'full' autocall, where all callable
83 arguments on the line, and '2' for 'full' autocall, where all callable
84 objects are automatically called (even if no arguments are present).
84 objects are automatically called (even if no arguments are present).
85 The default is '1'.""",
85 The default is '1'.""",
86 metavar='InteractiveShell.autocall')
86 metavar='InteractiveShell.autocall')
87 paa('--autoindent',
87 paa('--autoindent',
88 action='store_true', dest='InteractiveShell.autoindent',
88 action='store_true', dest='InteractiveShell.autoindent',
89 help='Turn on autoindenting.')
89 help='Turn on autoindenting.')
90 paa('--no-autoindent',
90 paa('--no-autoindent',
91 action='store_false', dest='InteractiveShell.autoindent',
91 action='store_false', dest='InteractiveShell.autoindent',
92 help='Turn off autoindenting.')
92 help='Turn off autoindenting.')
93 paa('--automagic',
93 paa('--automagic',
94 action='store_true', dest='InteractiveShell.automagic',
94 action='store_true', dest='InteractiveShell.automagic',
95 help=
95 help=
96 """Turn on the auto calling of magic commands. Type %%magic at the
96 """Turn on the auto calling of magic commands. Type %%magic at the
97 IPython prompt for more information.""")
97 IPython prompt for more information.""")
98 paa('--no-automagic',
98 paa('--no-automagic',
99 action='store_false', dest='InteractiveShell.automagic',
99 action='store_false', dest='InteractiveShell.automagic',
100 help='Turn off the auto calling of magic commands.')
100 help='Turn off the auto calling of magic commands.')
101 paa('--autoedit-syntax',
101 paa('--autoedit-syntax',
102 action='store_true', dest='InteractiveShell.autoedit_syntax',
102 action='store_true', dest='InteractiveShell.autoedit_syntax',
103 help='Turn on auto editing of files with syntax errors.')
103 help='Turn on auto editing of files with syntax errors.')
104 paa('--no-autoedit-syntax',
104 paa('--no-autoedit-syntax',
105 action='store_false', dest='InteractiveShell.autoedit_syntax',
105 action='store_false', dest='InteractiveShell.autoedit_syntax',
106 help='Turn off auto editing of files with syntax errors.')
106 help='Turn off auto editing of files with syntax errors.')
107 paa('--banner',
107 paa('--banner',
108 action='store_true', dest='Global.display_banner',
108 action='store_true', dest='Global.display_banner',
109 help='Display a banner upon starting IPython.')
109 help='Display a banner upon starting IPython.')
110 paa('--no-banner',
110 paa('--no-banner',
111 action='store_false', dest='Global.display_banner',
111 action='store_false', dest='Global.display_banner',
112 help="Don't display a banner upon starting IPython.")
112 help="Don't display a banner upon starting IPython.")
113 paa('--cache-size',
113 paa('--cache-size',
114 type=int, dest='InteractiveShell.cache_size',
114 type=int, dest='InteractiveShell.cache_size',
115 help=
115 help=
116 """Set the size of the output cache. The default is 1000, you can
116 """Set the size of the output cache. The default is 1000, you can
117 change it permanently in your config file. Setting it to 0 completely
117 change it permanently in your config file. Setting it to 0 completely
118 disables the caching system, and the minimum value accepted is 20 (if
118 disables the caching system, and the minimum value accepted is 20 (if
119 you provide a value less than 20, it is reset to 0 and a warning is
119 you provide a value less than 20, it is reset to 0 and a warning is
120 issued). This limit is defined because otherwise you'll spend more
120 issued). This limit is defined because otherwise you'll spend more
121 time re-flushing a too small cache than working""",
121 time re-flushing a too small cache than working""",
122 metavar='InteractiveShell.cache_size')
122 metavar='InteractiveShell.cache_size')
123 paa('--classic',
123 paa('--classic',
124 action='store_true', dest='Global.classic',
124 action='store_true', dest='Global.classic',
125 help="Gives IPython a similar feel to the classic Python prompt.")
125 help="Gives IPython a similar feel to the classic Python prompt.")
126 paa('--colors',
126 paa('--colors',
127 type=str, dest='InteractiveShell.colors',
127 type=str, dest='InteractiveShell.colors',
128 help="Set the color scheme (NoColor, Linux, and LightBG).",
128 help="Set the color scheme (NoColor, Linux, and LightBG).",
129 metavar='InteractiveShell.colors')
129 metavar='InteractiveShell.colors')
130 paa('--color-info',
130 paa('--color-info',
131 action='store_true', dest='InteractiveShell.color_info',
131 action='store_true', dest='InteractiveShell.color_info',
132 help=
132 help=
133 """IPython can display information about objects via a set of func-
133 """IPython can display information about objects via a set of func-
134 tions, and optionally can use colors for this, syntax highlighting
134 tions, and optionally can use colors for this, syntax highlighting
135 source code and various other elements. However, because this
135 source code and various other elements. However, because this
136 information is passed through a pager (like 'less') and many pagers get
136 information is passed through a pager (like 'less') and many pagers get
137 confused with color codes, this option is off by default. You can test
137 confused with color codes, this option is off by default. You can test
138 it and turn it on permanently in your ipython_config.py file if it
138 it and turn it on permanently in your ipython_config.py file if it
139 works for you. Test it and turn it on permanently if it works with
139 works for you. Test it and turn it on permanently if it works with
140 your system. The magic function %%color_info allows you to toggle this
140 your system. The magic function %%color_info allows you to toggle this
141 inter- actively for testing.""")
141 inter- actively for testing.""")
142 paa('--no-color-info',
142 paa('--no-color-info',
143 action='store_false', dest='InteractiveShell.color_info',
143 action='store_false', dest='InteractiveShell.color_info',
144 help="Disable using colors for info related things.")
144 help="Disable using colors for info related things.")
145 paa('--confirm-exit',
145 paa('--confirm-exit',
146 action='store_true', dest='InteractiveShell.confirm_exit',
146 action='store_true', dest='InteractiveShell.confirm_exit',
147 help=
147 help=
148 """Set to confirm when you try to exit IPython with an EOF (Control-D
148 """Set to confirm when you try to exit IPython with an EOF (Control-D
149 in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or
149 in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or
150 '%%Exit', you can force a direct exit without any confirmation.""")
150 '%%Exit', you can force a direct exit without any confirmation.""")
151 paa('--no-confirm-exit',
151 paa('--no-confirm-exit',
152 action='store_false', dest='InteractiveShell.confirm_exit',
152 action='store_false', dest='InteractiveShell.confirm_exit',
153 help="Don't prompt the user when exiting.")
153 help="Don't prompt the user when exiting.")
154 paa('--deep-reload',
154 paa('--deep-reload',
155 action='store_true', dest='InteractiveShell.deep_reload',
155 action='store_true', dest='InteractiveShell.deep_reload',
156 help=
156 help=
157 """Enable deep (recursive) reloading by default. IPython can use the
157 """Enable deep (recursive) reloading by default. IPython can use the
158 deep_reload module which reloads changes in modules recursively (it
158 deep_reload module which reloads changes in modules recursively (it
159 replaces the reload() function, so you don't need to change anything to
159 replaces the reload() function, so you don't need to change anything to
160 use it). deep_reload() forces a full reload of modules whose code may
160 use it). deep_reload() forces a full reload of modules whose code may
161 have changed, which the default reload() function does not. When
161 have changed, which the default reload() function does not. When
162 deep_reload is off, IPython will use the normal reload(), but
162 deep_reload is off, IPython will use the normal reload(), but
163 deep_reload will still be available as dreload(). This fea- ture is off
163 deep_reload will still be available as dreload(). This fea- ture is off
164 by default [which means that you have both normal reload() and
164 by default [which means that you have both normal reload() and
165 dreload()].""")
165 dreload()].""")
166 paa('--no-deep-reload',
166 paa('--no-deep-reload',
167 action='store_false', dest='InteractiveShell.deep_reload',
167 action='store_false', dest='InteractiveShell.deep_reload',
168 help="Disable deep (recursive) reloading by default.")
168 help="Disable deep (recursive) reloading by default.")
169 paa('--editor',
169 paa('--editor',
170 type=str, dest='InteractiveShell.editor',
170 type=str, dest='InteractiveShell.editor',
171 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
171 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
172 metavar='InteractiveShell.editor')
172 metavar='InteractiveShell.editor')
173 paa('--log','-l',
173 paa('--log','-l',
174 action='store_true', dest='InteractiveShell.logstart',
174 action='store_true', dest='InteractiveShell.logstart',
175 help="Start logging to the default log file (./ipython_log.py).")
175 help="Start logging to the default log file (./ipython_log.py).")
176 paa('--logfile','-lf',
176 paa('--logfile','-lf',
177 type=unicode, dest='InteractiveShell.logfile',
177 type=unicode, dest='InteractiveShell.logfile',
178 help="Start logging to logfile with this name.",
178 help="Start logging to logfile with this name.",
179 metavar='InteractiveShell.logfile')
179 metavar='InteractiveShell.logfile')
180 paa('--log-append','-la',
180 paa('--log-append','-la',
181 type=unicode, dest='InteractiveShell.logappend',
181 type=unicode, dest='InteractiveShell.logappend',
182 help="Start logging to the given file in append mode.",
182 help="Start logging to the given file in append mode.",
183 metavar='InteractiveShell.logfile')
183 metavar='InteractiveShell.logfile')
184 paa('--pdb',
184 paa('--pdb',
185 action='store_true', dest='InteractiveShell.pdb',
185 action='store_true', dest='InteractiveShell.pdb',
186 help="Enable auto calling the pdb debugger after every exception.")
186 help="Enable auto calling the pdb debugger after every exception.")
187 paa('--no-pdb',
187 paa('--no-pdb',
188 action='store_false', dest='InteractiveShell.pdb',
188 action='store_false', dest='InteractiveShell.pdb',
189 help="Disable auto calling the pdb debugger after every exception.")
189 help="Disable auto calling the pdb debugger after every exception.")
190 paa('--pprint',
190 paa('--pprint',
191 action='store_true', dest='InteractiveShell.pprint',
191 action='store_true', dest='InteractiveShell.pprint',
192 help="Enable auto pretty printing of results.")
192 help="Enable auto pretty printing of results.")
193 paa('--no-pprint',
193 paa('--no-pprint',
194 action='store_false', dest='InteractiveShell.pprint',
194 action='store_false', dest='InteractiveShell.pprint',
195 help="Disable auto auto pretty printing of results.")
195 help="Disable auto auto pretty printing of results.")
196 paa('--prompt-in1','-pi1',
196 paa('--prompt-in1','-pi1',
197 type=str, dest='InteractiveShell.prompt_in1',
197 type=str, dest='InteractiveShell.prompt_in1',
198 help=
198 help=
199 """Set the main input prompt ('In [\#]: '). Note that if you are using
199 """Set the main input prompt ('In [\#]: '). Note that if you are using
200 numbered prompts, the number is represented with a '\#' in the string.
200 numbered prompts, the number is represented with a '\#' in the string.
201 Don't forget to quote strings with spaces embedded in them. Most
201 Don't forget to quote strings with spaces embedded in them. Most
202 bash-like escapes can be used to customize IPython's prompts, as well
202 bash-like escapes can be used to customize IPython's prompts, as well
203 as a few additional ones which are IPython-spe- cific. All valid
203 as a few additional ones which are IPython-spe- cific. All valid
204 prompt escapes are described in detail in the Customization section of
204 prompt escapes are described in detail in the Customization section of
205 the IPython manual.""",
205 the IPython manual.""",
206 metavar='InteractiveShell.prompt_in1')
206 metavar='InteractiveShell.prompt_in1')
207 paa('--prompt-in2','-pi2',
207 paa('--prompt-in2','-pi2',
208 type=str, dest='InteractiveShell.prompt_in2',
208 type=str, dest='InteractiveShell.prompt_in2',
209 help=
209 help=
210 """Set the secondary input prompt (' .\D.: '). Similar to the previous
210 """Set the secondary input prompt (' .\D.: '). Similar to the previous
211 option, but used for the continuation prompts. The special sequence
211 option, but used for the continuation prompts. The special sequence
212 '\D' is similar to '\#', but with all digits replaced by dots (so you
212 '\D' is similar to '\#', but with all digits replaced by dots (so you
213 can have your continuation prompt aligned with your input prompt).
213 can have your continuation prompt aligned with your input prompt).
214 Default: ' .\D.: ' (note three spaces at the start for alignment with
214 Default: ' .\D.: ' (note three spaces at the start for alignment with
215 'In [\#]')""",
215 'In [\#]')""",
216 metavar='InteractiveShell.prompt_in2')
216 metavar='InteractiveShell.prompt_in2')
217 paa('--prompt-out','-po',
217 paa('--prompt-out','-po',
218 type=str, dest='InteractiveShell.prompt_out',
218 type=str, dest='InteractiveShell.prompt_out',
219 help="Set the output prompt ('Out[\#]:')",
219 help="Set the output prompt ('Out[\#]:')",
220 metavar='InteractiveShell.prompt_out')
220 metavar='InteractiveShell.prompt_out')
221 paa('--quick',
221 paa('--quick',
222 action='store_true', dest='Global.quick',
222 action='store_true', dest='Global.quick',
223 help="Enable quick startup with no config files.")
223 help="Enable quick startup with no config files.")
224 paa('--readline',
224 paa('--readline',
225 action='store_true', dest='InteractiveShell.readline_use',
225 action='store_true', dest='InteractiveShell.readline_use',
226 help="Enable readline for command line usage.")
226 help="Enable readline for command line usage.")
227 paa('--no-readline',
227 paa('--no-readline',
228 action='store_false', dest='InteractiveShell.readline_use',
228 action='store_false', dest='InteractiveShell.readline_use',
229 help="Disable readline for command line usage.")
229 help="Disable readline for command line usage.")
230 paa('--screen-length','-sl',
230 paa('--screen-length','-sl',
231 type=int, dest='InteractiveShell.screen_length',
231 type=int, dest='InteractiveShell.screen_length',
232 help=
232 help=
233 """Number of lines of your screen, used to control printing of very
233 """Number of lines of your screen, used to control printing of very
234 long strings. Strings longer than this number of lines will be sent
234 long strings. Strings longer than this number of lines will be sent
235 through a pager instead of directly printed. The default value for
235 through a pager instead of directly printed. The default value for
236 this is 0, which means IPython will auto-detect your screen size every
236 this is 0, which means IPython will auto-detect your screen size every
237 time it needs to print certain potentially long strings (this doesn't
237 time it needs to print certain potentially long strings (this doesn't
238 change the behavior of the 'print' keyword, it's only triggered
238 change the behavior of the 'print' keyword, it's only triggered
239 internally). If for some reason this isn't working well (it needs
239 internally). If for some reason this isn't working well (it needs
240 curses support), specify it yourself. Otherwise don't change the
240 curses support), specify it yourself. Otherwise don't change the
241 default.""",
241 default.""",
242 metavar='InteractiveShell.screen_length')
242 metavar='InteractiveShell.screen_length')
243 paa('--separate-in','-si',
243 paa('--separate-in','-si',
244 type=str, dest='InteractiveShell.separate_in',
244 type=str, dest='InteractiveShell.separate_in',
245 help="Separator before input prompts. Default '\\n'.",
245 help="Separator before input prompts. Default '\\n'.",
246 metavar='InteractiveShell.separate_in')
246 metavar='InteractiveShell.separate_in')
247 paa('--separate-out','-so',
247 paa('--separate-out','-so',
248 type=str, dest='InteractiveShell.separate_out',
248 type=str, dest='InteractiveShell.separate_out',
249 help="Separator before output prompts. Default 0 (nothing).",
249 help="Separator before output prompts. Default 0 (nothing).",
250 metavar='InteractiveShell.separate_out')
250 metavar='InteractiveShell.separate_out')
251 paa('--separate-out2','-so2',
251 paa('--separate-out2','-so2',
252 type=str, dest='InteractiveShell.separate_out2',
252 type=str, dest='InteractiveShell.separate_out2',
253 help="Separator after output prompts. Default 0 (nonight).",
253 help="Separator after output prompts. Default 0 (nonight).",
254 metavar='InteractiveShell.separate_out2')
254 metavar='InteractiveShell.separate_out2')
255 paa('--no-sep',
255 paa('--no-sep',
256 action='store_true', dest='Global.nosep',
256 action='store_true', dest='Global.nosep',
257 help="Eliminate all spacing between prompts.")
257 help="Eliminate all spacing between prompts.")
258 paa('--term-title',
258 paa('--term-title',
259 action='store_true', dest='InteractiveShell.term_title',
259 action='store_true', dest='InteractiveShell.term_title',
260 help="Enable auto setting the terminal title.")
260 help="Enable auto setting the terminal title.")
261 paa('--no-term-title',
261 paa('--no-term-title',
262 action='store_false', dest='InteractiveShell.term_title',
262 action='store_false', dest='InteractiveShell.term_title',
263 help="Disable auto setting the terminal title.")
263 help="Disable auto setting the terminal title.")
264 paa('--xmode',
264 paa('--xmode',
265 type=str, dest='InteractiveShell.xmode',
265 type=str, dest='InteractiveShell.xmode',
266 help=
266 help=
267 """Exception reporting mode ('Plain','Context','Verbose'). Plain:
267 """Exception reporting mode ('Plain','Context','Verbose'). Plain:
268 similar to python's normal traceback printing. Context: prints 5 lines
268 similar to python's normal traceback printing. Context: prints 5 lines
269 of context source code around each line in the traceback. Verbose:
269 of context source code around each line in the traceback. Verbose:
270 similar to Context, but additionally prints the variables currently
270 similar to Context, but additionally prints the variables currently
271 visible where the exception happened (shortening their strings if too
271 visible where the exception happened (shortening their strings if too
272 long). This can potentially be very slow, if you happen to have a huge
272 long). This can potentially be very slow, if you happen to have a huge
273 data structure whose string representation is complex to compute.
273 data structure whose string representation is complex to compute.
274 Your computer may appear to freeze for a while with cpu usage at 100%%.
274 Your computer may appear to freeze for a while with cpu usage at 100%%.
275 If this occurs, you can cancel the traceback with Ctrl-C (maybe hitting
275 If this occurs, you can cancel the traceback with Ctrl-C (maybe hitting
276 it more than once).
276 it more than once).
277 """,
277 """,
278 metavar='InteractiveShell.xmode')
278 metavar='InteractiveShell.xmode')
279 paa('--ext',
279 paa('--ext',
280 type=str, dest='Global.extra_extension',
280 type=str, dest='Global.extra_extension',
281 help="The dotted module name of an IPython extension to load.",
281 help="The dotted module name of an IPython extension to load.",
282 metavar='Global.extra_extension')
282 metavar='Global.extra_extension')
283 paa('-c',
283 paa('-c',
284 type=str, dest='Global.code_to_run',
284 type=str, dest='Global.code_to_run',
285 help="Execute the given command string.",
285 help="Execute the given command string.",
286 metavar='Global.code_to_run')
286 metavar='Global.code_to_run')
287 paa('-i',
287 paa('-i',
288 action='store_true', dest='Global.force_interact',
288 action='store_true', dest='Global.force_interact',
289 help=
289 help=
290 "If running code from the command line, become interactive afterwards.")
290 "If running code from the command line, become interactive afterwards.")
291
291
292 # Options to start with GUI control enabled from the beginning
292 # Options to start with GUI control enabled from the beginning
293 paa('--gui',
293 paa('--gui',
294 type=str, dest='Global.gui',
294 type=str, dest='Global.gui',
295 help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
295 help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
296 metavar='gui-mode')
296 metavar='gui-mode')
297 paa('--pylab','-pylab',
297 paa('--pylab','-pylab',
298 type=str, dest='Global.pylab',
298 type=str, dest='Global.pylab',
299 nargs='?', const='auto', metavar='gui-mode',
299 nargs='?', const='auto', metavar='gui-mode',
300 help="Pre-load matplotlib and numpy for interactive use. "+
300 help="Pre-load matplotlib and numpy for interactive use. "+
301 "If no value is given, the gui backend is matplotlib's, else use "+
301 "If no value is given, the gui backend is matplotlib's, else use "+
302 "one of: ['tk', 'qt', 'wx', 'gtk'].")
302 "one of: ['tk', 'qt', 'wx', 'gtk'].")
303
303
304 # Legacy GUI options. Leave them in for backwards compatibility, but the
304 # Legacy GUI options. Leave them in for backwards compatibility, but the
305 # 'thread' names are really a misnomer now.
305 # 'thread' names are really a misnomer now.
306 paa('--wthread', '-wthread',
306 paa('--wthread', '-wthread',
307 action='store_true', dest='Global.wthread',
307 action='store_true', dest='Global.wthread',
308 help=
308 help=
309 """Enable wxPython event loop integration. (DEPRECATED, use --gui wx)""")
309 """Enable wxPython event loop integration. (DEPRECATED, use --gui wx)""")
310 paa('--q4thread', '--qthread', '-q4thread', '-qthread',
310 paa('--q4thread', '--qthread', '-q4thread', '-qthread',
311 action='store_true', dest='Global.q4thread',
311 action='store_true', dest='Global.q4thread',
312 help=
312 help=
313 """Enable Qt4 event loop integration. Qt3 is no longer supported.
313 """Enable Qt4 event loop integration. Qt3 is no longer supported.
314 (DEPRECATED, use --gui qt)""")
314 (DEPRECATED, use --gui qt)""")
315 paa('--gthread', '-gthread',
315 paa('--gthread', '-gthread',
316 action='store_true', dest='Global.gthread',
316 action='store_true', dest='Global.gthread',
317 help=
317 help=
318 """Enable GTK event loop integration. (DEPRECATED, use --gui gtk)""")
318 """Enable GTK event loop integration. (DEPRECATED, use --gui gtk)""")
319
319
320
320
321 #-----------------------------------------------------------------------------
321 #-----------------------------------------------------------------------------
322 # Crash handler for this application
322 # Crash handler for this application
323 #-----------------------------------------------------------------------------
323 #-----------------------------------------------------------------------------
324
324
325
325
326 _message_template = """\
326 _message_template = """\
327 Oops, $self.app_name crashed. We do our best to make it stable, but...
327 Oops, $self.app_name crashed. We do our best to make it stable, but...
328
328
329 A crash report was automatically generated with the following information:
329 A crash report was automatically generated with the following information:
330 - A verbatim copy of the crash traceback.
330 - A verbatim copy of the crash traceback.
331 - A copy of your input history during this session.
331 - A copy of your input history during this session.
332 - Data on your current $self.app_name configuration.
332 - Data on your current $self.app_name configuration.
333
333
334 It was left in the file named:
334 It was left in the file named:
335 \t'$self.crash_report_fname'
335 \t'$self.crash_report_fname'
336 If you can email this file to the developers, the information in it will help
336 If you can email this file to the developers, the information in it will help
337 them in understanding and correcting the problem.
337 them in understanding and correcting the problem.
338
338
339 You can mail it to: $self.contact_name at $self.contact_email
339 You can mail it to: $self.contact_name at $self.contact_email
340 with the subject '$self.app_name Crash Report'.
340 with the subject '$self.app_name Crash Report'.
341
341
342 If you want to do it now, the following command will work (under Unix):
342 If you want to do it now, the following command will work (under Unix):
343 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
343 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
344
344
345 To ensure accurate tracking of this issue, please file a report about it at:
345 To ensure accurate tracking of this issue, please file a report about it at:
346 $self.bug_tracker
346 $self.bug_tracker
347 """
347 """
348
348
349 class IPAppCrashHandler(CrashHandler):
349 class IPAppCrashHandler(CrashHandler):
350 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
350 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
351
351
352 message_template = _message_template
352 message_template = _message_template
353
353
354 def __init__(self, app):
354 def __init__(self, app):
355 contact_name = release.authors['Fernando'][0]
355 contact_name = release.authors['Fernando'][0]
356 contact_email = release.authors['Fernando'][1]
356 contact_email = release.authors['Fernando'][1]
357 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
357 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
358 super(IPAppCrashHandler,self).__init__(
358 super(IPAppCrashHandler,self).__init__(
359 app, contact_name, contact_email, bug_tracker
359 app, contact_name, contact_email, bug_tracker
360 )
360 )
361
361
362 def make_report(self,traceback):
362 def make_report(self,traceback):
363 """Return a string containing a crash report."""
363 """Return a string containing a crash report."""
364
364
365 sec_sep = self.section_sep
365 sec_sep = self.section_sep
366 # Start with parent report
366 # Start with parent report
367 report = [super(IPAppCrashHandler, self).make_report(traceback)]
367 report = [super(IPAppCrashHandler, self).make_report(traceback)]
368 # Add interactive-specific info we may have
368 # Add interactive-specific info we may have
369 rpt_add = report.append
369 rpt_add = report.append
370 try:
370 try:
371 rpt_add(sec_sep+"History of session input:")
371 rpt_add(sec_sep+"History of session input:")
372 for line in self.app.shell.user_ns['_ih']:
372 for line in self.app.shell.user_ns['_ih']:
373 rpt_add(line)
373 rpt_add(line)
374 rpt_add('\n*** Last line of input (may not be in above history):\n')
374 rpt_add('\n*** Last line of input (may not be in above history):\n')
375 rpt_add(self.app.shell._last_input_line+'\n')
375 rpt_add(self.app.shell._last_input_line+'\n')
376 except:
376 except:
377 pass
377 pass
378
378
379 return ''.join(report)
379 return ''.join(report)
380
380
381
381
382 #-----------------------------------------------------------------------------
382 #-----------------------------------------------------------------------------
383 # Main classes and functions
383 # Main classes and functions
384 #-----------------------------------------------------------------------------
384 #-----------------------------------------------------------------------------
385
385
386 class IPythonApp(Application):
386 class IPythonApp(Application):
387 name = u'ipython'
387 name = u'ipython'
388 #: argparse formats better the 'usage' than the 'description' field
388 #: argparse formats better the 'usage' than the 'description' field
389 description = None
389 description = None
390 usage = usage.cl_usage
390 usage = usage.cl_usage
391 command_line_loader = IPAppConfigLoader
391 command_line_loader = IPAppConfigLoader
392 default_config_file_name = default_config_file_name
392 default_config_file_name = default_config_file_name
393 crash_handler_class = IPAppCrashHandler
393 crash_handler_class = IPAppCrashHandler
394
394
395 def create_default_config(self):
395 def create_default_config(self):
396 super(IPythonApp, self).create_default_config()
396 super(IPythonApp, self).create_default_config()
397 # Eliminate multiple lookups
397 # Eliminate multiple lookups
398 Global = self.default_config.Global
398 Global = self.default_config.Global
399
399
400 # Set all default values
400 # Set all default values
401 Global.display_banner = True
401 Global.display_banner = True
402
402
403 # If the -c flag is given or a file is given to run at the cmd line
403 # If the -c flag is given or a file is given to run at the cmd line
404 # like "ipython foo.py", normally we exit without starting the main
404 # like "ipython foo.py", normally we exit without starting the main
405 # loop. The force_interact config variable allows a user to override
405 # loop. The force_interact config variable allows a user to override
406 # this and interact. It is also set by the -i cmd line flag, just
406 # this and interact. It is also set by the -i cmd line flag, just
407 # like Python.
407 # like Python.
408 Global.force_interact = False
408 Global.force_interact = False
409
409
410 # By default always interact by starting the IPython mainloop.
410 # By default always interact by starting the IPython mainloop.
411 Global.interact = True
411 Global.interact = True
412
412
413 # No GUI integration by default
413 # No GUI integration by default
414 Global.gui = False
414 Global.gui = False
415 # Pylab off by default
415 # Pylab off by default
416 Global.pylab = False
416 Global.pylab = False
417
417
418 # Deprecated versions of gui support that used threading, we support
418 # Deprecated versions of gui support that used threading, we support
419 # them just for bacwards compatibility as an alternate spelling for
419 # them just for bacwards compatibility as an alternate spelling for
420 # '--gui X'
420 # '--gui X'
421 Global.qthread = False
421 Global.qthread = False
422 Global.q4thread = False
422 Global.q4thread = False
423 Global.wthread = False
423 Global.wthread = False
424 Global.gthread = False
424 Global.gthread = False
425
425
426 def load_file_config(self):
426 def load_file_config(self):
427 if hasattr(self.command_line_config.Global, 'quick'):
427 if hasattr(self.command_line_config.Global, 'quick'):
428 if self.command_line_config.Global.quick:
428 if self.command_line_config.Global.quick:
429 self.file_config = Config()
429 self.file_config = Config()
430 return
430 return
431 super(IPythonApp, self).load_file_config()
431 super(IPythonApp, self).load_file_config()
432
432
433 def post_load_file_config(self):
433 def post_load_file_config(self):
434 if hasattr(self.command_line_config.Global, 'extra_extension'):
434 if hasattr(self.command_line_config.Global, 'extra_extension'):
435 if not hasattr(self.file_config.Global, 'extensions'):
435 if not hasattr(self.file_config.Global, 'extensions'):
436 self.file_config.Global.extensions = []
436 self.file_config.Global.extensions = []
437 self.file_config.Global.extensions.append(
437 self.file_config.Global.extensions.append(
438 self.command_line_config.Global.extra_extension)
438 self.command_line_config.Global.extra_extension)
439 del self.command_line_config.Global.extra_extension
439 del self.command_line_config.Global.extra_extension
440
440
441 def pre_construct(self):
441 def pre_construct(self):
442 config = self.master_config
442 config = self.master_config
443
443
444 if hasattr(config.Global, 'classic'):
444 if hasattr(config.Global, 'classic'):
445 if config.Global.classic:
445 if config.Global.classic:
446 config.InteractiveShell.cache_size = 0
446 config.InteractiveShell.cache_size = 0
447 config.InteractiveShell.pprint = 0
447 config.InteractiveShell.pprint = 0
448 config.InteractiveShell.prompt_in1 = '>>> '
448 config.InteractiveShell.prompt_in1 = '>>> '
449 config.InteractiveShell.prompt_in2 = '... '
449 config.InteractiveShell.prompt_in2 = '... '
450 config.InteractiveShell.prompt_out = ''
450 config.InteractiveShell.prompt_out = ''
451 config.InteractiveShell.separate_in = \
451 config.InteractiveShell.separate_in = \
452 config.InteractiveShell.separate_out = \
452 config.InteractiveShell.separate_out = \
453 config.InteractiveShell.separate_out2 = ''
453 config.InteractiveShell.separate_out2 = ''
454 config.InteractiveShell.colors = 'NoColor'
454 config.InteractiveShell.colors = 'NoColor'
455 config.InteractiveShell.xmode = 'Plain'
455 config.InteractiveShell.xmode = 'Plain'
456
456
457 if hasattr(config.Global, 'nosep'):
457 if hasattr(config.Global, 'nosep'):
458 if config.Global.nosep:
458 if config.Global.nosep:
459 config.InteractiveShell.separate_in = \
459 config.InteractiveShell.separate_in = \
460 config.InteractiveShell.separate_out = \
460 config.InteractiveShell.separate_out = \
461 config.InteractiveShell.separate_out2 = ''
461 config.InteractiveShell.separate_out2 = ''
462
462
463 # if there is code of files to run from the cmd line, don't interact
463 # if there is code of files to run from the cmd line, don't interact
464 # unless the -i flag (Global.force_interact) is true.
464 # unless the -i flag (Global.force_interact) is true.
465 code_to_run = config.Global.get('code_to_run','')
465 code_to_run = config.Global.get('code_to_run','')
466 file_to_run = False
466 file_to_run = False
467 if self.extra_args and self.extra_args[0]:
467 if self.extra_args and self.extra_args[0]:
468 file_to_run = True
468 file_to_run = True
469 if file_to_run or code_to_run:
469 if file_to_run or code_to_run:
470 if not config.Global.force_interact:
470 if not config.Global.force_interact:
471 config.Global.interact = False
471 config.Global.interact = False
472
472
473 def construct(self):
473 def construct(self):
474 # I am a little hesitant to put these into InteractiveShell itself.
474 # I am a little hesitant to put these into InteractiveShell itself.
475 # But that might be the place for them
475 # But that might be the place for them
476 sys.path.insert(0, '')
476 sys.path.insert(0, '')
477
477
478 # Create an InteractiveShell instance
478 # Create an InteractiveShell instance.
479 self.shell = InteractiveShell(None, self.master_config)
479 self.shell = InteractiveShell.instance(config=self.master_config)
480
480
481 def post_construct(self):
481 def post_construct(self):
482 """Do actions after construct, but before starting the app."""
482 """Do actions after construct, but before starting the app."""
483 config = self.master_config
483 config = self.master_config
484
484
485 # shell.display_banner should always be False for the terminal
485 # shell.display_banner should always be False for the terminal
486 # based app, because we call shell.show_banner() by hand below
486 # based app, because we call shell.show_banner() by hand below
487 # so the banner shows *before* all extension loading stuff.
487 # so the banner shows *before* all extension loading stuff.
488 self.shell.display_banner = False
488 self.shell.display_banner = False
489 if config.Global.display_banner and \
489 if config.Global.display_banner and \
490 config.Global.interact:
490 config.Global.interact:
491 self.shell.show_banner()
491 self.shell.show_banner()
492
492
493 # Make sure there is a space below the banner.
493 # Make sure there is a space below the banner.
494 if self.log_level <= logging.INFO: print
494 if self.log_level <= logging.INFO: print
495
495
496 # Now a variety of things that happen after the banner is printed.
496 # Now a variety of things that happen after the banner is printed.
497 self._enable_gui_pylab()
497 self._enable_gui_pylab()
498 self._load_extensions()
498 self._load_extensions()
499 self._run_exec_lines()
499 self._run_exec_lines()
500 self._run_exec_files()
500 self._run_exec_files()
501 self._run_cmd_line_code()
501 self._run_cmd_line_code()
502
502
503 def _enable_gui_pylab(self):
503 def _enable_gui_pylab(self):
504 """Enable GUI event loop integration, taking pylab into account."""
504 """Enable GUI event loop integration, taking pylab into account."""
505 Global = self.master_config.Global
505 Global = self.master_config.Global
506
506
507 # Select which gui to use
507 # Select which gui to use
508 if Global.gui:
508 if Global.gui:
509 gui = Global.gui
509 gui = Global.gui
510 # The following are deprecated, but there's likely to be a lot of use
510 # The following are deprecated, but there's likely to be a lot of use
511 # of this form out there, so we might as well support it for now. But
511 # of this form out there, so we might as well support it for now. But
512 # the --gui option above takes precedence.
512 # the --gui option above takes precedence.
513 elif Global.wthread:
513 elif Global.wthread:
514 gui = inputhook.GUI_WX
514 gui = inputhook.GUI_WX
515 elif Global.qthread:
515 elif Global.qthread:
516 gui = inputhook.GUI_QT
516 gui = inputhook.GUI_QT
517 elif Global.gthread:
517 elif Global.gthread:
518 gui = inputhook.GUI_GTK
518 gui = inputhook.GUI_GTK
519 else:
519 else:
520 gui = None
520 gui = None
521
521
522 # Using --pylab will also require gui activation, though which toolkit
522 # Using --pylab will also require gui activation, though which toolkit
523 # to use may be chosen automatically based on mpl configuration.
523 # to use may be chosen automatically based on mpl configuration.
524 if Global.pylab:
524 if Global.pylab:
525 activate = self.shell.enable_pylab
525 activate = self.shell.enable_pylab
526 if Global.pylab == 'auto':
526 if Global.pylab == 'auto':
527 gui = None
527 gui = None
528 else:
528 else:
529 gui = Global.pylab
529 gui = Global.pylab
530 else:
530 else:
531 # Enable only GUI integration, no pylab
531 # Enable only GUI integration, no pylab
532 activate = inputhook.enable_gui
532 activate = inputhook.enable_gui
533
533
534 if gui or Global.pylab:
534 if gui or Global.pylab:
535 try:
535 try:
536 self.log.info("Enabling GUI event loop integration, "
536 self.log.info("Enabling GUI event loop integration, "
537 "toolkit=%s, pylab=%s" % (gui, Global.pylab) )
537 "toolkit=%s, pylab=%s" % (gui, Global.pylab) )
538 activate(gui)
538 activate(gui)
539 except:
539 except:
540 self.log.warn("Error in enabling GUI event loop integration:")
540 self.log.warn("Error in enabling GUI event loop integration:")
541 self.shell.showtraceback()
541 self.shell.showtraceback()
542
542
543 def _load_extensions(self):
543 def _load_extensions(self):
544 """Load all IPython extensions in Global.extensions.
544 """Load all IPython extensions in Global.extensions.
545
545
546 This uses the :meth:`InteractiveShell.load_extensions` to load all
546 This uses the :meth:`ExtensionManager.load_extensions` to load all
547 the extensions listed in ``self.master_config.Global.extensions``.
547 the extensions listed in ``self.master_config.Global.extensions``.
548 """
548 """
549 try:
549 try:
550 if hasattr(self.master_config.Global, 'extensions'):
550 if hasattr(self.master_config.Global, 'extensions'):
551 self.log.debug("Loading IPython extensions...")
551 self.log.debug("Loading IPython extensions...")
552 extensions = self.master_config.Global.extensions
552 extensions = self.master_config.Global.extensions
553 for ext in extensions:
553 for ext in extensions:
554 try:
554 try:
555 self.log.info("Loading IPython extension: %s" % ext)
555 self.log.info("Loading IPython extension: %s" % ext)
556 self.shell.load_extension(ext)
556 self.shell.extension_manager.load_extension(ext)
557 except:
557 except:
558 self.log.warn("Error in loading extension: %s" % ext)
558 self.log.warn("Error in loading extension: %s" % ext)
559 self.shell.showtraceback()
559 self.shell.showtraceback()
560 except:
560 except:
561 self.log.warn("Unknown error in loading extensions:")
561 self.log.warn("Unknown error in loading extensions:")
562 self.shell.showtraceback()
562 self.shell.showtraceback()
563
563
564 def _run_exec_lines(self):
564 def _run_exec_lines(self):
565 """Run lines of code in Global.exec_lines in the user's namespace."""
565 """Run lines of code in Global.exec_lines in the user's namespace."""
566 try:
566 try:
567 if hasattr(self.master_config.Global, 'exec_lines'):
567 if hasattr(self.master_config.Global, 'exec_lines'):
568 self.log.debug("Running code from Global.exec_lines...")
568 self.log.debug("Running code from Global.exec_lines...")
569 exec_lines = self.master_config.Global.exec_lines
569 exec_lines = self.master_config.Global.exec_lines
570 for line in exec_lines:
570 for line in exec_lines:
571 try:
571 try:
572 self.log.info("Running code in user namespace: %s" %
572 self.log.info("Running code in user namespace: %s" %
573 line)
573 line)
574 self.shell.runlines(line)
574 self.shell.runlines(line)
575 except:
575 except:
576 self.log.warn("Error in executing line in user "
576 self.log.warn("Error in executing line in user "
577 "namespace: %s" % line)
577 "namespace: %s" % line)
578 self.shell.showtraceback()
578 self.shell.showtraceback()
579 except:
579 except:
580 self.log.warn("Unknown error in handling Global.exec_lines:")
580 self.log.warn("Unknown error in handling Global.exec_lines:")
581 self.shell.showtraceback()
581 self.shell.showtraceback()
582
582
583 def _exec_file(self, fname):
583 def _exec_file(self, fname):
584 full_filename = filefind(fname, [u'.', self.ipython_dir])
584 full_filename = filefind(fname, [u'.', self.ipython_dir])
585 if os.path.isfile(full_filename):
585 if os.path.isfile(full_filename):
586 if full_filename.endswith(u'.py'):
586 if full_filename.endswith(u'.py'):
587 self.log.info("Running file in user namespace: %s" %
587 self.log.info("Running file in user namespace: %s" %
588 full_filename)
588 full_filename)
589 # Ensure that __file__ is always defined to match Python behavior
589 # Ensure that __file__ is always defined to match Python behavior
590 self.shell.user_ns['__file__'] = fname
590 self.shell.user_ns['__file__'] = fname
591 try:
591 try:
592 self.shell.safe_execfile(full_filename, self.shell.user_ns)
592 self.shell.safe_execfile(full_filename, self.shell.user_ns)
593 finally:
593 finally:
594 del self.shell.user_ns['__file__']
594 del self.shell.user_ns['__file__']
595 elif full_filename.endswith('.ipy'):
595 elif full_filename.endswith('.ipy'):
596 self.log.info("Running file in user namespace: %s" %
596 self.log.info("Running file in user namespace: %s" %
597 full_filename)
597 full_filename)
598 self.shell.safe_execfile_ipy(full_filename)
598 self.shell.safe_execfile_ipy(full_filename)
599 else:
599 else:
600 self.log.warn("File does not have a .py or .ipy extension: <%s>"
600 self.log.warn("File does not have a .py or .ipy extension: <%s>"
601 % full_filename)
601 % full_filename)
602 def _run_exec_files(self):
602 def _run_exec_files(self):
603 try:
603 try:
604 if hasattr(self.master_config.Global, 'exec_files'):
604 if hasattr(self.master_config.Global, 'exec_files'):
605 self.log.debug("Running files in Global.exec_files...")
605 self.log.debug("Running files in Global.exec_files...")
606 exec_files = self.master_config.Global.exec_files
606 exec_files = self.master_config.Global.exec_files
607 for fname in exec_files:
607 for fname in exec_files:
608 self._exec_file(fname)
608 self._exec_file(fname)
609 except:
609 except:
610 self.log.warn("Unknown error in handling Global.exec_files:")
610 self.log.warn("Unknown error in handling Global.exec_files:")
611 self.shell.showtraceback()
611 self.shell.showtraceback()
612
612
613 def _run_cmd_line_code(self):
613 def _run_cmd_line_code(self):
614 if hasattr(self.master_config.Global, 'code_to_run'):
614 if hasattr(self.master_config.Global, 'code_to_run'):
615 line = self.master_config.Global.code_to_run
615 line = self.master_config.Global.code_to_run
616 try:
616 try:
617 self.log.info("Running code given at command line (-c): %s" %
617 self.log.info("Running code given at command line (-c): %s" %
618 line)
618 line)
619 self.shell.runlines(line)
619 self.shell.runlines(line)
620 except:
620 except:
621 self.log.warn("Error in executing line in user namespace: %s" %
621 self.log.warn("Error in executing line in user namespace: %s" %
622 line)
622 line)
623 self.shell.showtraceback()
623 self.shell.showtraceback()
624 return
624 return
625 # Like Python itself, ignore the second if the first of these is present
625 # Like Python itself, ignore the second if the first of these is present
626 try:
626 try:
627 fname = self.extra_args[0]
627 fname = self.extra_args[0]
628 except:
628 except:
629 pass
629 pass
630 else:
630 else:
631 try:
631 try:
632 self._exec_file(fname)
632 self._exec_file(fname)
633 except:
633 except:
634 self.log.warn("Error in executing file in user namespace: %s" %
634 self.log.warn("Error in executing file in user namespace: %s" %
635 fname)
635 fname)
636 self.shell.showtraceback()
636 self.shell.showtraceback()
637
637
638 def start_app(self):
638 def start_app(self):
639 if self.master_config.Global.interact:
639 if self.master_config.Global.interact:
640 self.log.debug("Starting IPython's mainloop...")
640 self.log.debug("Starting IPython's mainloop...")
641 self.shell.mainloop()
641 self.shell.mainloop()
642 else:
642 else:
643 self.log.debug("IPython not interactive, start_app is no-op...")
643 self.log.debug("IPython not interactive, start_app is no-op...")
644
644
645
645
646 def load_default_config(ipython_dir=None):
646 def load_default_config(ipython_dir=None):
647 """Load the default config file from the default ipython_dir.
647 """Load the default config file from the default ipython_dir.
648
648
649 This is useful for embedded shells.
649 This is useful for embedded shells.
650 """
650 """
651 if ipython_dir is None:
651 if ipython_dir is None:
652 ipython_dir = get_ipython_dir()
652 ipython_dir = get_ipython_dir()
653 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
653 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
654 config = cl.load_config()
654 config = cl.load_config()
655 return config
655 return config
656
656
657
657
658 def launch_new_instance():
658 def launch_new_instance():
659 """Create and run a full blown IPython instance"""
659 """Create and run a full blown IPython instance"""
660 app = IPythonApp()
660 app = IPythonApp()
661 app.start()
661 app.start()
662
662
663
663
664 if __name__ == '__main__':
664 if __name__ == '__main__':
665 launch_new_instance()
665 launch_new_instance()
@@ -1,2582 +1,2511 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """Main IPython class."""
3 Main IPython Component
4 """
5
3
6 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
8 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
9 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2010 The IPython Development Team
10 #
8 #
11 # 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
12 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
14
12
15 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
16 # Imports
14 # Imports
17 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
18
16
19 from __future__ import with_statement
17 from __future__ import with_statement
20 from __future__ import absolute_import
18 from __future__ import absolute_import
21
19
22 import __builtin__
20 import __builtin__
23 import bdb
21 import bdb
24 import codeop
22 import codeop
25 import exceptions
23 import exceptions
26 import new
24 import new
27 import os
25 import os
28 import re
26 import re
29 import string
27 import string
30 import sys
28 import sys
31 import tempfile
29 import tempfile
32 from contextlib import nested
30 from contextlib import nested
33
31
34 from IPython.core import debugger, oinspect
32 from IPython.core import debugger, oinspect
35 from IPython.core import history as ipcorehist
33 from IPython.core import history as ipcorehist
36 from IPython.core import prefilter
34 from IPython.core import prefilter
37 from IPython.core import shadowns
35 from IPython.core import shadowns
38 from IPython.core import ultratb
36 from IPython.core import ultratb
39 from IPython.core.alias import AliasManager
37 from IPython.core.alias import AliasManager
40 from IPython.core.builtin_trap import BuiltinTrap
38 from IPython.core.builtin_trap import BuiltinTrap
41 from IPython.core.component import Component
39 from IPython.config.configurable import Configurable
42 from IPython.core.display_trap import DisplayTrap
40 from IPython.core.display_trap import DisplayTrap
43 from IPython.core.error import TryNext, UsageError
41 from IPython.core.error import TryNext, UsageError
42 from IPython.core.extensions import ExtensionManager
44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
43 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
45 from IPython.core.logger import Logger
44 from IPython.core.logger import Logger
46 from IPython.core.magic import Magic
45 from IPython.core.magic import Magic
47 from IPython.core.prefilter import PrefilterManager
46 from IPython.core.prefilter import PrefilterManager
48 from IPython.core.prompts import CachedOutput
47 from IPython.core.prompts import CachedOutput
49 from IPython.core.usage import interactive_usage, default_banner
48 from IPython.core.usage import interactive_usage, default_banner
50 import IPython.core.hooks
49 import IPython.core.hooks
51 from IPython.external.Itpl import ItplNS
50 from IPython.external.Itpl import ItplNS
52 from IPython.lib.inputhook import enable_gui
51 from IPython.lib.inputhook import enable_gui
53 from IPython.lib.backgroundjobs import BackgroundJobManager
52 from IPython.lib.backgroundjobs import BackgroundJobManager
54 from IPython.lib.pylabtools import pylab_activate
53 from IPython.lib.pylabtools import pylab_activate
55 from IPython.utils import PyColorize
54 from IPython.utils import PyColorize
56 from IPython.utils import pickleshare
55 from IPython.utils import pickleshare
57 from IPython.utils.doctestreload import doctest_reload
56 from IPython.utils.doctestreload import doctest_reload
58 from IPython.utils.ipstruct import Struct
57 from IPython.utils.ipstruct import Struct
59 from IPython.utils.io import Term, ask_yes_no
58 from IPython.utils.io import Term, ask_yes_no
60 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
59 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
61 from IPython.utils.process import (
60 from IPython.utils.process import (
62 abbrev_cwd,
61 abbrev_cwd,
63 getoutput,
62 getoutput,
64 getoutputerror
63 getoutputerror
65 )
64 )
66 # import IPython.utils.rlineimpl as readline
65 # import IPython.utils.rlineimpl as readline
67 from IPython.utils.strdispatch import StrDispatch
66 from IPython.utils.strdispatch import StrDispatch
68 from IPython.utils.syspathcontext import prepended_to_syspath
67 from IPython.utils.syspathcontext import prepended_to_syspath
69 from IPython.utils.terminal import toggle_set_term_title, set_term_title
68 from IPython.utils.terminal import toggle_set_term_title, set_term_title
70 from IPython.utils.warn import warn, error, fatal
69 from IPython.utils.warn import warn, error, fatal
71 from IPython.utils.traitlets import (
70 from IPython.utils.traitlets import (
72 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode
71 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode, Instance
73 )
72 )
74
73
75 # from IPython.utils import growl
74 # from IPython.utils import growl
76 # growl.start("IPython")
75 # growl.start("IPython")
77
76
78 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
79 # Globals
78 # Globals
80 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
81
80
82 # store the builtin raw_input globally, and use this always, in case user code
81 # store the builtin raw_input globally, and use this always, in case user code
83 # overwrites it (like wx.py.PyShell does)
82 # overwrites it (like wx.py.PyShell does)
84 raw_input_original = raw_input
83 raw_input_original = raw_input
85
84
86 # compiled regexps for autoindent management
85 # compiled regexps for autoindent management
87 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
86 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
88
87
89 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
90 # Utilities
89 # Utilities
91 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
92
91
93 ini_spaces_re = re.compile(r'^(\s+)')
92 ini_spaces_re = re.compile(r'^(\s+)')
94
93
95
94
96 def num_ini_spaces(strng):
95 def num_ini_spaces(strng):
97 """Return the number of initial spaces in a string"""
96 """Return the number of initial spaces in a string"""
98
97
99 ini_spaces = ini_spaces_re.match(strng)
98 ini_spaces = ini_spaces_re.match(strng)
100 if ini_spaces:
99 if ini_spaces:
101 return ini_spaces.end()
100 return ini_spaces.end()
102 else:
101 else:
103 return 0
102 return 0
104
103
105
104
106 def softspace(file, newvalue):
105 def softspace(file, newvalue):
107 """Copied from code.py, to remove the dependency"""
106 """Copied from code.py, to remove the dependency"""
108
107
109 oldvalue = 0
108 oldvalue = 0
110 try:
109 try:
111 oldvalue = file.softspace
110 oldvalue = file.softspace
112 except AttributeError:
111 except AttributeError:
113 pass
112 pass
114 try:
113 try:
115 file.softspace = newvalue
114 file.softspace = newvalue
116 except (AttributeError, TypeError):
115 except (AttributeError, TypeError):
117 # "attribute-less object" or "read-only attributes"
116 # "attribute-less object" or "read-only attributes"
118 pass
117 pass
119 return oldvalue
118 return oldvalue
120
119
121
120
122 def no_op(*a, **kw): pass
121 def no_op(*a, **kw): pass
123
122
124 class SpaceInInput(exceptions.Exception): pass
123 class SpaceInInput(exceptions.Exception): pass
125
124
126 class Bunch: pass
125 class Bunch: pass
127
126
128 class InputList(list):
127 class InputList(list):
129 """Class to store user input.
128 """Class to store user input.
130
129
131 It's basically a list, but slices return a string instead of a list, thus
130 It's basically a list, but slices return a string instead of a list, thus
132 allowing things like (assuming 'In' is an instance):
131 allowing things like (assuming 'In' is an instance):
133
132
134 exec In[4:7]
133 exec In[4:7]
135
134
136 or
135 or
137
136
138 exec In[5:9] + In[14] + In[21:25]"""
137 exec In[5:9] + In[14] + In[21:25]"""
139
138
140 def __getslice__(self,i,j):
139 def __getslice__(self,i,j):
141 return ''.join(list.__getslice__(self,i,j))
140 return ''.join(list.__getslice__(self,i,j))
142
141
143
142
144 class SyntaxTB(ultratb.ListTB):
143 class SyntaxTB(ultratb.ListTB):
145 """Extension which holds some state: the last exception value"""
144 """Extension which holds some state: the last exception value"""
146
145
147 def __init__(self,color_scheme = 'NoColor'):
146 def __init__(self,color_scheme = 'NoColor'):
148 ultratb.ListTB.__init__(self,color_scheme)
147 ultratb.ListTB.__init__(self,color_scheme)
149 self.last_syntax_error = None
148 self.last_syntax_error = None
150
149
151 def __call__(self, etype, value, elist):
150 def __call__(self, etype, value, elist):
152 self.last_syntax_error = value
151 self.last_syntax_error = value
153 ultratb.ListTB.__call__(self,etype,value,elist)
152 ultratb.ListTB.__call__(self,etype,value,elist)
154
153
155 def clear_err_state(self):
154 def clear_err_state(self):
156 """Return the current error state and clear it"""
155 """Return the current error state and clear it"""
157 e = self.last_syntax_error
156 e = self.last_syntax_error
158 self.last_syntax_error = None
157 self.last_syntax_error = None
159 return e
158 return e
160
159
161
160
162 def get_default_editor():
161 def get_default_editor():
163 try:
162 try:
164 ed = os.environ['EDITOR']
163 ed = os.environ['EDITOR']
165 except KeyError:
164 except KeyError:
166 if os.name == 'posix':
165 if os.name == 'posix':
167 ed = 'vi' # the only one guaranteed to be there!
166 ed = 'vi' # the only one guaranteed to be there!
168 else:
167 else:
169 ed = 'notepad' # same in Windows!
168 ed = 'notepad' # same in Windows!
170 return ed
169 return ed
171
170
172
171
173 def get_default_colors():
172 def get_default_colors():
174 if sys.platform=='darwin':
173 if sys.platform=='darwin':
175 return "LightBG"
174 return "LightBG"
176 elif os.name=='nt':
175 elif os.name=='nt':
177 return 'Linux'
176 return 'Linux'
178 else:
177 else:
179 return 'Linux'
178 return 'Linux'
180
179
181
180
182 class SeparateStr(Str):
181 class SeparateStr(Str):
183 """A Str subclass to validate separate_in, separate_out, etc.
182 """A Str subclass to validate separate_in, separate_out, etc.
184
183
185 This is a Str based trait that converts '0'->'' and '\\n'->'\n'.
184 This is a Str based trait that converts '0'->'' and '\\n'->'\n'.
186 """
185 """
187
186
188 def validate(self, obj, value):
187 def validate(self, obj, value):
189 if value == '0': value = ''
188 if value == '0': value = ''
190 value = value.replace('\\n','\n')
189 value = value.replace('\\n','\n')
191 return super(SeparateStr, self).validate(obj, value)
190 return super(SeparateStr, self).validate(obj, value)
192
191
193
192
194 #-----------------------------------------------------------------------------
193 #-----------------------------------------------------------------------------
195 # Main IPython class
194 # Main IPython class
196 #-----------------------------------------------------------------------------
195 #-----------------------------------------------------------------------------
197
196
198
197
199 class InteractiveShell(Component, Magic):
198 class InteractiveShell(Configurable, Magic):
200 """An enhanced, interactive shell for Python."""
199 """An enhanced, interactive shell for Python."""
201
200
202 autocall = Enum((0,1,2), default_value=1, config=True)
201 autocall = Enum((0,1,2), default_value=1, config=True)
203 autoedit_syntax = CBool(False, config=True)
202 autoedit_syntax = CBool(False, config=True)
204 autoindent = CBool(True, config=True)
203 autoindent = CBool(True, config=True)
205 automagic = CBool(True, config=True)
204 automagic = CBool(True, config=True)
206 banner = Str('')
205 banner = Str('')
207 banner1 = Str(default_banner, config=True)
206 banner1 = Str(default_banner, config=True)
208 banner2 = Str('', config=True)
207 banner2 = Str('', config=True)
209 cache_size = Int(1000, config=True)
208 cache_size = Int(1000, config=True)
210 color_info = CBool(True, config=True)
209 color_info = CBool(True, config=True)
211 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
210 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
212 default_value=get_default_colors(), config=True)
211 default_value=get_default_colors(), config=True)
213 confirm_exit = CBool(True, config=True)
212 confirm_exit = CBool(True, config=True)
214 debug = CBool(False, config=True)
213 debug = CBool(False, config=True)
215 deep_reload = CBool(False, config=True)
214 deep_reload = CBool(False, config=True)
216 # This display_banner only controls whether or not self.show_banner()
215 # This display_banner only controls whether or not self.show_banner()
217 # is called when mainloop/interact are called. The default is False
216 # is called when mainloop/interact are called. The default is False
218 # because for the terminal based application, the banner behavior
217 # because for the terminal based application, the banner behavior
219 # is controlled by Global.display_banner, which IPythonApp looks at
218 # is controlled by Global.display_banner, which IPythonApp looks at
220 # to determine if *it* should call show_banner() by hand or not.
219 # to determine if *it* should call show_banner() by hand or not.
221 display_banner = CBool(False) # This isn't configurable!
220 display_banner = CBool(False) # This isn't configurable!
222 embedded = CBool(False)
221 embedded = CBool(False)
223 embedded_active = CBool(False)
222 embedded_active = CBool(False)
224 editor = Str(get_default_editor(), config=True)
223 editor = Str(get_default_editor(), config=True)
225 filename = Str("<ipython console>")
224 filename = Str("<ipython console>")
226 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
225 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
227 logstart = CBool(False, config=True)
226 logstart = CBool(False, config=True)
228 logfile = Str('', config=True)
227 logfile = Str('', config=True)
229 logappend = Str('', config=True)
228 logappend = Str('', config=True)
230 object_info_string_level = Enum((0,1,2), default_value=0,
229 object_info_string_level = Enum((0,1,2), default_value=0,
231 config=True)
230 config=True)
232 pager = Str('less', config=True)
231 pager = Str('less', config=True)
233 pdb = CBool(False, config=True)
232 pdb = CBool(False, config=True)
234 pprint = CBool(True, config=True)
233 pprint = CBool(True, config=True)
235 profile = Str('', config=True)
234 profile = Str('', config=True)
236 prompt_in1 = Str('In [\\#]: ', config=True)
235 prompt_in1 = Str('In [\\#]: ', config=True)
237 prompt_in2 = Str(' .\\D.: ', config=True)
236 prompt_in2 = Str(' .\\D.: ', config=True)
238 prompt_out = Str('Out[\\#]: ', config=True)
237 prompt_out = Str('Out[\\#]: ', config=True)
239 prompts_pad_left = CBool(True, config=True)
238 prompts_pad_left = CBool(True, config=True)
240 quiet = CBool(False, config=True)
239 quiet = CBool(False, config=True)
241
240
242 readline_use = CBool(True, config=True)
241 readline_use = CBool(True, config=True)
243 readline_merge_completions = CBool(True, config=True)
242 readline_merge_completions = CBool(True, config=True)
244 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
243 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
245 readline_remove_delims = Str('-/~', config=True)
244 readline_remove_delims = Str('-/~', config=True)
246 readline_parse_and_bind = List([
245 readline_parse_and_bind = List([
247 'tab: complete',
246 'tab: complete',
248 '"\C-l": clear-screen',
247 '"\C-l": clear-screen',
249 'set show-all-if-ambiguous on',
248 'set show-all-if-ambiguous on',
250 '"\C-o": tab-insert',
249 '"\C-o": tab-insert',
251 '"\M-i": " "',
250 '"\M-i": " "',
252 '"\M-o": "\d\d\d\d"',
251 '"\M-o": "\d\d\d\d"',
253 '"\M-I": "\d\d\d\d"',
252 '"\M-I": "\d\d\d\d"',
254 '"\C-r": reverse-search-history',
253 '"\C-r": reverse-search-history',
255 '"\C-s": forward-search-history',
254 '"\C-s": forward-search-history',
256 '"\C-p": history-search-backward',
255 '"\C-p": history-search-backward',
257 '"\C-n": history-search-forward',
256 '"\C-n": history-search-forward',
258 '"\e[A": history-search-backward',
257 '"\e[A": history-search-backward',
259 '"\e[B": history-search-forward',
258 '"\e[B": history-search-forward',
260 '"\C-k": kill-line',
259 '"\C-k": kill-line',
261 '"\C-u": unix-line-discard',
260 '"\C-u": unix-line-discard',
262 ], allow_none=False, config=True)
261 ], allow_none=False, config=True)
263
262
264 screen_length = Int(0, config=True)
263 screen_length = Int(0, config=True)
265
264
266 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
265 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
267 separate_in = SeparateStr('\n', config=True)
266 separate_in = SeparateStr('\n', config=True)
268 separate_out = SeparateStr('', config=True)
267 separate_out = SeparateStr('', config=True)
269 separate_out2 = SeparateStr('', config=True)
268 separate_out2 = SeparateStr('', config=True)
270
269
271 system_header = Str('IPython system call: ', config=True)
270 system_header = Str('IPython system call: ', config=True)
272 system_verbose = CBool(False, config=True)
271 system_verbose = CBool(False, config=True)
273 term_title = CBool(False, config=True)
272 term_title = CBool(False, config=True)
274 wildcards_case_sensitive = CBool(True, config=True)
273 wildcards_case_sensitive = CBool(True, config=True)
275 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
274 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
276 default_value='Context', config=True)
275 default_value='Context', config=True)
277
276
278 autoexec = List(allow_none=False)
277 autoexec = List(allow_none=False)
279
278
280 # class attribute to indicate whether the class supports threads or not.
279 # class attribute to indicate whether the class supports threads or not.
281 # Subclasses with thread support should override this as needed.
280 # Subclasses with thread support should override this as needed.
282 isthreaded = False
281 isthreaded = False
283
282
284 def __init__(self, parent=None, config=None, ipython_dir=None, usage=None,
283 # Subcomponents of InteractiveShell
284 alias_manager = Instance('IPython.core.alias.AliasManager')
285 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
286 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
287 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
288 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
289
290 def __init__(self, config=None, ipython_dir=None, usage=None,
285 user_ns=None, user_global_ns=None,
291 user_ns=None, user_global_ns=None,
286 banner1=None, banner2=None, display_banner=None,
292 banner1=None, banner2=None, display_banner=None,
287 custom_exceptions=((),None)):
293 custom_exceptions=((),None)):
288
294
289 # This is where traits with a config_key argument are updated
295 # This is where traits with a config_key argument are updated
290 # from the values on config.
296 # from the values on config.
291 super(InteractiveShell, self).__init__(parent, config=config)
297 super(InteractiveShell, self).__init__(config=config)
292
298
293 # These are relatively independent and stateless
299 # These are relatively independent and stateless
294 self.init_ipython_dir(ipython_dir)
300 self.init_ipython_dir(ipython_dir)
295 self.init_instance_attrs()
301 self.init_instance_attrs()
296 self.init_term_title()
302 self.init_term_title()
297 self.init_usage(usage)
303 self.init_usage(usage)
298 self.init_banner(banner1, banner2, display_banner)
304 self.init_banner(banner1, banner2, display_banner)
299
305
300 # Create namespaces (user_ns, user_global_ns, etc.)
306 # Create namespaces (user_ns, user_global_ns, etc.)
301 self.init_create_namespaces(user_ns, user_global_ns)
307 self.init_create_namespaces(user_ns, user_global_ns)
302 # This has to be done after init_create_namespaces because it uses
308 # This has to be done after init_create_namespaces because it uses
303 # something in self.user_ns, but before init_sys_modules, which
309 # something in self.user_ns, but before init_sys_modules, which
304 # is the first thing to modify sys.
310 # is the first thing to modify sys.
305 self.save_sys_module_state()
311 self.save_sys_module_state()
306 self.init_sys_modules()
312 self.init_sys_modules()
307
313
308 self.init_history()
314 self.init_history()
309 self.init_encoding()
315 self.init_encoding()
310 self.init_prefilter()
316 self.init_prefilter()
311
317
312 Magic.__init__(self, self)
318 Magic.__init__(self, self)
313
319
314 self.init_syntax_highlighting()
320 self.init_syntax_highlighting()
315 self.init_hooks()
321 self.init_hooks()
316 self.init_pushd_popd_magic()
322 self.init_pushd_popd_magic()
317 self.init_traceback_handlers(custom_exceptions)
323 self.init_traceback_handlers(custom_exceptions)
318 self.init_user_ns()
324 self.init_user_ns()
319 self.init_logger()
325 self.init_logger()
320 self.init_alias()
326 self.init_alias()
321 self.init_builtins()
327 self.init_builtins()
322
328
323 # pre_config_initialization
329 # pre_config_initialization
324 self.init_shadow_hist()
330 self.init_shadow_hist()
325
331
326 # The next section should contain averything that was in ipmaker.
332 # The next section should contain averything that was in ipmaker.
327 self.init_logstart()
333 self.init_logstart()
328
334
329 # The following was in post_config_initialization
335 # The following was in post_config_initialization
330 self.init_inspector()
336 self.init_inspector()
331 self.init_readline()
337 self.init_readline()
332 self.init_prompts()
338 self.init_prompts()
333 self.init_displayhook()
339 self.init_displayhook()
334 self.init_reload_doctest()
340 self.init_reload_doctest()
335 self.init_magics()
341 self.init_magics()
336 self.init_pdb()
342 self.init_pdb()
343 self.init_extension_manager()
337 self.hooks.late_startup_hook()
344 self.hooks.late_startup_hook()
338
345
346 @classmethod
347 def instance(cls, *args, **kwargs):
348 """Returns a global InteractiveShell instance."""
349 if not hasattr(cls, "_instance"):
350 cls._instance = cls(*args, **kwargs)
351 return cls._instance
352
353 @classmethod
354 def initialized(cls):
355 return hasattr(cls, "_instance")
356
339 def get_ipython(self):
357 def get_ipython(self):
340 """Return the currently running IPython instance."""
358 """Return the currently running IPython instance."""
341 return self
359 return self
342
360
343 #-------------------------------------------------------------------------
361 #-------------------------------------------------------------------------
344 # Trait changed handlers
362 # Trait changed handlers
345 #-------------------------------------------------------------------------
363 #-------------------------------------------------------------------------
346
364
347 def _banner1_changed(self):
365 def _banner1_changed(self):
348 self.compute_banner()
366 self.compute_banner()
349
367
350 def _banner2_changed(self):
368 def _banner2_changed(self):
351 self.compute_banner()
369 self.compute_banner()
352
370
353 def _ipython_dir_changed(self, name, new):
371 def _ipython_dir_changed(self, name, new):
354 if not os.path.isdir(new):
372 if not os.path.isdir(new):
355 os.makedirs(new, mode = 0777)
373 os.makedirs(new, mode = 0777)
356 if not os.path.isdir(self.ipython_extension_dir):
357 os.makedirs(self.ipython_extension_dir, mode = 0777)
358
359 @property
360 def ipython_extension_dir(self):
361 return os.path.join(self.ipython_dir, 'extensions')
362
374
363 @property
375 @property
364 def usable_screen_length(self):
376 def usable_screen_length(self):
365 if self.screen_length == 0:
377 if self.screen_length == 0:
366 return 0
378 return 0
367 else:
379 else:
368 num_lines_bot = self.separate_in.count('\n')+1
380 num_lines_bot = self.separate_in.count('\n')+1
369 return self.screen_length - num_lines_bot
381 return self.screen_length - num_lines_bot
370
382
371 def _term_title_changed(self, name, new_value):
383 def _term_title_changed(self, name, new_value):
372 self.init_term_title()
384 self.init_term_title()
373
385
374 def set_autoindent(self,value=None):
386 def set_autoindent(self,value=None):
375 """Set the autoindent flag, checking for readline support.
387 """Set the autoindent flag, checking for readline support.
376
388
377 If called with no arguments, it acts as a toggle."""
389 If called with no arguments, it acts as a toggle."""
378
390
379 if not self.has_readline:
391 if not self.has_readline:
380 if os.name == 'posix':
392 if os.name == 'posix':
381 warn("The auto-indent feature requires the readline library")
393 warn("The auto-indent feature requires the readline library")
382 self.autoindent = 0
394 self.autoindent = 0
383 return
395 return
384 if value is None:
396 if value is None:
385 self.autoindent = not self.autoindent
397 self.autoindent = not self.autoindent
386 else:
398 else:
387 self.autoindent = value
399 self.autoindent = value
388
400
389 #-------------------------------------------------------------------------
401 #-------------------------------------------------------------------------
390 # init_* methods called by __init__
402 # init_* methods called by __init__
391 #-------------------------------------------------------------------------
403 #-------------------------------------------------------------------------
392
404
393 def init_ipython_dir(self, ipython_dir):
405 def init_ipython_dir(self, ipython_dir):
394 if ipython_dir is not None:
406 if ipython_dir is not None:
395 self.ipython_dir = ipython_dir
407 self.ipython_dir = ipython_dir
396 self.config.Global.ipython_dir = self.ipython_dir
408 self.config.Global.ipython_dir = self.ipython_dir
397 return
409 return
398
410
399 if hasattr(self.config.Global, 'ipython_dir'):
411 if hasattr(self.config.Global, 'ipython_dir'):
400 self.ipython_dir = self.config.Global.ipython_dir
412 self.ipython_dir = self.config.Global.ipython_dir
401 else:
413 else:
402 self.ipython_dir = get_ipython_dir()
414 self.ipython_dir = get_ipython_dir()
403
415
404 # All children can just read this
416 # All children can just read this
405 self.config.Global.ipython_dir = self.ipython_dir
417 self.config.Global.ipython_dir = self.ipython_dir
406
418
407 def init_instance_attrs(self):
419 def init_instance_attrs(self):
408 self.jobs = BackgroundJobManager()
420 self.jobs = BackgroundJobManager()
409 self.more = False
421 self.more = False
410
422
411 # command compiler
423 # command compiler
412 self.compile = codeop.CommandCompiler()
424 self.compile = codeop.CommandCompiler()
413
425
414 # User input buffer
426 # User input buffer
415 self.buffer = []
427 self.buffer = []
416
428
417 # Make an empty namespace, which extension writers can rely on both
429 # Make an empty namespace, which extension writers can rely on both
418 # existing and NEVER being used by ipython itself. This gives them a
430 # existing and NEVER being used by ipython itself. This gives them a
419 # convenient location for storing additional information and state
431 # convenient location for storing additional information and state
420 # their extensions may require, without fear of collisions with other
432 # their extensions may require, without fear of collisions with other
421 # ipython names that may develop later.
433 # ipython names that may develop later.
422 self.meta = Struct()
434 self.meta = Struct()
423
435
424 # Object variable to store code object waiting execution. This is
436 # Object variable to store code object waiting execution. This is
425 # used mainly by the multithreaded shells, but it can come in handy in
437 # used mainly by the multithreaded shells, but it can come in handy in
426 # other situations. No need to use a Queue here, since it's a single
438 # other situations. No need to use a Queue here, since it's a single
427 # item which gets cleared once run.
439 # item which gets cleared once run.
428 self.code_to_run = None
440 self.code_to_run = None
429
441
430 # Flag to mark unconditional exit
442 # Flag to mark unconditional exit
431 self.exit_now = False
443 self.exit_now = False
432
444
433 # Temporary files used for various purposes. Deleted at exit.
445 # Temporary files used for various purposes. Deleted at exit.
434 self.tempfiles = []
446 self.tempfiles = []
435
447
436 # Keep track of readline usage (later set by init_readline)
448 # Keep track of readline usage (later set by init_readline)
437 self.has_readline = False
449 self.has_readline = False
438
450
439 # keep track of where we started running (mainly for crash post-mortem)
451 # keep track of where we started running (mainly for crash post-mortem)
440 # This is not being used anywhere currently.
452 # This is not being used anywhere currently.
441 self.starting_dir = os.getcwd()
453 self.starting_dir = os.getcwd()
442
454
443 # Indentation management
455 # Indentation management
444 self.indent_current_nsp = 0
456 self.indent_current_nsp = 0
445
457
446 def init_term_title(self):
458 def init_term_title(self):
447 # Enable or disable the terminal title.
459 # Enable or disable the terminal title.
448 if self.term_title:
460 if self.term_title:
449 toggle_set_term_title(True)
461 toggle_set_term_title(True)
450 set_term_title('IPython: ' + abbrev_cwd())
462 set_term_title('IPython: ' + abbrev_cwd())
451 else:
463 else:
452 toggle_set_term_title(False)
464 toggle_set_term_title(False)
453
465
454 def init_usage(self, usage=None):
466 def init_usage(self, usage=None):
455 if usage is None:
467 if usage is None:
456 self.usage = interactive_usage
468 self.usage = interactive_usage
457 else:
469 else:
458 self.usage = usage
470 self.usage = usage
459
471
460 def init_encoding(self):
472 def init_encoding(self):
461 # Get system encoding at startup time. Certain terminals (like Emacs
473 # Get system encoding at startup time. Certain terminals (like Emacs
462 # under Win32 have it set to None, and we need to have a known valid
474 # under Win32 have it set to None, and we need to have a known valid
463 # encoding to use in the raw_input() method
475 # encoding to use in the raw_input() method
464 try:
476 try:
465 self.stdin_encoding = sys.stdin.encoding or 'ascii'
477 self.stdin_encoding = sys.stdin.encoding or 'ascii'
466 except AttributeError:
478 except AttributeError:
467 self.stdin_encoding = 'ascii'
479 self.stdin_encoding = 'ascii'
468
480
469 def init_syntax_highlighting(self):
481 def init_syntax_highlighting(self):
470 # Python source parser/formatter for syntax highlighting
482 # Python source parser/formatter for syntax highlighting
471 pyformat = PyColorize.Parser().format
483 pyformat = PyColorize.Parser().format
472 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
484 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
473
485
474 def init_pushd_popd_magic(self):
486 def init_pushd_popd_magic(self):
475 # for pushd/popd management
487 # for pushd/popd management
476 try:
488 try:
477 self.home_dir = get_home_dir()
489 self.home_dir = get_home_dir()
478 except HomeDirError, msg:
490 except HomeDirError, msg:
479 fatal(msg)
491 fatal(msg)
480
492
481 self.dir_stack = []
493 self.dir_stack = []
482
494
483 def init_logger(self):
495 def init_logger(self):
484 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
496 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
485 # local shortcut, this is used a LOT
497 # local shortcut, this is used a LOT
486 self.log = self.logger.log
498 self.log = self.logger.log
487
499
488 def init_logstart(self):
500 def init_logstart(self):
489 if self.logappend:
501 if self.logappend:
490 self.magic_logstart(self.logappend + ' append')
502 self.magic_logstart(self.logappend + ' append')
491 elif self.logfile:
503 elif self.logfile:
492 self.magic_logstart(self.logfile)
504 self.magic_logstart(self.logfile)
493 elif self.logstart:
505 elif self.logstart:
494 self.magic_logstart()
506 self.magic_logstart()
495
507
496 def init_builtins(self):
508 def init_builtins(self):
497 self.builtin_trap = BuiltinTrap(self)
509 self.builtin_trap = BuiltinTrap(self)
498
510
499 def init_inspector(self):
511 def init_inspector(self):
500 # Object inspector
512 # Object inspector
501 self.inspector = oinspect.Inspector(oinspect.InspectColors,
513 self.inspector = oinspect.Inspector(oinspect.InspectColors,
502 PyColorize.ANSICodeColors,
514 PyColorize.ANSICodeColors,
503 'NoColor',
515 'NoColor',
504 self.object_info_string_level)
516 self.object_info_string_level)
505
517
506 def init_prompts(self):
518 def init_prompts(self):
507 # Initialize cache, set in/out prompts and printing system
519 # Initialize cache, set in/out prompts and printing system
508 self.outputcache = CachedOutput(self,
520 self.outputcache = CachedOutput(self,
509 self.cache_size,
521 self.cache_size,
510 self.pprint,
522 self.pprint,
511 input_sep = self.separate_in,
523 input_sep = self.separate_in,
512 output_sep = self.separate_out,
524 output_sep = self.separate_out,
513 output_sep2 = self.separate_out2,
525 output_sep2 = self.separate_out2,
514 ps1 = self.prompt_in1,
526 ps1 = self.prompt_in1,
515 ps2 = self.prompt_in2,
527 ps2 = self.prompt_in2,
516 ps_out = self.prompt_out,
528 ps_out = self.prompt_out,
517 pad_left = self.prompts_pad_left)
529 pad_left = self.prompts_pad_left)
518
530
519 # user may have over-ridden the default print hook:
531 # user may have over-ridden the default print hook:
520 try:
532 try:
521 self.outputcache.__class__.display = self.hooks.display
533 self.outputcache.__class__.display = self.hooks.display
522 except AttributeError:
534 except AttributeError:
523 pass
535 pass
524
536
525 def init_displayhook(self):
537 def init_displayhook(self):
526 self.display_trap = DisplayTrap(self, self.outputcache)
538 self.display_trap = DisplayTrap(self.outputcache)
527
539
528 def init_reload_doctest(self):
540 def init_reload_doctest(self):
529 # Do a proper resetting of doctest, including the necessary displayhook
541 # Do a proper resetting of doctest, including the necessary displayhook
530 # monkeypatching
542 # monkeypatching
531 try:
543 try:
532 doctest_reload()
544 doctest_reload()
533 except ImportError:
545 except ImportError:
534 warn("doctest module does not exist.")
546 warn("doctest module does not exist.")
535
547
536 #-------------------------------------------------------------------------
548 #-------------------------------------------------------------------------
537 # Things related to the banner
549 # Things related to the banner
538 #-------------------------------------------------------------------------
550 #-------------------------------------------------------------------------
539
551
540 def init_banner(self, banner1, banner2, display_banner):
552 def init_banner(self, banner1, banner2, display_banner):
541 if banner1 is not None:
553 if banner1 is not None:
542 self.banner1 = banner1
554 self.banner1 = banner1
543 if banner2 is not None:
555 if banner2 is not None:
544 self.banner2 = banner2
556 self.banner2 = banner2
545 if display_banner is not None:
557 if display_banner is not None:
546 self.display_banner = display_banner
558 self.display_banner = display_banner
547 self.compute_banner()
559 self.compute_banner()
548
560
549 def show_banner(self, banner=None):
561 def show_banner(self, banner=None):
550 if banner is None:
562 if banner is None:
551 banner = self.banner
563 banner = self.banner
552 self.write(banner)
564 self.write(banner)
553
565
554 def compute_banner(self):
566 def compute_banner(self):
555 self.banner = self.banner1 + '\n'
567 self.banner = self.banner1 + '\n'
556 if self.profile:
568 if self.profile:
557 self.banner += '\nIPython profile: %s\n' % self.profile
569 self.banner += '\nIPython profile: %s\n' % self.profile
558 if self.banner2:
570 if self.banner2:
559 self.banner += '\n' + self.banner2 + '\n'
571 self.banner += '\n' + self.banner2 + '\n'
560
572
561 #-------------------------------------------------------------------------
573 #-------------------------------------------------------------------------
562 # Things related to injections into the sys module
574 # Things related to injections into the sys module
563 #-------------------------------------------------------------------------
575 #-------------------------------------------------------------------------
564
576
565 def save_sys_module_state(self):
577 def save_sys_module_state(self):
566 """Save the state of hooks in the sys module.
578 """Save the state of hooks in the sys module.
567
579
568 This has to be called after self.user_ns is created.
580 This has to be called after self.user_ns is created.
569 """
581 """
570 self._orig_sys_module_state = {}
582 self._orig_sys_module_state = {}
571 self._orig_sys_module_state['stdin'] = sys.stdin
583 self._orig_sys_module_state['stdin'] = sys.stdin
572 self._orig_sys_module_state['stdout'] = sys.stdout
584 self._orig_sys_module_state['stdout'] = sys.stdout
573 self._orig_sys_module_state['stderr'] = sys.stderr
585 self._orig_sys_module_state['stderr'] = sys.stderr
574 self._orig_sys_module_state['excepthook'] = sys.excepthook
586 self._orig_sys_module_state['excepthook'] = sys.excepthook
575 try:
587 try:
576 self._orig_sys_modules_main_name = self.user_ns['__name__']
588 self._orig_sys_modules_main_name = self.user_ns['__name__']
577 except KeyError:
589 except KeyError:
578 pass
590 pass
579
591
580 def restore_sys_module_state(self):
592 def restore_sys_module_state(self):
581 """Restore the state of the sys module."""
593 """Restore the state of the sys module."""
582 try:
594 try:
583 for k, v in self._orig_sys_module_state.items():
595 for k, v in self._orig_sys_module_state.items():
584 setattr(sys, k, v)
596 setattr(sys, k, v)
585 except AttributeError:
597 except AttributeError:
586 pass
598 pass
587 try:
599 try:
588 delattr(sys, 'ipcompleter')
600 delattr(sys, 'ipcompleter')
589 except AttributeError:
601 except AttributeError:
590 pass
602 pass
591 # Reset what what done in self.init_sys_modules
603 # Reset what what done in self.init_sys_modules
592 try:
604 try:
593 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
605 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
594 except (AttributeError, KeyError):
606 except (AttributeError, KeyError):
595 pass
607 pass
596
608
597 #-------------------------------------------------------------------------
609 #-------------------------------------------------------------------------
598 # Things related to hooks
610 # Things related to hooks
599 #-------------------------------------------------------------------------
611 #-------------------------------------------------------------------------
600
612
601 def init_hooks(self):
613 def init_hooks(self):
602 # hooks holds pointers used for user-side customizations
614 # hooks holds pointers used for user-side customizations
603 self.hooks = Struct()
615 self.hooks = Struct()
604
616
605 self.strdispatchers = {}
617 self.strdispatchers = {}
606
618
607 # Set all default hooks, defined in the IPython.hooks module.
619 # Set all default hooks, defined in the IPython.hooks module.
608 hooks = IPython.core.hooks
620 hooks = IPython.core.hooks
609 for hook_name in hooks.__all__:
621 for hook_name in hooks.__all__:
610 # default hooks have priority 100, i.e. low; user hooks should have
622 # default hooks have priority 100, i.e. low; user hooks should have
611 # 0-100 priority
623 # 0-100 priority
612 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
624 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
613
625
614 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
626 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
615 """set_hook(name,hook) -> sets an internal IPython hook.
627 """set_hook(name,hook) -> sets an internal IPython hook.
616
628
617 IPython exposes some of its internal API as user-modifiable hooks. By
629 IPython exposes some of its internal API as user-modifiable hooks. By
618 adding your function to one of these hooks, you can modify IPython's
630 adding your function to one of these hooks, you can modify IPython's
619 behavior to call at runtime your own routines."""
631 behavior to call at runtime your own routines."""
620
632
621 # At some point in the future, this should validate the hook before it
633 # At some point in the future, this should validate the hook before it
622 # accepts it. Probably at least check that the hook takes the number
634 # accepts it. Probably at least check that the hook takes the number
623 # of args it's supposed to.
635 # of args it's supposed to.
624
636
625 f = new.instancemethod(hook,self,self.__class__)
637 f = new.instancemethod(hook,self,self.__class__)
626
638
627 # check if the hook is for strdispatcher first
639 # check if the hook is for strdispatcher first
628 if str_key is not None:
640 if str_key is not None:
629 sdp = self.strdispatchers.get(name, StrDispatch())
641 sdp = self.strdispatchers.get(name, StrDispatch())
630 sdp.add_s(str_key, f, priority )
642 sdp.add_s(str_key, f, priority )
631 self.strdispatchers[name] = sdp
643 self.strdispatchers[name] = sdp
632 return
644 return
633 if re_key is not None:
645 if re_key is not None:
634 sdp = self.strdispatchers.get(name, StrDispatch())
646 sdp = self.strdispatchers.get(name, StrDispatch())
635 sdp.add_re(re.compile(re_key), f, priority )
647 sdp.add_re(re.compile(re_key), f, priority )
636 self.strdispatchers[name] = sdp
648 self.strdispatchers[name] = sdp
637 return
649 return
638
650
639 dp = getattr(self.hooks, name, None)
651 dp = getattr(self.hooks, name, None)
640 if name not in IPython.core.hooks.__all__:
652 if name not in IPython.core.hooks.__all__:
641 print "Warning! Hook '%s' is not one of %s" % (name, IPython.core.hooks.__all__ )
653 print "Warning! Hook '%s' is not one of %s" % (name, IPython.core.hooks.__all__ )
642 if not dp:
654 if not dp:
643 dp = IPython.core.hooks.CommandChainDispatcher()
655 dp = IPython.core.hooks.CommandChainDispatcher()
644
656
645 try:
657 try:
646 dp.add(f,priority)
658 dp.add(f,priority)
647 except AttributeError:
659 except AttributeError:
648 # it was not commandchain, plain old func - replace
660 # it was not commandchain, plain old func - replace
649 dp = f
661 dp = f
650
662
651 setattr(self.hooks,name, dp)
663 setattr(self.hooks,name, dp)
652
664
653 #-------------------------------------------------------------------------
665 #-------------------------------------------------------------------------
654 # Things related to the "main" module
666 # Things related to the "main" module
655 #-------------------------------------------------------------------------
667 #-------------------------------------------------------------------------
656
668
657 def new_main_mod(self,ns=None):
669 def new_main_mod(self,ns=None):
658 """Return a new 'main' module object for user code execution.
670 """Return a new 'main' module object for user code execution.
659 """
671 """
660 main_mod = self._user_main_module
672 main_mod = self._user_main_module
661 init_fakemod_dict(main_mod,ns)
673 init_fakemod_dict(main_mod,ns)
662 return main_mod
674 return main_mod
663
675
664 def cache_main_mod(self,ns,fname):
676 def cache_main_mod(self,ns,fname):
665 """Cache a main module's namespace.
677 """Cache a main module's namespace.
666
678
667 When scripts are executed via %run, we must keep a reference to the
679 When scripts are executed via %run, we must keep a reference to the
668 namespace of their __main__ module (a FakeModule instance) around so
680 namespace of their __main__ module (a FakeModule instance) around so
669 that Python doesn't clear it, rendering objects defined therein
681 that Python doesn't clear it, rendering objects defined therein
670 useless.
682 useless.
671
683
672 This method keeps said reference in a private dict, keyed by the
684 This method keeps said reference in a private dict, keyed by the
673 absolute path of the module object (which corresponds to the script
685 absolute path of the module object (which corresponds to the script
674 path). This way, for multiple executions of the same script we only
686 path). This way, for multiple executions of the same script we only
675 keep one copy of the namespace (the last one), thus preventing memory
687 keep one copy of the namespace (the last one), thus preventing memory
676 leaks from old references while allowing the objects from the last
688 leaks from old references while allowing the objects from the last
677 execution to be accessible.
689 execution to be accessible.
678
690
679 Note: we can not allow the actual FakeModule instances to be deleted,
691 Note: we can not allow the actual FakeModule instances to be deleted,
680 because of how Python tears down modules (it hard-sets all their
692 because of how Python tears down modules (it hard-sets all their
681 references to None without regard for reference counts). This method
693 references to None without regard for reference counts). This method
682 must therefore make a *copy* of the given namespace, to allow the
694 must therefore make a *copy* of the given namespace, to allow the
683 original module's __dict__ to be cleared and reused.
695 original module's __dict__ to be cleared and reused.
684
696
685
697
686 Parameters
698 Parameters
687 ----------
699 ----------
688 ns : a namespace (a dict, typically)
700 ns : a namespace (a dict, typically)
689
701
690 fname : str
702 fname : str
691 Filename associated with the namespace.
703 Filename associated with the namespace.
692
704
693 Examples
705 Examples
694 --------
706 --------
695
707
696 In [10]: import IPython
708 In [10]: import IPython
697
709
698 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
710 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
699
711
700 In [12]: IPython.__file__ in _ip._main_ns_cache
712 In [12]: IPython.__file__ in _ip._main_ns_cache
701 Out[12]: True
713 Out[12]: True
702 """
714 """
703 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
715 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
704
716
705 def clear_main_mod_cache(self):
717 def clear_main_mod_cache(self):
706 """Clear the cache of main modules.
718 """Clear the cache of main modules.
707
719
708 Mainly for use by utilities like %reset.
720 Mainly for use by utilities like %reset.
709
721
710 Examples
722 Examples
711 --------
723 --------
712
724
713 In [15]: import IPython
725 In [15]: import IPython
714
726
715 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
727 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
716
728
717 In [17]: len(_ip._main_ns_cache) > 0
729 In [17]: len(_ip._main_ns_cache) > 0
718 Out[17]: True
730 Out[17]: True
719
731
720 In [18]: _ip.clear_main_mod_cache()
732 In [18]: _ip.clear_main_mod_cache()
721
733
722 In [19]: len(_ip._main_ns_cache) == 0
734 In [19]: len(_ip._main_ns_cache) == 0
723 Out[19]: True
735 Out[19]: True
724 """
736 """
725 self._main_ns_cache.clear()
737 self._main_ns_cache.clear()
726
738
727 #-------------------------------------------------------------------------
739 #-------------------------------------------------------------------------
728 # Things related to debugging
740 # Things related to debugging
729 #-------------------------------------------------------------------------
741 #-------------------------------------------------------------------------
730
742
731 def init_pdb(self):
743 def init_pdb(self):
732 # Set calling of pdb on exceptions
744 # Set calling of pdb on exceptions
733 # self.call_pdb is a property
745 # self.call_pdb is a property
734 self.call_pdb = self.pdb
746 self.call_pdb = self.pdb
735
747
736 def _get_call_pdb(self):
748 def _get_call_pdb(self):
737 return self._call_pdb
749 return self._call_pdb
738
750
739 def _set_call_pdb(self,val):
751 def _set_call_pdb(self,val):
740
752
741 if val not in (0,1,False,True):
753 if val not in (0,1,False,True):
742 raise ValueError,'new call_pdb value must be boolean'
754 raise ValueError,'new call_pdb value must be boolean'
743
755
744 # store value in instance
756 # store value in instance
745 self._call_pdb = val
757 self._call_pdb = val
746
758
747 # notify the actual exception handlers
759 # notify the actual exception handlers
748 self.InteractiveTB.call_pdb = val
760 self.InteractiveTB.call_pdb = val
749 if self.isthreaded:
761 if self.isthreaded:
750 try:
762 try:
751 self.sys_excepthook.call_pdb = val
763 self.sys_excepthook.call_pdb = val
752 except:
764 except:
753 warn('Failed to activate pdb for threaded exception handler')
765 warn('Failed to activate pdb for threaded exception handler')
754
766
755 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
767 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
756 'Control auto-activation of pdb at exceptions')
768 'Control auto-activation of pdb at exceptions')
757
769
758 def debugger(self,force=False):
770 def debugger(self,force=False):
759 """Call the pydb/pdb debugger.
771 """Call the pydb/pdb debugger.
760
772
761 Keywords:
773 Keywords:
762
774
763 - force(False): by default, this routine checks the instance call_pdb
775 - force(False): by default, this routine checks the instance call_pdb
764 flag and does not actually invoke the debugger if the flag is false.
776 flag and does not actually invoke the debugger if the flag is false.
765 The 'force' option forces the debugger to activate even if the flag
777 The 'force' option forces the debugger to activate even if the flag
766 is false.
778 is false.
767 """
779 """
768
780
769 if not (force or self.call_pdb):
781 if not (force or self.call_pdb):
770 return
782 return
771
783
772 if not hasattr(sys,'last_traceback'):
784 if not hasattr(sys,'last_traceback'):
773 error('No traceback has been produced, nothing to debug.')
785 error('No traceback has been produced, nothing to debug.')
774 return
786 return
775
787
776 # use pydb if available
788 # use pydb if available
777 if debugger.has_pydb:
789 if debugger.has_pydb:
778 from pydb import pm
790 from pydb import pm
779 else:
791 else:
780 # fallback to our internal debugger
792 # fallback to our internal debugger
781 pm = lambda : self.InteractiveTB.debugger(force=True)
793 pm = lambda : self.InteractiveTB.debugger(force=True)
782 self.history_saving_wrapper(pm)()
794 self.history_saving_wrapper(pm)()
783
795
784 #-------------------------------------------------------------------------
796 #-------------------------------------------------------------------------
785 # Things related to IPython's various namespaces
797 # Things related to IPython's various namespaces
786 #-------------------------------------------------------------------------
798 #-------------------------------------------------------------------------
787
799
788 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
800 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
789 # Create the namespace where the user will operate. user_ns is
801 # Create the namespace where the user will operate. user_ns is
790 # normally the only one used, and it is passed to the exec calls as
802 # normally the only one used, and it is passed to the exec calls as
791 # the locals argument. But we do carry a user_global_ns namespace
803 # the locals argument. But we do carry a user_global_ns namespace
792 # given as the exec 'globals' argument, This is useful in embedding
804 # given as the exec 'globals' argument, This is useful in embedding
793 # situations where the ipython shell opens in a context where the
805 # situations where the ipython shell opens in a context where the
794 # distinction between locals and globals is meaningful. For
806 # distinction between locals and globals is meaningful. For
795 # non-embedded contexts, it is just the same object as the user_ns dict.
807 # non-embedded contexts, it is just the same object as the user_ns dict.
796
808
797 # FIXME. For some strange reason, __builtins__ is showing up at user
809 # FIXME. For some strange reason, __builtins__ is showing up at user
798 # level as a dict instead of a module. This is a manual fix, but I
810 # level as a dict instead of a module. This is a manual fix, but I
799 # should really track down where the problem is coming from. Alex
811 # should really track down where the problem is coming from. Alex
800 # Schmolck reported this problem first.
812 # Schmolck reported this problem first.
801
813
802 # A useful post by Alex Martelli on this topic:
814 # A useful post by Alex Martelli on this topic:
803 # Re: inconsistent value from __builtins__
815 # Re: inconsistent value from __builtins__
804 # Von: Alex Martelli <aleaxit@yahoo.com>
816 # Von: Alex Martelli <aleaxit@yahoo.com>
805 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
817 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
806 # Gruppen: comp.lang.python
818 # Gruppen: comp.lang.python
807
819
808 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
820 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
809 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
821 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
810 # > <type 'dict'>
822 # > <type 'dict'>
811 # > >>> print type(__builtins__)
823 # > >>> print type(__builtins__)
812 # > <type 'module'>
824 # > <type 'module'>
813 # > Is this difference in return value intentional?
825 # > Is this difference in return value intentional?
814
826
815 # Well, it's documented that '__builtins__' can be either a dictionary
827 # Well, it's documented that '__builtins__' can be either a dictionary
816 # or a module, and it's been that way for a long time. Whether it's
828 # or a module, and it's been that way for a long time. Whether it's
817 # intentional (or sensible), I don't know. In any case, the idea is
829 # intentional (or sensible), I don't know. In any case, the idea is
818 # that if you need to access the built-in namespace directly, you
830 # that if you need to access the built-in namespace directly, you
819 # should start with "import __builtin__" (note, no 's') which will
831 # should start with "import __builtin__" (note, no 's') which will
820 # definitely give you a module. Yeah, it's somewhat confusing:-(.
832 # definitely give you a module. Yeah, it's somewhat confusing:-(.
821
833
822 # These routines return properly built dicts as needed by the rest of
834 # These routines return properly built dicts as needed by the rest of
823 # the code, and can also be used by extension writers to generate
835 # the code, and can also be used by extension writers to generate
824 # properly initialized namespaces.
836 # properly initialized namespaces.
825 user_ns, user_global_ns = self.make_user_namespaces(user_ns, user_global_ns)
837 user_ns, user_global_ns = self.make_user_namespaces(user_ns, user_global_ns)
826
838
827 # Assign namespaces
839 # Assign namespaces
828 # This is the namespace where all normal user variables live
840 # This is the namespace where all normal user variables live
829 self.user_ns = user_ns
841 self.user_ns = user_ns
830 self.user_global_ns = user_global_ns
842 self.user_global_ns = user_global_ns
831
843
832 # An auxiliary namespace that checks what parts of the user_ns were
844 # An auxiliary namespace that checks what parts of the user_ns were
833 # loaded at startup, so we can list later only variables defined in
845 # loaded at startup, so we can list later only variables defined in
834 # actual interactive use. Since it is always a subset of user_ns, it
846 # actual interactive use. Since it is always a subset of user_ns, it
835 # doesn't need to be separately tracked in the ns_table.
847 # doesn't need to be separately tracked in the ns_table.
836 self.user_ns_hidden = {}
848 self.user_ns_hidden = {}
837
849
838 # A namespace to keep track of internal data structures to prevent
850 # A namespace to keep track of internal data structures to prevent
839 # them from cluttering user-visible stuff. Will be updated later
851 # them from cluttering user-visible stuff. Will be updated later
840 self.internal_ns = {}
852 self.internal_ns = {}
841
853
842 # Now that FakeModule produces a real module, we've run into a nasty
854 # Now that FakeModule produces a real module, we've run into a nasty
843 # problem: after script execution (via %run), the module where the user
855 # problem: after script execution (via %run), the module where the user
844 # code ran is deleted. Now that this object is a true module (needed
856 # code ran is deleted. Now that this object is a true module (needed
845 # so docetst and other tools work correctly), the Python module
857 # so docetst and other tools work correctly), the Python module
846 # teardown mechanism runs over it, and sets to None every variable
858 # teardown mechanism runs over it, and sets to None every variable
847 # present in that module. Top-level references to objects from the
859 # present in that module. Top-level references to objects from the
848 # script survive, because the user_ns is updated with them. However,
860 # script survive, because the user_ns is updated with them. However,
849 # calling functions defined in the script that use other things from
861 # calling functions defined in the script that use other things from
850 # the script will fail, because the function's closure had references
862 # the script will fail, because the function's closure had references
851 # to the original objects, which are now all None. So we must protect
863 # to the original objects, which are now all None. So we must protect
852 # these modules from deletion by keeping a cache.
864 # these modules from deletion by keeping a cache.
853 #
865 #
854 # To avoid keeping stale modules around (we only need the one from the
866 # To avoid keeping stale modules around (we only need the one from the
855 # last run), we use a dict keyed with the full path to the script, so
867 # last run), we use a dict keyed with the full path to the script, so
856 # only the last version of the module is held in the cache. Note,
868 # only the last version of the module is held in the cache. Note,
857 # however, that we must cache the module *namespace contents* (their
869 # however, that we must cache the module *namespace contents* (their
858 # __dict__). Because if we try to cache the actual modules, old ones
870 # __dict__). Because if we try to cache the actual modules, old ones
859 # (uncached) could be destroyed while still holding references (such as
871 # (uncached) could be destroyed while still holding references (such as
860 # those held by GUI objects that tend to be long-lived)>
872 # those held by GUI objects that tend to be long-lived)>
861 #
873 #
862 # The %reset command will flush this cache. See the cache_main_mod()
874 # The %reset command will flush this cache. See the cache_main_mod()
863 # and clear_main_mod_cache() methods for details on use.
875 # and clear_main_mod_cache() methods for details on use.
864
876
865 # This is the cache used for 'main' namespaces
877 # This is the cache used for 'main' namespaces
866 self._main_ns_cache = {}
878 self._main_ns_cache = {}
867 # And this is the single instance of FakeModule whose __dict__ we keep
879 # And this is the single instance of FakeModule whose __dict__ we keep
868 # copying and clearing for reuse on each %run
880 # copying and clearing for reuse on each %run
869 self._user_main_module = FakeModule()
881 self._user_main_module = FakeModule()
870
882
871 # A table holding all the namespaces IPython deals with, so that
883 # A table holding all the namespaces IPython deals with, so that
872 # introspection facilities can search easily.
884 # introspection facilities can search easily.
873 self.ns_table = {'user':user_ns,
885 self.ns_table = {'user':user_ns,
874 'user_global':user_global_ns,
886 'user_global':user_global_ns,
875 'internal':self.internal_ns,
887 'internal':self.internal_ns,
876 'builtin':__builtin__.__dict__
888 'builtin':__builtin__.__dict__
877 }
889 }
878
890
879 # Similarly, track all namespaces where references can be held and that
891 # Similarly, track all namespaces where references can be held and that
880 # we can safely clear (so it can NOT include builtin). This one can be
892 # we can safely clear (so it can NOT include builtin). This one can be
881 # a simple list.
893 # a simple list.
882 self.ns_refs_table = [ user_ns, user_global_ns, self.user_ns_hidden,
894 self.ns_refs_table = [ user_ns, user_global_ns, self.user_ns_hidden,
883 self.internal_ns, self._main_ns_cache ]
895 self.internal_ns, self._main_ns_cache ]
884
896
885 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
897 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
886 """Return a valid local and global user interactive namespaces.
898 """Return a valid local and global user interactive namespaces.
887
899
888 This builds a dict with the minimal information needed to operate as a
900 This builds a dict with the minimal information needed to operate as a
889 valid IPython user namespace, which you can pass to the various
901 valid IPython user namespace, which you can pass to the various
890 embedding classes in ipython. The default implementation returns the
902 embedding classes in ipython. The default implementation returns the
891 same dict for both the locals and the globals to allow functions to
903 same dict for both the locals and the globals to allow functions to
892 refer to variables in the namespace. Customized implementations can
904 refer to variables in the namespace. Customized implementations can
893 return different dicts. The locals dictionary can actually be anything
905 return different dicts. The locals dictionary can actually be anything
894 following the basic mapping protocol of a dict, but the globals dict
906 following the basic mapping protocol of a dict, but the globals dict
895 must be a true dict, not even a subclass. It is recommended that any
907 must be a true dict, not even a subclass. It is recommended that any
896 custom object for the locals namespace synchronize with the globals
908 custom object for the locals namespace synchronize with the globals
897 dict somehow.
909 dict somehow.
898
910
899 Raises TypeError if the provided globals namespace is not a true dict.
911 Raises TypeError if the provided globals namespace is not a true dict.
900
912
901 Parameters
913 Parameters
902 ----------
914 ----------
903 user_ns : dict-like, optional
915 user_ns : dict-like, optional
904 The current user namespace. The items in this namespace should
916 The current user namespace. The items in this namespace should
905 be included in the output. If None, an appropriate blank
917 be included in the output. If None, an appropriate blank
906 namespace should be created.
918 namespace should be created.
907 user_global_ns : dict, optional
919 user_global_ns : dict, optional
908 The current user global namespace. The items in this namespace
920 The current user global namespace. The items in this namespace
909 should be included in the output. If None, an appropriate
921 should be included in the output. If None, an appropriate
910 blank namespace should be created.
922 blank namespace should be created.
911
923
912 Returns
924 Returns
913 -------
925 -------
914 A pair of dictionary-like object to be used as the local namespace
926 A pair of dictionary-like object to be used as the local namespace
915 of the interpreter and a dict to be used as the global namespace.
927 of the interpreter and a dict to be used as the global namespace.
916 """
928 """
917
929
918
930
919 # We must ensure that __builtin__ (without the final 's') is always
931 # We must ensure that __builtin__ (without the final 's') is always
920 # available and pointing to the __builtin__ *module*. For more details:
932 # available and pointing to the __builtin__ *module*. For more details:
921 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
933 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
922
934
923 if user_ns is None:
935 if user_ns is None:
924 # Set __name__ to __main__ to better match the behavior of the
936 # Set __name__ to __main__ to better match the behavior of the
925 # normal interpreter.
937 # normal interpreter.
926 user_ns = {'__name__' :'__main__',
938 user_ns = {'__name__' :'__main__',
927 '__builtin__' : __builtin__,
939 '__builtin__' : __builtin__,
928 '__builtins__' : __builtin__,
940 '__builtins__' : __builtin__,
929 }
941 }
930 else:
942 else:
931 user_ns.setdefault('__name__','__main__')
943 user_ns.setdefault('__name__','__main__')
932 user_ns.setdefault('__builtin__',__builtin__)
944 user_ns.setdefault('__builtin__',__builtin__)
933 user_ns.setdefault('__builtins__',__builtin__)
945 user_ns.setdefault('__builtins__',__builtin__)
934
946
935 if user_global_ns is None:
947 if user_global_ns is None:
936 user_global_ns = user_ns
948 user_global_ns = user_ns
937 if type(user_global_ns) is not dict:
949 if type(user_global_ns) is not dict:
938 raise TypeError("user_global_ns must be a true dict; got %r"
950 raise TypeError("user_global_ns must be a true dict; got %r"
939 % type(user_global_ns))
951 % type(user_global_ns))
940
952
941 return user_ns, user_global_ns
953 return user_ns, user_global_ns
942
954
943 def init_sys_modules(self):
955 def init_sys_modules(self):
944 # We need to insert into sys.modules something that looks like a
956 # We need to insert into sys.modules something that looks like a
945 # module but which accesses the IPython namespace, for shelve and
957 # module but which accesses the IPython namespace, for shelve and
946 # pickle to work interactively. Normally they rely on getting
958 # pickle to work interactively. Normally they rely on getting
947 # everything out of __main__, but for embedding purposes each IPython
959 # everything out of __main__, but for embedding purposes each IPython
948 # instance has its own private namespace, so we can't go shoving
960 # instance has its own private namespace, so we can't go shoving
949 # everything into __main__.
961 # everything into __main__.
950
962
951 # note, however, that we should only do this for non-embedded
963 # note, however, that we should only do this for non-embedded
952 # ipythons, which really mimic the __main__.__dict__ with their own
964 # ipythons, which really mimic the __main__.__dict__ with their own
953 # namespace. Embedded instances, on the other hand, should not do
965 # namespace. Embedded instances, on the other hand, should not do
954 # this because they need to manage the user local/global namespaces
966 # this because they need to manage the user local/global namespaces
955 # only, but they live within a 'normal' __main__ (meaning, they
967 # only, but they live within a 'normal' __main__ (meaning, they
956 # shouldn't overtake the execution environment of the script they're
968 # shouldn't overtake the execution environment of the script they're
957 # embedded in).
969 # embedded in).
958
970
959 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
971 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
960
972
961 try:
973 try:
962 main_name = self.user_ns['__name__']
974 main_name = self.user_ns['__name__']
963 except KeyError:
975 except KeyError:
964 raise KeyError('user_ns dictionary MUST have a "__name__" key')
976 raise KeyError('user_ns dictionary MUST have a "__name__" key')
965 else:
977 else:
966 sys.modules[main_name] = FakeModule(self.user_ns)
978 sys.modules[main_name] = FakeModule(self.user_ns)
967
979
968 def init_user_ns(self):
980 def init_user_ns(self):
969 """Initialize all user-visible namespaces to their minimum defaults.
981 """Initialize all user-visible namespaces to their minimum defaults.
970
982
971 Certain history lists are also initialized here, as they effectively
983 Certain history lists are also initialized here, as they effectively
972 act as user namespaces.
984 act as user namespaces.
973
985
974 Notes
986 Notes
975 -----
987 -----
976 All data structures here are only filled in, they are NOT reset by this
988 All data structures here are only filled in, they are NOT reset by this
977 method. If they were not empty before, data will simply be added to
989 method. If they were not empty before, data will simply be added to
978 therm.
990 therm.
979 """
991 """
980 # This function works in two parts: first we put a few things in
992 # This function works in two parts: first we put a few things in
981 # user_ns, and we sync that contents into user_ns_hidden so that these
993 # user_ns, and we sync that contents into user_ns_hidden so that these
982 # initial variables aren't shown by %who. After the sync, we add the
994 # initial variables aren't shown by %who. After the sync, we add the
983 # rest of what we *do* want the user to see with %who even on a new
995 # rest of what we *do* want the user to see with %who even on a new
984 # session (probably nothing, so theye really only see their own stuff)
996 # session (probably nothing, so theye really only see their own stuff)
985
997
986 # The user dict must *always* have a __builtin__ reference to the
998 # The user dict must *always* have a __builtin__ reference to the
987 # Python standard __builtin__ namespace, which must be imported.
999 # Python standard __builtin__ namespace, which must be imported.
988 # This is so that certain operations in prompt evaluation can be
1000 # This is so that certain operations in prompt evaluation can be
989 # reliably executed with builtins. Note that we can NOT use
1001 # reliably executed with builtins. Note that we can NOT use
990 # __builtins__ (note the 's'), because that can either be a dict or a
1002 # __builtins__ (note the 's'), because that can either be a dict or a
991 # module, and can even mutate at runtime, depending on the context
1003 # module, and can even mutate at runtime, depending on the context
992 # (Python makes no guarantees on it). In contrast, __builtin__ is
1004 # (Python makes no guarantees on it). In contrast, __builtin__ is
993 # always a module object, though it must be explicitly imported.
1005 # always a module object, though it must be explicitly imported.
994
1006
995 # For more details:
1007 # For more details:
996 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1008 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
997 ns = dict(__builtin__ = __builtin__)
1009 ns = dict(__builtin__ = __builtin__)
998
1010
999 # Put 'help' in the user namespace
1011 # Put 'help' in the user namespace
1000 try:
1012 try:
1001 from site import _Helper
1013 from site import _Helper
1002 ns['help'] = _Helper()
1014 ns['help'] = _Helper()
1003 except ImportError:
1015 except ImportError:
1004 warn('help() not available - check site.py')
1016 warn('help() not available - check site.py')
1005
1017
1006 # make global variables for user access to the histories
1018 # make global variables for user access to the histories
1007 ns['_ih'] = self.input_hist
1019 ns['_ih'] = self.input_hist
1008 ns['_oh'] = self.output_hist
1020 ns['_oh'] = self.output_hist
1009 ns['_dh'] = self.dir_hist
1021 ns['_dh'] = self.dir_hist
1010
1022
1011 ns['_sh'] = shadowns
1023 ns['_sh'] = shadowns
1012
1024
1013 # user aliases to input and output histories. These shouldn't show up
1025 # user aliases to input and output histories. These shouldn't show up
1014 # in %who, as they can have very large reprs.
1026 # in %who, as they can have very large reprs.
1015 ns['In'] = self.input_hist
1027 ns['In'] = self.input_hist
1016 ns['Out'] = self.output_hist
1028 ns['Out'] = self.output_hist
1017
1029
1018 # Store myself as the public api!!!
1030 # Store myself as the public api!!!
1019 ns['get_ipython'] = self.get_ipython
1031 ns['get_ipython'] = self.get_ipython
1020
1032
1021 # Sync what we've added so far to user_ns_hidden so these aren't seen
1033 # Sync what we've added so far to user_ns_hidden so these aren't seen
1022 # by %who
1034 # by %who
1023 self.user_ns_hidden.update(ns)
1035 self.user_ns_hidden.update(ns)
1024
1036
1025 # Anything put into ns now would show up in %who. Think twice before
1037 # Anything put into ns now would show up in %who. Think twice before
1026 # putting anything here, as we really want %who to show the user their
1038 # putting anything here, as we really want %who to show the user their
1027 # stuff, not our variables.
1039 # stuff, not our variables.
1028
1040
1029 # Finally, update the real user's namespace
1041 # Finally, update the real user's namespace
1030 self.user_ns.update(ns)
1042 self.user_ns.update(ns)
1031
1043
1032
1044
1033 def reset(self):
1045 def reset(self):
1034 """Clear all internal namespaces.
1046 """Clear all internal namespaces.
1035
1047
1036 Note that this is much more aggressive than %reset, since it clears
1048 Note that this is much more aggressive than %reset, since it clears
1037 fully all namespaces, as well as all input/output lists.
1049 fully all namespaces, as well as all input/output lists.
1038 """
1050 """
1039 for ns in self.ns_refs_table:
1051 for ns in self.ns_refs_table:
1040 ns.clear()
1052 ns.clear()
1041
1053
1042 self.alias_manager.clear_aliases()
1054 self.alias_manager.clear_aliases()
1043
1055
1044 # Clear input and output histories
1056 # Clear input and output histories
1045 self.input_hist[:] = []
1057 self.input_hist[:] = []
1046 self.input_hist_raw[:] = []
1058 self.input_hist_raw[:] = []
1047 self.output_hist.clear()
1059 self.output_hist.clear()
1048
1060
1049 # Restore the user namespaces to minimal usability
1061 # Restore the user namespaces to minimal usability
1050 self.init_user_ns()
1062 self.init_user_ns()
1051
1063
1052 # Restore the default and user aliases
1064 # Restore the default and user aliases
1053 self.alias_manager.init_aliases()
1065 self.alias_manager.init_aliases()
1054
1066
1055 def reset_selective(self, regex=None):
1067 def reset_selective(self, regex=None):
1056 """Clear selective variables from internal namespaces based on a specified regular expression.
1068 """Clear selective variables from internal namespaces based on a specified regular expression.
1057
1069
1058 Parameters
1070 Parameters
1059 ----------
1071 ----------
1060 regex : string or compiled pattern, optional
1072 regex : string or compiled pattern, optional
1061 A regular expression pattern that will be used in searching variable names in the users
1073 A regular expression pattern that will be used in searching variable names in the users
1062 namespaces.
1074 namespaces.
1063 """
1075 """
1064 if regex is not None:
1076 if regex is not None:
1065 try:
1077 try:
1066 m = re.compile(regex)
1078 m = re.compile(regex)
1067 except TypeError:
1079 except TypeError:
1068 raise TypeError('regex must be a string or compiled pattern')
1080 raise TypeError('regex must be a string or compiled pattern')
1069 # Search for keys in each namespace that match the given regex
1081 # Search for keys in each namespace that match the given regex
1070 # If a match is found, delete the key/value pair.
1082 # If a match is found, delete the key/value pair.
1071 for ns in self.ns_refs_table:
1083 for ns in self.ns_refs_table:
1072 for var in ns:
1084 for var in ns:
1073 if m.search(var):
1085 if m.search(var):
1074 del ns[var]
1086 del ns[var]
1075
1087
1076 def push(self, variables, interactive=True):
1088 def push(self, variables, interactive=True):
1077 """Inject a group of variables into the IPython user namespace.
1089 """Inject a group of variables into the IPython user namespace.
1078
1090
1079 Parameters
1091 Parameters
1080 ----------
1092 ----------
1081 variables : dict, str or list/tuple of str
1093 variables : dict, str or list/tuple of str
1082 The variables to inject into the user's namespace. If a dict,
1094 The variables to inject into the user's namespace. If a dict,
1083 a simple update is done. If a str, the string is assumed to
1095 a simple update is done. If a str, the string is assumed to
1084 have variable names separated by spaces. A list/tuple of str
1096 have variable names separated by spaces. A list/tuple of str
1085 can also be used to give the variable names. If just the variable
1097 can also be used to give the variable names. If just the variable
1086 names are give (list/tuple/str) then the variable values looked
1098 names are give (list/tuple/str) then the variable values looked
1087 up in the callers frame.
1099 up in the callers frame.
1088 interactive : bool
1100 interactive : bool
1089 If True (default), the variables will be listed with the ``who``
1101 If True (default), the variables will be listed with the ``who``
1090 magic.
1102 magic.
1091 """
1103 """
1092 vdict = None
1104 vdict = None
1093
1105
1094 # We need a dict of name/value pairs to do namespace updates.
1106 # We need a dict of name/value pairs to do namespace updates.
1095 if isinstance(variables, dict):
1107 if isinstance(variables, dict):
1096 vdict = variables
1108 vdict = variables
1097 elif isinstance(variables, (basestring, list, tuple)):
1109 elif isinstance(variables, (basestring, list, tuple)):
1098 if isinstance(variables, basestring):
1110 if isinstance(variables, basestring):
1099 vlist = variables.split()
1111 vlist = variables.split()
1100 else:
1112 else:
1101 vlist = variables
1113 vlist = variables
1102 vdict = {}
1114 vdict = {}
1103 cf = sys._getframe(1)
1115 cf = sys._getframe(1)
1104 for name in vlist:
1116 for name in vlist:
1105 try:
1117 try:
1106 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1118 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1107 except:
1119 except:
1108 print ('Could not get variable %s from %s' %
1120 print ('Could not get variable %s from %s' %
1109 (name,cf.f_code.co_name))
1121 (name,cf.f_code.co_name))
1110 else:
1122 else:
1111 raise ValueError('variables must be a dict/str/list/tuple')
1123 raise ValueError('variables must be a dict/str/list/tuple')
1112
1124
1113 # Propagate variables to user namespace
1125 # Propagate variables to user namespace
1114 self.user_ns.update(vdict)
1126 self.user_ns.update(vdict)
1115
1127
1116 # And configure interactive visibility
1128 # And configure interactive visibility
1117 config_ns = self.user_ns_hidden
1129 config_ns = self.user_ns_hidden
1118 if interactive:
1130 if interactive:
1119 for name, val in vdict.iteritems():
1131 for name, val in vdict.iteritems():
1120 config_ns.pop(name, None)
1132 config_ns.pop(name, None)
1121 else:
1133 else:
1122 for name,val in vdict.iteritems():
1134 for name,val in vdict.iteritems():
1123 config_ns[name] = val
1135 config_ns[name] = val
1124
1136
1125 #-------------------------------------------------------------------------
1137 #-------------------------------------------------------------------------
1126 # Things related to history management
1138 # Things related to history management
1127 #-------------------------------------------------------------------------
1139 #-------------------------------------------------------------------------
1128
1140
1129 def init_history(self):
1141 def init_history(self):
1130 # List of input with multi-line handling.
1142 # List of input with multi-line handling.
1131 self.input_hist = InputList()
1143 self.input_hist = InputList()
1132 # This one will hold the 'raw' input history, without any
1144 # This one will hold the 'raw' input history, without any
1133 # pre-processing. This will allow users to retrieve the input just as
1145 # pre-processing. This will allow users to retrieve the input just as
1134 # it was exactly typed in by the user, with %hist -r.
1146 # it was exactly typed in by the user, with %hist -r.
1135 self.input_hist_raw = InputList()
1147 self.input_hist_raw = InputList()
1136
1148
1137 # list of visited directories
1149 # list of visited directories
1138 try:
1150 try:
1139 self.dir_hist = [os.getcwd()]
1151 self.dir_hist = [os.getcwd()]
1140 except OSError:
1152 except OSError:
1141 self.dir_hist = []
1153 self.dir_hist = []
1142
1154
1143 # dict of output history
1155 # dict of output history
1144 self.output_hist = {}
1156 self.output_hist = {}
1145
1157
1146 # Now the history file
1158 # Now the history file
1147 if self.profile:
1159 if self.profile:
1148 histfname = 'history-%s' % self.profile
1160 histfname = 'history-%s' % self.profile
1149 else:
1161 else:
1150 histfname = 'history'
1162 histfname = 'history'
1151 self.histfile = os.path.join(self.ipython_dir, histfname)
1163 self.histfile = os.path.join(self.ipython_dir, histfname)
1152
1164
1153 # Fill the history zero entry, user counter starts at 1
1165 # Fill the history zero entry, user counter starts at 1
1154 self.input_hist.append('\n')
1166 self.input_hist.append('\n')
1155 self.input_hist_raw.append('\n')
1167 self.input_hist_raw.append('\n')
1156
1168
1157 def init_shadow_hist(self):
1169 def init_shadow_hist(self):
1158 try:
1170 try:
1159 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1171 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1160 except exceptions.UnicodeDecodeError:
1172 except exceptions.UnicodeDecodeError:
1161 print "Your ipython_dir can't be decoded to unicode!"
1173 print "Your ipython_dir can't be decoded to unicode!"
1162 print "Please set HOME environment variable to something that"
1174 print "Please set HOME environment variable to something that"
1163 print r"only has ASCII characters, e.g. c:\home"
1175 print r"only has ASCII characters, e.g. c:\home"
1164 print "Now it is", self.ipython_dir
1176 print "Now it is", self.ipython_dir
1165 sys.exit()
1177 sys.exit()
1166 self.shadowhist = ipcorehist.ShadowHist(self.db)
1178 self.shadowhist = ipcorehist.ShadowHist(self.db)
1167
1179
1168 def savehist(self):
1180 def savehist(self):
1169 """Save input history to a file (via readline library)."""
1181 """Save input history to a file (via readline library)."""
1170
1182
1171 try:
1183 try:
1172 self.readline.write_history_file(self.histfile)
1184 self.readline.write_history_file(self.histfile)
1173 except:
1185 except:
1174 print 'Unable to save IPython command history to file: ' + \
1186 print 'Unable to save IPython command history to file: ' + \
1175 `self.histfile`
1187 `self.histfile`
1176
1188
1177 def reloadhist(self):
1189 def reloadhist(self):
1178 """Reload the input history from disk file."""
1190 """Reload the input history from disk file."""
1179
1191
1180 try:
1192 try:
1181 self.readline.clear_history()
1193 self.readline.clear_history()
1182 self.readline.read_history_file(self.shell.histfile)
1194 self.readline.read_history_file(self.shell.histfile)
1183 except AttributeError:
1195 except AttributeError:
1184 pass
1196 pass
1185
1197
1186 def history_saving_wrapper(self, func):
1198 def history_saving_wrapper(self, func):
1187 """ Wrap func for readline history saving
1199 """ Wrap func for readline history saving
1188
1200
1189 Convert func into callable that saves & restores
1201 Convert func into callable that saves & restores
1190 history around the call """
1202 history around the call """
1191
1203
1192 if self.has_readline:
1204 if self.has_readline:
1193 from IPython.utils import rlineimpl as readline
1205 from IPython.utils import rlineimpl as readline
1194 else:
1206 else:
1195 return func
1207 return func
1196
1208
1197 def wrapper():
1209 def wrapper():
1198 self.savehist()
1210 self.savehist()
1199 try:
1211 try:
1200 func()
1212 func()
1201 finally:
1213 finally:
1202 readline.read_history_file(self.histfile)
1214 readline.read_history_file(self.histfile)
1203 return wrapper
1215 return wrapper
1204
1216
1205 #-------------------------------------------------------------------------
1217 #-------------------------------------------------------------------------
1206 # Things related to exception handling and tracebacks (not debugging)
1218 # Things related to exception handling and tracebacks (not debugging)
1207 #-------------------------------------------------------------------------
1219 #-------------------------------------------------------------------------
1208
1220
1209 def init_traceback_handlers(self, custom_exceptions):
1221 def init_traceback_handlers(self, custom_exceptions):
1210 # Syntax error handler.
1222 # Syntax error handler.
1211 self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
1223 self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
1212
1224
1213 # The interactive one is initialized with an offset, meaning we always
1225 # The interactive one is initialized with an offset, meaning we always
1214 # want to remove the topmost item in the traceback, which is our own
1226 # want to remove the topmost item in the traceback, which is our own
1215 # internal code. Valid modes: ['Plain','Context','Verbose']
1227 # internal code. Valid modes: ['Plain','Context','Verbose']
1216 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1228 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1217 color_scheme='NoColor',
1229 color_scheme='NoColor',
1218 tb_offset = 1)
1230 tb_offset = 1)
1219
1231
1220 # The instance will store a pointer to the system-wide exception hook,
1232 # The instance will store a pointer to the system-wide exception hook,
1221 # so that runtime code (such as magics) can access it. This is because
1233 # so that runtime code (such as magics) can access it. This is because
1222 # during the read-eval loop, it may get temporarily overwritten.
1234 # during the read-eval loop, it may get temporarily overwritten.
1223 self.sys_excepthook = sys.excepthook
1235 self.sys_excepthook = sys.excepthook
1224
1236
1225 # and add any custom exception handlers the user may have specified
1237 # and add any custom exception handlers the user may have specified
1226 self.set_custom_exc(*custom_exceptions)
1238 self.set_custom_exc(*custom_exceptions)
1227
1239
1228 # Set the exception mode
1240 # Set the exception mode
1229 self.InteractiveTB.set_mode(mode=self.xmode)
1241 self.InteractiveTB.set_mode(mode=self.xmode)
1230
1242
1231 def set_custom_exc(self,exc_tuple,handler):
1243 def set_custom_exc(self,exc_tuple,handler):
1232 """set_custom_exc(exc_tuple,handler)
1244 """set_custom_exc(exc_tuple,handler)
1233
1245
1234 Set a custom exception handler, which will be called if any of the
1246 Set a custom exception handler, which will be called if any of the
1235 exceptions in exc_tuple occur in the mainloop (specifically, in the
1247 exceptions in exc_tuple occur in the mainloop (specifically, in the
1236 runcode() method.
1248 runcode() method.
1237
1249
1238 Inputs:
1250 Inputs:
1239
1251
1240 - exc_tuple: a *tuple* of valid exceptions to call the defined
1252 - exc_tuple: a *tuple* of valid exceptions to call the defined
1241 handler for. It is very important that you use a tuple, and NOT A
1253 handler for. It is very important that you use a tuple, and NOT A
1242 LIST here, because of the way Python's except statement works. If
1254 LIST here, because of the way Python's except statement works. If
1243 you only want to trap a single exception, use a singleton tuple:
1255 you only want to trap a single exception, use a singleton tuple:
1244
1256
1245 exc_tuple == (MyCustomException,)
1257 exc_tuple == (MyCustomException,)
1246
1258
1247 - handler: this must be defined as a function with the following
1259 - handler: this must be defined as a function with the following
1248 basic interface: def my_handler(self,etype,value,tb).
1260 basic interface: def my_handler(self,etype,value,tb).
1249
1261
1250 This will be made into an instance method (via new.instancemethod)
1262 This will be made into an instance method (via new.instancemethod)
1251 of IPython itself, and it will be called if any of the exceptions
1263 of IPython itself, and it will be called if any of the exceptions
1252 listed in the exc_tuple are caught. If the handler is None, an
1264 listed in the exc_tuple are caught. If the handler is None, an
1253 internal basic one is used, which just prints basic info.
1265 internal basic one is used, which just prints basic info.
1254
1266
1255 WARNING: by putting in your own exception handler into IPython's main
1267 WARNING: by putting in your own exception handler into IPython's main
1256 execution loop, you run a very good chance of nasty crashes. This
1268 execution loop, you run a very good chance of nasty crashes. This
1257 facility should only be used if you really know what you are doing."""
1269 facility should only be used if you really know what you are doing."""
1258
1270
1259 assert type(exc_tuple)==type(()) , \
1271 assert type(exc_tuple)==type(()) , \
1260 "The custom exceptions must be given AS A TUPLE."
1272 "The custom exceptions must be given AS A TUPLE."
1261
1273
1262 def dummy_handler(self,etype,value,tb):
1274 def dummy_handler(self,etype,value,tb):
1263 print '*** Simple custom exception handler ***'
1275 print '*** Simple custom exception handler ***'
1264 print 'Exception type :',etype
1276 print 'Exception type :',etype
1265 print 'Exception value:',value
1277 print 'Exception value:',value
1266 print 'Traceback :',tb
1278 print 'Traceback :',tb
1267 print 'Source code :','\n'.join(self.buffer)
1279 print 'Source code :','\n'.join(self.buffer)
1268
1280
1269 if handler is None: handler = dummy_handler
1281 if handler is None: handler = dummy_handler
1270
1282
1271 self.CustomTB = new.instancemethod(handler,self,self.__class__)
1283 self.CustomTB = new.instancemethod(handler,self,self.__class__)
1272 self.custom_exceptions = exc_tuple
1284 self.custom_exceptions = exc_tuple
1273
1285
1274 def excepthook(self, etype, value, tb):
1286 def excepthook(self, etype, value, tb):
1275 """One more defense for GUI apps that call sys.excepthook.
1287 """One more defense for GUI apps that call sys.excepthook.
1276
1288
1277 GUI frameworks like wxPython trap exceptions and call
1289 GUI frameworks like wxPython trap exceptions and call
1278 sys.excepthook themselves. I guess this is a feature that
1290 sys.excepthook themselves. I guess this is a feature that
1279 enables them to keep running after exceptions that would
1291 enables them to keep running after exceptions that would
1280 otherwise kill their mainloop. This is a bother for IPython
1292 otherwise kill their mainloop. This is a bother for IPython
1281 which excepts to catch all of the program exceptions with a try:
1293 which excepts to catch all of the program exceptions with a try:
1282 except: statement.
1294 except: statement.
1283
1295
1284 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1296 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1285 any app directly invokes sys.excepthook, it will look to the user like
1297 any app directly invokes sys.excepthook, it will look to the user like
1286 IPython crashed. In order to work around this, we can disable the
1298 IPython crashed. In order to work around this, we can disable the
1287 CrashHandler and replace it with this excepthook instead, which prints a
1299 CrashHandler and replace it with this excepthook instead, which prints a
1288 regular traceback using our InteractiveTB. In this fashion, apps which
1300 regular traceback using our InteractiveTB. In this fashion, apps which
1289 call sys.excepthook will generate a regular-looking exception from
1301 call sys.excepthook will generate a regular-looking exception from
1290 IPython, and the CrashHandler will only be triggered by real IPython
1302 IPython, and the CrashHandler will only be triggered by real IPython
1291 crashes.
1303 crashes.
1292
1304
1293 This hook should be used sparingly, only in places which are not likely
1305 This hook should be used sparingly, only in places which are not likely
1294 to be true IPython errors.
1306 to be true IPython errors.
1295 """
1307 """
1296 self.showtraceback((etype,value,tb),tb_offset=0)
1308 self.showtraceback((etype,value,tb),tb_offset=0)
1297
1309
1298 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1310 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1299 exception_only=False):
1311 exception_only=False):
1300 """Display the exception that just occurred.
1312 """Display the exception that just occurred.
1301
1313
1302 If nothing is known about the exception, this is the method which
1314 If nothing is known about the exception, this is the method which
1303 should be used throughout the code for presenting user tracebacks,
1315 should be used throughout the code for presenting user tracebacks,
1304 rather than directly invoking the InteractiveTB object.
1316 rather than directly invoking the InteractiveTB object.
1305
1317
1306 A specific showsyntaxerror() also exists, but this method can take
1318 A specific showsyntaxerror() also exists, but this method can take
1307 care of calling it if needed, so unless you are explicitly catching a
1319 care of calling it if needed, so unless you are explicitly catching a
1308 SyntaxError exception, don't try to analyze the stack manually and
1320 SyntaxError exception, don't try to analyze the stack manually and
1309 simply call this method."""
1321 simply call this method."""
1310
1322
1311 try:
1323 try:
1312 if exc_tuple is None:
1324 if exc_tuple is None:
1313 etype, value, tb = sys.exc_info()
1325 etype, value, tb = sys.exc_info()
1314 else:
1326 else:
1315 etype, value, tb = exc_tuple
1327 etype, value, tb = exc_tuple
1316
1328
1317 if etype is None:
1329 if etype is None:
1318 if hasattr(sys, 'last_type'):
1330 if hasattr(sys, 'last_type'):
1319 etype, value, tb = sys.last_type, sys.last_value, \
1331 etype, value, tb = sys.last_type, sys.last_value, \
1320 sys.last_traceback
1332 sys.last_traceback
1321 else:
1333 else:
1322 self.write('No traceback available to show.\n')
1334 self.write('No traceback available to show.\n')
1323 return
1335 return
1324
1336
1325 if etype is SyntaxError:
1337 if etype is SyntaxError:
1326 # Though this won't be called by syntax errors in the input
1338 # Though this won't be called by syntax errors in the input
1327 # line, there may be SyntaxError cases whith imported code.
1339 # line, there may be SyntaxError cases whith imported code.
1328 self.showsyntaxerror(filename)
1340 self.showsyntaxerror(filename)
1329 elif etype is UsageError:
1341 elif etype is UsageError:
1330 print "UsageError:", value
1342 print "UsageError:", value
1331 else:
1343 else:
1332 # WARNING: these variables are somewhat deprecated and not
1344 # WARNING: these variables are somewhat deprecated and not
1333 # necessarily safe to use in a threaded environment, but tools
1345 # necessarily safe to use in a threaded environment, but tools
1334 # like pdb depend on their existence, so let's set them. If we
1346 # like pdb depend on their existence, so let's set them. If we
1335 # find problems in the field, we'll need to revisit their use.
1347 # find problems in the field, we'll need to revisit their use.
1336 sys.last_type = etype
1348 sys.last_type = etype
1337 sys.last_value = value
1349 sys.last_value = value
1338 sys.last_traceback = tb
1350 sys.last_traceback = tb
1339
1351
1340 if etype in self.custom_exceptions:
1352 if etype in self.custom_exceptions:
1341 self.CustomTB(etype,value,tb)
1353 self.CustomTB(etype,value,tb)
1342 else:
1354 else:
1343 if exception_only:
1355 if exception_only:
1344 m = ('An exception has occurred, use %tb to see the '
1356 m = ('An exception has occurred, use %tb to see the '
1345 'full traceback.')
1357 'full traceback.')
1346 print m
1358 print m
1347 self.InteractiveTB.show_exception_only(etype, value)
1359 self.InteractiveTB.show_exception_only(etype, value)
1348 else:
1360 else:
1349 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1361 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1350 if self.InteractiveTB.call_pdb:
1362 if self.InteractiveTB.call_pdb:
1351 # pdb mucks up readline, fix it back
1363 # pdb mucks up readline, fix it back
1352 self.set_completer()
1364 self.set_completer()
1353
1365
1354 except KeyboardInterrupt:
1366 except KeyboardInterrupt:
1355 self.write("\nKeyboardInterrupt\n")
1367 self.write("\nKeyboardInterrupt\n")
1356
1368
1357
1369
1358 def showsyntaxerror(self, filename=None):
1370 def showsyntaxerror(self, filename=None):
1359 """Display the syntax error that just occurred.
1371 """Display the syntax error that just occurred.
1360
1372
1361 This doesn't display a stack trace because there isn't one.
1373 This doesn't display a stack trace because there isn't one.
1362
1374
1363 If a filename is given, it is stuffed in the exception instead
1375 If a filename is given, it is stuffed in the exception instead
1364 of what was there before (because Python's parser always uses
1376 of what was there before (because Python's parser always uses
1365 "<string>" when reading from a string).
1377 "<string>" when reading from a string).
1366 """
1378 """
1367 etype, value, last_traceback = sys.exc_info()
1379 etype, value, last_traceback = sys.exc_info()
1368
1380
1369 # See note about these variables in showtraceback() above
1381 # See note about these variables in showtraceback() above
1370 sys.last_type = etype
1382 sys.last_type = etype
1371 sys.last_value = value
1383 sys.last_value = value
1372 sys.last_traceback = last_traceback
1384 sys.last_traceback = last_traceback
1373
1385
1374 if filename and etype is SyntaxError:
1386 if filename and etype is SyntaxError:
1375 # Work hard to stuff the correct filename in the exception
1387 # Work hard to stuff the correct filename in the exception
1376 try:
1388 try:
1377 msg, (dummy_filename, lineno, offset, line) = value
1389 msg, (dummy_filename, lineno, offset, line) = value
1378 except:
1390 except:
1379 # Not the format we expect; leave it alone
1391 # Not the format we expect; leave it alone
1380 pass
1392 pass
1381 else:
1393 else:
1382 # Stuff in the right filename
1394 # Stuff in the right filename
1383 try:
1395 try:
1384 # Assume SyntaxError is a class exception
1396 # Assume SyntaxError is a class exception
1385 value = SyntaxError(msg, (filename, lineno, offset, line))
1397 value = SyntaxError(msg, (filename, lineno, offset, line))
1386 except:
1398 except:
1387 # If that failed, assume SyntaxError is a string
1399 # If that failed, assume SyntaxError is a string
1388 value = msg, (filename, lineno, offset, line)
1400 value = msg, (filename, lineno, offset, line)
1389 self.SyntaxTB(etype,value,[])
1401 self.SyntaxTB(etype,value,[])
1390
1402
1391 def edit_syntax_error(self):
1403 def edit_syntax_error(self):
1392 """The bottom half of the syntax error handler called in the main loop.
1404 """The bottom half of the syntax error handler called in the main loop.
1393
1405
1394 Loop until syntax error is fixed or user cancels.
1406 Loop until syntax error is fixed or user cancels.
1395 """
1407 """
1396
1408
1397 while self.SyntaxTB.last_syntax_error:
1409 while self.SyntaxTB.last_syntax_error:
1398 # copy and clear last_syntax_error
1410 # copy and clear last_syntax_error
1399 err = self.SyntaxTB.clear_err_state()
1411 err = self.SyntaxTB.clear_err_state()
1400 if not self._should_recompile(err):
1412 if not self._should_recompile(err):
1401 return
1413 return
1402 try:
1414 try:
1403 # may set last_syntax_error again if a SyntaxError is raised
1415 # may set last_syntax_error again if a SyntaxError is raised
1404 self.safe_execfile(err.filename,self.user_ns)
1416 self.safe_execfile(err.filename,self.user_ns)
1405 except:
1417 except:
1406 self.showtraceback()
1418 self.showtraceback()
1407 else:
1419 else:
1408 try:
1420 try:
1409 f = file(err.filename)
1421 f = file(err.filename)
1410 try:
1422 try:
1411 # This should be inside a display_trap block and I
1423 # This should be inside a display_trap block and I
1412 # think it is.
1424 # think it is.
1413 sys.displayhook(f.read())
1425 sys.displayhook(f.read())
1414 finally:
1426 finally:
1415 f.close()
1427 f.close()
1416 except:
1428 except:
1417 self.showtraceback()
1429 self.showtraceback()
1418
1430
1419 def _should_recompile(self,e):
1431 def _should_recompile(self,e):
1420 """Utility routine for edit_syntax_error"""
1432 """Utility routine for edit_syntax_error"""
1421
1433
1422 if e.filename in ('<ipython console>','<input>','<string>',
1434 if e.filename in ('<ipython console>','<input>','<string>',
1423 '<console>','<BackgroundJob compilation>',
1435 '<console>','<BackgroundJob compilation>',
1424 None):
1436 None):
1425
1437
1426 return False
1438 return False
1427 try:
1439 try:
1428 if (self.autoedit_syntax and
1440 if (self.autoedit_syntax and
1429 not self.ask_yes_no('Return to editor to correct syntax error? '
1441 not self.ask_yes_no('Return to editor to correct syntax error? '
1430 '[Y/n] ','y')):
1442 '[Y/n] ','y')):
1431 return False
1443 return False
1432 except EOFError:
1444 except EOFError:
1433 return False
1445 return False
1434
1446
1435 def int0(x):
1447 def int0(x):
1436 try:
1448 try:
1437 return int(x)
1449 return int(x)
1438 except TypeError:
1450 except TypeError:
1439 return 0
1451 return 0
1440 # always pass integer line and offset values to editor hook
1452 # always pass integer line and offset values to editor hook
1441 try:
1453 try:
1442 self.hooks.fix_error_editor(e.filename,
1454 self.hooks.fix_error_editor(e.filename,
1443 int0(e.lineno),int0(e.offset),e.msg)
1455 int0(e.lineno),int0(e.offset),e.msg)
1444 except TryNext:
1456 except TryNext:
1445 warn('Could not open editor')
1457 warn('Could not open editor')
1446 return False
1458 return False
1447 return True
1459 return True
1448
1460
1449 #-------------------------------------------------------------------------
1461 #-------------------------------------------------------------------------
1450 # Things related to tab completion
1462 # Things related to tab completion
1451 #-------------------------------------------------------------------------
1463 #-------------------------------------------------------------------------
1452
1464
1453 def complete(self, text):
1465 def complete(self, text):
1454 """Return a sorted list of all possible completions on text.
1466 """Return a sorted list of all possible completions on text.
1455
1467
1456 Inputs:
1468 Inputs:
1457
1469
1458 - text: a string of text to be completed on.
1470 - text: a string of text to be completed on.
1459
1471
1460 This is a wrapper around the completion mechanism, similar to what
1472 This is a wrapper around the completion mechanism, similar to what
1461 readline does at the command line when the TAB key is hit. By
1473 readline does at the command line when the TAB key is hit. By
1462 exposing it as a method, it can be used by other non-readline
1474 exposing it as a method, it can be used by other non-readline
1463 environments (such as GUIs) for text completion.
1475 environments (such as GUIs) for text completion.
1464
1476
1465 Simple usage example:
1477 Simple usage example:
1466
1478
1467 In [7]: x = 'hello'
1479 In [7]: x = 'hello'
1468
1480
1469 In [8]: x
1481 In [8]: x
1470 Out[8]: 'hello'
1482 Out[8]: 'hello'
1471
1483
1472 In [9]: print x
1484 In [9]: print x
1473 hello
1485 hello
1474
1486
1475 In [10]: _ip.complete('x.l')
1487 In [10]: _ip.complete('x.l')
1476 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1488 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1477 """
1489 """
1478
1490
1479 # Inject names into __builtin__ so we can complete on the added names.
1491 # Inject names into __builtin__ so we can complete on the added names.
1480 with self.builtin_trap:
1492 with self.builtin_trap:
1481 complete = self.Completer.complete
1493 complete = self.Completer.complete
1482 state = 0
1494 state = 0
1483 # use a dict so we get unique keys, since ipyhton's multiple
1495 # use a dict so we get unique keys, since ipyhton's multiple
1484 # completers can return duplicates. When we make 2.4 a requirement,
1496 # completers can return duplicates. When we make 2.4 a requirement,
1485 # start using sets instead, which are faster.
1497 # start using sets instead, which are faster.
1486 comps = {}
1498 comps = {}
1487 while True:
1499 while True:
1488 newcomp = complete(text,state,line_buffer=text)
1500 newcomp = complete(text,state,line_buffer=text)
1489 if newcomp is None:
1501 if newcomp is None:
1490 break
1502 break
1491 comps[newcomp] = 1
1503 comps[newcomp] = 1
1492 state += 1
1504 state += 1
1493 outcomps = comps.keys()
1505 outcomps = comps.keys()
1494 outcomps.sort()
1506 outcomps.sort()
1495 #print "T:",text,"OC:",outcomps # dbg
1507 #print "T:",text,"OC:",outcomps # dbg
1496 #print "vars:",self.user_ns.keys()
1508 #print "vars:",self.user_ns.keys()
1497 return outcomps
1509 return outcomps
1498
1510
1499 def set_custom_completer(self,completer,pos=0):
1511 def set_custom_completer(self,completer,pos=0):
1500 """Adds a new custom completer function.
1512 """Adds a new custom completer function.
1501
1513
1502 The position argument (defaults to 0) is the index in the completers
1514 The position argument (defaults to 0) is the index in the completers
1503 list where you want the completer to be inserted."""
1515 list where you want the completer to be inserted."""
1504
1516
1505 newcomp = new.instancemethod(completer,self.Completer,
1517 newcomp = new.instancemethod(completer,self.Completer,
1506 self.Completer.__class__)
1518 self.Completer.__class__)
1507 self.Completer.matchers.insert(pos,newcomp)
1519 self.Completer.matchers.insert(pos,newcomp)
1508
1520
1509 def set_completer(self):
1521 def set_completer(self):
1510 """Reset readline's completer to be our own."""
1522 """Reset readline's completer to be our own."""
1511 self.readline.set_completer(self.Completer.complete)
1523 self.readline.set_completer(self.Completer.complete)
1512
1524
1513 def set_completer_frame(self, frame=None):
1525 def set_completer_frame(self, frame=None):
1514 """Set the frame of the completer."""
1526 """Set the frame of the completer."""
1515 if frame:
1527 if frame:
1516 self.Completer.namespace = frame.f_locals
1528 self.Completer.namespace = frame.f_locals
1517 self.Completer.global_namespace = frame.f_globals
1529 self.Completer.global_namespace = frame.f_globals
1518 else:
1530 else:
1519 self.Completer.namespace = self.user_ns
1531 self.Completer.namespace = self.user_ns
1520 self.Completer.global_namespace = self.user_global_ns
1532 self.Completer.global_namespace = self.user_global_ns
1521
1533
1522 #-------------------------------------------------------------------------
1534 #-------------------------------------------------------------------------
1523 # Things related to readline
1535 # Things related to readline
1524 #-------------------------------------------------------------------------
1536 #-------------------------------------------------------------------------
1525
1537
1526 def init_readline(self):
1538 def init_readline(self):
1527 """Command history completion/saving/reloading."""
1539 """Command history completion/saving/reloading."""
1528
1540
1529 if self.readline_use:
1541 if self.readline_use:
1530 import IPython.utils.rlineimpl as readline
1542 import IPython.utils.rlineimpl as readline
1531
1543
1532 self.rl_next_input = None
1544 self.rl_next_input = None
1533 self.rl_do_indent = False
1545 self.rl_do_indent = False
1534
1546
1535 if not self.readline_use or not readline.have_readline:
1547 if not self.readline_use or not readline.have_readline:
1536 self.has_readline = False
1548 self.has_readline = False
1537 self.readline = None
1549 self.readline = None
1538 # Set a number of methods that depend on readline to be no-op
1550 # Set a number of methods that depend on readline to be no-op
1539 self.savehist = no_op
1551 self.savehist = no_op
1540 self.reloadhist = no_op
1552 self.reloadhist = no_op
1541 self.set_completer = no_op
1553 self.set_completer = no_op
1542 self.set_custom_completer = no_op
1554 self.set_custom_completer = no_op
1543 self.set_completer_frame = no_op
1555 self.set_completer_frame = no_op
1544 warn('Readline services not available or not loaded.')
1556 warn('Readline services not available or not loaded.')
1545 else:
1557 else:
1546 self.has_readline = True
1558 self.has_readline = True
1547 self.readline = readline
1559 self.readline = readline
1548 sys.modules['readline'] = readline
1560 sys.modules['readline'] = readline
1549 import atexit
1561 import atexit
1550 from IPython.core.completer import IPCompleter
1562 from IPython.core.completer import IPCompleter
1551 self.Completer = IPCompleter(self,
1563 self.Completer = IPCompleter(self,
1552 self.user_ns,
1564 self.user_ns,
1553 self.user_global_ns,
1565 self.user_global_ns,
1554 self.readline_omit__names,
1566 self.readline_omit__names,
1555 self.alias_manager.alias_table)
1567 self.alias_manager.alias_table)
1556 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1568 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1557 self.strdispatchers['complete_command'] = sdisp
1569 self.strdispatchers['complete_command'] = sdisp
1558 self.Completer.custom_completers = sdisp
1570 self.Completer.custom_completers = sdisp
1559 # Platform-specific configuration
1571 # Platform-specific configuration
1560 if os.name == 'nt':
1572 if os.name == 'nt':
1561 self.readline_startup_hook = readline.set_pre_input_hook
1573 self.readline_startup_hook = readline.set_pre_input_hook
1562 else:
1574 else:
1563 self.readline_startup_hook = readline.set_startup_hook
1575 self.readline_startup_hook = readline.set_startup_hook
1564
1576
1565 # Load user's initrc file (readline config)
1577 # Load user's initrc file (readline config)
1566 # Or if libedit is used, load editrc.
1578 # Or if libedit is used, load editrc.
1567 inputrc_name = os.environ.get('INPUTRC')
1579 inputrc_name = os.environ.get('INPUTRC')
1568 if inputrc_name is None:
1580 if inputrc_name is None:
1569 home_dir = get_home_dir()
1581 home_dir = get_home_dir()
1570 if home_dir is not None:
1582 if home_dir is not None:
1571 inputrc_name = '.inputrc'
1583 inputrc_name = '.inputrc'
1572 if readline.uses_libedit:
1584 if readline.uses_libedit:
1573 inputrc_name = '.editrc'
1585 inputrc_name = '.editrc'
1574 inputrc_name = os.path.join(home_dir, inputrc_name)
1586 inputrc_name = os.path.join(home_dir, inputrc_name)
1575 if os.path.isfile(inputrc_name):
1587 if os.path.isfile(inputrc_name):
1576 try:
1588 try:
1577 readline.read_init_file(inputrc_name)
1589 readline.read_init_file(inputrc_name)
1578 except:
1590 except:
1579 warn('Problems reading readline initialization file <%s>'
1591 warn('Problems reading readline initialization file <%s>'
1580 % inputrc_name)
1592 % inputrc_name)
1581
1593
1582 # save this in sys so embedded copies can restore it properly
1594 # save this in sys so embedded copies can restore it properly
1583 sys.ipcompleter = self.Completer.complete
1595 sys.ipcompleter = self.Completer.complete
1584 self.set_completer()
1596 self.set_completer()
1585
1597
1586 # Configure readline according to user's prefs
1598 # Configure readline according to user's prefs
1587 # This is only done if GNU readline is being used. If libedit
1599 # This is only done if GNU readline is being used. If libedit
1588 # is being used (as on Leopard) the readline config is
1600 # is being used (as on Leopard) the readline config is
1589 # not run as the syntax for libedit is different.
1601 # not run as the syntax for libedit is different.
1590 if not readline.uses_libedit:
1602 if not readline.uses_libedit:
1591 for rlcommand in self.readline_parse_and_bind:
1603 for rlcommand in self.readline_parse_and_bind:
1592 #print "loading rl:",rlcommand # dbg
1604 #print "loading rl:",rlcommand # dbg
1593 readline.parse_and_bind(rlcommand)
1605 readline.parse_and_bind(rlcommand)
1594
1606
1595 # Remove some chars from the delimiters list. If we encounter
1607 # Remove some chars from the delimiters list. If we encounter
1596 # unicode chars, discard them.
1608 # unicode chars, discard them.
1597 delims = readline.get_completer_delims().encode("ascii", "ignore")
1609 delims = readline.get_completer_delims().encode("ascii", "ignore")
1598 delims = delims.translate(string._idmap,
1610 delims = delims.translate(string._idmap,
1599 self.readline_remove_delims)
1611 self.readline_remove_delims)
1600 readline.set_completer_delims(delims)
1612 readline.set_completer_delims(delims)
1601 # otherwise we end up with a monster history after a while:
1613 # otherwise we end up with a monster history after a while:
1602 readline.set_history_length(1000)
1614 readline.set_history_length(1000)
1603 try:
1615 try:
1604 #print '*** Reading readline history' # dbg
1616 #print '*** Reading readline history' # dbg
1605 readline.read_history_file(self.histfile)
1617 readline.read_history_file(self.histfile)
1606 except IOError:
1618 except IOError:
1607 pass # It doesn't exist yet.
1619 pass # It doesn't exist yet.
1608
1620
1609 atexit.register(self.atexit_operations)
1621 atexit.register(self.atexit_operations)
1610 del atexit
1622 del atexit
1611
1623
1612 # Configure auto-indent for all platforms
1624 # Configure auto-indent for all platforms
1613 self.set_autoindent(self.autoindent)
1625 self.set_autoindent(self.autoindent)
1614
1626
1615 def set_next_input(self, s):
1627 def set_next_input(self, s):
1616 """ Sets the 'default' input string for the next command line.
1628 """ Sets the 'default' input string for the next command line.
1617
1629
1618 Requires readline.
1630 Requires readline.
1619
1631
1620 Example:
1632 Example:
1621
1633
1622 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1634 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1623 [D:\ipython]|2> Hello Word_ # cursor is here
1635 [D:\ipython]|2> Hello Word_ # cursor is here
1624 """
1636 """
1625
1637
1626 self.rl_next_input = s
1638 self.rl_next_input = s
1627
1639
1628 def pre_readline(self):
1640 def pre_readline(self):
1629 """readline hook to be used at the start of each line.
1641 """readline hook to be used at the start of each line.
1630
1642
1631 Currently it handles auto-indent only."""
1643 Currently it handles auto-indent only."""
1632
1644
1633 #debugx('self.indent_current_nsp','pre_readline:')
1645 #debugx('self.indent_current_nsp','pre_readline:')
1634
1646
1635 if self.rl_do_indent:
1647 if self.rl_do_indent:
1636 self.readline.insert_text(self._indent_current_str())
1648 self.readline.insert_text(self._indent_current_str())
1637 if self.rl_next_input is not None:
1649 if self.rl_next_input is not None:
1638 self.readline.insert_text(self.rl_next_input)
1650 self.readline.insert_text(self.rl_next_input)
1639 self.rl_next_input = None
1651 self.rl_next_input = None
1640
1652
1641 def _indent_current_str(self):
1653 def _indent_current_str(self):
1642 """return the current level of indentation as a string"""
1654 """return the current level of indentation as a string"""
1643 return self.indent_current_nsp * ' '
1655 return self.indent_current_nsp * ' '
1644
1656
1645 #-------------------------------------------------------------------------
1657 #-------------------------------------------------------------------------
1646 # Things related to magics
1658 # Things related to magics
1647 #-------------------------------------------------------------------------
1659 #-------------------------------------------------------------------------
1648
1660
1649 def init_magics(self):
1661 def init_magics(self):
1650 # Set user colors (don't do it in the constructor above so that it
1662 # Set user colors (don't do it in the constructor above so that it
1651 # doesn't crash if colors option is invalid)
1663 # doesn't crash if colors option is invalid)
1652 self.magic_colors(self.colors)
1664 self.magic_colors(self.colors)
1653 # History was moved to a separate module
1665 # History was moved to a separate module
1654 from . import history
1666 from . import history
1655 history.init_ipython(self)
1667 history.init_ipython(self)
1656
1668
1657 def magic(self,arg_s):
1669 def magic(self,arg_s):
1658 """Call a magic function by name.
1670 """Call a magic function by name.
1659
1671
1660 Input: a string containing the name of the magic function to call and any
1672 Input: a string containing the name of the magic function to call and any
1661 additional arguments to be passed to the magic.
1673 additional arguments to be passed to the magic.
1662
1674
1663 magic('name -opt foo bar') is equivalent to typing at the ipython
1675 magic('name -opt foo bar') is equivalent to typing at the ipython
1664 prompt:
1676 prompt:
1665
1677
1666 In[1]: %name -opt foo bar
1678 In[1]: %name -opt foo bar
1667
1679
1668 To call a magic without arguments, simply use magic('name').
1680 To call a magic without arguments, simply use magic('name').
1669
1681
1670 This provides a proper Python function to call IPython's magics in any
1682 This provides a proper Python function to call IPython's magics in any
1671 valid Python code you can type at the interpreter, including loops and
1683 valid Python code you can type at the interpreter, including loops and
1672 compound statements.
1684 compound statements.
1673 """
1685 """
1674 args = arg_s.split(' ',1)
1686 args = arg_s.split(' ',1)
1675 magic_name = args[0]
1687 magic_name = args[0]
1676 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1688 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1677
1689
1678 try:
1690 try:
1679 magic_args = args[1]
1691 magic_args = args[1]
1680 except IndexError:
1692 except IndexError:
1681 magic_args = ''
1693 magic_args = ''
1682 fn = getattr(self,'magic_'+magic_name,None)
1694 fn = getattr(self,'magic_'+magic_name,None)
1683 if fn is None:
1695 if fn is None:
1684 error("Magic function `%s` not found." % magic_name)
1696 error("Magic function `%s` not found." % magic_name)
1685 else:
1697 else:
1686 magic_args = self.var_expand(magic_args,1)
1698 magic_args = self.var_expand(magic_args,1)
1687 with nested(self.builtin_trap,):
1699 with nested(self.builtin_trap,):
1688 result = fn(magic_args)
1700 result = fn(magic_args)
1689 return result
1701 return result
1690
1702
1691 def define_magic(self, magicname, func):
1703 def define_magic(self, magicname, func):
1692 """Expose own function as magic function for ipython
1704 """Expose own function as magic function for ipython
1693
1705
1694 def foo_impl(self,parameter_s=''):
1706 def foo_impl(self,parameter_s=''):
1695 'My very own magic!. (Use docstrings, IPython reads them).'
1707 'My very own magic!. (Use docstrings, IPython reads them).'
1696 print 'Magic function. Passed parameter is between < >:'
1708 print 'Magic function. Passed parameter is between < >:'
1697 print '<%s>' % parameter_s
1709 print '<%s>' % parameter_s
1698 print 'The self object is:',self
1710 print 'The self object is:',self
1699
1711
1700 self.define_magic('foo',foo_impl)
1712 self.define_magic('foo',foo_impl)
1701 """
1713 """
1702
1714
1703 import new
1715 import new
1704 im = new.instancemethod(func,self, self.__class__)
1716 im = new.instancemethod(func,self, self.__class__)
1705 old = getattr(self, "magic_" + magicname, None)
1717 old = getattr(self, "magic_" + magicname, None)
1706 setattr(self, "magic_" + magicname, im)
1718 setattr(self, "magic_" + magicname, im)
1707 return old
1719 return old
1708
1720
1709 #-------------------------------------------------------------------------
1721 #-------------------------------------------------------------------------
1710 # Things related to macros
1722 # Things related to macros
1711 #-------------------------------------------------------------------------
1723 #-------------------------------------------------------------------------
1712
1724
1713 def define_macro(self, name, themacro):
1725 def define_macro(self, name, themacro):
1714 """Define a new macro
1726 """Define a new macro
1715
1727
1716 Parameters
1728 Parameters
1717 ----------
1729 ----------
1718 name : str
1730 name : str
1719 The name of the macro.
1731 The name of the macro.
1720 themacro : str or Macro
1732 themacro : str or Macro
1721 The action to do upon invoking the macro. If a string, a new
1733 The action to do upon invoking the macro. If a string, a new
1722 Macro object is created by passing the string to it.
1734 Macro object is created by passing the string to it.
1723 """
1735 """
1724
1736
1725 from IPython.core import macro
1737 from IPython.core import macro
1726
1738
1727 if isinstance(themacro, basestring):
1739 if isinstance(themacro, basestring):
1728 themacro = macro.Macro(themacro)
1740 themacro = macro.Macro(themacro)
1729 if not isinstance(themacro, macro.Macro):
1741 if not isinstance(themacro, macro.Macro):
1730 raise ValueError('A macro must be a string or a Macro instance.')
1742 raise ValueError('A macro must be a string or a Macro instance.')
1731 self.user_ns[name] = themacro
1743 self.user_ns[name] = themacro
1732
1744
1733 #-------------------------------------------------------------------------
1745 #-------------------------------------------------------------------------
1734 # Things related to the running of system commands
1746 # Things related to the running of system commands
1735 #-------------------------------------------------------------------------
1747 #-------------------------------------------------------------------------
1736
1748
1737 def system(self, cmd):
1749 def system(self, cmd):
1738 """Make a system call, using IPython."""
1750 """Make a system call, using IPython."""
1739 return self.hooks.shell_hook(self.var_expand(cmd, depth=2))
1751 return self.hooks.shell_hook(self.var_expand(cmd, depth=2))
1740
1752
1741 #-------------------------------------------------------------------------
1753 #-------------------------------------------------------------------------
1742 # Things related to aliases
1754 # Things related to aliases
1743 #-------------------------------------------------------------------------
1755 #-------------------------------------------------------------------------
1744
1756
1745 def init_alias(self):
1757 def init_alias(self):
1746 self.alias_manager = AliasManager(self, config=self.config)
1758 self.alias_manager = AliasManager(self, config=self.config)
1747 self.ns_table['alias'] = self.alias_manager.alias_table,
1759 self.ns_table['alias'] = self.alias_manager.alias_table,
1748
1760
1749 #-------------------------------------------------------------------------
1761 #-------------------------------------------------------------------------
1762 # Things related to extensions
1763 #-------------------------------------------------------------------------
1764
1765 def init_extension_manager(self):
1766 self.extension_manager = ExtensionManager(self, config=self.config)
1767
1768 #-------------------------------------------------------------------------
1750 # Things related to the running of code
1769 # Things related to the running of code
1751 #-------------------------------------------------------------------------
1770 #-------------------------------------------------------------------------
1752
1771
1753 def ex(self, cmd):
1772 def ex(self, cmd):
1754 """Execute a normal python statement in user namespace."""
1773 """Execute a normal python statement in user namespace."""
1755 with nested(self.builtin_trap,):
1774 with nested(self.builtin_trap,):
1756 exec cmd in self.user_global_ns, self.user_ns
1775 exec cmd in self.user_global_ns, self.user_ns
1757
1776
1758 def ev(self, expr):
1777 def ev(self, expr):
1759 """Evaluate python expression expr in user namespace.
1778 """Evaluate python expression expr in user namespace.
1760
1779
1761 Returns the result of evaluation
1780 Returns the result of evaluation
1762 """
1781 """
1763 with nested(self.builtin_trap,):
1782 with nested(self.builtin_trap,):
1764 return eval(expr, self.user_global_ns, self.user_ns)
1783 return eval(expr, self.user_global_ns, self.user_ns)
1765
1784
1766 def mainloop(self, display_banner=None):
1785 def mainloop(self, display_banner=None):
1767 """Start the mainloop.
1786 """Start the mainloop.
1768
1787
1769 If an optional banner argument is given, it will override the
1788 If an optional banner argument is given, it will override the
1770 internally created default banner.
1789 internally created default banner.
1771 """
1790 """
1772
1791
1773 with nested(self.builtin_trap, self.display_trap):
1792 with nested(self.builtin_trap, self.display_trap):
1774
1793
1775 # if you run stuff with -c <cmd>, raw hist is not updated
1794 # if you run stuff with -c <cmd>, raw hist is not updated
1776 # ensure that it's in sync
1795 # ensure that it's in sync
1777 if len(self.input_hist) != len (self.input_hist_raw):
1796 if len(self.input_hist) != len (self.input_hist_raw):
1778 self.input_hist_raw = InputList(self.input_hist)
1797 self.input_hist_raw = InputList(self.input_hist)
1779
1798
1780 while 1:
1799 while 1:
1781 try:
1800 try:
1782 self.interact(display_banner=display_banner)
1801 self.interact(display_banner=display_banner)
1783 #self.interact_with_readline()
1802 #self.interact_with_readline()
1784 # XXX for testing of a readline-decoupled repl loop, call
1803 # XXX for testing of a readline-decoupled repl loop, call
1785 # interact_with_readline above
1804 # interact_with_readline above
1786 break
1805 break
1787 except KeyboardInterrupt:
1806 except KeyboardInterrupt:
1788 # this should not be necessary, but KeyboardInterrupt
1807 # this should not be necessary, but KeyboardInterrupt
1789 # handling seems rather unpredictable...
1808 # handling seems rather unpredictable...
1790 self.write("\nKeyboardInterrupt in interact()\n")
1809 self.write("\nKeyboardInterrupt in interact()\n")
1791
1810
1792 def interact_prompt(self):
1811 def interact_prompt(self):
1793 """ Print the prompt (in read-eval-print loop)
1812 """ Print the prompt (in read-eval-print loop)
1794
1813
1795 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1814 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1796 used in standard IPython flow.
1815 used in standard IPython flow.
1797 """
1816 """
1798 if self.more:
1817 if self.more:
1799 try:
1818 try:
1800 prompt = self.hooks.generate_prompt(True)
1819 prompt = self.hooks.generate_prompt(True)
1801 except:
1820 except:
1802 self.showtraceback()
1821 self.showtraceback()
1803 if self.autoindent:
1822 if self.autoindent:
1804 self.rl_do_indent = True
1823 self.rl_do_indent = True
1805
1824
1806 else:
1825 else:
1807 try:
1826 try:
1808 prompt = self.hooks.generate_prompt(False)
1827 prompt = self.hooks.generate_prompt(False)
1809 except:
1828 except:
1810 self.showtraceback()
1829 self.showtraceback()
1811 self.write(prompt)
1830 self.write(prompt)
1812
1831
1813 def interact_handle_input(self,line):
1832 def interact_handle_input(self,line):
1814 """ Handle the input line (in read-eval-print loop)
1833 """ Handle the input line (in read-eval-print loop)
1815
1834
1816 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1835 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1817 used in standard IPython flow.
1836 used in standard IPython flow.
1818 """
1837 """
1819 if line.lstrip() == line:
1838 if line.lstrip() == line:
1820 self.shadowhist.add(line.strip())
1839 self.shadowhist.add(line.strip())
1821 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1840 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1822
1841
1823 if line.strip():
1842 if line.strip():
1824 if self.more:
1843 if self.more:
1825 self.input_hist_raw[-1] += '%s\n' % line
1844 self.input_hist_raw[-1] += '%s\n' % line
1826 else:
1845 else:
1827 self.input_hist_raw.append('%s\n' % line)
1846 self.input_hist_raw.append('%s\n' % line)
1828
1847
1829
1848
1830 self.more = self.push_line(lineout)
1849 self.more = self.push_line(lineout)
1831 if (self.SyntaxTB.last_syntax_error and
1850 if (self.SyntaxTB.last_syntax_error and
1832 self.autoedit_syntax):
1851 self.autoedit_syntax):
1833 self.edit_syntax_error()
1852 self.edit_syntax_error()
1834
1853
1835 def interact_with_readline(self):
1854 def interact_with_readline(self):
1836 """ Demo of using interact_handle_input, interact_prompt
1855 """ Demo of using interact_handle_input, interact_prompt
1837
1856
1838 This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
1857 This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
1839 it should work like this.
1858 it should work like this.
1840 """
1859 """
1841 self.readline_startup_hook(self.pre_readline)
1860 self.readline_startup_hook(self.pre_readline)
1842 while not self.exit_now:
1861 while not self.exit_now:
1843 self.interact_prompt()
1862 self.interact_prompt()
1844 if self.more:
1863 if self.more:
1845 self.rl_do_indent = True
1864 self.rl_do_indent = True
1846 else:
1865 else:
1847 self.rl_do_indent = False
1866 self.rl_do_indent = False
1848 line = raw_input_original().decode(self.stdin_encoding)
1867 line = raw_input_original().decode(self.stdin_encoding)
1849 self.interact_handle_input(line)
1868 self.interact_handle_input(line)
1850
1869
1851 def interact(self, display_banner=None):
1870 def interact(self, display_banner=None):
1852 """Closely emulate the interactive Python console."""
1871 """Closely emulate the interactive Python console."""
1853
1872
1854 # batch run -> do not interact
1873 # batch run -> do not interact
1855 if self.exit_now:
1874 if self.exit_now:
1856 return
1875 return
1857
1876
1858 if display_banner is None:
1877 if display_banner is None:
1859 display_banner = self.display_banner
1878 display_banner = self.display_banner
1860 if display_banner:
1879 if display_banner:
1861 self.show_banner()
1880 self.show_banner()
1862
1881
1863 more = 0
1882 more = 0
1864
1883
1865 # Mark activity in the builtins
1884 # Mark activity in the builtins
1866 __builtin__.__dict__['__IPYTHON__active'] += 1
1885 __builtin__.__dict__['__IPYTHON__active'] += 1
1867
1886
1868 if self.has_readline:
1887 if self.has_readline:
1869 self.readline_startup_hook(self.pre_readline)
1888 self.readline_startup_hook(self.pre_readline)
1870 # exit_now is set by a call to %Exit or %Quit, through the
1889 # exit_now is set by a call to %Exit or %Quit, through the
1871 # ask_exit callback.
1890 # ask_exit callback.
1872
1891
1873 while not self.exit_now:
1892 while not self.exit_now:
1874 self.hooks.pre_prompt_hook()
1893 self.hooks.pre_prompt_hook()
1875 if more:
1894 if more:
1876 try:
1895 try:
1877 prompt = self.hooks.generate_prompt(True)
1896 prompt = self.hooks.generate_prompt(True)
1878 except:
1897 except:
1879 self.showtraceback()
1898 self.showtraceback()
1880 if self.autoindent:
1899 if self.autoindent:
1881 self.rl_do_indent = True
1900 self.rl_do_indent = True
1882
1901
1883 else:
1902 else:
1884 try:
1903 try:
1885 prompt = self.hooks.generate_prompt(False)
1904 prompt = self.hooks.generate_prompt(False)
1886 except:
1905 except:
1887 self.showtraceback()
1906 self.showtraceback()
1888 try:
1907 try:
1889 line = self.raw_input(prompt, more)
1908 line = self.raw_input(prompt, more)
1890 if self.exit_now:
1909 if self.exit_now:
1891 # quick exit on sys.std[in|out] close
1910 # quick exit on sys.std[in|out] close
1892 break
1911 break
1893 if self.autoindent:
1912 if self.autoindent:
1894 self.rl_do_indent = False
1913 self.rl_do_indent = False
1895
1914
1896 except KeyboardInterrupt:
1915 except KeyboardInterrupt:
1897 #double-guard against keyboardinterrupts during kbdint handling
1916 #double-guard against keyboardinterrupts during kbdint handling
1898 try:
1917 try:
1899 self.write('\nKeyboardInterrupt\n')
1918 self.write('\nKeyboardInterrupt\n')
1900 self.resetbuffer()
1919 self.resetbuffer()
1901 # keep cache in sync with the prompt counter:
1920 # keep cache in sync with the prompt counter:
1902 self.outputcache.prompt_count -= 1
1921 self.outputcache.prompt_count -= 1
1903
1922
1904 if self.autoindent:
1923 if self.autoindent:
1905 self.indent_current_nsp = 0
1924 self.indent_current_nsp = 0
1906 more = 0
1925 more = 0
1907 except KeyboardInterrupt:
1926 except KeyboardInterrupt:
1908 pass
1927 pass
1909 except EOFError:
1928 except EOFError:
1910 if self.autoindent:
1929 if self.autoindent:
1911 self.rl_do_indent = False
1930 self.rl_do_indent = False
1912 if self.has_readline:
1931 if self.has_readline:
1913 self.readline_startup_hook(None)
1932 self.readline_startup_hook(None)
1914 self.write('\n')
1933 self.write('\n')
1915 self.exit()
1934 self.exit()
1916 except bdb.BdbQuit:
1935 except bdb.BdbQuit:
1917 warn('The Python debugger has exited with a BdbQuit exception.\n'
1936 warn('The Python debugger has exited with a BdbQuit exception.\n'
1918 'Because of how pdb handles the stack, it is impossible\n'
1937 'Because of how pdb handles the stack, it is impossible\n'
1919 'for IPython to properly format this particular exception.\n'
1938 'for IPython to properly format this particular exception.\n'
1920 'IPython will resume normal operation.')
1939 'IPython will resume normal operation.')
1921 except:
1940 except:
1922 # exceptions here are VERY RARE, but they can be triggered
1941 # exceptions here are VERY RARE, but they can be triggered
1923 # asynchronously by signal handlers, for example.
1942 # asynchronously by signal handlers, for example.
1924 self.showtraceback()
1943 self.showtraceback()
1925 else:
1944 else:
1926 more = self.push_line(line)
1945 more = self.push_line(line)
1927 if (self.SyntaxTB.last_syntax_error and
1946 if (self.SyntaxTB.last_syntax_error and
1928 self.autoedit_syntax):
1947 self.autoedit_syntax):
1929 self.edit_syntax_error()
1948 self.edit_syntax_error()
1930
1949
1931 # We are off again...
1950 # We are off again...
1932 __builtin__.__dict__['__IPYTHON__active'] -= 1
1951 __builtin__.__dict__['__IPYTHON__active'] -= 1
1933
1952
1934 # Turn off the exit flag, so the mainloop can be restarted if desired
1953 # Turn off the exit flag, so the mainloop can be restarted if desired
1935 self.exit_now = False
1954 self.exit_now = False
1936
1955
1937 def safe_execfile(self, fname, *where, **kw):
1956 def safe_execfile(self, fname, *where, **kw):
1938 """A safe version of the builtin execfile().
1957 """A safe version of the builtin execfile().
1939
1958
1940 This version will never throw an exception, but instead print
1959 This version will never throw an exception, but instead print
1941 helpful error messages to the screen. This only works on pure
1960 helpful error messages to the screen. This only works on pure
1942 Python files with the .py extension.
1961 Python files with the .py extension.
1943
1962
1944 Parameters
1963 Parameters
1945 ----------
1964 ----------
1946 fname : string
1965 fname : string
1947 The name of the file to be executed.
1966 The name of the file to be executed.
1948 where : tuple
1967 where : tuple
1949 One or two namespaces, passed to execfile() as (globals,locals).
1968 One or two namespaces, passed to execfile() as (globals,locals).
1950 If only one is given, it is passed as both.
1969 If only one is given, it is passed as both.
1951 exit_ignore : bool (False)
1970 exit_ignore : bool (False)
1952 If True, then silence SystemExit for non-zero status (it is always
1971 If True, then silence SystemExit for non-zero status (it is always
1953 silenced for zero status, as it is so common).
1972 silenced for zero status, as it is so common).
1954 """
1973 """
1955 kw.setdefault('exit_ignore', False)
1974 kw.setdefault('exit_ignore', False)
1956
1975
1957 fname = os.path.abspath(os.path.expanduser(fname))
1976 fname = os.path.abspath(os.path.expanduser(fname))
1958
1977
1959 # Make sure we have a .py file
1978 # Make sure we have a .py file
1960 if not fname.endswith('.py'):
1979 if not fname.endswith('.py'):
1961 warn('File must end with .py to be run using execfile: <%s>' % fname)
1980 warn('File must end with .py to be run using execfile: <%s>' % fname)
1962
1981
1963 # Make sure we can open the file
1982 # Make sure we can open the file
1964 try:
1983 try:
1965 with open(fname) as thefile:
1984 with open(fname) as thefile:
1966 pass
1985 pass
1967 except:
1986 except:
1968 warn('Could not open file <%s> for safe execution.' % fname)
1987 warn('Could not open file <%s> for safe execution.' % fname)
1969 return
1988 return
1970
1989
1971 # Find things also in current directory. This is needed to mimic the
1990 # Find things also in current directory. This is needed to mimic the
1972 # behavior of running a script from the system command line, where
1991 # behavior of running a script from the system command line, where
1973 # Python inserts the script's directory into sys.path
1992 # Python inserts the script's directory into sys.path
1974 dname = os.path.dirname(fname)
1993 dname = os.path.dirname(fname)
1975
1994
1976 with prepended_to_syspath(dname):
1995 with prepended_to_syspath(dname):
1977 try:
1996 try:
1978 execfile(fname,*where)
1997 execfile(fname,*where)
1979 except SystemExit, status:
1998 except SystemExit, status:
1980 # If the call was made with 0 or None exit status (sys.exit(0)
1999 # If the call was made with 0 or None exit status (sys.exit(0)
1981 # or sys.exit() ), don't bother showing a traceback, as both of
2000 # or sys.exit() ), don't bother showing a traceback, as both of
1982 # these are considered normal by the OS:
2001 # these are considered normal by the OS:
1983 # > python -c'import sys;sys.exit(0)'; echo $?
2002 # > python -c'import sys;sys.exit(0)'; echo $?
1984 # 0
2003 # 0
1985 # > python -c'import sys;sys.exit()'; echo $?
2004 # > python -c'import sys;sys.exit()'; echo $?
1986 # 0
2005 # 0
1987 # For other exit status, we show the exception unless
2006 # For other exit status, we show the exception unless
1988 # explicitly silenced, but only in short form.
2007 # explicitly silenced, but only in short form.
1989 if status.code not in (0, None) and not kw['exit_ignore']:
2008 if status.code not in (0, None) and not kw['exit_ignore']:
1990 self.showtraceback(exception_only=True)
2009 self.showtraceback(exception_only=True)
1991 except:
2010 except:
1992 self.showtraceback()
2011 self.showtraceback()
1993
2012
1994 def safe_execfile_ipy(self, fname):
2013 def safe_execfile_ipy(self, fname):
1995 """Like safe_execfile, but for .ipy files with IPython syntax.
2014 """Like safe_execfile, but for .ipy files with IPython syntax.
1996
2015
1997 Parameters
2016 Parameters
1998 ----------
2017 ----------
1999 fname : str
2018 fname : str
2000 The name of the file to execute. The filename must have a
2019 The name of the file to execute. The filename must have a
2001 .ipy extension.
2020 .ipy extension.
2002 """
2021 """
2003 fname = os.path.abspath(os.path.expanduser(fname))
2022 fname = os.path.abspath(os.path.expanduser(fname))
2004
2023
2005 # Make sure we have a .py file
2024 # Make sure we have a .py file
2006 if not fname.endswith('.ipy'):
2025 if not fname.endswith('.ipy'):
2007 warn('File must end with .py to be run using execfile: <%s>' % fname)
2026 warn('File must end with .py to be run using execfile: <%s>' % fname)
2008
2027
2009 # Make sure we can open the file
2028 # Make sure we can open the file
2010 try:
2029 try:
2011 with open(fname) as thefile:
2030 with open(fname) as thefile:
2012 pass
2031 pass
2013 except:
2032 except:
2014 warn('Could not open file <%s> for safe execution.' % fname)
2033 warn('Could not open file <%s> for safe execution.' % fname)
2015 return
2034 return
2016
2035
2017 # Find things also in current directory. This is needed to mimic the
2036 # Find things also in current directory. This is needed to mimic the
2018 # behavior of running a script from the system command line, where
2037 # behavior of running a script from the system command line, where
2019 # Python inserts the script's directory into sys.path
2038 # Python inserts the script's directory into sys.path
2020 dname = os.path.dirname(fname)
2039 dname = os.path.dirname(fname)
2021
2040
2022 with prepended_to_syspath(dname):
2041 with prepended_to_syspath(dname):
2023 try:
2042 try:
2024 with open(fname) as thefile:
2043 with open(fname) as thefile:
2025 script = thefile.read()
2044 script = thefile.read()
2026 # self.runlines currently captures all exceptions
2045 # self.runlines currently captures all exceptions
2027 # raise in user code. It would be nice if there were
2046 # raise in user code. It would be nice if there were
2028 # versions of runlines, execfile that did raise, so
2047 # versions of runlines, execfile that did raise, so
2029 # we could catch the errors.
2048 # we could catch the errors.
2030 self.runlines(script, clean=True)
2049 self.runlines(script, clean=True)
2031 except:
2050 except:
2032 self.showtraceback()
2051 self.showtraceback()
2033 warn('Unknown failure executing file: <%s>' % fname)
2052 warn('Unknown failure executing file: <%s>' % fname)
2034
2053
2035 def _is_secondary_block_start(self, s):
2054 def _is_secondary_block_start(self, s):
2036 if not s.endswith(':'):
2055 if not s.endswith(':'):
2037 return False
2056 return False
2038 if (s.startswith('elif') or
2057 if (s.startswith('elif') or
2039 s.startswith('else') or
2058 s.startswith('else') or
2040 s.startswith('except') or
2059 s.startswith('except') or
2041 s.startswith('finally')):
2060 s.startswith('finally')):
2042 return True
2061 return True
2043
2062
2044 def cleanup_ipy_script(self, script):
2063 def cleanup_ipy_script(self, script):
2045 """Make a script safe for self.runlines()
2064 """Make a script safe for self.runlines()
2046
2065
2047 Currently, IPython is lines based, with blocks being detected by
2066 Currently, IPython is lines based, with blocks being detected by
2048 empty lines. This is a problem for block based scripts that may
2067 empty lines. This is a problem for block based scripts that may
2049 not have empty lines after blocks. This script adds those empty
2068 not have empty lines after blocks. This script adds those empty
2050 lines to make scripts safe for running in the current line based
2069 lines to make scripts safe for running in the current line based
2051 IPython.
2070 IPython.
2052 """
2071 """
2053 res = []
2072 res = []
2054 lines = script.splitlines()
2073 lines = script.splitlines()
2055 level = 0
2074 level = 0
2056
2075
2057 for l in lines:
2076 for l in lines:
2058 lstripped = l.lstrip()
2077 lstripped = l.lstrip()
2059 stripped = l.strip()
2078 stripped = l.strip()
2060 if not stripped:
2079 if not stripped:
2061 continue
2080 continue
2062 newlevel = len(l) - len(lstripped)
2081 newlevel = len(l) - len(lstripped)
2063 if level > 0 and newlevel == 0 and \
2082 if level > 0 and newlevel == 0 and \
2064 not self._is_secondary_block_start(stripped):
2083 not self._is_secondary_block_start(stripped):
2065 # add empty line
2084 # add empty line
2066 res.append('')
2085 res.append('')
2067 res.append(l)
2086 res.append(l)
2068 level = newlevel
2087 level = newlevel
2069
2088
2070 return '\n'.join(res) + '\n'
2089 return '\n'.join(res) + '\n'
2071
2090
2072 def runlines(self, lines, clean=False):
2091 def runlines(self, lines, clean=False):
2073 """Run a string of one or more lines of source.
2092 """Run a string of one or more lines of source.
2074
2093
2075 This method is capable of running a string containing multiple source
2094 This method is capable of running a string containing multiple source
2076 lines, as if they had been entered at the IPython prompt. Since it
2095 lines, as if they had been entered at the IPython prompt. Since it
2077 exposes IPython's processing machinery, the given strings can contain
2096 exposes IPython's processing machinery, the given strings can contain
2078 magic calls (%magic), special shell access (!cmd), etc.
2097 magic calls (%magic), special shell access (!cmd), etc.
2079 """
2098 """
2080
2099
2081 if isinstance(lines, (list, tuple)):
2100 if isinstance(lines, (list, tuple)):
2082 lines = '\n'.join(lines)
2101 lines = '\n'.join(lines)
2083
2102
2084 if clean:
2103 if clean:
2085 lines = self.cleanup_ipy_script(lines)
2104 lines = self.cleanup_ipy_script(lines)
2086
2105
2087 # We must start with a clean buffer, in case this is run from an
2106 # We must start with a clean buffer, in case this is run from an
2088 # interactive IPython session (via a magic, for example).
2107 # interactive IPython session (via a magic, for example).
2089 self.resetbuffer()
2108 self.resetbuffer()
2090 lines = lines.splitlines()
2109 lines = lines.splitlines()
2091 more = 0
2110 more = 0
2092
2111
2093 with nested(self.builtin_trap, self.display_trap):
2112 with nested(self.builtin_trap, self.display_trap):
2094 for line in lines:
2113 for line in lines:
2095 # skip blank lines so we don't mess up the prompt counter, but do
2114 # skip blank lines so we don't mess up the prompt counter, but do
2096 # NOT skip even a blank line if we are in a code block (more is
2115 # NOT skip even a blank line if we are in a code block (more is
2097 # true)
2116 # true)
2098
2117
2099 if line or more:
2118 if line or more:
2100 # push to raw history, so hist line numbers stay in sync
2119 # push to raw history, so hist line numbers stay in sync
2101 self.input_hist_raw.append("# " + line + "\n")
2120 self.input_hist_raw.append("# " + line + "\n")
2102 prefiltered = self.prefilter_manager.prefilter_lines(line,more)
2121 prefiltered = self.prefilter_manager.prefilter_lines(line,more)
2103 more = self.push_line(prefiltered)
2122 more = self.push_line(prefiltered)
2104 # IPython's runsource returns None if there was an error
2123 # IPython's runsource returns None if there was an error
2105 # compiling the code. This allows us to stop processing right
2124 # compiling the code. This allows us to stop processing right
2106 # away, so the user gets the error message at the right place.
2125 # away, so the user gets the error message at the right place.
2107 if more is None:
2126 if more is None:
2108 break
2127 break
2109 else:
2128 else:
2110 self.input_hist_raw.append("\n")
2129 self.input_hist_raw.append("\n")
2111 # final newline in case the input didn't have it, so that the code
2130 # final newline in case the input didn't have it, so that the code
2112 # actually does get executed
2131 # actually does get executed
2113 if more:
2132 if more:
2114 self.push_line('\n')
2133 self.push_line('\n')
2115
2134
2116 def runsource(self, source, filename='<input>', symbol='single'):
2135 def runsource(self, source, filename='<input>', symbol='single'):
2117 """Compile and run some source in the interpreter.
2136 """Compile and run some source in the interpreter.
2118
2137
2119 Arguments are as for compile_command().
2138 Arguments are as for compile_command().
2120
2139
2121 One several things can happen:
2140 One several things can happen:
2122
2141
2123 1) The input is incorrect; compile_command() raised an
2142 1) The input is incorrect; compile_command() raised an
2124 exception (SyntaxError or OverflowError). A syntax traceback
2143 exception (SyntaxError or OverflowError). A syntax traceback
2125 will be printed by calling the showsyntaxerror() method.
2144 will be printed by calling the showsyntaxerror() method.
2126
2145
2127 2) The input is incomplete, and more input is required;
2146 2) The input is incomplete, and more input is required;
2128 compile_command() returned None. Nothing happens.
2147 compile_command() returned None. Nothing happens.
2129
2148
2130 3) The input is complete; compile_command() returned a code
2149 3) The input is complete; compile_command() returned a code
2131 object. The code is executed by calling self.runcode() (which
2150 object. The code is executed by calling self.runcode() (which
2132 also handles run-time exceptions, except for SystemExit).
2151 also handles run-time exceptions, except for SystemExit).
2133
2152
2134 The return value is:
2153 The return value is:
2135
2154
2136 - True in case 2
2155 - True in case 2
2137
2156
2138 - False in the other cases, unless an exception is raised, where
2157 - False in the other cases, unless an exception is raised, where
2139 None is returned instead. This can be used by external callers to
2158 None is returned instead. This can be used by external callers to
2140 know whether to continue feeding input or not.
2159 know whether to continue feeding input or not.
2141
2160
2142 The return value can be used to decide whether to use sys.ps1 or
2161 The return value can be used to decide whether to use sys.ps1 or
2143 sys.ps2 to prompt the next line."""
2162 sys.ps2 to prompt the next line."""
2144
2163
2145 # if the source code has leading blanks, add 'if 1:\n' to it
2164 # if the source code has leading blanks, add 'if 1:\n' to it
2146 # this allows execution of indented pasted code. It is tempting
2165 # this allows execution of indented pasted code. It is tempting
2147 # to add '\n' at the end of source to run commands like ' a=1'
2166 # to add '\n' at the end of source to run commands like ' a=1'
2148 # directly, but this fails for more complicated scenarios
2167 # directly, but this fails for more complicated scenarios
2149 source=source.encode(self.stdin_encoding)
2168 source=source.encode(self.stdin_encoding)
2150 if source[:1] in [' ', '\t']:
2169 if source[:1] in [' ', '\t']:
2151 source = 'if 1:\n%s' % source
2170 source = 'if 1:\n%s' % source
2152
2171
2153 try:
2172 try:
2154 code = self.compile(source,filename,symbol)
2173 code = self.compile(source,filename,symbol)
2155 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2174 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2156 # Case 1
2175 # Case 1
2157 self.showsyntaxerror(filename)
2176 self.showsyntaxerror(filename)
2158 return None
2177 return None
2159
2178
2160 if code is None:
2179 if code is None:
2161 # Case 2
2180 # Case 2
2162 return True
2181 return True
2163
2182
2164 # Case 3
2183 # Case 3
2165 # We store the code object so that threaded shells and
2184 # We store the code object so that threaded shells and
2166 # custom exception handlers can access all this info if needed.
2185 # custom exception handlers can access all this info if needed.
2167 # The source corresponding to this can be obtained from the
2186 # The source corresponding to this can be obtained from the
2168 # buffer attribute as '\n'.join(self.buffer).
2187 # buffer attribute as '\n'.join(self.buffer).
2169 self.code_to_run = code
2188 self.code_to_run = code
2170 # now actually execute the code object
2189 # now actually execute the code object
2171 if self.runcode(code) == 0:
2190 if self.runcode(code) == 0:
2172 return False
2191 return False
2173 else:
2192 else:
2174 return None
2193 return None
2175
2194
2176 def runcode(self,code_obj):
2195 def runcode(self,code_obj):
2177 """Execute a code object.
2196 """Execute a code object.
2178
2197
2179 When an exception occurs, self.showtraceback() is called to display a
2198 When an exception occurs, self.showtraceback() is called to display a
2180 traceback.
2199 traceback.
2181
2200
2182 Return value: a flag indicating whether the code to be run completed
2201 Return value: a flag indicating whether the code to be run completed
2183 successfully:
2202 successfully:
2184
2203
2185 - 0: successful execution.
2204 - 0: successful execution.
2186 - 1: an error occurred.
2205 - 1: an error occurred.
2187 """
2206 """
2188
2207
2189 # Set our own excepthook in case the user code tries to call it
2208 # Set our own excepthook in case the user code tries to call it
2190 # directly, so that the IPython crash handler doesn't get triggered
2209 # directly, so that the IPython crash handler doesn't get triggered
2191 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2210 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2192
2211
2193 # we save the original sys.excepthook in the instance, in case config
2212 # we save the original sys.excepthook in the instance, in case config
2194 # code (such as magics) needs access to it.
2213 # code (such as magics) needs access to it.
2195 self.sys_excepthook = old_excepthook
2214 self.sys_excepthook = old_excepthook
2196 outflag = 1 # happens in more places, so it's easier as default
2215 outflag = 1 # happens in more places, so it's easier as default
2197 try:
2216 try:
2198 try:
2217 try:
2199 self.hooks.pre_runcode_hook()
2218 self.hooks.pre_runcode_hook()
2200 exec code_obj in self.user_global_ns, self.user_ns
2219 exec code_obj in self.user_global_ns, self.user_ns
2201 finally:
2220 finally:
2202 # Reset our crash handler in place
2221 # Reset our crash handler in place
2203 sys.excepthook = old_excepthook
2222 sys.excepthook = old_excepthook
2204 except SystemExit:
2223 except SystemExit:
2205 self.resetbuffer()
2224 self.resetbuffer()
2206 self.showtraceback(exception_only=True)
2225 self.showtraceback(exception_only=True)
2207 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2226 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2208 except self.custom_exceptions:
2227 except self.custom_exceptions:
2209 etype,value,tb = sys.exc_info()
2228 etype,value,tb = sys.exc_info()
2210 self.CustomTB(etype,value,tb)
2229 self.CustomTB(etype,value,tb)
2211 except:
2230 except:
2212 self.showtraceback()
2231 self.showtraceback()
2213 else:
2232 else:
2214 outflag = 0
2233 outflag = 0
2215 if softspace(sys.stdout, 0):
2234 if softspace(sys.stdout, 0):
2216 print
2235 print
2217 # Flush out code object which has been run (and source)
2236 # Flush out code object which has been run (and source)
2218 self.code_to_run = None
2237 self.code_to_run = None
2219 return outflag
2238 return outflag
2220
2239
2221 def push_line(self, line):
2240 def push_line(self, line):
2222 """Push a line to the interpreter.
2241 """Push a line to the interpreter.
2223
2242
2224 The line should not have a trailing newline; it may have
2243 The line should not have a trailing newline; it may have
2225 internal newlines. The line is appended to a buffer and the
2244 internal newlines. The line is appended to a buffer and the
2226 interpreter's runsource() method is called with the
2245 interpreter's runsource() method is called with the
2227 concatenated contents of the buffer as source. If this
2246 concatenated contents of the buffer as source. If this
2228 indicates that the command was executed or invalid, the buffer
2247 indicates that the command was executed or invalid, the buffer
2229 is reset; otherwise, the command is incomplete, and the buffer
2248 is reset; otherwise, the command is incomplete, and the buffer
2230 is left as it was after the line was appended. The return
2249 is left as it was after the line was appended. The return
2231 value is 1 if more input is required, 0 if the line was dealt
2250 value is 1 if more input is required, 0 if the line was dealt
2232 with in some way (this is the same as runsource()).
2251 with in some way (this is the same as runsource()).
2233 """
2252 """
2234
2253
2235 # autoindent management should be done here, and not in the
2254 # autoindent management should be done here, and not in the
2236 # interactive loop, since that one is only seen by keyboard input. We
2255 # interactive loop, since that one is only seen by keyboard input. We
2237 # need this done correctly even for code run via runlines (which uses
2256 # need this done correctly even for code run via runlines (which uses
2238 # push).
2257 # push).
2239
2258
2240 #print 'push line: <%s>' % line # dbg
2259 #print 'push line: <%s>' % line # dbg
2241 for subline in line.splitlines():
2260 for subline in line.splitlines():
2242 self._autoindent_update(subline)
2261 self._autoindent_update(subline)
2243 self.buffer.append(line)
2262 self.buffer.append(line)
2244 more = self.runsource('\n'.join(self.buffer), self.filename)
2263 more = self.runsource('\n'.join(self.buffer), self.filename)
2245 if not more:
2264 if not more:
2246 self.resetbuffer()
2265 self.resetbuffer()
2247 return more
2266 return more
2248
2267
2249 def _autoindent_update(self,line):
2268 def _autoindent_update(self,line):
2250 """Keep track of the indent level."""
2269 """Keep track of the indent level."""
2251
2270
2252 #debugx('line')
2271 #debugx('line')
2253 #debugx('self.indent_current_nsp')
2272 #debugx('self.indent_current_nsp')
2254 if self.autoindent:
2273 if self.autoindent:
2255 if line:
2274 if line:
2256 inisp = num_ini_spaces(line)
2275 inisp = num_ini_spaces(line)
2257 if inisp < self.indent_current_nsp:
2276 if inisp < self.indent_current_nsp:
2258 self.indent_current_nsp = inisp
2277 self.indent_current_nsp = inisp
2259
2278
2260 if line[-1] == ':':
2279 if line[-1] == ':':
2261 self.indent_current_nsp += 4
2280 self.indent_current_nsp += 4
2262 elif dedent_re.match(line):
2281 elif dedent_re.match(line):
2263 self.indent_current_nsp -= 4
2282 self.indent_current_nsp -= 4
2264 else:
2283 else:
2265 self.indent_current_nsp = 0
2284 self.indent_current_nsp = 0
2266
2285
2267 def resetbuffer(self):
2286 def resetbuffer(self):
2268 """Reset the input buffer."""
2287 """Reset the input buffer."""
2269 self.buffer[:] = []
2288 self.buffer[:] = []
2270
2289
2271 def raw_input(self,prompt='',continue_prompt=False):
2290 def raw_input(self,prompt='',continue_prompt=False):
2272 """Write a prompt and read a line.
2291 """Write a prompt and read a line.
2273
2292
2274 The returned line does not include the trailing newline.
2293 The returned line does not include the trailing newline.
2275 When the user enters the EOF key sequence, EOFError is raised.
2294 When the user enters the EOF key sequence, EOFError is raised.
2276
2295
2277 Optional inputs:
2296 Optional inputs:
2278
2297
2279 - prompt(''): a string to be printed to prompt the user.
2298 - prompt(''): a string to be printed to prompt the user.
2280
2299
2281 - continue_prompt(False): whether this line is the first one or a
2300 - continue_prompt(False): whether this line is the first one or a
2282 continuation in a sequence of inputs.
2301 continuation in a sequence of inputs.
2283 """
2302 """
2284 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2303 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2285
2304
2286 # Code run by the user may have modified the readline completer state.
2305 # Code run by the user may have modified the readline completer state.
2287 # We must ensure that our completer is back in place.
2306 # We must ensure that our completer is back in place.
2288
2307
2289 if self.has_readline:
2308 if self.has_readline:
2290 self.set_completer()
2309 self.set_completer()
2291
2310
2292 try:
2311 try:
2293 line = raw_input_original(prompt).decode(self.stdin_encoding)
2312 line = raw_input_original(prompt).decode(self.stdin_encoding)
2294 except ValueError:
2313 except ValueError:
2295 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
2314 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
2296 " or sys.stdout.close()!\nExiting IPython!")
2315 " or sys.stdout.close()!\nExiting IPython!")
2297 self.ask_exit()
2316 self.ask_exit()
2298 return ""
2317 return ""
2299
2318
2300 # Try to be reasonably smart about not re-indenting pasted input more
2319 # Try to be reasonably smart about not re-indenting pasted input more
2301 # than necessary. We do this by trimming out the auto-indent initial
2320 # than necessary. We do this by trimming out the auto-indent initial
2302 # spaces, if the user's actual input started itself with whitespace.
2321 # spaces, if the user's actual input started itself with whitespace.
2303 #debugx('self.buffer[-1]')
2322 #debugx('self.buffer[-1]')
2304
2323
2305 if self.autoindent:
2324 if self.autoindent:
2306 if num_ini_spaces(line) > self.indent_current_nsp:
2325 if num_ini_spaces(line) > self.indent_current_nsp:
2307 line = line[self.indent_current_nsp:]
2326 line = line[self.indent_current_nsp:]
2308 self.indent_current_nsp = 0
2327 self.indent_current_nsp = 0
2309
2328
2310 # store the unfiltered input before the user has any chance to modify
2329 # store the unfiltered input before the user has any chance to modify
2311 # it.
2330 # it.
2312 if line.strip():
2331 if line.strip():
2313 if continue_prompt:
2332 if continue_prompt:
2314 self.input_hist_raw[-1] += '%s\n' % line
2333 self.input_hist_raw[-1] += '%s\n' % line
2315 if self.has_readline and self.readline_use:
2334 if self.has_readline and self.readline_use:
2316 try:
2335 try:
2317 histlen = self.readline.get_current_history_length()
2336 histlen = self.readline.get_current_history_length()
2318 if histlen > 1:
2337 if histlen > 1:
2319 newhist = self.input_hist_raw[-1].rstrip()
2338 newhist = self.input_hist_raw[-1].rstrip()
2320 self.readline.remove_history_item(histlen-1)
2339 self.readline.remove_history_item(histlen-1)
2321 self.readline.replace_history_item(histlen-2,
2340 self.readline.replace_history_item(histlen-2,
2322 newhist.encode(self.stdin_encoding))
2341 newhist.encode(self.stdin_encoding))
2323 except AttributeError:
2342 except AttributeError:
2324 pass # re{move,place}_history_item are new in 2.4.
2343 pass # re{move,place}_history_item are new in 2.4.
2325 else:
2344 else:
2326 self.input_hist_raw.append('%s\n' % line)
2345 self.input_hist_raw.append('%s\n' % line)
2327 # only entries starting at first column go to shadow history
2346 # only entries starting at first column go to shadow history
2328 if line.lstrip() == line:
2347 if line.lstrip() == line:
2329 self.shadowhist.add(line.strip())
2348 self.shadowhist.add(line.strip())
2330 elif not continue_prompt:
2349 elif not continue_prompt:
2331 self.input_hist_raw.append('\n')
2350 self.input_hist_raw.append('\n')
2332 try:
2351 try:
2333 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2352 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2334 except:
2353 except:
2335 # blanket except, in case a user-defined prefilter crashes, so it
2354 # blanket except, in case a user-defined prefilter crashes, so it
2336 # can't take all of ipython with it.
2355 # can't take all of ipython with it.
2337 self.showtraceback()
2356 self.showtraceback()
2338 return ''
2357 return ''
2339 else:
2358 else:
2340 return lineout
2359 return lineout
2341
2360
2342 #-------------------------------------------------------------------------
2361 #-------------------------------------------------------------------------
2343 # Working with components
2344 #-------------------------------------------------------------------------
2345
2346 def get_component(self, name=None, klass=None):
2347 """Fetch a component by name and klass in my tree."""
2348 c = Component.get_instances(root=self, name=name, klass=klass)
2349 if len(c) == 0:
2350 return None
2351 if len(c) == 1:
2352 return c[0]
2353 else:
2354 return c
2355
2356 #-------------------------------------------------------------------------
2357 # IPython extensions
2358 #-------------------------------------------------------------------------
2359
2360 def load_extension(self, module_str):
2361 """Load an IPython extension by its module name.
2362
2363 An IPython extension is an importable Python module that has
2364 a function with the signature::
2365
2366 def load_ipython_extension(ipython):
2367 # Do things with ipython
2368
2369 This function is called after your extension is imported and the
2370 currently active :class:`InteractiveShell` instance is passed as
2371 the only argument. You can do anything you want with IPython at
2372 that point, including defining new magic and aliases, adding new
2373 components, etc.
2374
2375 The :func:`load_ipython_extension` will be called again is you
2376 load or reload the extension again. It is up to the extension
2377 author to add code to manage that.
2378
2379 You can put your extension modules anywhere you want, as long as
2380 they can be imported by Python's standard import mechanism. However,
2381 to make it easy to write extensions, you can also put your extensions
2382 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
2383 is added to ``sys.path`` automatically.
2384
2385 If :func:`load_ipython_extension` returns anything, this function
2386 will return that object.
2387 """
2388 from IPython.utils.syspathcontext import prepended_to_syspath
2389
2390 if module_str not in sys.modules:
2391 with prepended_to_syspath(self.ipython_extension_dir):
2392 __import__(module_str)
2393 mod = sys.modules[module_str]
2394 return self._call_load_ipython_extension(mod)
2395
2396 def unload_extension(self, module_str):
2397 """Unload an IPython extension by its module name.
2398
2399 This function looks up the extension's name in ``sys.modules`` and
2400 simply calls ``mod.unload_ipython_extension(self)``.
2401 """
2402 if module_str in sys.modules:
2403 mod = sys.modules[module_str]
2404 self._call_unload_ipython_extension(mod)
2405
2406 def reload_extension(self, module_str):
2407 """Reload an IPython extension by calling reload.
2408
2409 If the module has not been loaded before,
2410 :meth:`InteractiveShell.load_extension` is called. Otherwise
2411 :func:`reload` is called and then the :func:`load_ipython_extension`
2412 function of the module, if it exists is called.
2413 """
2414 from IPython.utils.syspathcontext import prepended_to_syspath
2415
2416 with prepended_to_syspath(self.ipython_extension_dir):
2417 if module_str in sys.modules:
2418 mod = sys.modules[module_str]
2419 reload(mod)
2420 self._call_load_ipython_extension(mod)
2421 else:
2422 self.load_extension(module_str)
2423
2424 def _call_load_ipython_extension(self, mod):
2425 if hasattr(mod, 'load_ipython_extension'):
2426 return mod.load_ipython_extension(self)
2427
2428 def _call_unload_ipython_extension(self, mod):
2429 if hasattr(mod, 'unload_ipython_extension'):
2430 return mod.unload_ipython_extension(self)
2431
2432 #-------------------------------------------------------------------------
2433 # Things related to the prefilter
2362 # Things related to the prefilter
2434 #-------------------------------------------------------------------------
2363 #-------------------------------------------------------------------------
2435
2364
2436 def init_prefilter(self):
2365 def init_prefilter(self):
2437 self.prefilter_manager = PrefilterManager(self, config=self.config)
2366 self.prefilter_manager = PrefilterManager(self, config=self.config)
2438 # Ultimately this will be refactored in the new interpreter code, but
2367 # Ultimately this will be refactored in the new interpreter code, but
2439 # for now, we should expose the main prefilter method (there's legacy
2368 # for now, we should expose the main prefilter method (there's legacy
2440 # code out there that may rely on this).
2369 # code out there that may rely on this).
2441 self.prefilter = self.prefilter_manager.prefilter_lines
2370 self.prefilter = self.prefilter_manager.prefilter_lines
2442
2371
2443 #-------------------------------------------------------------------------
2372 #-------------------------------------------------------------------------
2444 # Utilities
2373 # Utilities
2445 #-------------------------------------------------------------------------
2374 #-------------------------------------------------------------------------
2446
2375
2447 def getoutput(self, cmd):
2376 def getoutput(self, cmd):
2448 return getoutput(self.var_expand(cmd,depth=2),
2377 return getoutput(self.var_expand(cmd,depth=2),
2449 header=self.system_header,
2378 header=self.system_header,
2450 verbose=self.system_verbose)
2379 verbose=self.system_verbose)
2451
2380
2452 def getoutputerror(self, cmd):
2381 def getoutputerror(self, cmd):
2453 return getoutputerror(self.var_expand(cmd,depth=2),
2382 return getoutputerror(self.var_expand(cmd,depth=2),
2454 header=self.system_header,
2383 header=self.system_header,
2455 verbose=self.system_verbose)
2384 verbose=self.system_verbose)
2456
2385
2457 def var_expand(self,cmd,depth=0):
2386 def var_expand(self,cmd,depth=0):
2458 """Expand python variables in a string.
2387 """Expand python variables in a string.
2459
2388
2460 The depth argument indicates how many frames above the caller should
2389 The depth argument indicates how many frames above the caller should
2461 be walked to look for the local namespace where to expand variables.
2390 be walked to look for the local namespace where to expand variables.
2462
2391
2463 The global namespace for expansion is always the user's interactive
2392 The global namespace for expansion is always the user's interactive
2464 namespace.
2393 namespace.
2465 """
2394 """
2466
2395
2467 return str(ItplNS(cmd,
2396 return str(ItplNS(cmd,
2468 self.user_ns, # globals
2397 self.user_ns, # globals
2469 # Skip our own frame in searching for locals:
2398 # Skip our own frame in searching for locals:
2470 sys._getframe(depth+1).f_locals # locals
2399 sys._getframe(depth+1).f_locals # locals
2471 ))
2400 ))
2472
2401
2473 def mktempfile(self,data=None):
2402 def mktempfile(self,data=None):
2474 """Make a new tempfile and return its filename.
2403 """Make a new tempfile and return its filename.
2475
2404
2476 This makes a call to tempfile.mktemp, but it registers the created
2405 This makes a call to tempfile.mktemp, but it registers the created
2477 filename internally so ipython cleans it up at exit time.
2406 filename internally so ipython cleans it up at exit time.
2478
2407
2479 Optional inputs:
2408 Optional inputs:
2480
2409
2481 - data(None): if data is given, it gets written out to the temp file
2410 - data(None): if data is given, it gets written out to the temp file
2482 immediately, and the file is closed again."""
2411 immediately, and the file is closed again."""
2483
2412
2484 filename = tempfile.mktemp('.py','ipython_edit_')
2413 filename = tempfile.mktemp('.py','ipython_edit_')
2485 self.tempfiles.append(filename)
2414 self.tempfiles.append(filename)
2486
2415
2487 if data:
2416 if data:
2488 tmp_file = open(filename,'w')
2417 tmp_file = open(filename,'w')
2489 tmp_file.write(data)
2418 tmp_file.write(data)
2490 tmp_file.close()
2419 tmp_file.close()
2491 return filename
2420 return filename
2492
2421
2493 def write(self,data):
2422 def write(self,data):
2494 """Write a string to the default output"""
2423 """Write a string to the default output"""
2495 Term.cout.write(data)
2424 Term.cout.write(data)
2496
2425
2497 def write_err(self,data):
2426 def write_err(self,data):
2498 """Write a string to the default error output"""
2427 """Write a string to the default error output"""
2499 Term.cerr.write(data)
2428 Term.cerr.write(data)
2500
2429
2501 def ask_yes_no(self,prompt,default=True):
2430 def ask_yes_no(self,prompt,default=True):
2502 if self.quiet:
2431 if self.quiet:
2503 return True
2432 return True
2504 return ask_yes_no(prompt,default)
2433 return ask_yes_no(prompt,default)
2505
2434
2506 #-------------------------------------------------------------------------
2435 #-------------------------------------------------------------------------
2507 # Things related to GUI support and pylab
2436 # Things related to GUI support and pylab
2508 #-------------------------------------------------------------------------
2437 #-------------------------------------------------------------------------
2509
2438
2510 def enable_pylab(self, gui=None):
2439 def enable_pylab(self, gui=None):
2511 """Activate pylab support at runtime.
2440 """Activate pylab support at runtime.
2512
2441
2513 This turns on support for matplotlib, preloads into the interactive
2442 This turns on support for matplotlib, preloads into the interactive
2514 namespace all of numpy and pylab, and configures IPython to correcdtly
2443 namespace all of numpy and pylab, and configures IPython to correcdtly
2515 interact with the GUI event loop. The GUI backend to be used can be
2444 interact with the GUI event loop. The GUI backend to be used can be
2516 optionally selected with the optional :param:`gui` argument.
2445 optionally selected with the optional :param:`gui` argument.
2517
2446
2518 Parameters
2447 Parameters
2519 ----------
2448 ----------
2520 gui : optional, string
2449 gui : optional, string
2521
2450
2522 If given, dictates the choice of matplotlib GUI backend to use
2451 If given, dictates the choice of matplotlib GUI backend to use
2523 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
2452 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
2524 'gtk'), otherwise we use the default chosen by matplotlib (as
2453 'gtk'), otherwise we use the default chosen by matplotlib (as
2525 dictated by the matplotlib build-time options plus the user's
2454 dictated by the matplotlib build-time options plus the user's
2526 matplotlibrc configuration file).
2455 matplotlibrc configuration file).
2527 """
2456 """
2528 # We want to prevent the loading of pylab to pollute the user's
2457 # We want to prevent the loading of pylab to pollute the user's
2529 # namespace as shown by the %who* magics, so we execute the activation
2458 # namespace as shown by the %who* magics, so we execute the activation
2530 # code in an empty namespace, and we update *both* user_ns and
2459 # code in an empty namespace, and we update *both* user_ns and
2531 # user_ns_hidden with this information.
2460 # user_ns_hidden with this information.
2532 ns = {}
2461 ns = {}
2533 gui = pylab_activate(ns, gui)
2462 gui = pylab_activate(ns, gui)
2534 self.user_ns.update(ns)
2463 self.user_ns.update(ns)
2535 self.user_ns_hidden.update(ns)
2464 self.user_ns_hidden.update(ns)
2536 # Now we must activate the gui pylab wants to use, and fix %run to take
2465 # Now we must activate the gui pylab wants to use, and fix %run to take
2537 # plot updates into account
2466 # plot updates into account
2538 enable_gui(gui)
2467 enable_gui(gui)
2539 self.magic_run = self._pylab_magic_run
2468 self.magic_run = self._pylab_magic_run
2540
2469
2541 #-------------------------------------------------------------------------
2470 #-------------------------------------------------------------------------
2542 # Things related to IPython exiting
2471 # Things related to IPython exiting
2543 #-------------------------------------------------------------------------
2472 #-------------------------------------------------------------------------
2544
2473
2545 def ask_exit(self):
2474 def ask_exit(self):
2546 """ Ask the shell to exit. Can be overiden and used as a callback. """
2475 """ Ask the shell to exit. Can be overiden and used as a callback. """
2547 self.exit_now = True
2476 self.exit_now = True
2548
2477
2549 def exit(self):
2478 def exit(self):
2550 """Handle interactive exit.
2479 """Handle interactive exit.
2551
2480
2552 This method calls the ask_exit callback."""
2481 This method calls the ask_exit callback."""
2553 if self.confirm_exit:
2482 if self.confirm_exit:
2554 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
2483 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
2555 self.ask_exit()
2484 self.ask_exit()
2556 else:
2485 else:
2557 self.ask_exit()
2486 self.ask_exit()
2558
2487
2559 def atexit_operations(self):
2488 def atexit_operations(self):
2560 """This will be executed at the time of exit.
2489 """This will be executed at the time of exit.
2561
2490
2562 Saving of persistent data should be performed here.
2491 Saving of persistent data should be performed here.
2563 """
2492 """
2564 self.savehist()
2493 self.savehist()
2565
2494
2566 # Cleanup all tempfiles left around
2495 # Cleanup all tempfiles left around
2567 for tfile in self.tempfiles:
2496 for tfile in self.tempfiles:
2568 try:
2497 try:
2569 os.unlink(tfile)
2498 os.unlink(tfile)
2570 except OSError:
2499 except OSError:
2571 pass
2500 pass
2572
2501
2573 # Clear all user namespaces to release all references cleanly.
2502 # Clear all user namespaces to release all references cleanly.
2574 self.reset()
2503 self.reset()
2575
2504
2576 # Run user hooks
2505 # Run user hooks
2577 self.hooks.shutdown_hook()
2506 self.hooks.shutdown_hook()
2578
2507
2579 def cleanup(self):
2508 def cleanup(self):
2580 self.restore_sys_module_state()
2509 self.restore_sys_module_state()
2581
2510
2582
2511
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,1050 +1,1016 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Prefiltering components.
4 Prefiltering components.
5
5
6 Prefilters transform user input before it is exec'd by Python. These
6 Prefilters transform user input before it is exec'd by Python. These
7 transforms are used to implement additional syntax such as !ls and %magic.
7 transforms are used to implement additional syntax such as !ls and %magic.
8
8
9 Authors:
9 Authors:
10
10
11 * Brian Granger
11 * Brian Granger
12 * Fernando Perez
12 * Fernando Perez
13 * Dan Milstein
13 * Dan Milstein
14 * Ville Vainio
14 * Ville Vainio
15 """
15 """
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2008-2009 The IPython Development Team
18 # Copyright (C) 2008-2009 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 import __builtin__
28 import __builtin__
29 import codeop
29 import codeop
30 import re
30 import re
31
31
32 from IPython.core.alias import AliasManager
32 from IPython.core.alias import AliasManager
33 from IPython.core.autocall import IPyAutocall
33 from IPython.core.autocall import IPyAutocall
34 from IPython.core.component import Component
34 from IPython.config.configurable import Configurable
35 from IPython.core.splitinput import split_user_input
35 from IPython.core.splitinput import split_user_input
36 from IPython.core.page import page
36 from IPython.core.page import page
37
37
38 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool
38 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool, Instance
39 from IPython.utils.io import Term
39 from IPython.utils.io import Term
40 from IPython.utils.text import make_quoted_expr
40 from IPython.utils.text import make_quoted_expr
41 from IPython.utils.autoattr import auto_attr
41 from IPython.utils.autoattr import auto_attr
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Global utilities, errors and constants
44 # Global utilities, errors and constants
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 # Warning, these cannot be changed unless various regular expressions
47 # Warning, these cannot be changed unless various regular expressions
48 # are updated in a number of places. Not great, but at least we told you.
48 # are updated in a number of places. Not great, but at least we told you.
49 ESC_SHELL = '!'
49 ESC_SHELL = '!'
50 ESC_SH_CAP = '!!'
50 ESC_SH_CAP = '!!'
51 ESC_HELP = '?'
51 ESC_HELP = '?'
52 ESC_MAGIC = '%'
52 ESC_MAGIC = '%'
53 ESC_QUOTE = ','
53 ESC_QUOTE = ','
54 ESC_QUOTE2 = ';'
54 ESC_QUOTE2 = ';'
55 ESC_PAREN = '/'
55 ESC_PAREN = '/'
56
56
57
57
58 class PrefilterError(Exception):
58 class PrefilterError(Exception):
59 pass
59 pass
60
60
61
61
62 # RegExp to identify potential function names
62 # RegExp to identify potential function names
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
64
64
65 # RegExp to exclude strings with this start from autocalling. In
65 # RegExp to exclude strings with this start from autocalling. In
66 # particular, all binary operators should be excluded, so that if foo is
66 # particular, all binary operators should be excluded, so that if foo is
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
69 # routine explicitely does so, to catch direct calls and rebindings of
69 # routine explicitely does so, to catch direct calls and rebindings of
70 # existing names.
70 # existing names.
71
71
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
73 # it affects the rest of the group in square brackets.
73 # it affects the rest of the group in square brackets.
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
75 r'|^is |^not |^in |^and |^or ')
75 r'|^is |^not |^in |^and |^or ')
76
76
77 # try to catch also methods for stuff in lists/tuples/dicts: off
77 # try to catch also methods for stuff in lists/tuples/dicts: off
78 # (experimental). For this to work, the line_split regexp would need
78 # (experimental). For this to work, the line_split regexp would need
79 # to be modified so it wouldn't break things at '['. That line is
79 # to be modified so it wouldn't break things at '['. That line is
80 # nasty enough that I shouldn't change it until I can test it _well_.
80 # nasty enough that I shouldn't change it until I can test it _well_.
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
82
82
83
83
84 # Handler Check Utilities
84 # Handler Check Utilities
85 def is_shadowed(identifier, ip):
85 def is_shadowed(identifier, ip):
86 """Is the given identifier defined in one of the namespaces which shadow
86 """Is the given identifier defined in one of the namespaces which shadow
87 the alias and magic namespaces? Note that an identifier is different
87 the alias and magic namespaces? Note that an identifier is different
88 than ifun, because it can not contain a '.' character."""
88 than ifun, because it can not contain a '.' character."""
89 # This is much safer than calling ofind, which can change state
89 # This is much safer than calling ofind, which can change state
90 return (identifier in ip.user_ns \
90 return (identifier in ip.user_ns \
91 or identifier in ip.internal_ns \
91 or identifier in ip.internal_ns \
92 or identifier in ip.ns_table['builtin'])
92 or identifier in ip.ns_table['builtin'])
93
93
94
94
95 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
96 # The LineInfo class used throughout
96 # The LineInfo class used throughout
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98
98
99
99
100 class LineInfo(object):
100 class LineInfo(object):
101 """A single line of input and associated info.
101 """A single line of input and associated info.
102
102
103 Includes the following as properties:
103 Includes the following as properties:
104
104
105 line
105 line
106 The original, raw line
106 The original, raw line
107
107
108 continue_prompt
108 continue_prompt
109 Is this line a continuation in a sequence of multiline input?
109 Is this line a continuation in a sequence of multiline input?
110
110
111 pre
111 pre
112 The initial esc character or whitespace.
112 The initial esc character or whitespace.
113
113
114 pre_char
114 pre_char
115 The escape character(s) in pre or the empty string if there isn't one.
115 The escape character(s) in pre or the empty string if there isn't one.
116 Note that '!!' is a possible value for pre_char. Otherwise it will
116 Note that '!!' is a possible value for pre_char. Otherwise it will
117 always be a single character.
117 always be a single character.
118
118
119 pre_whitespace
119 pre_whitespace
120 The leading whitespace from pre if it exists. If there is a pre_char,
120 The leading whitespace from pre if it exists. If there is a pre_char,
121 this is just ''.
121 this is just ''.
122
122
123 ifun
123 ifun
124 The 'function part', which is basically the maximal initial sequence
124 The 'function part', which is basically the maximal initial sequence
125 of valid python identifiers and the '.' character. This is what is
125 of valid python identifiers and the '.' character. This is what is
126 checked for alias and magic transformations, used for auto-calling,
126 checked for alias and magic transformations, used for auto-calling,
127 etc.
127 etc.
128
128
129 the_rest
129 the_rest
130 Everything else on the line.
130 Everything else on the line.
131 """
131 """
132 def __init__(self, line, continue_prompt):
132 def __init__(self, line, continue_prompt):
133 self.line = line
133 self.line = line
134 self.continue_prompt = continue_prompt
134 self.continue_prompt = continue_prompt
135 self.pre, self.ifun, self.the_rest = split_user_input(line)
135 self.pre, self.ifun, self.the_rest = split_user_input(line)
136
136
137 self.pre_char = self.pre.strip()
137 self.pre_char = self.pre.strip()
138 if self.pre_char:
138 if self.pre_char:
139 self.pre_whitespace = '' # No whitespace allowd before esc chars
139 self.pre_whitespace = '' # No whitespace allowd before esc chars
140 else:
140 else:
141 self.pre_whitespace = self.pre
141 self.pre_whitespace = self.pre
142
142
143 self._oinfo = None
143 self._oinfo = None
144
144
145 def ofind(self, ip):
145 def ofind(self, ip):
146 """Do a full, attribute-walking lookup of the ifun in the various
146 """Do a full, attribute-walking lookup of the ifun in the various
147 namespaces for the given IPython InteractiveShell instance.
147 namespaces for the given IPython InteractiveShell instance.
148
148
149 Return a dict with keys: found,obj,ospace,ismagic
149 Return a dict with keys: found,obj,ospace,ismagic
150
150
151 Note: can cause state changes because of calling getattr, but should
151 Note: can cause state changes because of calling getattr, but should
152 only be run if autocall is on and if the line hasn't matched any
152 only be run if autocall is on and if the line hasn't matched any
153 other, less dangerous handlers.
153 other, less dangerous handlers.
154
154
155 Does cache the results of the call, so can be called multiple times
155 Does cache the results of the call, so can be called multiple times
156 without worrying about *further* damaging state.
156 without worrying about *further* damaging state.
157 """
157 """
158 if not self._oinfo:
158 if not self._oinfo:
159 # ip.shell._ofind is actually on the Magic class!
159 # ip.shell._ofind is actually on the Magic class!
160 self._oinfo = ip.shell._ofind(self.ifun)
160 self._oinfo = ip.shell._ofind(self.ifun)
161 return self._oinfo
161 return self._oinfo
162
162
163 def __str__(self):
163 def __str__(self):
164 return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest)
164 return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest)
165
165
166
166
167 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
168 # Main Prefilter manager
168 # Main Prefilter manager
169 #-----------------------------------------------------------------------------
169 #-----------------------------------------------------------------------------
170
170
171
171
172 class PrefilterManager(Component):
172 class PrefilterManager(Configurable):
173 """Main prefilter component.
173 """Main prefilter component.
174
174
175 The IPython prefilter is run on all user input before it is run. The
175 The IPython prefilter is run on all user input before it is run. The
176 prefilter consumes lines of input and produces transformed lines of
176 prefilter consumes lines of input and produces transformed lines of
177 input.
177 input.
178
178
179 The iplementation consists of two phases:
179 The iplementation consists of two phases:
180
180
181 1. Transformers
181 1. Transformers
182 2. Checkers and handlers
182 2. Checkers and handlers
183
183
184 Over time, we plan on deprecating the checkers and handlers and doing
184 Over time, we plan on deprecating the checkers and handlers and doing
185 everything in the transformers.
185 everything in the transformers.
186
186
187 The transformers are instances of :class:`PrefilterTransformer` and have
187 The transformers are instances of :class:`PrefilterTransformer` and have
188 a single method :meth:`transform` that takes a line and returns a
188 a single method :meth:`transform` that takes a line and returns a
189 transformed line. The transformation can be accomplished using any
189 transformed line. The transformation can be accomplished using any
190 tool, but our current ones use regular expressions for speed. We also
190 tool, but our current ones use regular expressions for speed. We also
191 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
191 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
192
192
193 After all the transformers have been run, the line is fed to the checkers,
193 After all the transformers have been run, the line is fed to the checkers,
194 which are instances of :class:`PrefilterChecker`. The line is passed to
194 which are instances of :class:`PrefilterChecker`. The line is passed to
195 the :meth:`check` method, which either returns `None` or a
195 the :meth:`check` method, which either returns `None` or a
196 :class:`PrefilterHandler` instance. If `None` is returned, the other
196 :class:`PrefilterHandler` instance. If `None` is returned, the other
197 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
197 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
198 the line is passed to the :meth:`handle` method of the returned
198 the line is passed to the :meth:`handle` method of the returned
199 handler and no further checkers are tried.
199 handler and no further checkers are tried.
200
200
201 Both transformers and checkers have a `priority` attribute, that determines
201 Both transformers and checkers have a `priority` attribute, that determines
202 the order in which they are called. Smaller priorities are tried first.
202 the order in which they are called. Smaller priorities are tried first.
203
203
204 Both transformers and checkers also have `enabled` attribute, which is
204 Both transformers and checkers also have `enabled` attribute, which is
205 a boolean that determines if the instance is used.
205 a boolean that determines if the instance is used.
206
206
207 Users or developers can change the priority or enabled attribute of
207 Users or developers can change the priority or enabled attribute of
208 transformers or checkers, but they must call the :meth:`sort_checkers`
208 transformers or checkers, but they must call the :meth:`sort_checkers`
209 or :meth:`sort_transformers` method after changing the priority.
209 or :meth:`sort_transformers` method after changing the priority.
210 """
210 """
211
211
212 multi_line_specials = CBool(True, config=True)
212 multi_line_specials = CBool(True, config=True)
213 shell = Instance('IPython.core.iplib.InteractiveShell')
213
214
214 def __init__(self, parent, config=None):
215 def __init__(self, shell, config=None):
215 super(PrefilterManager, self).__init__(parent, config=config)
216 super(PrefilterManager, self).__init__(config=config)
217 self.shell = shell
216 self.init_transformers()
218 self.init_transformers()
217 self.init_handlers()
219 self.init_handlers()
218 self.init_checkers()
220 self.init_checkers()
219
221
220 @auto_attr
221 def shell(self):
222 return Component.get_instances(
223 root=self.root,
224 klass='IPython.core.iplib.InteractiveShell')[0]
225
226 #-------------------------------------------------------------------------
222 #-------------------------------------------------------------------------
227 # API for managing transformers
223 # API for managing transformers
228 #-------------------------------------------------------------------------
224 #-------------------------------------------------------------------------
229
225
230 def init_transformers(self):
226 def init_transformers(self):
231 """Create the default transformers."""
227 """Create the default transformers."""
232 self._transformers = []
228 self._transformers = []
233 for transformer_cls in _default_transformers:
229 for transformer_cls in _default_transformers:
234 transformer_cls(self, config=self.config)
230 transformer_cls(self.shell, self, config=self.config)
235
231
236 def sort_transformers(self):
232 def sort_transformers(self):
237 """Sort the transformers by priority.
233 """Sort the transformers by priority.
238
234
239 This must be called after the priority of a transformer is changed.
235 This must be called after the priority of a transformer is changed.
240 The :meth:`register_transformer` method calls this automatically.
236 The :meth:`register_transformer` method calls this automatically.
241 """
237 """
242 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
238 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
243
239
244 @property
240 @property
245 def transformers(self):
241 def transformers(self):
246 """Return a list of checkers, sorted by priority."""
242 """Return a list of checkers, sorted by priority."""
247 return self._transformers
243 return self._transformers
248
244
249 def register_transformer(self, transformer):
245 def register_transformer(self, transformer):
250 """Register a transformer instance."""
246 """Register a transformer instance."""
251 if transformer not in self._transformers:
247 if transformer not in self._transformers:
252 self._transformers.append(transformer)
248 self._transformers.append(transformer)
253 self.sort_transformers()
249 self.sort_transformers()
254
250
255 def unregister_transformer(self, transformer):
251 def unregister_transformer(self, transformer):
256 """Unregister a transformer instance."""
252 """Unregister a transformer instance."""
257 if transformer in self._transformers:
253 if transformer in self._transformers:
258 self._transformers.remove(transformer)
254 self._transformers.remove(transformer)
259
255
260 #-------------------------------------------------------------------------
256 #-------------------------------------------------------------------------
261 # API for managing checkers
257 # API for managing checkers
262 #-------------------------------------------------------------------------
258 #-------------------------------------------------------------------------
263
259
264 def init_checkers(self):
260 def init_checkers(self):
265 """Create the default checkers."""
261 """Create the default checkers."""
266 self._checkers = []
262 self._checkers = []
267 for checker in _default_checkers:
263 for checker in _default_checkers:
268 checker(self, config=self.config)
264 checker(self.shell, self, config=self.config)
269
265
270 def sort_checkers(self):
266 def sort_checkers(self):
271 """Sort the checkers by priority.
267 """Sort the checkers by priority.
272
268
273 This must be called after the priority of a checker is changed.
269 This must be called after the priority of a checker is changed.
274 The :meth:`register_checker` method calls this automatically.
270 The :meth:`register_checker` method calls this automatically.
275 """
271 """
276 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
272 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
277
273
278 @property
274 @property
279 def checkers(self):
275 def checkers(self):
280 """Return a list of checkers, sorted by priority."""
276 """Return a list of checkers, sorted by priority."""
281 return self._checkers
277 return self._checkers
282
278
283 def register_checker(self, checker):
279 def register_checker(self, checker):
284 """Register a checker instance."""
280 """Register a checker instance."""
285 if checker not in self._checkers:
281 if checker not in self._checkers:
286 self._checkers.append(checker)
282 self._checkers.append(checker)
287 self.sort_checkers()
283 self.sort_checkers()
288
284
289 def unregister_checker(self, checker):
285 def unregister_checker(self, checker):
290 """Unregister a checker instance."""
286 """Unregister a checker instance."""
291 if checker in self._checkers:
287 if checker in self._checkers:
292 self._checkers.remove(checker)
288 self._checkers.remove(checker)
293
289
294 #-------------------------------------------------------------------------
290 #-------------------------------------------------------------------------
295 # API for managing checkers
291 # API for managing checkers
296 #-------------------------------------------------------------------------
292 #-------------------------------------------------------------------------
297
293
298 def init_handlers(self):
294 def init_handlers(self):
299 """Create the default handlers."""
295 """Create the default handlers."""
300 self._handlers = {}
296 self._handlers = {}
301 self._esc_handlers = {}
297 self._esc_handlers = {}
302 for handler in _default_handlers:
298 for handler in _default_handlers:
303 handler(self, config=self.config)
299 handler(self.shell, self, config=self.config)
304
300
305 @property
301 @property
306 def handlers(self):
302 def handlers(self):
307 """Return a dict of all the handlers."""
303 """Return a dict of all the handlers."""
308 return self._handlers
304 return self._handlers
309
305
310 def register_handler(self, name, handler, esc_strings):
306 def register_handler(self, name, handler, esc_strings):
311 """Register a handler instance by name with esc_strings."""
307 """Register a handler instance by name with esc_strings."""
312 self._handlers[name] = handler
308 self._handlers[name] = handler
313 for esc_str in esc_strings:
309 for esc_str in esc_strings:
314 self._esc_handlers[esc_str] = handler
310 self._esc_handlers[esc_str] = handler
315
311
316 def unregister_handler(self, name, handler, esc_strings):
312 def unregister_handler(self, name, handler, esc_strings):
317 """Unregister a handler instance by name with esc_strings."""
313 """Unregister a handler instance by name with esc_strings."""
318 try:
314 try:
319 del self._handlers[name]
315 del self._handlers[name]
320 except KeyError:
316 except KeyError:
321 pass
317 pass
322 for esc_str in esc_strings:
318 for esc_str in esc_strings:
323 h = self._esc_handlers.get(esc_str)
319 h = self._esc_handlers.get(esc_str)
324 if h is handler:
320 if h is handler:
325 del self._esc_handlers[esc_str]
321 del self._esc_handlers[esc_str]
326
322
327 def get_handler_by_name(self, name):
323 def get_handler_by_name(self, name):
328 """Get a handler by its name."""
324 """Get a handler by its name."""
329 return self._handlers.get(name)
325 return self._handlers.get(name)
330
326
331 def get_handler_by_esc(self, esc_str):
327 def get_handler_by_esc(self, esc_str):
332 """Get a handler by its escape string."""
328 """Get a handler by its escape string."""
333 return self._esc_handlers.get(esc_str)
329 return self._esc_handlers.get(esc_str)
334
330
335 #-------------------------------------------------------------------------
331 #-------------------------------------------------------------------------
336 # Main prefiltering API
332 # Main prefiltering API
337 #-------------------------------------------------------------------------
333 #-------------------------------------------------------------------------
338
334
339 def prefilter_line_info(self, line_info):
335 def prefilter_line_info(self, line_info):
340 """Prefilter a line that has been converted to a LineInfo object.
336 """Prefilter a line that has been converted to a LineInfo object.
341
337
342 This implements the checker/handler part of the prefilter pipe.
338 This implements the checker/handler part of the prefilter pipe.
343 """
339 """
344 # print "prefilter_line_info: ", line_info
340 # print "prefilter_line_info: ", line_info
345 handler = self.find_handler(line_info)
341 handler = self.find_handler(line_info)
346 return handler.handle(line_info)
342 return handler.handle(line_info)
347
343
348 def find_handler(self, line_info):
344 def find_handler(self, line_info):
349 """Find a handler for the line_info by trying checkers."""
345 """Find a handler for the line_info by trying checkers."""
350 for checker in self.checkers:
346 for checker in self.checkers:
351 if checker.enabled:
347 if checker.enabled:
352 handler = checker.check(line_info)
348 handler = checker.check(line_info)
353 if handler:
349 if handler:
354 return handler
350 return handler
355 return self.get_handler_by_name('normal')
351 return self.get_handler_by_name('normal')
356
352
357 def transform_line(self, line, continue_prompt):
353 def transform_line(self, line, continue_prompt):
358 """Calls the enabled transformers in order of increasing priority."""
354 """Calls the enabled transformers in order of increasing priority."""
359 for transformer in self.transformers:
355 for transformer in self.transformers:
360 if transformer.enabled:
356 if transformer.enabled:
361 line = transformer.transform(line, continue_prompt)
357 line = transformer.transform(line, continue_prompt)
362 return line
358 return line
363
359
364 def prefilter_line(self, line, continue_prompt=False):
360 def prefilter_line(self, line, continue_prompt=False):
365 """Prefilter a single input line as text.
361 """Prefilter a single input line as text.
366
362
367 This method prefilters a single line of text by calling the
363 This method prefilters a single line of text by calling the
368 transformers and then the checkers/handlers.
364 transformers and then the checkers/handlers.
369 """
365 """
370
366
371 # print "prefilter_line: ", line, continue_prompt
367 # print "prefilter_line: ", line, continue_prompt
372 # All handlers *must* return a value, even if it's blank ('').
368 # All handlers *must* return a value, even if it's blank ('').
373
369
374 # Lines are NOT logged here. Handlers should process the line as
370 # Lines are NOT logged here. Handlers should process the line as
375 # needed, update the cache AND log it (so that the input cache array
371 # needed, update the cache AND log it (so that the input cache array
376 # stays synced).
372 # stays synced).
377
373
378 # save the line away in case we crash, so the post-mortem handler can
374 # save the line away in case we crash, so the post-mortem handler can
379 # record it
375 # record it
380 self.shell._last_input_line = line
376 self.shell._last_input_line = line
381
377
382 if not line:
378 if not line:
383 # Return immediately on purely empty lines, so that if the user
379 # Return immediately on purely empty lines, so that if the user
384 # previously typed some whitespace that started a continuation
380 # previously typed some whitespace that started a continuation
385 # prompt, he can break out of that loop with just an empty line.
381 # prompt, he can break out of that loop with just an empty line.
386 # This is how the default python prompt works.
382 # This is how the default python prompt works.
387
383
388 # Only return if the accumulated input buffer was just whitespace!
384 # Only return if the accumulated input buffer was just whitespace!
389 if ''.join(self.shell.buffer).isspace():
385 if ''.join(self.shell.buffer).isspace():
390 self.shell.buffer[:] = []
386 self.shell.buffer[:] = []
391 return ''
387 return ''
392
388
393 # At this point, we invoke our transformers.
389 # At this point, we invoke our transformers.
394 if not continue_prompt or (continue_prompt and self.multi_line_specials):
390 if not continue_prompt or (continue_prompt and self.multi_line_specials):
395 line = self.transform_line(line, continue_prompt)
391 line = self.transform_line(line, continue_prompt)
396
392
397 # Now we compute line_info for the checkers and handlers
393 # Now we compute line_info for the checkers and handlers
398 line_info = LineInfo(line, continue_prompt)
394 line_info = LineInfo(line, continue_prompt)
399
395
400 # the input history needs to track even empty lines
396 # the input history needs to track even empty lines
401 stripped = line.strip()
397 stripped = line.strip()
402
398
403 normal_handler = self.get_handler_by_name('normal')
399 normal_handler = self.get_handler_by_name('normal')
404 if not stripped:
400 if not stripped:
405 if not continue_prompt:
401 if not continue_prompt:
406 self.shell.outputcache.prompt_count -= 1
402 self.shell.outputcache.prompt_count -= 1
407
403
408 return normal_handler.handle(line_info)
404 return normal_handler.handle(line_info)
409
405
410 # special handlers are only allowed for single line statements
406 # special handlers are only allowed for single line statements
411 if continue_prompt and not self.multi_line_specials:
407 if continue_prompt and not self.multi_line_specials:
412 return normal_handler.handle(line_info)
408 return normal_handler.handle(line_info)
413
409
414 prefiltered = self.prefilter_line_info(line_info)
410 prefiltered = self.prefilter_line_info(line_info)
415 # print "prefiltered line: %r" % prefiltered
411 # print "prefiltered line: %r" % prefiltered
416 return prefiltered
412 return prefiltered
417
413
418 def prefilter_lines(self, lines, continue_prompt=False):
414 def prefilter_lines(self, lines, continue_prompt=False):
419 """Prefilter multiple input lines of text.
415 """Prefilter multiple input lines of text.
420
416
421 This is the main entry point for prefiltering multiple lines of
417 This is the main entry point for prefiltering multiple lines of
422 input. This simply calls :meth:`prefilter_line` for each line of
418 input. This simply calls :meth:`prefilter_line` for each line of
423 input.
419 input.
424
420
425 This covers cases where there are multiple lines in the user entry,
421 This covers cases where there are multiple lines in the user entry,
426 which is the case when the user goes back to a multiline history
422 which is the case when the user goes back to a multiline history
427 entry and presses enter.
423 entry and presses enter.
428 """
424 """
429 llines = lines.rstrip('\n').split('\n')
425 llines = lines.rstrip('\n').split('\n')
430 # We can get multiple lines in one shot, where multiline input 'blends'
426 # We can get multiple lines in one shot, where multiline input 'blends'
431 # into one line, in cases like recalling from the readline history
427 # into one line, in cases like recalling from the readline history
432 # buffer. We need to make sure that in such cases, we correctly
428 # buffer. We need to make sure that in such cases, we correctly
433 # communicate downstream which line is first and which are continuation
429 # communicate downstream which line is first and which are continuation
434 # ones.
430 # ones.
435 if len(llines) > 1:
431 if len(llines) > 1:
436 out = '\n'.join([self.prefilter_line(line, lnum>0)
432 out = '\n'.join([self.prefilter_line(line, lnum>0)
437 for lnum, line in enumerate(llines) ])
433 for lnum, line in enumerate(llines) ])
438 else:
434 else:
439 out = self.prefilter_line(llines[0], continue_prompt)
435 out = self.prefilter_line(llines[0], continue_prompt)
440
436
441 return out
437 return out
442
438
443 #-----------------------------------------------------------------------------
439 #-----------------------------------------------------------------------------
444 # Prefilter transformers
440 # Prefilter transformers
445 #-----------------------------------------------------------------------------
441 #-----------------------------------------------------------------------------
446
442
447
443
448 class PrefilterTransformer(Component):
444 class PrefilterTransformer(Configurable):
449 """Transform a line of user input."""
445 """Transform a line of user input."""
450
446
451 priority = Int(100, config=True)
447 priority = Int(100, config=True)
452 shell = Any
448 # Transformers don't currently use shell or prefilter_manager, but as we
453 prefilter_manager = Any
449 # move away from checkers and handlers, they will need them.
450 shell = Instance('IPython.core.iplib.InteractiveShell')
451 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
454 enabled = Bool(True, config=True)
452 enabled = Bool(True, config=True)
455
453
456 def __init__(self, parent, config=None):
454 def __init__(self, shell, prefilter_manager, config=None):
457 super(PrefilterTransformer, self).__init__(parent, config=config)
455 super(PrefilterTransformer, self).__init__(config=config)
456 self.shell = shell
457 self.prefilter_manager = prefilter_manager
458 self.prefilter_manager.register_transformer(self)
458 self.prefilter_manager.register_transformer(self)
459
459
460 @auto_attr
461 def shell(self):
462 return Component.get_instances(
463 root=self.root,
464 klass='IPython.core.iplib.InteractiveShell')[0]
465
466 @auto_attr
467 def prefilter_manager(self):
468 return PrefilterManager.get_instances(root=self.root)[0]
469
470 def transform(self, line, continue_prompt):
460 def transform(self, line, continue_prompt):
471 """Transform a line, returning the new one."""
461 """Transform a line, returning the new one."""
472 return None
462 return None
473
463
474 def __repr__(self):
464 def __repr__(self):
475 return "<%s(priority=%r, enabled=%r)>" % (
465 return "<%s(priority=%r, enabled=%r)>" % (
476 self.__class__.__name__, self.priority, self.enabled)
466 self.__class__.__name__, self.priority, self.enabled)
477
467
478
468
479 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
469 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
480 r'\s*=\s*!(?P<cmd>.*)')
470 r'\s*=\s*!(?P<cmd>.*)')
481
471
482
472
483 class AssignSystemTransformer(PrefilterTransformer):
473 class AssignSystemTransformer(PrefilterTransformer):
484 """Handle the `files = !ls` syntax."""
474 """Handle the `files = !ls` syntax."""
485
475
486 priority = Int(100, config=True)
476 priority = Int(100, config=True)
487
477
488 def transform(self, line, continue_prompt):
478 def transform(self, line, continue_prompt):
489 m = _assign_system_re.match(line)
479 m = _assign_system_re.match(line)
490 if m is not None:
480 if m is not None:
491 cmd = m.group('cmd')
481 cmd = m.group('cmd')
492 lhs = m.group('lhs')
482 lhs = m.group('lhs')
493 expr = make_quoted_expr("sc -l =%s" % cmd)
483 expr = make_quoted_expr("sc -l =%s" % cmd)
494 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
484 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
495 return new_line
485 return new_line
496 return line
486 return line
497
487
498
488
499 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
489 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
500 r'\s*=\s*%(?P<cmd>.*)')
490 r'\s*=\s*%(?P<cmd>.*)')
501
491
502 class AssignMagicTransformer(PrefilterTransformer):
492 class AssignMagicTransformer(PrefilterTransformer):
503 """Handle the `a = %who` syntax."""
493 """Handle the `a = %who` syntax."""
504
494
505 priority = Int(200, config=True)
495 priority = Int(200, config=True)
506
496
507 def transform(self, line, continue_prompt):
497 def transform(self, line, continue_prompt):
508 m = _assign_magic_re.match(line)
498 m = _assign_magic_re.match(line)
509 if m is not None:
499 if m is not None:
510 cmd = m.group('cmd')
500 cmd = m.group('cmd')
511 lhs = m.group('lhs')
501 lhs = m.group('lhs')
512 expr = make_quoted_expr(cmd)
502 expr = make_quoted_expr(cmd)
513 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
503 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
514 return new_line
504 return new_line
515 return line
505 return line
516
506
517
507
518 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
508 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
519
509
520 class PyPromptTransformer(PrefilterTransformer):
510 class PyPromptTransformer(PrefilterTransformer):
521 """Handle inputs that start with '>>> ' syntax."""
511 """Handle inputs that start with '>>> ' syntax."""
522
512
523 priority = Int(50, config=True)
513 priority = Int(50, config=True)
524
514
525 def transform(self, line, continue_prompt):
515 def transform(self, line, continue_prompt):
526
516
527 if not line or line.isspace() or line.strip() == '...':
517 if not line or line.isspace() or line.strip() == '...':
528 # This allows us to recognize multiple input prompts separated by
518 # This allows us to recognize multiple input prompts separated by
529 # blank lines and pasted in a single chunk, very common when
519 # blank lines and pasted in a single chunk, very common when
530 # pasting doctests or long tutorial passages.
520 # pasting doctests or long tutorial passages.
531 return ''
521 return ''
532 m = _classic_prompt_re.match(line)
522 m = _classic_prompt_re.match(line)
533 if m:
523 if m:
534 return line[len(m.group(0)):]
524 return line[len(m.group(0)):]
535 else:
525 else:
536 return line
526 return line
537
527
538
528
539 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
529 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
540
530
541 class IPyPromptTransformer(PrefilterTransformer):
531 class IPyPromptTransformer(PrefilterTransformer):
542 """Handle inputs that start classic IPython prompt syntax."""
532 """Handle inputs that start classic IPython prompt syntax."""
543
533
544 priority = Int(50, config=True)
534 priority = Int(50, config=True)
545
535
546 def transform(self, line, continue_prompt):
536 def transform(self, line, continue_prompt):
547
537
548 if not line or line.isspace() or line.strip() == '...':
538 if not line or line.isspace() or line.strip() == '...':
549 # This allows us to recognize multiple input prompts separated by
539 # This allows us to recognize multiple input prompts separated by
550 # blank lines and pasted in a single chunk, very common when
540 # blank lines and pasted in a single chunk, very common when
551 # pasting doctests or long tutorial passages.
541 # pasting doctests or long tutorial passages.
552 return ''
542 return ''
553 m = _ipy_prompt_re.match(line)
543 m = _ipy_prompt_re.match(line)
554 if m:
544 if m:
555 return line[len(m.group(0)):]
545 return line[len(m.group(0)):]
556 else:
546 else:
557 return line
547 return line
558
548
559 #-----------------------------------------------------------------------------
549 #-----------------------------------------------------------------------------
560 # Prefilter checkers
550 # Prefilter checkers
561 #-----------------------------------------------------------------------------
551 #-----------------------------------------------------------------------------
562
552
563
553
564 class PrefilterChecker(Component):
554 class PrefilterChecker(Configurable):
565 """Inspect an input line and return a handler for that line."""
555 """Inspect an input line and return a handler for that line."""
566
556
567 priority = Int(100, config=True)
557 priority = Int(100, config=True)
568 shell = Any
558 shell = Instance('IPython.core.iplib.InteractiveShell')
569 prefilter_manager = Any
559 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
570 enabled = Bool(True, config=True)
560 enabled = Bool(True, config=True)
571
561
572 def __init__(self, parent, config=None):
562 def __init__(self, shell, prefilter_manager, config=None):
573 super(PrefilterChecker, self).__init__(parent, config=config)
563 super(PrefilterChecker, self).__init__(config=config)
564 self.shell = shell
565 self.prefilter_manager = prefilter_manager
574 self.prefilter_manager.register_checker(self)
566 self.prefilter_manager.register_checker(self)
575
567
576 @auto_attr
577 def shell(self):
578 return Component.get_instances(
579 root=self.root,
580 klass='IPython.core.iplib.InteractiveShell')[0]
581
582 @auto_attr
583 def prefilter_manager(self):
584 return PrefilterManager.get_instances(root=self.root)[0]
585
586 def check(self, line_info):
568 def check(self, line_info):
587 """Inspect line_info and return a handler instance or None."""
569 """Inspect line_info and return a handler instance or None."""
588 return None
570 return None
589
571
590 def __repr__(self):
572 def __repr__(self):
591 return "<%s(priority=%r, enabled=%r)>" % (
573 return "<%s(priority=%r, enabled=%r)>" % (
592 self.__class__.__name__, self.priority, self.enabled)
574 self.__class__.__name__, self.priority, self.enabled)
593
575
594
576
595 class EmacsChecker(PrefilterChecker):
577 class EmacsChecker(PrefilterChecker):
596
578
597 priority = Int(100, config=True)
579 priority = Int(100, config=True)
598 enabled = Bool(False, config=True)
580 enabled = Bool(False, config=True)
599
581
600 def check(self, line_info):
582 def check(self, line_info):
601 "Emacs ipython-mode tags certain input lines."
583 "Emacs ipython-mode tags certain input lines."
602 if line_info.line.endswith('# PYTHON-MODE'):
584 if line_info.line.endswith('# PYTHON-MODE'):
603 return self.prefilter_manager.get_handler_by_name('emacs')
585 return self.prefilter_manager.get_handler_by_name('emacs')
604 else:
586 else:
605 return None
587 return None
606
588
607
589
608 class ShellEscapeChecker(PrefilterChecker):
590 class ShellEscapeChecker(PrefilterChecker):
609
591
610 priority = Int(200, config=True)
592 priority = Int(200, config=True)
611
593
612 def check(self, line_info):
594 def check(self, line_info):
613 if line_info.line.lstrip().startswith(ESC_SHELL):
595 if line_info.line.lstrip().startswith(ESC_SHELL):
614 return self.prefilter_manager.get_handler_by_name('shell')
596 return self.prefilter_manager.get_handler_by_name('shell')
615
597
616
598
617 class IPyAutocallChecker(PrefilterChecker):
599 class IPyAutocallChecker(PrefilterChecker):
618
600
619 priority = Int(300, config=True)
601 priority = Int(300, config=True)
620
602
621 def check(self, line_info):
603 def check(self, line_info):
622 "Instances of IPyAutocall in user_ns get autocalled immediately"
604 "Instances of IPyAutocall in user_ns get autocalled immediately"
623 obj = self.shell.user_ns.get(line_info.ifun, None)
605 obj = self.shell.user_ns.get(line_info.ifun, None)
624 if isinstance(obj, IPyAutocall):
606 if isinstance(obj, IPyAutocall):
625 obj.set_ip(self.shell)
607 obj.set_ip(self.shell)
626 return self.prefilter_manager.get_handler_by_name('auto')
608 return self.prefilter_manager.get_handler_by_name('auto')
627 else:
609 else:
628 return None
610 return None
629
611
630
612
631 class MultiLineMagicChecker(PrefilterChecker):
613 class MultiLineMagicChecker(PrefilterChecker):
632
614
633 priority = Int(400, config=True)
615 priority = Int(400, config=True)
634
616
635 def check(self, line_info):
617 def check(self, line_info):
636 "Allow ! and !! in multi-line statements if multi_line_specials is on"
618 "Allow ! and !! in multi-line statements if multi_line_specials is on"
637 # Note that this one of the only places we check the first character of
619 # Note that this one of the only places we check the first character of
638 # ifun and *not* the pre_char. Also note that the below test matches
620 # ifun and *not* the pre_char. Also note that the below test matches
639 # both ! and !!.
621 # both ! and !!.
640 if line_info.continue_prompt \
622 if line_info.continue_prompt \
641 and self.prefilter_manager.multi_line_specials:
623 and self.prefilter_manager.multi_line_specials:
642 if line_info.ifun.startswith(ESC_MAGIC):
624 if line_info.ifun.startswith(ESC_MAGIC):
643 return self.prefilter_manager.get_handler_by_name('magic')
625 return self.prefilter_manager.get_handler_by_name('magic')
644 else:
626 else:
645 return None
627 return None
646
628
647
629
648 class EscCharsChecker(PrefilterChecker):
630 class EscCharsChecker(PrefilterChecker):
649
631
650 priority = Int(500, config=True)
632 priority = Int(500, config=True)
651
633
652 def check(self, line_info):
634 def check(self, line_info):
653 """Check for escape character and return either a handler to handle it,
635 """Check for escape character and return either a handler to handle it,
654 or None if there is no escape char."""
636 or None if there is no escape char."""
655 if line_info.line[-1] == ESC_HELP \
637 if line_info.line[-1] == ESC_HELP \
656 and line_info.pre_char != ESC_SHELL \
638 and line_info.pre_char != ESC_SHELL \
657 and line_info.pre_char != ESC_SH_CAP:
639 and line_info.pre_char != ESC_SH_CAP:
658 # the ? can be at the end, but *not* for either kind of shell escape,
640 # the ? can be at the end, but *not* for either kind of shell escape,
659 # because a ? can be a vaild final char in a shell cmd
641 # because a ? can be a vaild final char in a shell cmd
660 return self.prefilter_manager.get_handler_by_name('help')
642 return self.prefilter_manager.get_handler_by_name('help')
661 else:
643 else:
662 # This returns None like it should if no handler exists
644 # This returns None like it should if no handler exists
663 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
645 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
664
646
665
647
666 class AssignmentChecker(PrefilterChecker):
648 class AssignmentChecker(PrefilterChecker):
667
649
668 priority = Int(600, config=True)
650 priority = Int(600, config=True)
669
651
670 def check(self, line_info):
652 def check(self, line_info):
671 """Check to see if user is assigning to a var for the first time, in
653 """Check to see if user is assigning to a var for the first time, in
672 which case we want to avoid any sort of automagic / autocall games.
654 which case we want to avoid any sort of automagic / autocall games.
673
655
674 This allows users to assign to either alias or magic names true python
656 This allows users to assign to either alias or magic names true python
675 variables (the magic/alias systems always take second seat to true
657 variables (the magic/alias systems always take second seat to true
676 python code). E.g. ls='hi', or ls,that=1,2"""
658 python code). E.g. ls='hi', or ls,that=1,2"""
677 if line_info.the_rest:
659 if line_info.the_rest:
678 if line_info.the_rest[0] in '=,':
660 if line_info.the_rest[0] in '=,':
679 return self.prefilter_manager.get_handler_by_name('normal')
661 return self.prefilter_manager.get_handler_by_name('normal')
680 else:
662 else:
681 return None
663 return None
682
664
683
665
684 class AutoMagicChecker(PrefilterChecker):
666 class AutoMagicChecker(PrefilterChecker):
685
667
686 priority = Int(700, config=True)
668 priority = Int(700, config=True)
687
669
688 def check(self, line_info):
670 def check(self, line_info):
689 """If the ifun is magic, and automagic is on, run it. Note: normal,
671 """If the ifun is magic, and automagic is on, run it. Note: normal,
690 non-auto magic would already have been triggered via '%' in
672 non-auto magic would already have been triggered via '%' in
691 check_esc_chars. This just checks for automagic. Also, before
673 check_esc_chars. This just checks for automagic. Also, before
692 triggering the magic handler, make sure that there is nothing in the
674 triggering the magic handler, make sure that there is nothing in the
693 user namespace which could shadow it."""
675 user namespace which could shadow it."""
694 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
676 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
695 return None
677 return None
696
678
697 # We have a likely magic method. Make sure we should actually call it.
679 # We have a likely magic method. Make sure we should actually call it.
698 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
680 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
699 return None
681 return None
700
682
701 head = line_info.ifun.split('.',1)[0]
683 head = line_info.ifun.split('.',1)[0]
702 if is_shadowed(head, self.shell):
684 if is_shadowed(head, self.shell):
703 return None
685 return None
704
686
705 return self.prefilter_manager.get_handler_by_name('magic')
687 return self.prefilter_manager.get_handler_by_name('magic')
706
688
707
689
708 class AliasChecker(PrefilterChecker):
690 class AliasChecker(PrefilterChecker):
709
691
710 priority = Int(800, config=True)
692 priority = Int(800, config=True)
711
693
712 @auto_attr
713 def alias_manager(self):
714 return AliasManager.get_instances(root=self.root)[0]
715
716 def check(self, line_info):
694 def check(self, line_info):
717 "Check if the initital identifier on the line is an alias."
695 "Check if the initital identifier on the line is an alias."
718 # Note: aliases can not contain '.'
696 # Note: aliases can not contain '.'
719 head = line_info.ifun.split('.',1)[0]
697 head = line_info.ifun.split('.',1)[0]
720 if line_info.ifun not in self.alias_manager \
698 if line_info.ifun not in self.shell.alias_manager \
721 or head not in self.alias_manager \
699 or head not in self.shell.alias_manager \
722 or is_shadowed(head, self.shell):
700 or is_shadowed(head, self.shell):
723 return None
701 return None
724
702
725 return self.prefilter_manager.get_handler_by_name('alias')
703 return self.prefilter_manager.get_handler_by_name('alias')
726
704
727
705
728 class PythonOpsChecker(PrefilterChecker):
706 class PythonOpsChecker(PrefilterChecker):
729
707
730 priority = Int(900, config=True)
708 priority = Int(900, config=True)
731
709
732 def check(self, line_info):
710 def check(self, line_info):
733 """If the 'rest' of the line begins with a function call or pretty much
711 """If the 'rest' of the line begins with a function call or pretty much
734 any python operator, we should simply execute the line (regardless of
712 any python operator, we should simply execute the line (regardless of
735 whether or not there's a possible autocall expansion). This avoids
713 whether or not there's a possible autocall expansion). This avoids
736 spurious (and very confusing) geattr() accesses."""
714 spurious (and very confusing) geattr() accesses."""
737 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
715 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
738 return self.prefilter_manager.get_handler_by_name('normal')
716 return self.prefilter_manager.get_handler_by_name('normal')
739 else:
717 else:
740 return None
718 return None
741
719
742
720
743 class AutocallChecker(PrefilterChecker):
721 class AutocallChecker(PrefilterChecker):
744
722
745 priority = Int(1000, config=True)
723 priority = Int(1000, config=True)
746
724
747 def check(self, line_info):
725 def check(self, line_info):
748 "Check if the initial word/function is callable and autocall is on."
726 "Check if the initial word/function is callable and autocall is on."
749 if not self.shell.autocall:
727 if not self.shell.autocall:
750 return None
728 return None
751
729
752 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
730 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
753 if not oinfo['found']:
731 if not oinfo['found']:
754 return None
732 return None
755
733
756 if callable(oinfo['obj']) \
734 if callable(oinfo['obj']) \
757 and (not re_exclude_auto.match(line_info.the_rest)) \
735 and (not re_exclude_auto.match(line_info.the_rest)) \
758 and re_fun_name.match(line_info.ifun):
736 and re_fun_name.match(line_info.ifun):
759 return self.prefilter_manager.get_handler_by_name('auto')
737 return self.prefilter_manager.get_handler_by_name('auto')
760 else:
738 else:
761 return None
739 return None
762
740
763
741
764 #-----------------------------------------------------------------------------
742 #-----------------------------------------------------------------------------
765 # Prefilter handlers
743 # Prefilter handlers
766 #-----------------------------------------------------------------------------
744 #-----------------------------------------------------------------------------
767
745
768
746
769 class PrefilterHandler(Component):
747 class PrefilterHandler(Configurable):
770
748
771 handler_name = Str('normal')
749 handler_name = Str('normal')
772 esc_strings = List([])
750 esc_strings = List([])
773 shell = Any
751 shell = Instance('IPython.core.iplib.InteractiveShell')
774 prefilter_manager = Any
752 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
775
753
776 def __init__(self, parent, config=None):
754 def __init__(self, shell, prefilter_manager, config=None):
777 super(PrefilterHandler, self).__init__(parent, config=config)
755 super(PrefilterHandler, self).__init__(config=config)
756 self.shell = shell
757 self.prefilter_manager = prefilter_manager
778 self.prefilter_manager.register_handler(
758 self.prefilter_manager.register_handler(
779 self.handler_name,
759 self.handler_name,
780 self,
760 self,
781 self.esc_strings
761 self.esc_strings
782 )
762 )
783
763
784 @auto_attr
785 def shell(self):
786 return Component.get_instances(
787 root=self.root,
788 klass='IPython.core.iplib.InteractiveShell')[0]
789
790 @auto_attr
791 def prefilter_manager(self):
792 return PrefilterManager.get_instances(root=self.root)[0]
793
794 def handle(self, line_info):
764 def handle(self, line_info):
795 # print "normal: ", line_info
765 # print "normal: ", line_info
796 """Handle normal input lines. Use as a template for handlers."""
766 """Handle normal input lines. Use as a template for handlers."""
797
767
798 # With autoindent on, we need some way to exit the input loop, and I
768 # With autoindent on, we need some way to exit the input loop, and I
799 # don't want to force the user to have to backspace all the way to
769 # don't want to force the user to have to backspace all the way to
800 # clear the line. The rule will be in this case, that either two
770 # clear the line. The rule will be in this case, that either two
801 # lines of pure whitespace in a row, or a line of pure whitespace but
771 # lines of pure whitespace in a row, or a line of pure whitespace but
802 # of a size different to the indent level, will exit the input loop.
772 # of a size different to the indent level, will exit the input loop.
803 line = line_info.line
773 line = line_info.line
804 continue_prompt = line_info.continue_prompt
774 continue_prompt = line_info.continue_prompt
805
775
806 if (continue_prompt and
776 if (continue_prompt and
807 self.shell.autoindent and
777 self.shell.autoindent and
808 line.isspace() and
778 line.isspace() and
809
779
810 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2
780 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2
811 or
781 or
812 not self.shell.buffer
782 not self.shell.buffer
813 or
783 or
814 (self.shell.buffer[-1]).isspace()
784 (self.shell.buffer[-1]).isspace()
815 )
785 )
816 ):
786 ):
817 line = ''
787 line = ''
818
788
819 self.shell.log(line, line, continue_prompt)
789 self.shell.log(line, line, continue_prompt)
820 return line
790 return line
821
791
822 def __str__(self):
792 def __str__(self):
823 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
793 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
824
794
825
795
826 class AliasHandler(PrefilterHandler):
796 class AliasHandler(PrefilterHandler):
827
797
828 handler_name = Str('alias')
798 handler_name = Str('alias')
829
799
830 @auto_attr
831 def alias_manager(self):
832 return AliasManager.get_instances(root=self.root)[0]
833
834 def handle(self, line_info):
800 def handle(self, line_info):
835 """Handle alias input lines. """
801 """Handle alias input lines. """
836 transformed = self.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
802 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
837 # pre is needed, because it carries the leading whitespace. Otherwise
803 # pre is needed, because it carries the leading whitespace. Otherwise
838 # aliases won't work in indented sections.
804 # aliases won't work in indented sections.
839 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
805 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
840 make_quoted_expr(transformed))
806 make_quoted_expr(transformed))
841
807
842 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
808 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
843 return line_out
809 return line_out
844
810
845
811
846 class ShellEscapeHandler(PrefilterHandler):
812 class ShellEscapeHandler(PrefilterHandler):
847
813
848 handler_name = Str('shell')
814 handler_name = Str('shell')
849 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
815 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
850
816
851 def handle(self, line_info):
817 def handle(self, line_info):
852 """Execute the line in a shell, empty return value"""
818 """Execute the line in a shell, empty return value"""
853 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
819 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
854
820
855 line = line_info.line
821 line = line_info.line
856 if line.lstrip().startswith(ESC_SH_CAP):
822 if line.lstrip().startswith(ESC_SH_CAP):
857 # rewrite LineInfo's line, ifun and the_rest to properly hold the
823 # rewrite LineInfo's line, ifun and the_rest to properly hold the
858 # call to %sx and the actual command to be executed, so
824 # call to %sx and the actual command to be executed, so
859 # handle_magic can work correctly. Note that this works even if
825 # handle_magic can work correctly. Note that this works even if
860 # the line is indented, so it handles multi_line_specials
826 # the line is indented, so it handles multi_line_specials
861 # properly.
827 # properly.
862 new_rest = line.lstrip()[2:]
828 new_rest = line.lstrip()[2:]
863 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
829 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
864 line_info.ifun = 'sx'
830 line_info.ifun = 'sx'
865 line_info.the_rest = new_rest
831 line_info.the_rest = new_rest
866 return magic_handler.handle(line_info)
832 return magic_handler.handle(line_info)
867 else:
833 else:
868 cmd = line.lstrip().lstrip(ESC_SHELL)
834 cmd = line.lstrip().lstrip(ESC_SHELL)
869 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
835 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
870 make_quoted_expr(cmd))
836 make_quoted_expr(cmd))
871 # update cache/log and return
837 # update cache/log and return
872 self.shell.log(line, line_out, line_info.continue_prompt)
838 self.shell.log(line, line_out, line_info.continue_prompt)
873 return line_out
839 return line_out
874
840
875
841
876 class MagicHandler(PrefilterHandler):
842 class MagicHandler(PrefilterHandler):
877
843
878 handler_name = Str('magic')
844 handler_name = Str('magic')
879 esc_strings = List([ESC_MAGIC])
845 esc_strings = List([ESC_MAGIC])
880
846
881 def handle(self, line_info):
847 def handle(self, line_info):
882 """Execute magic functions."""
848 """Execute magic functions."""
883 ifun = line_info.ifun
849 ifun = line_info.ifun
884 the_rest = line_info.the_rest
850 the_rest = line_info.the_rest
885 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
851 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
886 make_quoted_expr(ifun + " " + the_rest))
852 make_quoted_expr(ifun + " " + the_rest))
887 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
853 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
888 return cmd
854 return cmd
889
855
890
856
891 class AutoHandler(PrefilterHandler):
857 class AutoHandler(PrefilterHandler):
892
858
893 handler_name = Str('auto')
859 handler_name = Str('auto')
894 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
860 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
895
861
896 def handle(self, line_info):
862 def handle(self, line_info):
897 """Hande lines which can be auto-executed, quoting if requested."""
863 """Handle lines which can be auto-executed, quoting if requested."""
898 line = line_info.line
864 line = line_info.line
899 ifun = line_info.ifun
865 ifun = line_info.ifun
900 the_rest = line_info.the_rest
866 the_rest = line_info.the_rest
901 pre = line_info.pre
867 pre = line_info.pre
902 continue_prompt = line_info.continue_prompt
868 continue_prompt = line_info.continue_prompt
903 obj = line_info.ofind(self)['obj']
869 obj = line_info.ofind(self)['obj']
904 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
870 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
905
871
906 # This should only be active for single-line input!
872 # This should only be active for single-line input!
907 if continue_prompt:
873 if continue_prompt:
908 self.shell.log(line,line,continue_prompt)
874 self.shell.log(line,line,continue_prompt)
909 return line
875 return line
910
876
911 force_auto = isinstance(obj, IPyAutocall)
877 force_auto = isinstance(obj, IPyAutocall)
912 auto_rewrite = True
878 auto_rewrite = True
913
879
914 if pre == ESC_QUOTE:
880 if pre == ESC_QUOTE:
915 # Auto-quote splitting on whitespace
881 # Auto-quote splitting on whitespace
916 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
882 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
917 elif pre == ESC_QUOTE2:
883 elif pre == ESC_QUOTE2:
918 # Auto-quote whole string
884 # Auto-quote whole string
919 newcmd = '%s("%s")' % (ifun,the_rest)
885 newcmd = '%s("%s")' % (ifun,the_rest)
920 elif pre == ESC_PAREN:
886 elif pre == ESC_PAREN:
921 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
887 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
922 else:
888 else:
923 # Auto-paren.
889 # Auto-paren.
924 # We only apply it to argument-less calls if the autocall
890 # We only apply it to argument-less calls if the autocall
925 # parameter is set to 2. We only need to check that autocall is <
891 # parameter is set to 2. We only need to check that autocall is <
926 # 2, since this function isn't called unless it's at least 1.
892 # 2, since this function isn't called unless it's at least 1.
927 if not the_rest and (self.shell.autocall < 2) and not force_auto:
893 if not the_rest and (self.shell.autocall < 2) and not force_auto:
928 newcmd = '%s %s' % (ifun,the_rest)
894 newcmd = '%s %s' % (ifun,the_rest)
929 auto_rewrite = False
895 auto_rewrite = False
930 else:
896 else:
931 if not force_auto and the_rest.startswith('['):
897 if not force_auto and the_rest.startswith('['):
932 if hasattr(obj,'__getitem__'):
898 if hasattr(obj,'__getitem__'):
933 # Don't autocall in this case: item access for an object
899 # Don't autocall in this case: item access for an object
934 # which is BOTH callable and implements __getitem__.
900 # which is BOTH callable and implements __getitem__.
935 newcmd = '%s %s' % (ifun,the_rest)
901 newcmd = '%s %s' % (ifun,the_rest)
936 auto_rewrite = False
902 auto_rewrite = False
937 else:
903 else:
938 # if the object doesn't support [] access, go ahead and
904 # if the object doesn't support [] access, go ahead and
939 # autocall
905 # autocall
940 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
906 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
941 elif the_rest.endswith(';'):
907 elif the_rest.endswith(';'):
942 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
908 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
943 else:
909 else:
944 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
910 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
945
911
946 if auto_rewrite:
912 if auto_rewrite:
947 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
913 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
948
914
949 try:
915 try:
950 # plain ascii works better w/ pyreadline, on some machines, so
916 # plain ascii works better w/ pyreadline, on some machines, so
951 # we use it and only print uncolored rewrite if we have unicode
917 # we use it and only print uncolored rewrite if we have unicode
952 rw = str(rw)
918 rw = str(rw)
953 print >>Term.cout, rw
919 print >>Term.cout, rw
954 except UnicodeEncodeError:
920 except UnicodeEncodeError:
955 print "-------------->" + newcmd
921 print "-------------->" + newcmd
956
922
957 # log what is now valid Python, not the actual user input (without the
923 # log what is now valid Python, not the actual user input (without the
958 # final newline)
924 # final newline)
959 self.shell.log(line,newcmd,continue_prompt)
925 self.shell.log(line,newcmd,continue_prompt)
960 return newcmd
926 return newcmd
961
927
962
928
963 class HelpHandler(PrefilterHandler):
929 class HelpHandler(PrefilterHandler):
964
930
965 handler_name = Str('help')
931 handler_name = Str('help')
966 esc_strings = List([ESC_HELP])
932 esc_strings = List([ESC_HELP])
967
933
968 def handle(self, line_info):
934 def handle(self, line_info):
969 """Try to get some help for the object.
935 """Try to get some help for the object.
970
936
971 obj? or ?obj -> basic information.
937 obj? or ?obj -> basic information.
972 obj?? or ??obj -> more details.
938 obj?? or ??obj -> more details.
973 """
939 """
974 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
940 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
975 line = line_info.line
941 line = line_info.line
976 # We need to make sure that we don't process lines which would be
942 # We need to make sure that we don't process lines which would be
977 # otherwise valid python, such as "x=1 # what?"
943 # otherwise valid python, such as "x=1 # what?"
978 try:
944 try:
979 codeop.compile_command(line)
945 codeop.compile_command(line)
980 except SyntaxError:
946 except SyntaxError:
981 # We should only handle as help stuff which is NOT valid syntax
947 # We should only handle as help stuff which is NOT valid syntax
982 if line[0]==ESC_HELP:
948 if line[0]==ESC_HELP:
983 line = line[1:]
949 line = line[1:]
984 elif line[-1]==ESC_HELP:
950 elif line[-1]==ESC_HELP:
985 line = line[:-1]
951 line = line[:-1]
986 self.shell.log(line, '#?'+line, line_info.continue_prompt)
952 self.shell.log(line, '#?'+line, line_info.continue_prompt)
987 if line:
953 if line:
988 #print 'line:<%r>' % line # dbg
954 #print 'line:<%r>' % line # dbg
989 self.shell.magic_pinfo(line)
955 self.shell.magic_pinfo(line)
990 else:
956 else:
991 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
957 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
992 return '' # Empty string is needed here!
958 return '' # Empty string is needed here!
993 except:
959 except:
994 raise
960 raise
995 # Pass any other exceptions through to the normal handler
961 # Pass any other exceptions through to the normal handler
996 return normal_handler.handle(line_info)
962 return normal_handler.handle(line_info)
997 else:
963 else:
998 # If the code compiles ok, we should handle it normally
964 # If the code compiles ok, we should handle it normally
999 return normal_handler.handle(line_info)
965 return normal_handler.handle(line_info)
1000
966
1001
967
1002 class EmacsHandler(PrefilterHandler):
968 class EmacsHandler(PrefilterHandler):
1003
969
1004 handler_name = Str('emacs')
970 handler_name = Str('emacs')
1005 esc_strings = List([])
971 esc_strings = List([])
1006
972
1007 def handle(self, line_info):
973 def handle(self, line_info):
1008 """Handle input lines marked by python-mode."""
974 """Handle input lines marked by python-mode."""
1009
975
1010 # Currently, nothing is done. Later more functionality can be added
976 # Currently, nothing is done. Later more functionality can be added
1011 # here if needed.
977 # here if needed.
1012
978
1013 # The input cache shouldn't be updated
979 # The input cache shouldn't be updated
1014 return line_info.line
980 return line_info.line
1015
981
1016
982
1017 #-----------------------------------------------------------------------------
983 #-----------------------------------------------------------------------------
1018 # Defaults
984 # Defaults
1019 #-----------------------------------------------------------------------------
985 #-----------------------------------------------------------------------------
1020
986
1021
987
1022 _default_transformers = [
988 _default_transformers = [
1023 AssignSystemTransformer,
989 AssignSystemTransformer,
1024 AssignMagicTransformer,
990 AssignMagicTransformer,
1025 PyPromptTransformer,
991 PyPromptTransformer,
1026 IPyPromptTransformer,
992 IPyPromptTransformer,
1027 ]
993 ]
1028
994
1029 _default_checkers = [
995 _default_checkers = [
1030 EmacsChecker,
996 EmacsChecker,
1031 ShellEscapeChecker,
997 ShellEscapeChecker,
1032 IPyAutocallChecker,
998 IPyAutocallChecker,
1033 MultiLineMagicChecker,
999 MultiLineMagicChecker,
1034 EscCharsChecker,
1000 EscCharsChecker,
1035 AssignmentChecker,
1001 AssignmentChecker,
1036 AutoMagicChecker,
1002 AutoMagicChecker,
1037 AliasChecker,
1003 AliasChecker,
1038 PythonOpsChecker,
1004 PythonOpsChecker,
1039 AutocallChecker
1005 AutocallChecker
1040 ]
1006 ]
1041
1007
1042 _default_handlers = [
1008 _default_handlers = [
1043 PrefilterHandler,
1009 PrefilterHandler,
1044 AliasHandler,
1010 AliasHandler,
1045 ShellEscapeHandler,
1011 ShellEscapeHandler,
1046 MagicHandler,
1012 MagicHandler,
1047 AutoHandler,
1013 AutoHandler,
1048 HelpHandler,
1014 HelpHandler,
1049 EmacsHandler
1015 EmacsHandler
1050 ]
1016 ]
@@ -1,101 +1,101 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Simple tests for :mod:`IPython.extensions.pretty`.
4 Simple tests for :mod:`IPython.extensions.pretty`.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from unittest import TestCase
18 from unittest import TestCase
19
19
20 from IPython.core.component import Component, masquerade_as
20 from IPython.core.component import Component, masquerade_as
21 from IPython.core.iplib import InteractiveShell
21 from IPython.core.iplib import InteractiveShell
22 from IPython.extensions import pretty as pretty_ext
22 from IPython.extensions import pretty as pretty_ext
23 from IPython.external import pretty
23 from IPython.external import pretty
24 from IPython.testing import decorators as dec
24 from IPython.testing import decorators as dec
25 from IPython.testing import tools as tt
25 from IPython.testing import tools as tt
26 from IPython.utils.traitlets import Bool
26 from IPython.utils.traitlets import Bool
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Tests
29 # Tests
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 class InteractiveShellStub(Component):
32 class InteractiveShellStub(Component):
33 pprint = Bool(True)
33 pprint = Bool(True)
34
34
35 class A(object):
35 class A(object):
36 pass
36 pass
37
37
38 def a_pprinter(o, p, c):
38 def a_pprinter(o, p, c):
39 return p.text("<A>")
39 return p.text("<A>")
40
40
41 class TestPrettyResultDisplay(TestCase):
41 class TestPrettyResultDisplay(TestCase):
42
42
43 def setUp(self):
43 def setUp(self):
44 self.ip = InteractiveShellStub(None)
44 self.ip = InteractiveShellStub(None)
45 # This allows our stub to be retrieved instead of the real
45 # This allows our stub to be retrieved instead of the real
46 # InteractiveShell
46 # InteractiveShell
47 masquerade_as(self.ip, InteractiveShell)
47 masquerade_as(self.ip, InteractiveShell)
48 self.prd = pretty_ext.PrettyResultDisplay(self.ip,
48 self.prd = pretty_ext.PrettyResultDisplay(self.ip,
49 name='pretty_result_display')
49 name='pretty_result_display')
50
50
51 def test_for_type(self):
51 def test_for_type(self):
52 self.prd.for_type(A, a_pprinter)
52 self.prd.for_type(A, a_pprinter)
53 a = A()
53 a = A()
54 result = pretty.pretty(a)
54 result = pretty.pretty(a)
55 self.assertEquals(result, "<A>")
55 self.assertEquals(result, "<A>")
56
56
57 ipy_src = """
57 ipy_src = """
58 class A(object):
58 class A(object):
59 def __repr__(self):
59 def __repr__(self):
60 return 'A()'
60 return 'A()'
61
61
62 class B(object):
62 class B(object):
63 def __repr__(self):
63 def __repr__(self):
64 return 'B()'
64 return 'B()'
65
65
66 a = A()
66 a = A()
67 b = B()
67 b = B()
68
68
69 def a_pretty_printer(obj, p, cycle):
69 def a_pretty_printer(obj, p, cycle):
70 p.text('<A>')
70 p.text('<A>')
71
71
72 def b_pretty_printer(obj, p, cycle):
72 def b_pretty_printer(obj, p, cycle):
73 p.text('<B>')
73 p.text('<B>')
74
74
75
75
76 a
76 a
77 b
77 b
78
78
79 ip = get_ipython()
79 ip = get_ipython()
80 prd = ip.load_extension('pretty')
80 prd = ip.extension_manager.load_extension('pretty')
81 prd.for_type(A, a_pretty_printer)
81 prd.for_type(A, a_pretty_printer)
82 prd.for_type_by_name(B.__module__, B.__name__, b_pretty_printer)
82 prd.for_type_by_name(B.__module__, B.__name__, b_pretty_printer)
83
83
84 a
84 a
85 b
85 b
86 """
86 """
87 ipy_out = """
87 ipy_out = """
88 A()
88 A()
89 B()
89 B()
90 <A>
90 <A>
91 <B>
91 <B>
92 """
92 """
93
93
94 class TestPrettyInteractively(tt.TempFileMixin):
94 class TestPrettyInteractively(tt.TempFileMixin):
95
95
96 # XXX Unfortunately, ipexec_validate fails under win32. If someone helps
96 # XXX Unfortunately, ipexec_validate fails under win32. If someone helps
97 # us write a win32-compatible version, we can reactivate this test.
97 # us write a win32-compatible version, we can reactivate this test.
98 @dec.skip_win32
98 @dec.skip_win32
99 def test_printers(self):
99 def test_printers(self):
100 self.mktmp(ipy_src, '.ipy')
100 self.mktmp(ipy_src, '.ipy')
101 tt.ipexec_validate(self.fname, ipy_out)
101 tt.ipexec_validate(self.fname, ipy_out)
@@ -1,539 +1,539 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython cluster directory
4 The IPython cluster directory
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import with_statement
18 from __future__ import with_statement
19
19
20 import os
20 import os
21 import shutil
21 import shutil
22 import sys
22 import sys
23 import warnings
23 import warnings
24
24
25 from twisted.python import log
25 from twisted.python import log
26
26
27 from IPython.config.loader import PyFileConfigLoader
27 from IPython.config.loader import PyFileConfigLoader
28 from IPython.core.application import Application, BaseAppConfigLoader
28 from IPython.core.application import Application, BaseAppConfigLoader
29 from IPython.core.component import Component
29 from IPython.config.configurable import Configurable
30 from IPython.core.crashhandler import CrashHandler
30 from IPython.core.crashhandler import CrashHandler
31 from IPython.core import release
31 from IPython.core import release
32 from IPython.utils.path import (
32 from IPython.utils.path import (
33 get_ipython_package_dir,
33 get_ipython_package_dir,
34 expand_path
34 expand_path
35 )
35 )
36 from IPython.utils.traitlets import Unicode
36 from IPython.utils.traitlets import Unicode
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Warnings control
39 # Warnings control
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Twisted generates annoying warnings with Python 2.6, as will do other code
41 # Twisted generates annoying warnings with Python 2.6, as will do other code
42 # that imports 'sets' as of today
42 # that imports 'sets' as of today
43 warnings.filterwarnings('ignore', 'the sets module is deprecated',
43 warnings.filterwarnings('ignore', 'the sets module is deprecated',
44 DeprecationWarning )
44 DeprecationWarning )
45
45
46 # This one also comes from Twisted
46 # This one also comes from Twisted
47 warnings.filterwarnings('ignore', 'the sha module is deprecated',
47 warnings.filterwarnings('ignore', 'the sha module is deprecated',
48 DeprecationWarning)
48 DeprecationWarning)
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Module errors
51 # Module errors
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 class ClusterDirError(Exception):
54 class ClusterDirError(Exception):
55 pass
55 pass
56
56
57
57
58 class PIDFileError(Exception):
58 class PIDFileError(Exception):
59 pass
59 pass
60
60
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # Class for managing cluster directories
63 # Class for managing cluster directories
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65
65
66 class ClusterDir(Component):
66 class ClusterDir(Configurable):
67 """An object to manage the cluster directory and its resources.
67 """An object to manage the cluster directory and its resources.
68
68
69 The cluster directory is used by :command:`ipcontroller`,
69 The cluster directory is used by :command:`ipcontroller`,
70 :command:`ipcontroller` and :command:`ipcontroller` to manage the
70 :command:`ipcontroller` and :command:`ipcontroller` to manage the
71 configuration, logging and security of these applications.
71 configuration, logging and security of these applications.
72
72
73 This object knows how to find, create and manage these directories. This
73 This object knows how to find, create and manage these directories. This
74 should be used by any code that want's to handle cluster directories.
74 should be used by any code that want's to handle cluster directories.
75 """
75 """
76
76
77 security_dir_name = Unicode('security')
77 security_dir_name = Unicode('security')
78 log_dir_name = Unicode('log')
78 log_dir_name = Unicode('log')
79 pid_dir_name = Unicode('pid')
79 pid_dir_name = Unicode('pid')
80 security_dir = Unicode(u'')
80 security_dir = Unicode(u'')
81 log_dir = Unicode(u'')
81 log_dir = Unicode(u'')
82 pid_dir = Unicode(u'')
82 pid_dir = Unicode(u'')
83 location = Unicode(u'')
83 location = Unicode(u'')
84
84
85 def __init__(self, location):
85 def __init__(self, location):
86 super(ClusterDir, self).__init__(None)
86 super(ClusterDir, self).__init__(None)
87 self.location = location
87 self.location = location
88
88
89 def _location_changed(self, name, old, new):
89 def _location_changed(self, name, old, new):
90 if not os.path.isdir(new):
90 if not os.path.isdir(new):
91 os.makedirs(new)
91 os.makedirs(new)
92 self.security_dir = os.path.join(new, self.security_dir_name)
92 self.security_dir = os.path.join(new, self.security_dir_name)
93 self.log_dir = os.path.join(new, self.log_dir_name)
93 self.log_dir = os.path.join(new, self.log_dir_name)
94 self.pid_dir = os.path.join(new, self.pid_dir_name)
94 self.pid_dir = os.path.join(new, self.pid_dir_name)
95 self.check_dirs()
95 self.check_dirs()
96
96
97 def _log_dir_changed(self, name, old, new):
97 def _log_dir_changed(self, name, old, new):
98 self.check_log_dir()
98 self.check_log_dir()
99
99
100 def check_log_dir(self):
100 def check_log_dir(self):
101 if not os.path.isdir(self.log_dir):
101 if not os.path.isdir(self.log_dir):
102 os.mkdir(self.log_dir)
102 os.mkdir(self.log_dir)
103
103
104 def _security_dir_changed(self, name, old, new):
104 def _security_dir_changed(self, name, old, new):
105 self.check_security_dir()
105 self.check_security_dir()
106
106
107 def check_security_dir(self):
107 def check_security_dir(self):
108 if not os.path.isdir(self.security_dir):
108 if not os.path.isdir(self.security_dir):
109 os.mkdir(self.security_dir, 0700)
109 os.mkdir(self.security_dir, 0700)
110 os.chmod(self.security_dir, 0700)
110 os.chmod(self.security_dir, 0700)
111
111
112 def _pid_dir_changed(self, name, old, new):
112 def _pid_dir_changed(self, name, old, new):
113 self.check_pid_dir()
113 self.check_pid_dir()
114
114
115 def check_pid_dir(self):
115 def check_pid_dir(self):
116 if not os.path.isdir(self.pid_dir):
116 if not os.path.isdir(self.pid_dir):
117 os.mkdir(self.pid_dir, 0700)
117 os.mkdir(self.pid_dir, 0700)
118 os.chmod(self.pid_dir, 0700)
118 os.chmod(self.pid_dir, 0700)
119
119
120 def check_dirs(self):
120 def check_dirs(self):
121 self.check_security_dir()
121 self.check_security_dir()
122 self.check_log_dir()
122 self.check_log_dir()
123 self.check_pid_dir()
123 self.check_pid_dir()
124
124
125 def load_config_file(self, filename):
125 def load_config_file(self, filename):
126 """Load a config file from the top level of the cluster dir.
126 """Load a config file from the top level of the cluster dir.
127
127
128 Parameters
128 Parameters
129 ----------
129 ----------
130 filename : unicode or str
130 filename : unicode or str
131 The filename only of the config file that must be located in
131 The filename only of the config file that must be located in
132 the top-level of the cluster directory.
132 the top-level of the cluster directory.
133 """
133 """
134 loader = PyFileConfigLoader(filename, self.location)
134 loader = PyFileConfigLoader(filename, self.location)
135 return loader.load_config()
135 return loader.load_config()
136
136
137 def copy_config_file(self, config_file, path=None, overwrite=False):
137 def copy_config_file(self, config_file, path=None, overwrite=False):
138 """Copy a default config file into the active cluster directory.
138 """Copy a default config file into the active cluster directory.
139
139
140 Default configuration files are kept in :mod:`IPython.config.default`.
140 Default configuration files are kept in :mod:`IPython.config.default`.
141 This function moves these from that location to the working cluster
141 This function moves these from that location to the working cluster
142 directory.
142 directory.
143 """
143 """
144 if path is None:
144 if path is None:
145 import IPython.config.default
145 import IPython.config.default
146 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
146 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
147 path = os.path.sep.join(path)
147 path = os.path.sep.join(path)
148 src = os.path.join(path, config_file)
148 src = os.path.join(path, config_file)
149 dst = os.path.join(self.location, config_file)
149 dst = os.path.join(self.location, config_file)
150 if not os.path.isfile(dst) or overwrite:
150 if not os.path.isfile(dst) or overwrite:
151 shutil.copy(src, dst)
151 shutil.copy(src, dst)
152
152
153 def copy_all_config_files(self, path=None, overwrite=False):
153 def copy_all_config_files(self, path=None, overwrite=False):
154 """Copy all config files into the active cluster directory."""
154 """Copy all config files into the active cluster directory."""
155 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
155 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
156 u'ipcluster_config.py']:
156 u'ipcluster_config.py']:
157 self.copy_config_file(f, path=path, overwrite=overwrite)
157 self.copy_config_file(f, path=path, overwrite=overwrite)
158
158
159 @classmethod
159 @classmethod
160 def create_cluster_dir(csl, cluster_dir):
160 def create_cluster_dir(csl, cluster_dir):
161 """Create a new cluster directory given a full path.
161 """Create a new cluster directory given a full path.
162
162
163 Parameters
163 Parameters
164 ----------
164 ----------
165 cluster_dir : str
165 cluster_dir : str
166 The full path to the cluster directory. If it does exist, it will
166 The full path to the cluster directory. If it does exist, it will
167 be used. If not, it will be created.
167 be used. If not, it will be created.
168 """
168 """
169 return ClusterDir(cluster_dir)
169 return ClusterDir(cluster_dir)
170
170
171 @classmethod
171 @classmethod
172 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
172 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
173 """Create a cluster dir by profile name and path.
173 """Create a cluster dir by profile name and path.
174
174
175 Parameters
175 Parameters
176 ----------
176 ----------
177 path : str
177 path : str
178 The path (directory) to put the cluster directory in.
178 The path (directory) to put the cluster directory in.
179 profile : str
179 profile : str
180 The name of the profile. The name of the cluster directory will
180 The name of the profile. The name of the cluster directory will
181 be "cluster_<profile>".
181 be "cluster_<profile>".
182 """
182 """
183 if not os.path.isdir(path):
183 if not os.path.isdir(path):
184 raise ClusterDirError('Directory not found: %s' % path)
184 raise ClusterDirError('Directory not found: %s' % path)
185 cluster_dir = os.path.join(path, u'cluster_' + profile)
185 cluster_dir = os.path.join(path, u'cluster_' + profile)
186 return ClusterDir(cluster_dir)
186 return ClusterDir(cluster_dir)
187
187
188 @classmethod
188 @classmethod
189 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
189 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
190 """Find an existing cluster dir by profile name, return its ClusterDir.
190 """Find an existing cluster dir by profile name, return its ClusterDir.
191
191
192 This searches through a sequence of paths for a cluster dir. If it
192 This searches through a sequence of paths for a cluster dir. If it
193 is not found, a :class:`ClusterDirError` exception will be raised.
193 is not found, a :class:`ClusterDirError` exception will be raised.
194
194
195 The search path algorithm is:
195 The search path algorithm is:
196 1. ``os.getcwd()``
196 1. ``os.getcwd()``
197 2. ``ipython_dir``
197 2. ``ipython_dir``
198 3. The directories found in the ":" separated
198 3. The directories found in the ":" separated
199 :env:`IPCLUSTER_DIR_PATH` environment variable.
199 :env:`IPCLUSTER_DIR_PATH` environment variable.
200
200
201 Parameters
201 Parameters
202 ----------
202 ----------
203 ipython_dir : unicode or str
203 ipython_dir : unicode or str
204 The IPython directory to use.
204 The IPython directory to use.
205 profile : unicode or str
205 profile : unicode or str
206 The name of the profile. The name of the cluster directory
206 The name of the profile. The name of the cluster directory
207 will be "cluster_<profile>".
207 will be "cluster_<profile>".
208 """
208 """
209 dirname = u'cluster_' + profile
209 dirname = u'cluster_' + profile
210 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
210 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
211 if cluster_dir_paths:
211 if cluster_dir_paths:
212 cluster_dir_paths = cluster_dir_paths.split(':')
212 cluster_dir_paths = cluster_dir_paths.split(':')
213 else:
213 else:
214 cluster_dir_paths = []
214 cluster_dir_paths = []
215 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
215 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
216 for p in paths:
216 for p in paths:
217 cluster_dir = os.path.join(p, dirname)
217 cluster_dir = os.path.join(p, dirname)
218 if os.path.isdir(cluster_dir):
218 if os.path.isdir(cluster_dir):
219 return ClusterDir(cluster_dir)
219 return ClusterDir(cluster_dir)
220 else:
220 else:
221 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
221 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
222
222
223 @classmethod
223 @classmethod
224 def find_cluster_dir(cls, cluster_dir):
224 def find_cluster_dir(cls, cluster_dir):
225 """Find/create a cluster dir and return its ClusterDir.
225 """Find/create a cluster dir and return its ClusterDir.
226
226
227 This will create the cluster directory if it doesn't exist.
227 This will create the cluster directory if it doesn't exist.
228
228
229 Parameters
229 Parameters
230 ----------
230 ----------
231 cluster_dir : unicode or str
231 cluster_dir : unicode or str
232 The path of the cluster directory. This is expanded using
232 The path of the cluster directory. This is expanded using
233 :func:`IPython.utils.genutils.expand_path`.
233 :func:`IPython.utils.genutils.expand_path`.
234 """
234 """
235 cluster_dir = expand_path(cluster_dir)
235 cluster_dir = expand_path(cluster_dir)
236 if not os.path.isdir(cluster_dir):
236 if not os.path.isdir(cluster_dir):
237 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
237 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
238 return ClusterDir(cluster_dir)
238 return ClusterDir(cluster_dir)
239
239
240
240
241 #-----------------------------------------------------------------------------
241 #-----------------------------------------------------------------------------
242 # Command line options
242 # Command line options
243 #-----------------------------------------------------------------------------
243 #-----------------------------------------------------------------------------
244
244
245 class ClusterDirConfigLoader(BaseAppConfigLoader):
245 class ClusterDirConfigLoader(BaseAppConfigLoader):
246
246
247 def _add_cluster_profile(self, parser):
247 def _add_cluster_profile(self, parser):
248 paa = parser.add_argument
248 paa = parser.add_argument
249 paa('-p', '--profile',
249 paa('-p', '--profile',
250 dest='Global.profile',type=unicode,
250 dest='Global.profile',type=unicode,
251 help=
251 help=
252 """The string name of the profile to be used. This determines the name
252 """The string name of the profile to be used. This determines the name
253 of the cluster dir as: cluster_<profile>. The default profile is named
253 of the cluster dir as: cluster_<profile>. The default profile is named
254 'default'. The cluster directory is resolve this way if the
254 'default'. The cluster directory is resolve this way if the
255 --cluster-dir option is not used.""",
255 --cluster-dir option is not used.""",
256 metavar='Global.profile')
256 metavar='Global.profile')
257
257
258 def _add_cluster_dir(self, parser):
258 def _add_cluster_dir(self, parser):
259 paa = parser.add_argument
259 paa = parser.add_argument
260 paa('--cluster-dir',
260 paa('--cluster-dir',
261 dest='Global.cluster_dir',type=unicode,
261 dest='Global.cluster_dir',type=unicode,
262 help="""Set the cluster dir. This overrides the logic used by the
262 help="""Set the cluster dir. This overrides the logic used by the
263 --profile option.""",
263 --profile option.""",
264 metavar='Global.cluster_dir')
264 metavar='Global.cluster_dir')
265
265
266 def _add_work_dir(self, parser):
266 def _add_work_dir(self, parser):
267 paa = parser.add_argument
267 paa = parser.add_argument
268 paa('--work-dir',
268 paa('--work-dir',
269 dest='Global.work_dir',type=unicode,
269 dest='Global.work_dir',type=unicode,
270 help='Set the working dir for the process.',
270 help='Set the working dir for the process.',
271 metavar='Global.work_dir')
271 metavar='Global.work_dir')
272
272
273 def _add_clean_logs(self, parser):
273 def _add_clean_logs(self, parser):
274 paa = parser.add_argument
274 paa = parser.add_argument
275 paa('--clean-logs',
275 paa('--clean-logs',
276 dest='Global.clean_logs', action='store_true',
276 dest='Global.clean_logs', action='store_true',
277 help='Delete old log flies before starting.')
277 help='Delete old log flies before starting.')
278
278
279 def _add_no_clean_logs(self, parser):
279 def _add_no_clean_logs(self, parser):
280 paa = parser.add_argument
280 paa = parser.add_argument
281 paa('--no-clean-logs',
281 paa('--no-clean-logs',
282 dest='Global.clean_logs', action='store_false',
282 dest='Global.clean_logs', action='store_false',
283 help="Don't Delete old log flies before starting.")
283 help="Don't Delete old log flies before starting.")
284
284
285 def _add_arguments(self):
285 def _add_arguments(self):
286 super(ClusterDirConfigLoader, self)._add_arguments()
286 super(ClusterDirConfigLoader, self)._add_arguments()
287 self._add_cluster_profile(self.parser)
287 self._add_cluster_profile(self.parser)
288 self._add_cluster_dir(self.parser)
288 self._add_cluster_dir(self.parser)
289 self._add_work_dir(self.parser)
289 self._add_work_dir(self.parser)
290 self._add_clean_logs(self.parser)
290 self._add_clean_logs(self.parser)
291 self._add_no_clean_logs(self.parser)
291 self._add_no_clean_logs(self.parser)
292
292
293
293
294 #-----------------------------------------------------------------------------
294 #-----------------------------------------------------------------------------
295 # Crash handler for this application
295 # Crash handler for this application
296 #-----------------------------------------------------------------------------
296 #-----------------------------------------------------------------------------
297
297
298
298
299 _message_template = """\
299 _message_template = """\
300 Oops, $self.app_name crashed. We do our best to make it stable, but...
300 Oops, $self.app_name crashed. We do our best to make it stable, but...
301
301
302 A crash report was automatically generated with the following information:
302 A crash report was automatically generated with the following information:
303 - A verbatim copy of the crash traceback.
303 - A verbatim copy of the crash traceback.
304 - Data on your current $self.app_name configuration.
304 - Data on your current $self.app_name configuration.
305
305
306 It was left in the file named:
306 It was left in the file named:
307 \t'$self.crash_report_fname'
307 \t'$self.crash_report_fname'
308 If you can email this file to the developers, the information in it will help
308 If you can email this file to the developers, the information in it will help
309 them in understanding and correcting the problem.
309 them in understanding and correcting the problem.
310
310
311 You can mail it to: $self.contact_name at $self.contact_email
311 You can mail it to: $self.contact_name at $self.contact_email
312 with the subject '$self.app_name Crash Report'.
312 with the subject '$self.app_name Crash Report'.
313
313
314 If you want to do it now, the following command will work (under Unix):
314 If you want to do it now, the following command will work (under Unix):
315 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
315 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
316
316
317 To ensure accurate tracking of this issue, please file a report about it at:
317 To ensure accurate tracking of this issue, please file a report about it at:
318 $self.bug_tracker
318 $self.bug_tracker
319 """
319 """
320
320
321 class ClusterDirCrashHandler(CrashHandler):
321 class ClusterDirCrashHandler(CrashHandler):
322 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
322 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
323
323
324 message_template = _message_template
324 message_template = _message_template
325
325
326 def __init__(self, app):
326 def __init__(self, app):
327 contact_name = release.authors['Brian'][0]
327 contact_name = release.authors['Brian'][0]
328 contact_email = release.authors['Brian'][1]
328 contact_email = release.authors['Brian'][1]
329 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
329 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
330 super(ClusterDirCrashHandler,self).__init__(
330 super(ClusterDirCrashHandler,self).__init__(
331 app, contact_name, contact_email, bug_tracker
331 app, contact_name, contact_email, bug_tracker
332 )
332 )
333
333
334
334
335 #-----------------------------------------------------------------------------
335 #-----------------------------------------------------------------------------
336 # Main application
336 # Main application
337 #-----------------------------------------------------------------------------
337 #-----------------------------------------------------------------------------
338
338
339 class ApplicationWithClusterDir(Application):
339 class ApplicationWithClusterDir(Application):
340 """An application that puts everything into a cluster directory.
340 """An application that puts everything into a cluster directory.
341
341
342 Instead of looking for things in the ipython_dir, this type of application
342 Instead of looking for things in the ipython_dir, this type of application
343 will use its own private directory called the "cluster directory"
343 will use its own private directory called the "cluster directory"
344 for things like config files, log files, etc.
344 for things like config files, log files, etc.
345
345
346 The cluster directory is resolved as follows:
346 The cluster directory is resolved as follows:
347
347
348 * If the ``--cluster-dir`` option is given, it is used.
348 * If the ``--cluster-dir`` option is given, it is used.
349 * If ``--cluster-dir`` is not given, the application directory is
349 * If ``--cluster-dir`` is not given, the application directory is
350 resolve using the profile name as ``cluster_<profile>``. The search
350 resolve using the profile name as ``cluster_<profile>``. The search
351 path for this directory is then i) cwd if it is found there
351 path for this directory is then i) cwd if it is found there
352 and ii) in ipython_dir otherwise.
352 and ii) in ipython_dir otherwise.
353
353
354 The config file for the application is to be put in the cluster
354 The config file for the application is to be put in the cluster
355 dir and named the value of the ``config_file_name`` class attribute.
355 dir and named the value of the ``config_file_name`` class attribute.
356 """
356 """
357
357
358 command_line_loader = ClusterDirConfigLoader
358 command_line_loader = ClusterDirConfigLoader
359 crash_handler_class = ClusterDirCrashHandler
359 crash_handler_class = ClusterDirCrashHandler
360 auto_create_cluster_dir = True
360 auto_create_cluster_dir = True
361
361
362 def create_default_config(self):
362 def create_default_config(self):
363 super(ApplicationWithClusterDir, self).create_default_config()
363 super(ApplicationWithClusterDir, self).create_default_config()
364 self.default_config.Global.profile = u'default'
364 self.default_config.Global.profile = u'default'
365 self.default_config.Global.cluster_dir = u''
365 self.default_config.Global.cluster_dir = u''
366 self.default_config.Global.work_dir = os.getcwd()
366 self.default_config.Global.work_dir = os.getcwd()
367 self.default_config.Global.log_to_file = False
367 self.default_config.Global.log_to_file = False
368 self.default_config.Global.clean_logs = False
368 self.default_config.Global.clean_logs = False
369
369
370 def find_resources(self):
370 def find_resources(self):
371 """This resolves the cluster directory.
371 """This resolves the cluster directory.
372
372
373 This tries to find the cluster directory and if successful, it will
373 This tries to find the cluster directory and if successful, it will
374 have done:
374 have done:
375 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
375 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
376 the application.
376 the application.
377 * Sets ``self.cluster_dir`` attribute of the application and config
377 * Sets ``self.cluster_dir`` attribute of the application and config
378 objects.
378 objects.
379
379
380 The algorithm used for this is as follows:
380 The algorithm used for this is as follows:
381 1. Try ``Global.cluster_dir``.
381 1. Try ``Global.cluster_dir``.
382 2. Try using ``Global.profile``.
382 2. Try using ``Global.profile``.
383 3. If both of these fail and ``self.auto_create_cluster_dir`` is
383 3. If both of these fail and ``self.auto_create_cluster_dir`` is
384 ``True``, then create the new cluster dir in the IPython directory.
384 ``True``, then create the new cluster dir in the IPython directory.
385 4. If all fails, then raise :class:`ClusterDirError`.
385 4. If all fails, then raise :class:`ClusterDirError`.
386 """
386 """
387
387
388 try:
388 try:
389 cluster_dir = self.command_line_config.Global.cluster_dir
389 cluster_dir = self.command_line_config.Global.cluster_dir
390 except AttributeError:
390 except AttributeError:
391 cluster_dir = self.default_config.Global.cluster_dir
391 cluster_dir = self.default_config.Global.cluster_dir
392 cluster_dir = expand_path(cluster_dir)
392 cluster_dir = expand_path(cluster_dir)
393 try:
393 try:
394 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
394 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
395 except ClusterDirError:
395 except ClusterDirError:
396 pass
396 pass
397 else:
397 else:
398 self.log.info('Using existing cluster dir: %s' % \
398 self.log.info('Using existing cluster dir: %s' % \
399 self.cluster_dir_obj.location
399 self.cluster_dir_obj.location
400 )
400 )
401 self.finish_cluster_dir()
401 self.finish_cluster_dir()
402 return
402 return
403
403
404 try:
404 try:
405 self.profile = self.command_line_config.Global.profile
405 self.profile = self.command_line_config.Global.profile
406 except AttributeError:
406 except AttributeError:
407 self.profile = self.default_config.Global.profile
407 self.profile = self.default_config.Global.profile
408 try:
408 try:
409 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
409 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
410 self.ipython_dir, self.profile)
410 self.ipython_dir, self.profile)
411 except ClusterDirError:
411 except ClusterDirError:
412 pass
412 pass
413 else:
413 else:
414 self.log.info('Using existing cluster dir: %s' % \
414 self.log.info('Using existing cluster dir: %s' % \
415 self.cluster_dir_obj.location
415 self.cluster_dir_obj.location
416 )
416 )
417 self.finish_cluster_dir()
417 self.finish_cluster_dir()
418 return
418 return
419
419
420 if self.auto_create_cluster_dir:
420 if self.auto_create_cluster_dir:
421 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
421 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
422 self.ipython_dir, self.profile
422 self.ipython_dir, self.profile
423 )
423 )
424 self.log.info('Creating new cluster dir: %s' % \
424 self.log.info('Creating new cluster dir: %s' % \
425 self.cluster_dir_obj.location
425 self.cluster_dir_obj.location
426 )
426 )
427 self.finish_cluster_dir()
427 self.finish_cluster_dir()
428 else:
428 else:
429 raise ClusterDirError('Could not find a valid cluster directory.')
429 raise ClusterDirError('Could not find a valid cluster directory.')
430
430
431 def finish_cluster_dir(self):
431 def finish_cluster_dir(self):
432 # Set the cluster directory
432 # Set the cluster directory
433 self.cluster_dir = self.cluster_dir_obj.location
433 self.cluster_dir = self.cluster_dir_obj.location
434
434
435 # These have to be set because they could be different from the one
435 # These have to be set because they could be different from the one
436 # that we just computed. Because command line has the highest
436 # that we just computed. Because command line has the highest
437 # priority, this will always end up in the master_config.
437 # priority, this will always end up in the master_config.
438 self.default_config.Global.cluster_dir = self.cluster_dir
438 self.default_config.Global.cluster_dir = self.cluster_dir
439 self.command_line_config.Global.cluster_dir = self.cluster_dir
439 self.command_line_config.Global.cluster_dir = self.cluster_dir
440
440
441 def find_config_file_name(self):
441 def find_config_file_name(self):
442 """Find the config file name for this application."""
442 """Find the config file name for this application."""
443 # For this type of Application it should be set as a class attribute.
443 # For this type of Application it should be set as a class attribute.
444 if not hasattr(self, 'default_config_file_name'):
444 if not hasattr(self, 'default_config_file_name'):
445 self.log.critical("No config filename found")
445 self.log.critical("No config filename found")
446 else:
446 else:
447 self.config_file_name = self.default_config_file_name
447 self.config_file_name = self.default_config_file_name
448
448
449 def find_config_file_paths(self):
449 def find_config_file_paths(self):
450 # Set the search path to to the cluster directory. We should NOT
450 # Set the search path to to the cluster directory. We should NOT
451 # include IPython.config.default here as the default config files
451 # include IPython.config.default here as the default config files
452 # are ALWAYS automatically moved to the cluster directory.
452 # are ALWAYS automatically moved to the cluster directory.
453 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
453 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
454 self.config_file_paths = (self.cluster_dir,)
454 self.config_file_paths = (self.cluster_dir,)
455
455
456 def pre_construct(self):
456 def pre_construct(self):
457 # The log and security dirs were set earlier, but here we put them
457 # The log and security dirs were set earlier, but here we put them
458 # into the config and log them.
458 # into the config and log them.
459 config = self.master_config
459 config = self.master_config
460 sdir = self.cluster_dir_obj.security_dir
460 sdir = self.cluster_dir_obj.security_dir
461 self.security_dir = config.Global.security_dir = sdir
461 self.security_dir = config.Global.security_dir = sdir
462 ldir = self.cluster_dir_obj.log_dir
462 ldir = self.cluster_dir_obj.log_dir
463 self.log_dir = config.Global.log_dir = ldir
463 self.log_dir = config.Global.log_dir = ldir
464 pdir = self.cluster_dir_obj.pid_dir
464 pdir = self.cluster_dir_obj.pid_dir
465 self.pid_dir = config.Global.pid_dir = pdir
465 self.pid_dir = config.Global.pid_dir = pdir
466 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
466 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
467 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
467 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
468 # Change to the working directory. We do this just before construct
468 # Change to the working directory. We do this just before construct
469 # is called so all the components there have the right working dir.
469 # is called so all the components there have the right working dir.
470 self.to_work_dir()
470 self.to_work_dir()
471
471
472 def to_work_dir(self):
472 def to_work_dir(self):
473 wd = self.master_config.Global.work_dir
473 wd = self.master_config.Global.work_dir
474 if unicode(wd) != unicode(os.getcwd()):
474 if unicode(wd) != unicode(os.getcwd()):
475 os.chdir(wd)
475 os.chdir(wd)
476 self.log.info("Changing to working dir: %s" % wd)
476 self.log.info("Changing to working dir: %s" % wd)
477
477
478 def start_logging(self):
478 def start_logging(self):
479 # Remove old log files
479 # Remove old log files
480 if self.master_config.Global.clean_logs:
480 if self.master_config.Global.clean_logs:
481 log_dir = self.master_config.Global.log_dir
481 log_dir = self.master_config.Global.log_dir
482 for f in os.listdir(log_dir):
482 for f in os.listdir(log_dir):
483 if f.startswith(self.name + u'-') and f.endswith('.log'):
483 if f.startswith(self.name + u'-') and f.endswith('.log'):
484 os.remove(os.path.join(log_dir, f))
484 os.remove(os.path.join(log_dir, f))
485 # Start logging to the new log file
485 # Start logging to the new log file
486 if self.master_config.Global.log_to_file:
486 if self.master_config.Global.log_to_file:
487 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
487 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
488 logfile = os.path.join(self.log_dir, log_filename)
488 logfile = os.path.join(self.log_dir, log_filename)
489 open_log_file = open(logfile, 'w')
489 open_log_file = open(logfile, 'w')
490 else:
490 else:
491 open_log_file = sys.stdout
491 open_log_file = sys.stdout
492 log.startLogging(open_log_file)
492 log.startLogging(open_log_file)
493
493
494 def write_pid_file(self, overwrite=False):
494 def write_pid_file(self, overwrite=False):
495 """Create a .pid file in the pid_dir with my pid.
495 """Create a .pid file in the pid_dir with my pid.
496
496
497 This must be called after pre_construct, which sets `self.pid_dir`.
497 This must be called after pre_construct, which sets `self.pid_dir`.
498 This raises :exc:`PIDFileError` if the pid file exists already.
498 This raises :exc:`PIDFileError` if the pid file exists already.
499 """
499 """
500 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
500 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
501 if os.path.isfile(pid_file):
501 if os.path.isfile(pid_file):
502 pid = self.get_pid_from_file()
502 pid = self.get_pid_from_file()
503 if not overwrite:
503 if not overwrite:
504 raise PIDFileError(
504 raise PIDFileError(
505 'The pid file [%s] already exists. \nThis could mean that this '
505 'The pid file [%s] already exists. \nThis could mean that this '
506 'server is already running with [pid=%s].' % (pid_file, pid)
506 'server is already running with [pid=%s].' % (pid_file, pid)
507 )
507 )
508 with open(pid_file, 'w') as f:
508 with open(pid_file, 'w') as f:
509 self.log.info("Creating pid file: %s" % pid_file)
509 self.log.info("Creating pid file: %s" % pid_file)
510 f.write(repr(os.getpid())+'\n')
510 f.write(repr(os.getpid())+'\n')
511
511
512 def remove_pid_file(self):
512 def remove_pid_file(self):
513 """Remove the pid file.
513 """Remove the pid file.
514
514
515 This should be called at shutdown by registering a callback with
515 This should be called at shutdown by registering a callback with
516 :func:`reactor.addSystemEventTrigger`. This needs to return
516 :func:`reactor.addSystemEventTrigger`. This needs to return
517 ``None``.
517 ``None``.
518 """
518 """
519 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
519 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
520 if os.path.isfile(pid_file):
520 if os.path.isfile(pid_file):
521 try:
521 try:
522 self.log.info("Removing pid file: %s" % pid_file)
522 self.log.info("Removing pid file: %s" % pid_file)
523 os.remove(pid_file)
523 os.remove(pid_file)
524 except:
524 except:
525 self.log.warn("Error removing the pid file: %s" % pid_file)
525 self.log.warn("Error removing the pid file: %s" % pid_file)
526
526
527 def get_pid_from_file(self):
527 def get_pid_from_file(self):
528 """Get the pid from the pid file.
528 """Get the pid from the pid file.
529
529
530 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
530 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
531 """
531 """
532 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
532 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
533 if os.path.isfile(pid_file):
533 if os.path.isfile(pid_file):
534 with open(pid_file, 'r') as f:
534 with open(pid_file, 'r') as f:
535 pid = int(f.read().strip())
535 pid = int(f.read().strip())
536 return pid
536 return pid
537 else:
537 else:
538 raise PIDFileError('pid file not found: %s' % pid_file)
538 raise PIDFileError('pid file not found: %s' % pid_file)
539
539
@@ -1,79 +1,79 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A class for creating a Twisted service that is configured using IPython's
4 A class for creating a Twisted service that is configured using IPython's
5 configuration system.
5 configuration system.
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2009 The IPython Development Team
10 #
10 #
11 # 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 in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import zope.interface as zi
19 import zope.interface as zi
20
20
21 from IPython.core.component import Component
21 from IPython.config.configurable import Configurable
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Code
24 # Code
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27
27
28 class IConfiguredObjectFactory(zi.Interface):
28 class IConfiguredObjectFactory(zi.Interface):
29 """I am a component that creates a configured object.
29 """I am a component that creates a configured object.
30
30
31 This class is useful if you want to configure a class that is not a
31 This class is useful if you want to configure a class that is not a
32 subclass of :class:`IPython.core.component.Component`.
32 subclass of :class:`IPython.config.configurable.Configurable`.
33 """
33 """
34
34
35 def __init__(config):
35 def __init__(config):
36 """Get ready to configure the object using config."""
36 """Get ready to configure the object using config."""
37
37
38 def create():
38 def create():
39 """Return an instance of the configured object."""
39 """Return an instance of the configured object."""
40
40
41
41
42 class ConfiguredObjectFactory(Component):
42 class ConfiguredObjectFactory(Configurable):
43
43
44 zi.implements(IConfiguredObjectFactory)
44 zi.implements(IConfiguredObjectFactory)
45
45
46 def __init__(self, config):
46 def __init__(self, config):
47 super(ConfiguredObjectFactory, self).__init__(None, config=config)
47 super(ConfiguredObjectFactory, self).__init__(config=config)
48
48
49 def create(self):
49 def create(self):
50 raise NotImplementedError('create must be implemented in a subclass')
50 raise NotImplementedError('create must be implemented in a subclass')
51
51
52
52
53 class IAdaptedConfiguredObjectFactory(zi.Interface):
53 class IAdaptedConfiguredObjectFactory(zi.Interface):
54 """I am a component that adapts and configures an object.
54 """I am a component that adapts and configures an object.
55
55
56 This class is useful if you have the adapt an instance and configure it.
56 This class is useful if you have the adapt an instance and configure it.
57 """
57 """
58
58
59 def __init__(config, adaptee=None):
59 def __init__(config, adaptee=None):
60 """Get ready to adapt adaptee and then configure it using config."""
60 """Get ready to adapt adaptee and then configure it using config."""
61
61
62 def create():
62 def create():
63 """Return an instance of the adapted and configured object."""
63 """Return an instance of the adapted and configured object."""
64
64
65
65
66 class AdaptedConfiguredObjectFactory(Component):
66 class AdaptedConfiguredObjectFactory(Configurable):
67
67
68 # zi.implements(IAdaptedConfiguredObjectFactory)
68 # zi.implements(IAdaptedConfiguredObjectFactory)
69
69
70 def __init__(self, config, adaptee):
70 def __init__(self, config, adaptee):
71 # print
71 # print
72 # print "config pre:", config
72 # print "config pre:", config
73 super(AdaptedConfiguredObjectFactory, self).__init__(None, config=config)
73 super(AdaptedConfiguredObjectFactory, self).__init__(config=config)
74 # print
74 # print
75 # print "config post:", config
75 # print "config post:", config
76 self.adaptee = adaptee
76 self.adaptee = adaptee
77
77
78 def create(self):
78 def create(self):
79 raise NotImplementedError('create must be implemented in a subclass') No newline at end of file
79 raise NotImplementedError('create must be implemented in a subclass')
@@ -1,296 +1,296 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Foolscap related utilities.
4 Foolscap related utilities.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import with_statement
18 from __future__ import with_statement
19
19
20 import os
20 import os
21 import tempfile
21 import tempfile
22
22
23 from twisted.internet import reactor, defer
23 from twisted.internet import reactor, defer
24 from twisted.python import log
24 from twisted.python import log
25
25
26 import foolscap
26 import foolscap
27 try:
27 try:
28 from foolscap.api import Tub, UnauthenticatedTub
28 from foolscap.api import Tub, UnauthenticatedTub
29 except ImportError:
29 except ImportError:
30 from foolscap import Tub, UnauthenticatedTub
30 from foolscap import Tub, UnauthenticatedTub
31
31
32 from IPython.config.loader import Config
32 from IPython.config.loader import Config
33 from IPython.kernel.configobjfactory import AdaptedConfiguredObjectFactory
33 from IPython.kernel.configobjfactory import AdaptedConfiguredObjectFactory
34 from IPython.kernel.error import SecurityError
34 from IPython.kernel.error import SecurityError
35
35
36 from IPython.utils.importstring import import_item
36 from IPython.utils.importstring import import_item
37 from IPython.utils.path import expand_path
37 from IPython.utils.path import expand_path
38 from IPython.utils.traitlets import Int, Str, Bool, Instance
38 from IPython.utils.traitlets import Int, Str, Bool, Instance
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Code
41 # Code
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44
44
45 # We do this so if a user doesn't have OpenSSL installed, it will try to use
45 # We do this so if a user doesn't have OpenSSL installed, it will try to use
46 # an UnauthenticatedTub. But, they will still run into problems if they
46 # an UnauthenticatedTub. But, they will still run into problems if they
47 # try to use encrypted furls.
47 # try to use encrypted furls.
48 try:
48 try:
49 import OpenSSL
49 import OpenSSL
50 except:
50 except:
51 Tub = UnauthenticatedTub
51 Tub = UnauthenticatedTub
52 have_crypto = False
52 have_crypto = False
53 else:
53 else:
54 have_crypto = True
54 have_crypto = True
55
55
56
56
57 class FURLError(Exception):
57 class FURLError(Exception):
58 pass
58 pass
59
59
60
60
61 def check_furl_file_security(furl_file, secure):
61 def check_furl_file_security(furl_file, secure):
62 """Remove the old furl_file if changing security modes."""
62 """Remove the old furl_file if changing security modes."""
63 furl_file = expand_path(furl_file)
63 furl_file = expand_path(furl_file)
64 if os.path.isfile(furl_file):
64 if os.path.isfile(furl_file):
65 with open(furl_file, 'r') as f:
65 with open(furl_file, 'r') as f:
66 oldfurl = f.read().strip()
66 oldfurl = f.read().strip()
67 if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure):
67 if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure):
68 os.remove(furl_file)
68 os.remove(furl_file)
69
69
70
70
71 def is_secure(furl):
71 def is_secure(furl):
72 """Is the given FURL secure or not."""
72 """Is the given FURL secure or not."""
73 if is_valid_furl(furl):
73 if is_valid_furl(furl):
74 if furl.startswith("pb://"):
74 if furl.startswith("pb://"):
75 return True
75 return True
76 elif furl.startswith("pbu://"):
76 elif furl.startswith("pbu://"):
77 return False
77 return False
78 else:
78 else:
79 raise FURLError("invalid FURL: %s" % furl)
79 raise FURLError("invalid FURL: %s" % furl)
80
80
81
81
82 def is_valid_furl(furl):
82 def is_valid_furl(furl):
83 """Is the str a valid FURL or not."""
83 """Is the str a valid FURL or not."""
84 if isinstance(furl, str):
84 if isinstance(furl, str):
85 if furl.startswith("pb://") or furl.startswith("pbu://"):
85 if furl.startswith("pb://") or furl.startswith("pbu://"):
86 return True
86 return True
87 else:
87 else:
88 return False
88 return False
89 else:
89 else:
90 return False
90 return False
91
91
92
92
93 def is_valid_furl_file(furl_or_file):
93 def is_valid_furl_file(furl_or_file):
94 """See if furl_or_file exists and contains a valid FURL.
94 """See if furl_or_file exists and contains a valid FURL.
95
95
96 This doesn't try to read the contents because often we have to validate
96 This doesn't try to read the contents because often we have to validate
97 FURL files that are created, but don't yet have a FURL written to them.
97 FURL files that are created, but don't yet have a FURL written to them.
98 """
98 """
99 if isinstance(furl_or_file, (str, unicode)):
99 if isinstance(furl_or_file, (str, unicode)):
100 path, furl_filename = os.path.split(furl_or_file)
100 path, furl_filename = os.path.split(furl_or_file)
101 if os.path.isdir(path) and furl_filename.endswith('.furl'):
101 if os.path.isdir(path) and furl_filename.endswith('.furl'):
102 return True
102 return True
103 return False
103 return False
104
104
105
105
106 def find_furl(furl_or_file):
106 def find_furl(furl_or_file):
107 """Find, validate and return a FURL in a string or file.
107 """Find, validate and return a FURL in a string or file.
108
108
109 This calls :func:`IPython.utils.path.expand_path` on the argument to
109 This calls :func:`IPython.utils.path.expand_path` on the argument to
110 properly handle ``~`` and ``$`` variables in the path.
110 properly handle ``~`` and ``$`` variables in the path.
111 """
111 """
112 if is_valid_furl(furl_or_file):
112 if is_valid_furl(furl_or_file):
113 return furl_or_file
113 return furl_or_file
114 furl_or_file = expand_path(furl_or_file)
114 furl_or_file = expand_path(furl_or_file)
115 if is_valid_furl_file(furl_or_file):
115 if is_valid_furl_file(furl_or_file):
116 with open(furl_or_file, 'r') as f:
116 with open(furl_or_file, 'r') as f:
117 furl = f.read().strip()
117 furl = f.read().strip()
118 if is_valid_furl(furl):
118 if is_valid_furl(furl):
119 return furl
119 return furl
120 raise FURLError("Not a valid FURL or FURL file: %r" % furl_or_file)
120 raise FURLError("Not a valid FURL or FURL file: %r" % furl_or_file)
121
121
122
122
123 def is_valid_furl_or_file(furl_or_file):
123 def is_valid_furl_or_file(furl_or_file):
124 """Validate a FURL or a FURL file.
124 """Validate a FURL or a FURL file.
125
125
126 If ``furl_or_file`` looks like a file, we simply make sure its directory
126 If ``furl_or_file`` looks like a file, we simply make sure its directory
127 exists and that it has a ``.furl`` file extension. We don't try to see
127 exists and that it has a ``.furl`` file extension. We don't try to see
128 if the FURL file exists or to read its contents. This is useful for
128 if the FURL file exists or to read its contents. This is useful for
129 cases where auto re-connection is being used.
129 cases where auto re-connection is being used.
130 """
130 """
131 if is_valid_furl(furl_or_file) or is_valid_furl_file(furl_or_file):
131 if is_valid_furl(furl_or_file) or is_valid_furl_file(furl_or_file):
132 return True
132 return True
133 else:
133 else:
134 return False
134 return False
135
135
136
136
137 def validate_furl_or_file(furl_or_file):
137 def validate_furl_or_file(furl_or_file):
138 """Like :func:`is_valid_furl_or_file`, but raises an error."""
138 """Like :func:`is_valid_furl_or_file`, but raises an error."""
139 if not is_valid_furl_or_file(furl_or_file):
139 if not is_valid_furl_or_file(furl_or_file):
140 raise FURLError('Not a valid FURL or FURL file: %r' % furl_or_file)
140 raise FURLError('Not a valid FURL or FURL file: %r' % furl_or_file)
141
141
142
142
143 def get_temp_furlfile(filename):
143 def get_temp_furlfile(filename):
144 """Return a temporary FURL file."""
144 """Return a temporary FURL file."""
145 return tempfile.mktemp(dir=os.path.dirname(filename),
145 return tempfile.mktemp(dir=os.path.dirname(filename),
146 prefix=os.path.basename(filename))
146 prefix=os.path.basename(filename))
147
147
148
148
149 def make_tub(ip, port, secure, cert_file):
149 def make_tub(ip, port, secure, cert_file):
150 """Create a listening tub given an ip, port, and cert_file location.
150 """Create a listening tub given an ip, port, and cert_file location.
151
151
152 Parameters
152 Parameters
153 ----------
153 ----------
154 ip : str
154 ip : str
155 The ip address or hostname that the tub should listen on.
155 The ip address or hostname that the tub should listen on.
156 Empty means all interfaces.
156 Empty means all interfaces.
157 port : int
157 port : int
158 The port that the tub should listen on. A value of 0 means
158 The port that the tub should listen on. A value of 0 means
159 pick a random port
159 pick a random port
160 secure: bool
160 secure: bool
161 Will the connection be secure (in the Foolscap sense).
161 Will the connection be secure (in the Foolscap sense).
162 cert_file: str
162 cert_file: str
163 A filename of a file to be used for theSSL certificate.
163 A filename of a file to be used for theSSL certificate.
164
164
165 Returns
165 Returns
166 -------
166 -------
167 A tub, listener tuple.
167 A tub, listener tuple.
168 """
168 """
169 if secure:
169 if secure:
170 if have_crypto:
170 if have_crypto:
171 tub = Tub(certFile=cert_file)
171 tub = Tub(certFile=cert_file)
172 else:
172 else:
173 raise SecurityError("OpenSSL/pyOpenSSL is not available, so we "
173 raise SecurityError("OpenSSL/pyOpenSSL is not available, so we "
174 "can't run in secure mode. Try running without "
174 "can't run in secure mode. Try running without "
175 "security using 'ipcontroller -xy'.")
175 "security using 'ipcontroller -xy'.")
176 else:
176 else:
177 tub = UnauthenticatedTub()
177 tub = UnauthenticatedTub()
178
178
179 # Set the strport based on the ip and port and start listening
179 # Set the strport based on the ip and port and start listening
180 if ip == '':
180 if ip == '':
181 strport = "tcp:%i" % port
181 strport = "tcp:%i" % port
182 else:
182 else:
183 strport = "tcp:%i:interface=%s" % (port, ip)
183 strport = "tcp:%i:interface=%s" % (port, ip)
184 log.msg("Starting listener with [secure=%r] on: %s" % (secure, strport))
184 log.msg("Starting listener with [secure=%r] on: %s" % (secure, strport))
185 listener = tub.listenOn(strport)
185 listener = tub.listenOn(strport)
186
186
187 return tub, listener
187 return tub, listener
188
188
189
189
190 class FCServiceFactory(AdaptedConfiguredObjectFactory):
190 class FCServiceFactory(AdaptedConfiguredObjectFactory):
191 """This class creates a tub with various services running in it.
191 """This class creates a tub with various services running in it.
192
192
193 The basic idea is that :meth:`create` returns a running :class:`Tub`
193 The basic idea is that :meth:`create` returns a running :class:`Tub`
194 instance that has a number of Foolscap references registered in it.
194 instance that has a number of Foolscap references registered in it. This
195 This class is a subclass of :class:`IPython.core.component.Component`
195 class is a subclass of :class:`IPython.config.configurable.Configurable`
196 so the IPython configuration and component system are used.
196 so the IPython configuration system is used.
197
197
198 Attributes
198 Attributes
199 ----------
199 ----------
200 interfaces : Config
200 interfaces : Config
201 A Config instance whose values are sub-Config objects having two
201 A Config instance whose values are sub-Config objects having two
202 keys: furl_file and interface_chain.
202 keys: furl_file and interface_chain.
203
203
204 The other attributes are the standard ones for Foolscap.
204 The other attributes are the standard ones for Foolscap.
205 """
205 """
206
206
207 ip = Str('', config=True)
207 ip = Str('', config=True)
208 port = Int(0, config=True)
208 port = Int(0, config=True)
209 secure = Bool(True, config=True)
209 secure = Bool(True, config=True)
210 cert_file = Str('', config=True)
210 cert_file = Str('', config=True)
211 location = Str('', config=True)
211 location = Str('', config=True)
212 reuse_furls = Bool(False, config=True)
212 reuse_furls = Bool(False, config=True)
213 interfaces = Instance(klass=Config, kw={}, allow_none=False, config=True)
213 interfaces = Instance(klass=Config, kw={}, allow_none=False, config=True)
214
214
215 def __init__(self, config, adaptee):
215 def __init__(self, config, adaptee):
216 super(FCServiceFactory, self).__init__(config, adaptee)
216 super(FCServiceFactory, self).__init__(config, adaptee)
217 self._check_reuse_furls()
217 self._check_reuse_furls()
218
218
219 def _ip_changed(self, name, old, new):
219 def _ip_changed(self, name, old, new):
220 if new == 'localhost' or new == '127.0.0.1':
220 if new == 'localhost' or new == '127.0.0.1':
221 self.location = '127.0.0.1'
221 self.location = '127.0.0.1'
222
222
223 def _check_reuse_furls(self):
223 def _check_reuse_furls(self):
224 furl_files = [i.furl_file for i in self.interfaces.values()]
224 furl_files = [i.furl_file for i in self.interfaces.values()]
225 for ff in furl_files:
225 for ff in furl_files:
226 fullfile = self._get_security_file(ff)
226 fullfile = self._get_security_file(ff)
227 if self.reuse_furls:
227 if self.reuse_furls:
228 if self.port==0:
228 if self.port==0:
229 raise FURLError("You are trying to reuse the FURL file "
229 raise FURLError("You are trying to reuse the FURL file "
230 "for this connection, but the port for this connection "
230 "for this connection, but the port for this connection "
231 "is set to 0 (autoselect). To reuse the FURL file "
231 "is set to 0 (autoselect). To reuse the FURL file "
232 "you need to specify specific port to listen on."
232 "you need to specify specific port to listen on."
233 )
233 )
234 else:
234 else:
235 log.msg("Reusing FURL file: %s" % fullfile)
235 log.msg("Reusing FURL file: %s" % fullfile)
236 else:
236 else:
237 if os.path.isfile(fullfile):
237 if os.path.isfile(fullfile):
238 log.msg("Removing old FURL file: %s" % fullfile)
238 log.msg("Removing old FURL file: %s" % fullfile)
239 os.remove(fullfile)
239 os.remove(fullfile)
240
240
241 def _get_security_file(self, filename):
241 def _get_security_file(self, filename):
242 return os.path.join(self.config.Global.security_dir, filename)
242 return os.path.join(self.config.Global.security_dir, filename)
243
243
244 def create(self):
244 def create(self):
245 """Create and return the Foolscap tub with everything running."""
245 """Create and return the Foolscap tub with everything running."""
246
246
247 self.tub, self.listener = make_tub(
247 self.tub, self.listener = make_tub(
248 self.ip, self.port, self.secure,
248 self.ip, self.port, self.secure,
249 self._get_security_file(self.cert_file)
249 self._get_security_file(self.cert_file)
250 )
250 )
251 # log.msg("Interfaces to register [%r]: %r" % \
251 # log.msg("Interfaces to register [%r]: %r" % \
252 # (self.__class__, self.interfaces))
252 # (self.__class__, self.interfaces))
253 if not self.secure:
253 if not self.secure:
254 log.msg("WARNING: running with no security: %s" % \
254 log.msg("WARNING: running with no security: %s" % \
255 self.__class__.__name__)
255 self.__class__.__name__)
256 reactor.callWhenRunning(self.set_location_and_register)
256 reactor.callWhenRunning(self.set_location_and_register)
257 return self.tub
257 return self.tub
258
258
259 def set_location_and_register(self):
259 def set_location_and_register(self):
260 """Set the location for the tub and return a deferred."""
260 """Set the location for the tub and return a deferred."""
261
261
262 if self.location == '':
262 if self.location == '':
263 d = self.tub.setLocationAutomatically()
263 d = self.tub.setLocationAutomatically()
264 else:
264 else:
265 d = defer.maybeDeferred(self.tub.setLocation,
265 d = defer.maybeDeferred(self.tub.setLocation,
266 "%s:%i" % (self.location, self.listener.getPortnum()))
266 "%s:%i" % (self.location, self.listener.getPortnum()))
267 self.adapt_to_interfaces(d)
267 self.adapt_to_interfaces(d)
268
268
269 def adapt_to_interfaces(self, d):
269 def adapt_to_interfaces(self, d):
270 """Run through the interfaces, adapt and register."""
270 """Run through the interfaces, adapt and register."""
271
271
272 for ifname, ifconfig in self.interfaces.iteritems():
272 for ifname, ifconfig in self.interfaces.iteritems():
273 ff = self._get_security_file(ifconfig.furl_file)
273 ff = self._get_security_file(ifconfig.furl_file)
274 log.msg("Adapting [%s] to interface: %s" % \
274 log.msg("Adapting [%s] to interface: %s" % \
275 (self.adaptee.__class__.__name__, ifname))
275 (self.adaptee.__class__.__name__, ifname))
276 log.msg("Saving FURL for interface [%s] to file: %s" % (ifname, ff))
276 log.msg("Saving FURL for interface [%s] to file: %s" % (ifname, ff))
277 check_furl_file_security(ff, self.secure)
277 check_furl_file_security(ff, self.secure)
278 adaptee = self.adaptee
278 adaptee = self.adaptee
279 for i in ifconfig.interface_chain:
279 for i in ifconfig.interface_chain:
280 adaptee = import_item(i)(adaptee)
280 adaptee = import_item(i)(adaptee)
281 d.addCallback(self.register, adaptee, furl_file=ff)
281 d.addCallback(self.register, adaptee, furl_file=ff)
282
282
283 def register(self, empty, ref, furl_file):
283 def register(self, empty, ref, furl_file):
284 """Register the reference with the FURL file.
284 """Register the reference with the FURL file.
285
285
286 The FURL file is created and then moved to make sure that when the
286 The FURL file is created and then moved to make sure that when the
287 file appears, the buffer has been flushed and the file closed. This
287 file appears, the buffer has been flushed and the file closed. This
288 is not done if we are re-using FURLS however.
288 is not done if we are re-using FURLS however.
289 """
289 """
290 if self.reuse_furls:
290 if self.reuse_furls:
291 self.tub.registerReference(ref, furlFile=furl_file)
291 self.tub.registerReference(ref, furlFile=furl_file)
292 else:
292 else:
293 temp_furl_file = get_temp_furlfile(furl_file)
293 temp_furl_file = get_temp_furlfile(furl_file)
294 self.tub.registerReference(ref, furlFile=temp_furl_file)
294 self.tub.registerReference(ref, furlFile=temp_furl_file)
295 os.rename(temp_furl_file, furl_file)
295 os.rename(temp_furl_file, furl_file)
296
296
@@ -1,835 +1,835 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Facilities for launching IPython processes asynchronously.
4 Facilities for launching IPython processes asynchronously.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21
21
22 from IPython.core.component import Component
22 from IPython.config.configurable import Configurable
23 from IPython.external import Itpl
23 from IPython.external import Itpl
24 from IPython.utils.traitlets import Str, Int, List, Unicode
24 from IPython.utils.traitlets import Str, Int, List, Unicode
25 from IPython.utils.path import get_ipython_module_path
25 from IPython.utils.path import get_ipython_module_path
26 from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError
26 from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError
27 from IPython.kernel.twistedutil import (
27 from IPython.kernel.twistedutil import (
28 gatherBoth,
28 gatherBoth,
29 make_deferred,
29 make_deferred,
30 sleep_deferred
30 sleep_deferred
31 )
31 )
32 from IPython.kernel.winhpcjob import (
32 from IPython.kernel.winhpcjob import (
33 IPControllerTask, IPEngineTask,
33 IPControllerTask, IPEngineTask,
34 IPControllerJob, IPEngineSetJob
34 IPControllerJob, IPEngineSetJob
35 )
35 )
36
36
37 from twisted.internet import reactor, defer
37 from twisted.internet import reactor, defer
38 from twisted.internet.defer import inlineCallbacks
38 from twisted.internet.defer import inlineCallbacks
39 from twisted.internet.protocol import ProcessProtocol
39 from twisted.internet.protocol import ProcessProtocol
40 from twisted.internet.utils import getProcessOutput
40 from twisted.internet.utils import getProcessOutput
41 from twisted.internet.error import ProcessDone, ProcessTerminated
41 from twisted.internet.error import ProcessDone, ProcessTerminated
42 from twisted.python import log
42 from twisted.python import log
43 from twisted.python.failure import Failure
43 from twisted.python.failure import Failure
44
44
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Paths to the kernel apps
47 # Paths to the kernel apps
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 ipcluster_cmd_argv = pycmd2argv(get_ipython_module_path(
51 ipcluster_cmd_argv = pycmd2argv(get_ipython_module_path(
52 'IPython.kernel.ipclusterapp'
52 'IPython.kernel.ipclusterapp'
53 ))
53 ))
54
54
55 ipengine_cmd_argv = pycmd2argv(get_ipython_module_path(
55 ipengine_cmd_argv = pycmd2argv(get_ipython_module_path(
56 'IPython.kernel.ipengineapp'
56 'IPython.kernel.ipengineapp'
57 ))
57 ))
58
58
59 ipcontroller_cmd_argv = pycmd2argv(get_ipython_module_path(
59 ipcontroller_cmd_argv = pycmd2argv(get_ipython_module_path(
60 'IPython.kernel.ipcontrollerapp'
60 'IPython.kernel.ipcontrollerapp'
61 ))
61 ))
62
62
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 # Base launchers and errors
64 # Base launchers and errors
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67
67
68 class LauncherError(Exception):
68 class LauncherError(Exception):
69 pass
69 pass
70
70
71
71
72 class ProcessStateError(LauncherError):
72 class ProcessStateError(LauncherError):
73 pass
73 pass
74
74
75
75
76 class UnknownStatus(LauncherError):
76 class UnknownStatus(LauncherError):
77 pass
77 pass
78
78
79
79
80 class BaseLauncher(Component):
80 class BaseLauncher(Configurable):
81 """An asbtraction for starting, stopping and signaling a process."""
81 """An asbtraction for starting, stopping and signaling a process."""
82
82
83 # In all of the launchers, the work_dir is where child processes will be
83 # In all of the launchers, the work_dir is where child processes will be
84 # run. This will usually be the cluster_dir, but may not be. any work_dir
84 # run. This will usually be the cluster_dir, but may not be. any work_dir
85 # passed into the __init__ method will override the config value.
85 # passed into the __init__ method will override the config value.
86 # This should not be used to set the work_dir for the actual engine
86 # This should not be used to set the work_dir for the actual engine
87 # and controller. Instead, use their own config files or the
87 # and controller. Instead, use their own config files or the
88 # controller_args, engine_args attributes of the launchers to add
88 # controller_args, engine_args attributes of the launchers to add
89 # the --work-dir option.
89 # the --work-dir option.
90 work_dir = Unicode(u'')
90 work_dir = Unicode(u'')
91
91
92 def __init__(self, work_dir, parent=None, name=None, config=None):
92 def __init__(self, work_dir, config=None):
93 super(BaseLauncher, self).__init__(parent, name, config)
93 super(BaseLauncher, self).__init__(config)
94 self.work_dir = work_dir
94 self.work_dir = work_dir
95 self.state = 'before' # can be before, running, after
95 self.state = 'before' # can be before, running, after
96 self.stop_deferreds = []
96 self.stop_deferreds = []
97 self.start_data = None
97 self.start_data = None
98 self.stop_data = None
98 self.stop_data = None
99
99
100 @property
100 @property
101 def args(self):
101 def args(self):
102 """A list of cmd and args that will be used to start the process.
102 """A list of cmd and args that will be used to start the process.
103
103
104 This is what is passed to :func:`spawnProcess` and the first element
104 This is what is passed to :func:`spawnProcess` and the first element
105 will be the process name.
105 will be the process name.
106 """
106 """
107 return self.find_args()
107 return self.find_args()
108
108
109 def find_args(self):
109 def find_args(self):
110 """The ``.args`` property calls this to find the args list.
110 """The ``.args`` property calls this to find the args list.
111
111
112 Subcommand should implement this to construct the cmd and args.
112 Subcommand should implement this to construct the cmd and args.
113 """
113 """
114 raise NotImplementedError('find_args must be implemented in a subclass')
114 raise NotImplementedError('find_args must be implemented in a subclass')
115
115
116 @property
116 @property
117 def arg_str(self):
117 def arg_str(self):
118 """The string form of the program arguments."""
118 """The string form of the program arguments."""
119 return ' '.join(self.args)
119 return ' '.join(self.args)
120
120
121 @property
121 @property
122 def running(self):
122 def running(self):
123 """Am I running."""
123 """Am I running."""
124 if self.state == 'running':
124 if self.state == 'running':
125 return True
125 return True
126 else:
126 else:
127 return False
127 return False
128
128
129 def start(self):
129 def start(self):
130 """Start the process.
130 """Start the process.
131
131
132 This must return a deferred that fires with information about the
132 This must return a deferred that fires with information about the
133 process starting (like a pid, job id, etc.).
133 process starting (like a pid, job id, etc.).
134 """
134 """
135 return defer.fail(
135 return defer.fail(
136 Failure(NotImplementedError(
136 Failure(NotImplementedError(
137 'start must be implemented in a subclass')
137 'start must be implemented in a subclass')
138 )
138 )
139 )
139 )
140
140
141 def stop(self):
141 def stop(self):
142 """Stop the process and notify observers of stopping.
142 """Stop the process and notify observers of stopping.
143
143
144 This must return a deferred that fires with information about the
144 This must return a deferred that fires with information about the
145 processing stopping, like errors that occur while the process is
145 processing stopping, like errors that occur while the process is
146 attempting to be shut down. This deferred won't fire when the process
146 attempting to be shut down. This deferred won't fire when the process
147 actually stops. To observe the actual process stopping, see
147 actually stops. To observe the actual process stopping, see
148 :func:`observe_stop`.
148 :func:`observe_stop`.
149 """
149 """
150 return defer.fail(
150 return defer.fail(
151 Failure(NotImplementedError(
151 Failure(NotImplementedError(
152 'stop must be implemented in a subclass')
152 'stop must be implemented in a subclass')
153 )
153 )
154 )
154 )
155
155
156 def observe_stop(self):
156 def observe_stop(self):
157 """Get a deferred that will fire when the process stops.
157 """Get a deferred that will fire when the process stops.
158
158
159 The deferred will fire with data that contains information about
159 The deferred will fire with data that contains information about
160 the exit status of the process.
160 the exit status of the process.
161 """
161 """
162 if self.state=='after':
162 if self.state=='after':
163 return defer.succeed(self.stop_data)
163 return defer.succeed(self.stop_data)
164 else:
164 else:
165 d = defer.Deferred()
165 d = defer.Deferred()
166 self.stop_deferreds.append(d)
166 self.stop_deferreds.append(d)
167 return d
167 return d
168
168
169 def notify_start(self, data):
169 def notify_start(self, data):
170 """Call this to trigger startup actions.
170 """Call this to trigger startup actions.
171
171
172 This logs the process startup and sets the state to 'running'. It is
172 This logs the process startup and sets the state to 'running'. It is
173 a pass-through so it can be used as a callback.
173 a pass-through so it can be used as a callback.
174 """
174 """
175
175
176 log.msg('Process %r started: %r' % (self.args[0], data))
176 log.msg('Process %r started: %r' % (self.args[0], data))
177 self.start_data = data
177 self.start_data = data
178 self.state = 'running'
178 self.state = 'running'
179 return data
179 return data
180
180
181 def notify_stop(self, data):
181 def notify_stop(self, data):
182 """Call this to trigger process stop actions.
182 """Call this to trigger process stop actions.
183
183
184 This logs the process stopping and sets the state to 'after'. Call
184 This logs the process stopping and sets the state to 'after'. Call
185 this to trigger all the deferreds from :func:`observe_stop`."""
185 this to trigger all the deferreds from :func:`observe_stop`."""
186
186
187 log.msg('Process %r stopped: %r' % (self.args[0], data))
187 log.msg('Process %r stopped: %r' % (self.args[0], data))
188 self.stop_data = data
188 self.stop_data = data
189 self.state = 'after'
189 self.state = 'after'
190 for i in range(len(self.stop_deferreds)):
190 for i in range(len(self.stop_deferreds)):
191 d = self.stop_deferreds.pop()
191 d = self.stop_deferreds.pop()
192 d.callback(data)
192 d.callback(data)
193 return data
193 return data
194
194
195 def signal(self, sig):
195 def signal(self, sig):
196 """Signal the process.
196 """Signal the process.
197
197
198 Return a semi-meaningless deferred after signaling the process.
198 Return a semi-meaningless deferred after signaling the process.
199
199
200 Parameters
200 Parameters
201 ----------
201 ----------
202 sig : str or int
202 sig : str or int
203 'KILL', 'INT', etc., or any signal number
203 'KILL', 'INT', etc., or any signal number
204 """
204 """
205 return defer.fail(
205 return defer.fail(
206 Failure(NotImplementedError(
206 Failure(NotImplementedError(
207 'signal must be implemented in a subclass')
207 'signal must be implemented in a subclass')
208 )
208 )
209 )
209 )
210
210
211
211
212 #-----------------------------------------------------------------------------
212 #-----------------------------------------------------------------------------
213 # Local process launchers
213 # Local process launchers
214 #-----------------------------------------------------------------------------
214 #-----------------------------------------------------------------------------
215
215
216
216
217 class LocalProcessLauncherProtocol(ProcessProtocol):
217 class LocalProcessLauncherProtocol(ProcessProtocol):
218 """A ProcessProtocol to go with the LocalProcessLauncher."""
218 """A ProcessProtocol to go with the LocalProcessLauncher."""
219
219
220 def __init__(self, process_launcher):
220 def __init__(self, process_launcher):
221 self.process_launcher = process_launcher
221 self.process_launcher = process_launcher
222 self.pid = None
222 self.pid = None
223
223
224 def connectionMade(self):
224 def connectionMade(self):
225 self.pid = self.transport.pid
225 self.pid = self.transport.pid
226 self.process_launcher.notify_start(self.transport.pid)
226 self.process_launcher.notify_start(self.transport.pid)
227
227
228 def processEnded(self, status):
228 def processEnded(self, status):
229 value = status.value
229 value = status.value
230 if isinstance(value, ProcessDone):
230 if isinstance(value, ProcessDone):
231 self.process_launcher.notify_stop(
231 self.process_launcher.notify_stop(
232 {'exit_code':0,
232 {'exit_code':0,
233 'signal':None,
233 'signal':None,
234 'status':None,
234 'status':None,
235 'pid':self.pid
235 'pid':self.pid
236 }
236 }
237 )
237 )
238 elif isinstance(value, ProcessTerminated):
238 elif isinstance(value, ProcessTerminated):
239 self.process_launcher.notify_stop(
239 self.process_launcher.notify_stop(
240 {'exit_code':value.exitCode,
240 {'exit_code':value.exitCode,
241 'signal':value.signal,
241 'signal':value.signal,
242 'status':value.status,
242 'status':value.status,
243 'pid':self.pid
243 'pid':self.pid
244 }
244 }
245 )
245 )
246 else:
246 else:
247 raise UnknownStatus("Unknown exit status, this is probably a "
247 raise UnknownStatus("Unknown exit status, this is probably a "
248 "bug in Twisted")
248 "bug in Twisted")
249
249
250 def outReceived(self, data):
250 def outReceived(self, data):
251 log.msg(data)
251 log.msg(data)
252
252
253 def errReceived(self, data):
253 def errReceived(self, data):
254 log.err(data)
254 log.err(data)
255
255
256
256
257 class LocalProcessLauncher(BaseLauncher):
257 class LocalProcessLauncher(BaseLauncher):
258 """Start and stop an external process in an asynchronous manner.
258 """Start and stop an external process in an asynchronous manner.
259
259
260 This will launch the external process with a working directory of
260 This will launch the external process with a working directory of
261 ``self.work_dir``.
261 ``self.work_dir``.
262 """
262 """
263
263
264 # This is used to to construct self.args, which is passed to
264 # This is used to to construct self.args, which is passed to
265 # spawnProcess.
265 # spawnProcess.
266 cmd_and_args = List([])
266 cmd_and_args = List([])
267
267
268 def __init__(self, work_dir, parent=None, name=None, config=None):
268 def __init__(self, work_dir, config=None):
269 super(LocalProcessLauncher, self).__init__(
269 super(LocalProcessLauncher, self).__init__(
270 work_dir, parent, name, config
270 work_dir, config
271 )
271 )
272 self.process_protocol = None
272 self.process_protocol = None
273 self.start_deferred = None
273 self.start_deferred = None
274
274
275 def find_args(self):
275 def find_args(self):
276 return self.cmd_and_args
276 return self.cmd_and_args
277
277
278 def start(self):
278 def start(self):
279 if self.state == 'before':
279 if self.state == 'before':
280 self.process_protocol = LocalProcessLauncherProtocol(self)
280 self.process_protocol = LocalProcessLauncherProtocol(self)
281 self.start_deferred = defer.Deferred()
281 self.start_deferred = defer.Deferred()
282 self.process_transport = reactor.spawnProcess(
282 self.process_transport = reactor.spawnProcess(
283 self.process_protocol,
283 self.process_protocol,
284 str(self.args[0]), # twisted expects these to be str, not unicode
284 str(self.args[0]), # twisted expects these to be str, not unicode
285 [str(a) for a in self.args], # str expected, not unicode
285 [str(a) for a in self.args], # str expected, not unicode
286 env=os.environ,
286 env=os.environ,
287 path=self.work_dir # start in the work_dir
287 path=self.work_dir # start in the work_dir
288 )
288 )
289 return self.start_deferred
289 return self.start_deferred
290 else:
290 else:
291 s = 'The process was already started and has state: %r' % self.state
291 s = 'The process was already started and has state: %r' % self.state
292 return defer.fail(ProcessStateError(s))
292 return defer.fail(ProcessStateError(s))
293
293
294 def notify_start(self, data):
294 def notify_start(self, data):
295 super(LocalProcessLauncher, self).notify_start(data)
295 super(LocalProcessLauncher, self).notify_start(data)
296 self.start_deferred.callback(data)
296 self.start_deferred.callback(data)
297
297
298 def stop(self):
298 def stop(self):
299 return self.interrupt_then_kill()
299 return self.interrupt_then_kill()
300
300
301 @make_deferred
301 @make_deferred
302 def signal(self, sig):
302 def signal(self, sig):
303 if self.state == 'running':
303 if self.state == 'running':
304 self.process_transport.signalProcess(sig)
304 self.process_transport.signalProcess(sig)
305
305
306 @inlineCallbacks
306 @inlineCallbacks
307 def interrupt_then_kill(self, delay=2.0):
307 def interrupt_then_kill(self, delay=2.0):
308 """Send INT, wait a delay and then send KILL."""
308 """Send INT, wait a delay and then send KILL."""
309 yield self.signal('INT')
309 yield self.signal('INT')
310 yield sleep_deferred(delay)
310 yield sleep_deferred(delay)
311 yield self.signal('KILL')
311 yield self.signal('KILL')
312
312
313
313
314 class LocalControllerLauncher(LocalProcessLauncher):
314 class LocalControllerLauncher(LocalProcessLauncher):
315 """Launch a controller as a regular external process."""
315 """Launch a controller as a regular external process."""
316
316
317 controller_cmd = List(ipcontroller_cmd_argv, config=True)
317 controller_cmd = List(ipcontroller_cmd_argv, config=True)
318 # Command line arguments to ipcontroller.
318 # Command line arguments to ipcontroller.
319 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
319 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
320
320
321 def find_args(self):
321 def find_args(self):
322 return self.controller_cmd + self.controller_args
322 return self.controller_cmd + self.controller_args
323
323
324 def start(self, cluster_dir):
324 def start(self, cluster_dir):
325 """Start the controller by cluster_dir."""
325 """Start the controller by cluster_dir."""
326 self.controller_args.extend(['--cluster-dir', cluster_dir])
326 self.controller_args.extend(['--cluster-dir', cluster_dir])
327 self.cluster_dir = unicode(cluster_dir)
327 self.cluster_dir = unicode(cluster_dir)
328 log.msg("Starting LocalControllerLauncher: %r" % self.args)
328 log.msg("Starting LocalControllerLauncher: %r" % self.args)
329 return super(LocalControllerLauncher, self).start()
329 return super(LocalControllerLauncher, self).start()
330
330
331
331
332 class LocalEngineLauncher(LocalProcessLauncher):
332 class LocalEngineLauncher(LocalProcessLauncher):
333 """Launch a single engine as a regular externall process."""
333 """Launch a single engine as a regular externall process."""
334
334
335 engine_cmd = List(ipengine_cmd_argv, config=True)
335 engine_cmd = List(ipengine_cmd_argv, config=True)
336 # Command line arguments for ipengine.
336 # Command line arguments for ipengine.
337 engine_args = List(
337 engine_args = List(
338 ['--log-to-file','--log-level', '40'], config=True
338 ['--log-to-file','--log-level', '40'], config=True
339 )
339 )
340
340
341 def find_args(self):
341 def find_args(self):
342 return self.engine_cmd + self.engine_args
342 return self.engine_cmd + self.engine_args
343
343
344 def start(self, cluster_dir):
344 def start(self, cluster_dir):
345 """Start the engine by cluster_dir."""
345 """Start the engine by cluster_dir."""
346 self.engine_args.extend(['--cluster-dir', cluster_dir])
346 self.engine_args.extend(['--cluster-dir', cluster_dir])
347 self.cluster_dir = unicode(cluster_dir)
347 self.cluster_dir = unicode(cluster_dir)
348 return super(LocalEngineLauncher, self).start()
348 return super(LocalEngineLauncher, self).start()
349
349
350
350
351 class LocalEngineSetLauncher(BaseLauncher):
351 class LocalEngineSetLauncher(BaseLauncher):
352 """Launch a set of engines as regular external processes."""
352 """Launch a set of engines as regular external processes."""
353
353
354 # Command line arguments for ipengine.
354 # Command line arguments for ipengine.
355 engine_args = List(
355 engine_args = List(
356 ['--log-to-file','--log-level', '40'], config=True
356 ['--log-to-file','--log-level', '40'], config=True
357 )
357 )
358
358
359 def __init__(self, work_dir, parent=None, name=None, config=None):
359 def __init__(self, work_dir, config=None):
360 super(LocalEngineSetLauncher, self).__init__(
360 super(LocalEngineSetLauncher, self).__init__(
361 work_dir, parent, name, config
361 work_dir, config
362 )
362 )
363 self.launchers = []
363 self.launchers = []
364
364
365 def start(self, n, cluster_dir):
365 def start(self, n, cluster_dir):
366 """Start n engines by profile or cluster_dir."""
366 """Start n engines by profile or cluster_dir."""
367 self.cluster_dir = unicode(cluster_dir)
367 self.cluster_dir = unicode(cluster_dir)
368 dlist = []
368 dlist = []
369 for i in range(n):
369 for i in range(n):
370 el = LocalEngineLauncher(self.work_dir, self)
370 el = LocalEngineLauncher(self.work_dir, self.config)
371 # Copy the engine args over to each engine launcher.
371 # Copy the engine args over to each engine launcher.
372 import copy
372 import copy
373 el.engine_args = copy.deepcopy(self.engine_args)
373 el.engine_args = copy.deepcopy(self.engine_args)
374 d = el.start(cluster_dir)
374 d = el.start(cluster_dir)
375 if i==0:
375 if i==0:
376 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
376 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
377 self.launchers.append(el)
377 self.launchers.append(el)
378 dlist.append(d)
378 dlist.append(d)
379 # The consumeErrors here could be dangerous
379 # The consumeErrors here could be dangerous
380 dfinal = gatherBoth(dlist, consumeErrors=True)
380 dfinal = gatherBoth(dlist, consumeErrors=True)
381 dfinal.addCallback(self.notify_start)
381 dfinal.addCallback(self.notify_start)
382 return dfinal
382 return dfinal
383
383
384 def find_args(self):
384 def find_args(self):
385 return ['engine set']
385 return ['engine set']
386
386
387 def signal(self, sig):
387 def signal(self, sig):
388 dlist = []
388 dlist = []
389 for el in self.launchers:
389 for el in self.launchers:
390 d = el.signal(sig)
390 d = el.signal(sig)
391 dlist.append(d)
391 dlist.append(d)
392 dfinal = gatherBoth(dlist, consumeErrors=True)
392 dfinal = gatherBoth(dlist, consumeErrors=True)
393 return dfinal
393 return dfinal
394
394
395 def interrupt_then_kill(self, delay=1.0):
395 def interrupt_then_kill(self, delay=1.0):
396 dlist = []
396 dlist = []
397 for el in self.launchers:
397 for el in self.launchers:
398 d = el.interrupt_then_kill(delay)
398 d = el.interrupt_then_kill(delay)
399 dlist.append(d)
399 dlist.append(d)
400 dfinal = gatherBoth(dlist, consumeErrors=True)
400 dfinal = gatherBoth(dlist, consumeErrors=True)
401 return dfinal
401 return dfinal
402
402
403 def stop(self):
403 def stop(self):
404 return self.interrupt_then_kill()
404 return self.interrupt_then_kill()
405
405
406 def observe_stop(self):
406 def observe_stop(self):
407 dlist = [el.observe_stop() for el in self.launchers]
407 dlist = [el.observe_stop() for el in self.launchers]
408 dfinal = gatherBoth(dlist, consumeErrors=False)
408 dfinal = gatherBoth(dlist, consumeErrors=False)
409 dfinal.addCallback(self.notify_stop)
409 dfinal.addCallback(self.notify_stop)
410 return dfinal
410 return dfinal
411
411
412
412
413 #-----------------------------------------------------------------------------
413 #-----------------------------------------------------------------------------
414 # MPIExec launchers
414 # MPIExec launchers
415 #-----------------------------------------------------------------------------
415 #-----------------------------------------------------------------------------
416
416
417
417
418 class MPIExecLauncher(LocalProcessLauncher):
418 class MPIExecLauncher(LocalProcessLauncher):
419 """Launch an external process using mpiexec."""
419 """Launch an external process using mpiexec."""
420
420
421 # The mpiexec command to use in starting the process.
421 # The mpiexec command to use in starting the process.
422 mpi_cmd = List(['mpiexec'], config=True)
422 mpi_cmd = List(['mpiexec'], config=True)
423 # The command line arguments to pass to mpiexec.
423 # The command line arguments to pass to mpiexec.
424 mpi_args = List([], config=True)
424 mpi_args = List([], config=True)
425 # The program to start using mpiexec.
425 # The program to start using mpiexec.
426 program = List(['date'], config=True)
426 program = List(['date'], config=True)
427 # The command line argument to the program.
427 # The command line argument to the program.
428 program_args = List([], config=True)
428 program_args = List([], config=True)
429 # The number of instances of the program to start.
429 # The number of instances of the program to start.
430 n = Int(1, config=True)
430 n = Int(1, config=True)
431
431
432 def find_args(self):
432 def find_args(self):
433 """Build self.args using all the fields."""
433 """Build self.args using all the fields."""
434 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
434 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
435 self.program + self.program_args
435 self.program + self.program_args
436
436
437 def start(self, n):
437 def start(self, n):
438 """Start n instances of the program using mpiexec."""
438 """Start n instances of the program using mpiexec."""
439 self.n = n
439 self.n = n
440 return super(MPIExecLauncher, self).start()
440 return super(MPIExecLauncher, self).start()
441
441
442
442
443 class MPIExecControllerLauncher(MPIExecLauncher):
443 class MPIExecControllerLauncher(MPIExecLauncher):
444 """Launch a controller using mpiexec."""
444 """Launch a controller using mpiexec."""
445
445
446 controller_cmd = List(ipcontroller_cmd_argv, config=True)
446 controller_cmd = List(ipcontroller_cmd_argv, config=True)
447 # Command line arguments to ipcontroller.
447 # Command line arguments to ipcontroller.
448 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
448 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
449 n = Int(1, config=False)
449 n = Int(1, config=False)
450
450
451 def start(self, cluster_dir):
451 def start(self, cluster_dir):
452 """Start the controller by cluster_dir."""
452 """Start the controller by cluster_dir."""
453 self.controller_args.extend(['--cluster-dir', cluster_dir])
453 self.controller_args.extend(['--cluster-dir', cluster_dir])
454 self.cluster_dir = unicode(cluster_dir)
454 self.cluster_dir = unicode(cluster_dir)
455 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
455 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
456 return super(MPIExecControllerLauncher, self).start(1)
456 return super(MPIExecControllerLauncher, self).start(1)
457
457
458 def find_args(self):
458 def find_args(self):
459 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
459 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
460 self.controller_cmd + self.controller_args
460 self.controller_cmd + self.controller_args
461
461
462
462
463 class MPIExecEngineSetLauncher(MPIExecLauncher):
463 class MPIExecEngineSetLauncher(MPIExecLauncher):
464
464
465 engine_cmd = List(ipengine_cmd_argv, config=True)
465 engine_cmd = List(ipengine_cmd_argv, config=True)
466 # Command line arguments for ipengine.
466 # Command line arguments for ipengine.
467 engine_args = List(
467 engine_args = List(
468 ['--log-to-file','--log-level', '40'], config=True
468 ['--log-to-file','--log-level', '40'], config=True
469 )
469 )
470 n = Int(1, config=True)
470 n = Int(1, config=True)
471
471
472 def start(self, n, cluster_dir):
472 def start(self, n, cluster_dir):
473 """Start n engines by profile or cluster_dir."""
473 """Start n engines by profile or cluster_dir."""
474 self.engine_args.extend(['--cluster-dir', cluster_dir])
474 self.engine_args.extend(['--cluster-dir', cluster_dir])
475 self.cluster_dir = unicode(cluster_dir)
475 self.cluster_dir = unicode(cluster_dir)
476 self.n = n
476 self.n = n
477 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
477 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
478 return super(MPIExecEngineSetLauncher, self).start(n)
478 return super(MPIExecEngineSetLauncher, self).start(n)
479
479
480 def find_args(self):
480 def find_args(self):
481 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
481 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
482 self.engine_cmd + self.engine_args
482 self.engine_cmd + self.engine_args
483
483
484
484
485 #-----------------------------------------------------------------------------
485 #-----------------------------------------------------------------------------
486 # SSH launchers
486 # SSH launchers
487 #-----------------------------------------------------------------------------
487 #-----------------------------------------------------------------------------
488
488
489 # TODO: Get SSH Launcher working again.
489 # TODO: Get SSH Launcher working again.
490
490
491 class SSHLauncher(BaseLauncher):
491 class SSHLauncher(BaseLauncher):
492 """A minimal launcher for ssh.
492 """A minimal launcher for ssh.
493
493
494 To be useful this will probably have to be extended to use the ``sshx``
494 To be useful this will probably have to be extended to use the ``sshx``
495 idea for environment variables. There could be other things this needs
495 idea for environment variables. There could be other things this needs
496 as well.
496 as well.
497 """
497 """
498
498
499 ssh_cmd = List(['ssh'], config=True)
499 ssh_cmd = List(['ssh'], config=True)
500 ssh_args = List([], config=True)
500 ssh_args = List([], config=True)
501 program = List(['date'], config=True)
501 program = List(['date'], config=True)
502 program_args = List([], config=True)
502 program_args = List([], config=True)
503 hostname = Str('', config=True)
503 hostname = Str('', config=True)
504 user = Str('', config=True)
504 user = Str('', config=True)
505 location = Str('')
505 location = Str('')
506
506
507 def _hostname_changed(self, name, old, new):
507 def _hostname_changed(self, name, old, new):
508 self.location = '%s@%s' % (self.user, new)
508 self.location = '%s@%s' % (self.user, new)
509
509
510 def _user_changed(self, name, old, new):
510 def _user_changed(self, name, old, new):
511 self.location = '%s@%s' % (new, self.hostname)
511 self.location = '%s@%s' % (new, self.hostname)
512
512
513 def find_args(self):
513 def find_args(self):
514 return self.ssh_cmd + self.ssh_args + [self.location] + \
514 return self.ssh_cmd + self.ssh_args + [self.location] + \
515 self.program + self.program_args
515 self.program + self.program_args
516
516
517 def start(self, n, hostname=None, user=None):
517 def start(self, n, hostname=None, user=None):
518 if hostname is not None:
518 if hostname is not None:
519 self.hostname = hostname
519 self.hostname = hostname
520 if user is not None:
520 if user is not None:
521 self.user = user
521 self.user = user
522 return super(SSHLauncher, self).start()
522 return super(SSHLauncher, self).start()
523
523
524
524
525 class SSHControllerLauncher(SSHLauncher):
525 class SSHControllerLauncher(SSHLauncher):
526 pass
526 pass
527
527
528
528
529 class SSHEngineSetLauncher(BaseLauncher):
529 class SSHEngineSetLauncher(BaseLauncher):
530 pass
530 pass
531
531
532
532
533 #-----------------------------------------------------------------------------
533 #-----------------------------------------------------------------------------
534 # Windows HPC Server 2008 scheduler launchers
534 # Windows HPC Server 2008 scheduler launchers
535 #-----------------------------------------------------------------------------
535 #-----------------------------------------------------------------------------
536
536
537
537
538 # This is only used on Windows.
538 # This is only used on Windows.
539 def find_job_cmd():
539 def find_job_cmd():
540 if os.name=='nt':
540 if os.name=='nt':
541 try:
541 try:
542 return find_cmd('job')
542 return find_cmd('job')
543 except FindCmdError:
543 except FindCmdError:
544 return 'job'
544 return 'job'
545 else:
545 else:
546 return 'job'
546 return 'job'
547
547
548
548
549 class WindowsHPCLauncher(BaseLauncher):
549 class WindowsHPCLauncher(BaseLauncher):
550
550
551 # A regular expression used to get the job id from the output of the
551 # A regular expression used to get the job id from the output of the
552 # submit_command.
552 # submit_command.
553 job_id_regexp = Str(r'\d+', config=True)
553 job_id_regexp = Str(r'\d+', config=True)
554 # The filename of the instantiated job script.
554 # The filename of the instantiated job script.
555 job_file_name = Unicode(u'ipython_job.xml', config=True)
555 job_file_name = Unicode(u'ipython_job.xml', config=True)
556 # The full path to the instantiated job script. This gets made dynamically
556 # The full path to the instantiated job script. This gets made dynamically
557 # by combining the work_dir with the job_file_name.
557 # by combining the work_dir with the job_file_name.
558 job_file = Unicode(u'')
558 job_file = Unicode(u'')
559 # The hostname of the scheduler to submit the job to
559 # The hostname of the scheduler to submit the job to
560 scheduler = Str('', config=True)
560 scheduler = Str('', config=True)
561 job_cmd = Str(find_job_cmd(), config=True)
561 job_cmd = Str(find_job_cmd(), config=True)
562
562
563 def __init__(self, work_dir, parent=None, name=None, config=None):
563 def __init__(self, work_dir, config=None):
564 super(WindowsHPCLauncher, self).__init__(
564 super(WindowsHPCLauncher, self).__init__(
565 work_dir, parent, name, config
565 work_dir, config
566 )
566 )
567
567
568 @property
568 @property
569 def job_file(self):
569 def job_file(self):
570 return os.path.join(self.work_dir, self.job_file_name)
570 return os.path.join(self.work_dir, self.job_file_name)
571
571
572 def write_job_file(self, n):
572 def write_job_file(self, n):
573 raise NotImplementedError("Implement write_job_file in a subclass.")
573 raise NotImplementedError("Implement write_job_file in a subclass.")
574
574
575 def find_args(self):
575 def find_args(self):
576 return ['job.exe']
576 return ['job.exe']
577
577
578 def parse_job_id(self, output):
578 def parse_job_id(self, output):
579 """Take the output of the submit command and return the job id."""
579 """Take the output of the submit command and return the job id."""
580 m = re.search(self.job_id_regexp, output)
580 m = re.search(self.job_id_regexp, output)
581 if m is not None:
581 if m is not None:
582 job_id = m.group()
582 job_id = m.group()
583 else:
583 else:
584 raise LauncherError("Job id couldn't be determined: %s" % output)
584 raise LauncherError("Job id couldn't be determined: %s" % output)
585 self.job_id = job_id
585 self.job_id = job_id
586 log.msg('Job started with job id: %r' % job_id)
586 log.msg('Job started with job id: %r' % job_id)
587 return job_id
587 return job_id
588
588
589 @inlineCallbacks
589 @inlineCallbacks
590 def start(self, n):
590 def start(self, n):
591 """Start n copies of the process using the Win HPC job scheduler."""
591 """Start n copies of the process using the Win HPC job scheduler."""
592 self.write_job_file(n)
592 self.write_job_file(n)
593 args = [
593 args = [
594 'submit',
594 'submit',
595 '/jobfile:%s' % self.job_file,
595 '/jobfile:%s' % self.job_file,
596 '/scheduler:%s' % self.scheduler
596 '/scheduler:%s' % self.scheduler
597 ]
597 ]
598 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
598 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
599 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
599 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
600 output = yield getProcessOutput(str(self.job_cmd),
600 output = yield getProcessOutput(str(self.job_cmd),
601 [str(a) for a in args],
601 [str(a) for a in args],
602 env=dict((str(k),str(v)) for k,v in os.environ.items()),
602 env=dict((str(k),str(v)) for k,v in os.environ.items()),
603 path=self.work_dir
603 path=self.work_dir
604 )
604 )
605 job_id = self.parse_job_id(output)
605 job_id = self.parse_job_id(output)
606 self.notify_start(job_id)
606 self.notify_start(job_id)
607 defer.returnValue(job_id)
607 defer.returnValue(job_id)
608
608
609 @inlineCallbacks
609 @inlineCallbacks
610 def stop(self):
610 def stop(self):
611 args = [
611 args = [
612 'cancel',
612 'cancel',
613 self.job_id,
613 self.job_id,
614 '/scheduler:%s' % self.scheduler
614 '/scheduler:%s' % self.scheduler
615 ]
615 ]
616 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
616 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
617 try:
617 try:
618 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
618 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
619 output = yield getProcessOutput(str(self.job_cmd),
619 output = yield getProcessOutput(str(self.job_cmd),
620 [str(a) for a in args],
620 [str(a) for a in args],
621 env=dict((str(k),str(v)) for k,v in os.environ.items()),
621 env=dict((str(k),str(v)) for k,v in os.environ.items()),
622 path=self.work_dir
622 path=self.work_dir
623 )
623 )
624 except:
624 except:
625 output = 'The job already appears to be stoppped: %r' % self.job_id
625 output = 'The job already appears to be stoppped: %r' % self.job_id
626 self.notify_stop(output) # Pass the output of the kill cmd
626 self.notify_stop(output) # Pass the output of the kill cmd
627 defer.returnValue(output)
627 defer.returnValue(output)
628
628
629
629
630 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
630 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
631
631
632 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
632 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
633 extra_args = List([], config=False)
633 extra_args = List([], config=False)
634
634
635 def write_job_file(self, n):
635 def write_job_file(self, n):
636 job = IPControllerJob(self)
636 job = IPControllerJob(self)
637
637
638 t = IPControllerTask(self)
638 t = IPControllerTask(self)
639 # The tasks work directory is *not* the actual work directory of
639 # The tasks work directory is *not* the actual work directory of
640 # the controller. It is used as the base path for the stdout/stderr
640 # the controller. It is used as the base path for the stdout/stderr
641 # files that the scheduler redirects to.
641 # files that the scheduler redirects to.
642 t.work_directory = self.cluster_dir
642 t.work_directory = self.cluster_dir
643 # Add the --cluster-dir and from self.start().
643 # Add the --cluster-dir and from self.start().
644 t.controller_args.extend(self.extra_args)
644 t.controller_args.extend(self.extra_args)
645 job.add_task(t)
645 job.add_task(t)
646
646
647 log.msg("Writing job description file: %s" % self.job_file)
647 log.msg("Writing job description file: %s" % self.job_file)
648 job.write(self.job_file)
648 job.write(self.job_file)
649
649
650 @property
650 @property
651 def job_file(self):
651 def job_file(self):
652 return os.path.join(self.cluster_dir, self.job_file_name)
652 return os.path.join(self.cluster_dir, self.job_file_name)
653
653
654 def start(self, cluster_dir):
654 def start(self, cluster_dir):
655 """Start the controller by cluster_dir."""
655 """Start the controller by cluster_dir."""
656 self.extra_args = ['--cluster-dir', cluster_dir]
656 self.extra_args = ['--cluster-dir', cluster_dir]
657 self.cluster_dir = unicode(cluster_dir)
657 self.cluster_dir = unicode(cluster_dir)
658 return super(WindowsHPCControllerLauncher, self).start(1)
658 return super(WindowsHPCControllerLauncher, self).start(1)
659
659
660
660
661 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
661 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
662
662
663 job_file_name = Unicode(u'ipengineset_job.xml', config=True)
663 job_file_name = Unicode(u'ipengineset_job.xml', config=True)
664 extra_args = List([], config=False)
664 extra_args = List([], config=False)
665
665
666 def write_job_file(self, n):
666 def write_job_file(self, n):
667 job = IPEngineSetJob(self)
667 job = IPEngineSetJob(self)
668
668
669 for i in range(n):
669 for i in range(n):
670 t = IPEngineTask(self)
670 t = IPEngineTask(self)
671 # The tasks work directory is *not* the actual work directory of
671 # The tasks work directory is *not* the actual work directory of
672 # the engine. It is used as the base path for the stdout/stderr
672 # the engine. It is used as the base path for the stdout/stderr
673 # files that the scheduler redirects to.
673 # files that the scheduler redirects to.
674 t.work_directory = self.cluster_dir
674 t.work_directory = self.cluster_dir
675 # Add the --cluster-dir and from self.start().
675 # Add the --cluster-dir and from self.start().
676 t.engine_args.extend(self.extra_args)
676 t.engine_args.extend(self.extra_args)
677 job.add_task(t)
677 job.add_task(t)
678
678
679 log.msg("Writing job description file: %s" % self.job_file)
679 log.msg("Writing job description file: %s" % self.job_file)
680 job.write(self.job_file)
680 job.write(self.job_file)
681
681
682 @property
682 @property
683 def job_file(self):
683 def job_file(self):
684 return os.path.join(self.cluster_dir, self.job_file_name)
684 return os.path.join(self.cluster_dir, self.job_file_name)
685
685
686 def start(self, n, cluster_dir):
686 def start(self, n, cluster_dir):
687 """Start the controller by cluster_dir."""
687 """Start the controller by cluster_dir."""
688 self.extra_args = ['--cluster-dir', cluster_dir]
688 self.extra_args = ['--cluster-dir', cluster_dir]
689 self.cluster_dir = unicode(cluster_dir)
689 self.cluster_dir = unicode(cluster_dir)
690 return super(WindowsHPCEngineSetLauncher, self).start(n)
690 return super(WindowsHPCEngineSetLauncher, self).start(n)
691
691
692
692
693 #-----------------------------------------------------------------------------
693 #-----------------------------------------------------------------------------
694 # Batch (PBS) system launchers
694 # Batch (PBS) system launchers
695 #-----------------------------------------------------------------------------
695 #-----------------------------------------------------------------------------
696
696
697 # TODO: Get PBS launcher working again.
697 # TODO: Get PBS launcher working again.
698
698
699 class BatchSystemLauncher(BaseLauncher):
699 class BatchSystemLauncher(BaseLauncher):
700 """Launch an external process using a batch system.
700 """Launch an external process using a batch system.
701
701
702 This class is designed to work with UNIX batch systems like PBS, LSF,
702 This class is designed to work with UNIX batch systems like PBS, LSF,
703 GridEngine, etc. The overall model is that there are different commands
703 GridEngine, etc. The overall model is that there are different commands
704 like qsub, qdel, etc. that handle the starting and stopping of the process.
704 like qsub, qdel, etc. that handle the starting and stopping of the process.
705
705
706 This class also has the notion of a batch script. The ``batch_template``
706 This class also has the notion of a batch script. The ``batch_template``
707 attribute can be set to a string that is a template for the batch script.
707 attribute can be set to a string that is a template for the batch script.
708 This template is instantiated using Itpl. Thus the template can use
708 This template is instantiated using Itpl. Thus the template can use
709 ${n} fot the number of instances. Subclasses can add additional variables
709 ${n} fot the number of instances. Subclasses can add additional variables
710 to the template dict.
710 to the template dict.
711 """
711 """
712
712
713 # Subclasses must fill these in. See PBSEngineSet
713 # Subclasses must fill these in. See PBSEngineSet
714 # The name of the command line program used to submit jobs.
714 # The name of the command line program used to submit jobs.
715 submit_command = Str('', config=True)
715 submit_command = Str('', config=True)
716 # The name of the command line program used to delete jobs.
716 # The name of the command line program used to delete jobs.
717 delete_command = Str('', config=True)
717 delete_command = Str('', config=True)
718 # A regular expression used to get the job id from the output of the
718 # A regular expression used to get the job id from the output of the
719 # submit_command.
719 # submit_command.
720 job_id_regexp = Str('', config=True)
720 job_id_regexp = Str('', config=True)
721 # The string that is the batch script template itself.
721 # The string that is the batch script template itself.
722 batch_template = Str('', config=True)
722 batch_template = Str('', config=True)
723 # The filename of the instantiated batch script.
723 # The filename of the instantiated batch script.
724 batch_file_name = Unicode(u'batch_script', config=True)
724 batch_file_name = Unicode(u'batch_script', config=True)
725 # The full path to the instantiated batch script.
725 # The full path to the instantiated batch script.
726 batch_file = Unicode(u'')
726 batch_file = Unicode(u'')
727
727
728 def __init__(self, work_dir, parent=None, name=None, config=None):
728 def __init__(self, work_dir, config=None):
729 super(BatchSystemLauncher, self).__init__(
729 super(BatchSystemLauncher, self).__init__(
730 work_dir, parent, name, config
730 work_dir, config
731 )
731 )
732 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
732 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
733 self.context = {}
733 self.context = {}
734
734
735 def parse_job_id(self, output):
735 def parse_job_id(self, output):
736 """Take the output of the submit command and return the job id."""
736 """Take the output of the submit command and return the job id."""
737 m = re.match(self.job_id_regexp, output)
737 m = re.match(self.job_id_regexp, output)
738 if m is not None:
738 if m is not None:
739 job_id = m.group()
739 job_id = m.group()
740 else:
740 else:
741 raise LauncherError("Job id couldn't be determined: %s" % output)
741 raise LauncherError("Job id couldn't be determined: %s" % output)
742 self.job_id = job_id
742 self.job_id = job_id
743 log.msg('Job started with job id: %r' % job_id)
743 log.msg('Job started with job id: %r' % job_id)
744 return job_id
744 return job_id
745
745
746 def write_batch_script(self, n):
746 def write_batch_script(self, n):
747 """Instantiate and write the batch script to the work_dir."""
747 """Instantiate and write the batch script to the work_dir."""
748 self.context['n'] = n
748 self.context['n'] = n
749 script_as_string = Itpl.itplns(self.batch_template, self.context)
749 script_as_string = Itpl.itplns(self.batch_template, self.context)
750 log.msg('Writing instantiated batch script: %s' % self.batch_file)
750 log.msg('Writing instantiated batch script: %s' % self.batch_file)
751 f = open(self.batch_file, 'w')
751 f = open(self.batch_file, 'w')
752 f.write(script_as_string)
752 f.write(script_as_string)
753 f.close()
753 f.close()
754
754
755 @inlineCallbacks
755 @inlineCallbacks
756 def start(self, n):
756 def start(self, n):
757 """Start n copies of the process using a batch system."""
757 """Start n copies of the process using a batch system."""
758 self.write_batch_script(n)
758 self.write_batch_script(n)
759 output = yield getProcessOutput(self.submit_command,
759 output = yield getProcessOutput(self.submit_command,
760 [self.batch_file], env=os.environ)
760 [self.batch_file], env=os.environ)
761 job_id = self.parse_job_id(output)
761 job_id = self.parse_job_id(output)
762 self.notify_start(job_id)
762 self.notify_start(job_id)
763 defer.returnValue(job_id)
763 defer.returnValue(job_id)
764
764
765 @inlineCallbacks
765 @inlineCallbacks
766 def stop(self):
766 def stop(self):
767 output = yield getProcessOutput(self.delete_command,
767 output = yield getProcessOutput(self.delete_command,
768 [self.job_id], env=os.environ
768 [self.job_id], env=os.environ
769 )
769 )
770 self.notify_stop(output) # Pass the output of the kill cmd
770 self.notify_stop(output) # Pass the output of the kill cmd
771 defer.returnValue(output)
771 defer.returnValue(output)
772
772
773
773
774 class PBSLauncher(BatchSystemLauncher):
774 class PBSLauncher(BatchSystemLauncher):
775 """A BatchSystemLauncher subclass for PBS."""
775 """A BatchSystemLauncher subclass for PBS."""
776
776
777 submit_command = Str('qsub', config=True)
777 submit_command = Str('qsub', config=True)
778 delete_command = Str('qdel', config=True)
778 delete_command = Str('qdel', config=True)
779 job_id_regexp = Str(r'\d+', config=True)
779 job_id_regexp = Str(r'\d+', config=True)
780 batch_template = Str('', config=True)
780 batch_template = Str('', config=True)
781 batch_file_name = Unicode(u'pbs_batch_script', config=True)
781 batch_file_name = Unicode(u'pbs_batch_script', config=True)
782 batch_file = Unicode(u'')
782 batch_file = Unicode(u'')
783
783
784
784
785 class PBSControllerLauncher(PBSLauncher):
785 class PBSControllerLauncher(PBSLauncher):
786 """Launch a controller using PBS."""
786 """Launch a controller using PBS."""
787
787
788 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
788 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
789
789
790 def start(self, cluster_dir):
790 def start(self, cluster_dir):
791 """Start the controller by profile or cluster_dir."""
791 """Start the controller by profile or cluster_dir."""
792 # Here we save profile and cluster_dir in the context so they
792 # Here we save profile and cluster_dir in the context so they
793 # can be used in the batch script template as ${profile} and
793 # can be used in the batch script template as ${profile} and
794 # ${cluster_dir}
794 # ${cluster_dir}
795 self.context['cluster_dir'] = cluster_dir
795 self.context['cluster_dir'] = cluster_dir
796 self.cluster_dir = unicode(cluster_dir)
796 self.cluster_dir = unicode(cluster_dir)
797 log.msg("Starting PBSControllerLauncher: %r" % self.args)
797 log.msg("Starting PBSControllerLauncher: %r" % self.args)
798 return super(PBSControllerLauncher, self).start(1)
798 return super(PBSControllerLauncher, self).start(1)
799
799
800
800
801 class PBSEngineSetLauncher(PBSLauncher):
801 class PBSEngineSetLauncher(PBSLauncher):
802
802
803 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
803 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
804
804
805 def start(self, n, cluster_dir):
805 def start(self, n, cluster_dir):
806 """Start n engines by profile or cluster_dir."""
806 """Start n engines by profile or cluster_dir."""
807 self.program_args.extend(['--cluster-dir', cluster_dir])
807 self.program_args.extend(['--cluster-dir', cluster_dir])
808 self.cluster_dir = unicode(cluster_dir)
808 self.cluster_dir = unicode(cluster_dir)
809 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
809 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
810 return super(PBSEngineSetLauncher, self).start(n)
810 return super(PBSEngineSetLauncher, self).start(n)
811
811
812
812
813 #-----------------------------------------------------------------------------
813 #-----------------------------------------------------------------------------
814 # A launcher for ipcluster itself!
814 # A launcher for ipcluster itself!
815 #-----------------------------------------------------------------------------
815 #-----------------------------------------------------------------------------
816
816
817
817
818 class IPClusterLauncher(LocalProcessLauncher):
818 class IPClusterLauncher(LocalProcessLauncher):
819 """Launch the ipcluster program in an external process."""
819 """Launch the ipcluster program in an external process."""
820
820
821 ipcluster_cmd = List(ipcluster_cmd_argv, config=True)
821 ipcluster_cmd = List(ipcluster_cmd_argv, config=True)
822 # Command line arguments to pass to ipcluster.
822 # Command line arguments to pass to ipcluster.
823 ipcluster_args = List(
823 ipcluster_args = List(
824 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
824 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
825 ipcluster_subcommand = Str('start')
825 ipcluster_subcommand = Str('start')
826 ipcluster_n = Int(2)
826 ipcluster_n = Int(2)
827
827
828 def find_args(self):
828 def find_args(self):
829 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
829 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
830 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
830 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
831
831
832 def start(self):
832 def start(self):
833 log.msg("Starting ipcluster: %r" % self.args)
833 log.msg("Starting ipcluster: %r" % self.args)
834 return super(IPClusterLauncher, self).start()
834 return super(IPClusterLauncher, self).start()
835
835
@@ -1,316 +1,316 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Job and task components for writing .xml files that the Windows HPC Server
4 Job and task components for writing .xml files that the Windows HPC Server
5 2008 can use to start jobs.
5 2008 can use to start jobs.
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2009 The IPython Development Team
10 #
10 #
11 # 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 in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from __future__ import with_statement
19 from __future__ import with_statement
20
20
21 import os
21 import os
22 import re
22 import re
23 import uuid
23 import uuid
24
24
25 from xml.etree import ElementTree as ET
25 from xml.etree import ElementTree as ET
26
26
27 from IPython.core.component import Component
27 from IPython.config.configurable import Configurable
28 from IPython.utils.traitlets import (
28 from IPython.utils.traitlets import (
29 Str, Int, List, Instance,
29 Str, Int, List, Instance,
30 Enum, Bool, CStr
30 Enum, Bool, CStr
31 )
31 )
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Job and Task Component
34 # Job and Task classes
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37
37
38 def as_str(value):
38 def as_str(value):
39 if isinstance(value, str):
39 if isinstance(value, str):
40 return value
40 return value
41 elif isinstance(value, bool):
41 elif isinstance(value, bool):
42 if value:
42 if value:
43 return 'true'
43 return 'true'
44 else:
44 else:
45 return 'false'
45 return 'false'
46 elif isinstance(value, (int, float)):
46 elif isinstance(value, (int, float)):
47 return repr(value)
47 return repr(value)
48 else:
48 else:
49 return value
49 return value
50
50
51
51
52 def indent(elem, level=0):
52 def indent(elem, level=0):
53 i = "\n" + level*" "
53 i = "\n" + level*" "
54 if len(elem):
54 if len(elem):
55 if not elem.text or not elem.text.strip():
55 if not elem.text or not elem.text.strip():
56 elem.text = i + " "
56 elem.text = i + " "
57 if not elem.tail or not elem.tail.strip():
57 if not elem.tail or not elem.tail.strip():
58 elem.tail = i
58 elem.tail = i
59 for elem in elem:
59 for elem in elem:
60 indent(elem, level+1)
60 indent(elem, level+1)
61 if not elem.tail or not elem.tail.strip():
61 if not elem.tail or not elem.tail.strip():
62 elem.tail = i
62 elem.tail = i
63 else:
63 else:
64 if level and (not elem.tail or not elem.tail.strip()):
64 if level and (not elem.tail or not elem.tail.strip()):
65 elem.tail = i
65 elem.tail = i
66
66
67
67
68 def find_username():
68 def find_username():
69 domain = os.environ.get('USERDOMAIN')
69 domain = os.environ.get('USERDOMAIN')
70 username = os.environ.get('USERNAME','')
70 username = os.environ.get('USERNAME','')
71 if domain is None:
71 if domain is None:
72 return username
72 return username
73 else:
73 else:
74 return '%s\\%s' % (domain, username)
74 return '%s\\%s' % (domain, username)
75
75
76
76
77 class WinHPCJob(Component):
77 class WinHPCJob(Configurable):
78
78
79 job_id = Str('')
79 job_id = Str('')
80 job_name = Str('MyJob', config=True)
80 job_name = Str('MyJob', config=True)
81 min_cores = Int(1, config=True)
81 min_cores = Int(1, config=True)
82 max_cores = Int(1, config=True)
82 max_cores = Int(1, config=True)
83 min_sockets = Int(1, config=True)
83 min_sockets = Int(1, config=True)
84 max_sockets = Int(1, config=True)
84 max_sockets = Int(1, config=True)
85 min_nodes = Int(1, config=True)
85 min_nodes = Int(1, config=True)
86 max_nodes = Int(1, config=True)
86 max_nodes = Int(1, config=True)
87 unit_type = Str("Core", config=True)
87 unit_type = Str("Core", config=True)
88 auto_calculate_min = Bool(True, config=True)
88 auto_calculate_min = Bool(True, config=True)
89 auto_calculate_max = Bool(True, config=True)
89 auto_calculate_max = Bool(True, config=True)
90 run_until_canceled = Bool(False, config=True)
90 run_until_canceled = Bool(False, config=True)
91 is_exclusive = Bool(False, config=True)
91 is_exclusive = Bool(False, config=True)
92 username = Str(find_username(), config=True)
92 username = Str(find_username(), config=True)
93 job_type = Str('Batch', config=True)
93 job_type = Str('Batch', config=True)
94 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
94 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
95 default_value='Highest', config=True)
95 default_value='Highest', config=True)
96 requested_nodes = Str('', config=True)
96 requested_nodes = Str('', config=True)
97 project = Str('IPython', config=True)
97 project = Str('IPython', config=True)
98 xmlns = Str('http://schemas.microsoft.com/HPCS2008/scheduler/')
98 xmlns = Str('http://schemas.microsoft.com/HPCS2008/scheduler/')
99 version = Str("2.000")
99 version = Str("2.000")
100 tasks = List([])
100 tasks = List([])
101
101
102 @property
102 @property
103 def owner(self):
103 def owner(self):
104 return self.username
104 return self.username
105
105
106 def _write_attr(self, root, attr, key):
106 def _write_attr(self, root, attr, key):
107 s = as_str(getattr(self, attr, ''))
107 s = as_str(getattr(self, attr, ''))
108 if s:
108 if s:
109 root.set(key, s)
109 root.set(key, s)
110
110
111 def as_element(self):
111 def as_element(self):
112 # We have to add _A_ type things to get the right order than
112 # We have to add _A_ type things to get the right order than
113 # the MSFT XML parser expects.
113 # the MSFT XML parser expects.
114 root = ET.Element('Job')
114 root = ET.Element('Job')
115 self._write_attr(root, 'version', '_A_Version')
115 self._write_attr(root, 'version', '_A_Version')
116 self._write_attr(root, 'job_name', '_B_Name')
116 self._write_attr(root, 'job_name', '_B_Name')
117 self._write_attr(root, 'unit_type', '_C_UnitType')
117 self._write_attr(root, 'unit_type', '_C_UnitType')
118 self._write_attr(root, 'min_cores', '_D_MinCores')
118 self._write_attr(root, 'min_cores', '_D_MinCores')
119 self._write_attr(root, 'max_cores', '_E_MaxCores')
119 self._write_attr(root, 'max_cores', '_E_MaxCores')
120 self._write_attr(root, 'min_sockets', '_F_MinSockets')
120 self._write_attr(root, 'min_sockets', '_F_MinSockets')
121 self._write_attr(root, 'max_sockets', '_G_MaxSockets')
121 self._write_attr(root, 'max_sockets', '_G_MaxSockets')
122 self._write_attr(root, 'min_nodes', '_H_MinNodes')
122 self._write_attr(root, 'min_nodes', '_H_MinNodes')
123 self._write_attr(root, 'max_nodes', '_I_MaxNodes')
123 self._write_attr(root, 'max_nodes', '_I_MaxNodes')
124 self._write_attr(root, 'run_until_canceled', '_J_RunUntilCanceled')
124 self._write_attr(root, 'run_until_canceled', '_J_RunUntilCanceled')
125 self._write_attr(root, 'is_exclusive', '_K_IsExclusive')
125 self._write_attr(root, 'is_exclusive', '_K_IsExclusive')
126 self._write_attr(root, 'username', '_L_UserName')
126 self._write_attr(root, 'username', '_L_UserName')
127 self._write_attr(root, 'job_type', '_M_JobType')
127 self._write_attr(root, 'job_type', '_M_JobType')
128 self._write_attr(root, 'priority', '_N_Priority')
128 self._write_attr(root, 'priority', '_N_Priority')
129 self._write_attr(root, 'requested_nodes', '_O_RequestedNodes')
129 self._write_attr(root, 'requested_nodes', '_O_RequestedNodes')
130 self._write_attr(root, 'auto_calculate_max', '_P_AutoCalculateMax')
130 self._write_attr(root, 'auto_calculate_max', '_P_AutoCalculateMax')
131 self._write_attr(root, 'auto_calculate_min', '_Q_AutoCalculateMin')
131 self._write_attr(root, 'auto_calculate_min', '_Q_AutoCalculateMin')
132 self._write_attr(root, 'project', '_R_Project')
132 self._write_attr(root, 'project', '_R_Project')
133 self._write_attr(root, 'owner', '_S_Owner')
133 self._write_attr(root, 'owner', '_S_Owner')
134 self._write_attr(root, 'xmlns', '_T_xmlns')
134 self._write_attr(root, 'xmlns', '_T_xmlns')
135 dependencies = ET.SubElement(root, "Dependencies")
135 dependencies = ET.SubElement(root, "Dependencies")
136 etasks = ET.SubElement(root, "Tasks")
136 etasks = ET.SubElement(root, "Tasks")
137 for t in self.tasks:
137 for t in self.tasks:
138 etasks.append(t.as_element())
138 etasks.append(t.as_element())
139 return root
139 return root
140
140
141 def tostring(self):
141 def tostring(self):
142 """Return the string representation of the job description XML."""
142 """Return the string representation of the job description XML."""
143 root = self.as_element()
143 root = self.as_element()
144 indent(root)
144 indent(root)
145 txt = ET.tostring(root, encoding="utf-8")
145 txt = ET.tostring(root, encoding="utf-8")
146 # Now remove the tokens used to order the attributes.
146 # Now remove the tokens used to order the attributes.
147 txt = re.sub(r'_[A-Z]_','',txt)
147 txt = re.sub(r'_[A-Z]_','',txt)
148 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
148 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
149 return txt
149 return txt
150
150
151 def write(self, filename):
151 def write(self, filename):
152 """Write the XML job description to a file."""
152 """Write the XML job description to a file."""
153 txt = self.tostring()
153 txt = self.tostring()
154 with open(filename, 'w') as f:
154 with open(filename, 'w') as f:
155 f.write(txt)
155 f.write(txt)
156
156
157 def add_task(self, task):
157 def add_task(self, task):
158 """Add a task to the job.
158 """Add a task to the job.
159
159
160 Parameters
160 Parameters
161 ----------
161 ----------
162 task : :class:`WinHPCTask`
162 task : :class:`WinHPCTask`
163 The task object to add.
163 The task object to add.
164 """
164 """
165 self.tasks.append(task)
165 self.tasks.append(task)
166
166
167
167
168 class WinHPCTask(Component):
168 class WinHPCTask(Configurable):
169
169
170 task_id = Str('')
170 task_id = Str('')
171 task_name = Str('')
171 task_name = Str('')
172 version = Str("2.000")
172 version = Str("2.000")
173 min_cores = Int(1, config=True)
173 min_cores = Int(1, config=True)
174 max_cores = Int(1, config=True)
174 max_cores = Int(1, config=True)
175 min_sockets = Int(1, config=True)
175 min_sockets = Int(1, config=True)
176 max_sockets = Int(1, config=True)
176 max_sockets = Int(1, config=True)
177 min_nodes = Int(1, config=True)
177 min_nodes = Int(1, config=True)
178 max_nodes = Int(1, config=True)
178 max_nodes = Int(1, config=True)
179 unit_type = Str("Core", config=True)
179 unit_type = Str("Core", config=True)
180 command_line = CStr('', config=True)
180 command_line = CStr('', config=True)
181 work_directory = CStr('', config=True)
181 work_directory = CStr('', config=True)
182 is_rerunnaable = Bool(True, config=True)
182 is_rerunnaable = Bool(True, config=True)
183 std_out_file_path = CStr('', config=True)
183 std_out_file_path = CStr('', config=True)
184 std_err_file_path = CStr('', config=True)
184 std_err_file_path = CStr('', config=True)
185 is_parametric = Bool(False, config=True)
185 is_parametric = Bool(False, config=True)
186 environment_variables = Instance(dict, args=(), config=True)
186 environment_variables = Instance(dict, args=(), config=True)
187
187
188 def _write_attr(self, root, attr, key):
188 def _write_attr(self, root, attr, key):
189 s = as_str(getattr(self, attr, ''))
189 s = as_str(getattr(self, attr, ''))
190 if s:
190 if s:
191 root.set(key, s)
191 root.set(key, s)
192
192
193 def as_element(self):
193 def as_element(self):
194 root = ET.Element('Task')
194 root = ET.Element('Task')
195 self._write_attr(root, 'version', '_A_Version')
195 self._write_attr(root, 'version', '_A_Version')
196 self._write_attr(root, 'task_name', '_B_Name')
196 self._write_attr(root, 'task_name', '_B_Name')
197 self._write_attr(root, 'min_cores', '_C_MinCores')
197 self._write_attr(root, 'min_cores', '_C_MinCores')
198 self._write_attr(root, 'max_cores', '_D_MaxCores')
198 self._write_attr(root, 'max_cores', '_D_MaxCores')
199 self._write_attr(root, 'min_sockets', '_E_MinSockets')
199 self._write_attr(root, 'min_sockets', '_E_MinSockets')
200 self._write_attr(root, 'max_sockets', '_F_MaxSockets')
200 self._write_attr(root, 'max_sockets', '_F_MaxSockets')
201 self._write_attr(root, 'min_nodes', '_G_MinNodes')
201 self._write_attr(root, 'min_nodes', '_G_MinNodes')
202 self._write_attr(root, 'max_nodes', '_H_MaxNodes')
202 self._write_attr(root, 'max_nodes', '_H_MaxNodes')
203 self._write_attr(root, 'command_line', '_I_CommandLine')
203 self._write_attr(root, 'command_line', '_I_CommandLine')
204 self._write_attr(root, 'work_directory', '_J_WorkDirectory')
204 self._write_attr(root, 'work_directory', '_J_WorkDirectory')
205 self._write_attr(root, 'is_rerunnaable', '_K_IsRerunnable')
205 self._write_attr(root, 'is_rerunnaable', '_K_IsRerunnable')
206 self._write_attr(root, 'std_out_file_path', '_L_StdOutFilePath')
206 self._write_attr(root, 'std_out_file_path', '_L_StdOutFilePath')
207 self._write_attr(root, 'std_err_file_path', '_M_StdErrFilePath')
207 self._write_attr(root, 'std_err_file_path', '_M_StdErrFilePath')
208 self._write_attr(root, 'is_parametric', '_N_IsParametric')
208 self._write_attr(root, 'is_parametric', '_N_IsParametric')
209 self._write_attr(root, 'unit_type', '_O_UnitType')
209 self._write_attr(root, 'unit_type', '_O_UnitType')
210 root.append(self.get_env_vars())
210 root.append(self.get_env_vars())
211 return root
211 return root
212
212
213 def get_env_vars(self):
213 def get_env_vars(self):
214 env_vars = ET.Element('EnvironmentVariables')
214 env_vars = ET.Element('EnvironmentVariables')
215 for k, v in self.environment_variables.items():
215 for k, v in self.environment_variables.items():
216 variable = ET.SubElement(env_vars, "Variable")
216 variable = ET.SubElement(env_vars, "Variable")
217 name = ET.SubElement(variable, "Name")
217 name = ET.SubElement(variable, "Name")
218 name.text = k
218 name.text = k
219 value = ET.SubElement(variable, "Value")
219 value = ET.SubElement(variable, "Value")
220 value.text = v
220 value.text = v
221 return env_vars
221 return env_vars
222
222
223
223
224
224
225 # By declaring these, we can configure the controller and engine separately!
225 # By declaring these, we can configure the controller and engine separately!
226
226
227 class IPControllerJob(WinHPCJob):
227 class IPControllerJob(WinHPCJob):
228 job_name = Str('IPController', config=False)
228 job_name = Str('IPController', config=False)
229 is_exclusive = Bool(False, config=True)
229 is_exclusive = Bool(False, config=True)
230 username = Str(find_username(), config=True)
230 username = Str(find_username(), config=True)
231 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
231 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
232 default_value='Highest', config=True)
232 default_value='Highest', config=True)
233 requested_nodes = Str('', config=True)
233 requested_nodes = Str('', config=True)
234 project = Str('IPython', config=True)
234 project = Str('IPython', config=True)
235
235
236
236
237 class IPEngineSetJob(WinHPCJob):
237 class IPEngineSetJob(WinHPCJob):
238 job_name = Str('IPEngineSet', config=False)
238 job_name = Str('IPEngineSet', config=False)
239 is_exclusive = Bool(False, config=True)
239 is_exclusive = Bool(False, config=True)
240 username = Str(find_username(), config=True)
240 username = Str(find_username(), config=True)
241 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
241 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
242 default_value='Highest', config=True)
242 default_value='Highest', config=True)
243 requested_nodes = Str('', config=True)
243 requested_nodes = Str('', config=True)
244 project = Str('IPython', config=True)
244 project = Str('IPython', config=True)
245
245
246
246
247 class IPControllerTask(WinHPCTask):
247 class IPControllerTask(WinHPCTask):
248
248
249 task_name = Str('IPController', config=True)
249 task_name = Str('IPController', config=True)
250 controller_cmd = List(['ipcontroller.exe'], config=True)
250 controller_cmd = List(['ipcontroller.exe'], config=True)
251 controller_args = List(['--log-to-file', '--log-level', '40'], config=True)
251 controller_args = List(['--log-to-file', '--log-level', '40'], config=True)
252 # I don't want these to be configurable
252 # I don't want these to be configurable
253 std_out_file_path = CStr('', config=False)
253 std_out_file_path = CStr('', config=False)
254 std_err_file_path = CStr('', config=False)
254 std_err_file_path = CStr('', config=False)
255 min_cores = Int(1, config=False)
255 min_cores = Int(1, config=False)
256 max_cores = Int(1, config=False)
256 max_cores = Int(1, config=False)
257 min_sockets = Int(1, config=False)
257 min_sockets = Int(1, config=False)
258 max_sockets = Int(1, config=False)
258 max_sockets = Int(1, config=False)
259 min_nodes = Int(1, config=False)
259 min_nodes = Int(1, config=False)
260 max_nodes = Int(1, config=False)
260 max_nodes = Int(1, config=False)
261 unit_type = Str("Core", config=False)
261 unit_type = Str("Core", config=False)
262 work_directory = CStr('', config=False)
262 work_directory = CStr('', config=False)
263
263
264 def __init__(self, parent, name=None, config=None):
264 def __init__(self, config=None):
265 super(IPControllerTask, self).__init__(parent, name, config)
265 super(IPControllerTask, self).__init__(config)
266 the_uuid = uuid.uuid1()
266 the_uuid = uuid.uuid1()
267 self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid)
267 self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid)
268 self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid)
268 self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid)
269
269
270 @property
270 @property
271 def command_line(self):
271 def command_line(self):
272 return ' '.join(self.controller_cmd + self.controller_args)
272 return ' '.join(self.controller_cmd + self.controller_args)
273
273
274
274
275 class IPEngineTask(WinHPCTask):
275 class IPEngineTask(WinHPCTask):
276
276
277 task_name = Str('IPEngine', config=True)
277 task_name = Str('IPEngine', config=True)
278 engine_cmd = List(['ipengine.exe'], config=True)
278 engine_cmd = List(['ipengine.exe'], config=True)
279 engine_args = List(['--log-to-file', '--log-level', '40'], config=True)
279 engine_args = List(['--log-to-file', '--log-level', '40'], config=True)
280 # I don't want these to be configurable
280 # I don't want these to be configurable
281 std_out_file_path = CStr('', config=False)
281 std_out_file_path = CStr('', config=False)
282 std_err_file_path = CStr('', config=False)
282 std_err_file_path = CStr('', config=False)
283 min_cores = Int(1, config=False)
283 min_cores = Int(1, config=False)
284 max_cores = Int(1, config=False)
284 max_cores = Int(1, config=False)
285 min_sockets = Int(1, config=False)
285 min_sockets = Int(1, config=False)
286 max_sockets = Int(1, config=False)
286 max_sockets = Int(1, config=False)
287 min_nodes = Int(1, config=False)
287 min_nodes = Int(1, config=False)
288 max_nodes = Int(1, config=False)
288 max_nodes = Int(1, config=False)
289 unit_type = Str("Core", config=False)
289 unit_type = Str("Core", config=False)
290 work_directory = CStr('', config=False)
290 work_directory = CStr('', config=False)
291
291
292 def __init__(self, parent, name=None, config=None):
292 def __init__(self, config=None):
293 super(IPEngineTask,self).__init__(parent, name, config)
293 super(IPEngineTask,self).__init__(config)
294 the_uuid = uuid.uuid1()
294 the_uuid = uuid.uuid1()
295 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
295 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
296 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
296 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
297
297
298 @property
298 @property
299 def command_line(self):
299 def command_line(self):
300 return ' '.join(self.engine_cmd + self.engine_args)
300 return ' '.join(self.engine_cmd + self.engine_args)
301
301
302
302
303 # j = WinHPCJob(None)
303 # j = WinHPCJob(None)
304 # j.job_name = 'IPCluster'
304 # j.job_name = 'IPCluster'
305 # j.username = 'GNET\\bgranger'
305 # j.username = 'GNET\\bgranger'
306 # j.requested_nodes = 'GREEN'
306 # j.requested_nodes = 'GREEN'
307 #
307 #
308 # t = WinHPCTask(None)
308 # t = WinHPCTask(None)
309 # t.task_name = 'Controller'
309 # t.task_name = 'Controller'
310 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
310 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
311 # t.work_directory = r"\\blue\domainusers$\bgranger\.ipython\cluster_default"
311 # t.work_directory = r"\\blue\domainusers$\bgranger\.ipython\cluster_default"
312 # t.std_out_file_path = 'controller-out.txt'
312 # t.std_out_file_path = 'controller-out.txt'
313 # t.std_err_file_path = 'controller-err.txt'
313 # t.std_err_file_path = 'controller-err.txt'
314 # t.environment_variables['PYTHONPATH'] = r"\\blue\domainusers$\bgranger\Python\Python25\Lib\site-packages"
314 # t.environment_variables['PYTHONPATH'] = r"\\blue\domainusers$\bgranger\Python\Python25\Lib\site-packages"
315 # j.add_task(t)
315 # j.add_task(t)
316
316
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
General Comments 0
You need to be logged in to leave comments. Login now