##// 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 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 IPython's alias component
4 System command aliases.
5 5
6 6 Authors:
7 7
8 * Fernando Perez
8 9 * Brian Granger
9 10 """
10 11
11 12 #-----------------------------------------------------------------------------
12 13 # Copyright (C) 2008-2009 The IPython Development Team
13 14 #
14 15 # Distributed under the terms of the BSD License. The full license is in
15 16 # the file COPYING, distributed as part of this software.
16 17 #-----------------------------------------------------------------------------
17 18
18 19 #-----------------------------------------------------------------------------
19 20 # Imports
20 21 #-----------------------------------------------------------------------------
21 22
22 23 import __builtin__
23 24 import keyword
24 25 import os
25 26 import re
26 27 import sys
27 28
28 from IPython.core.component import Component
29 from IPython.config.configurable import Configurable
29 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 33 from IPython.utils.autoattr import auto_attr
33 34 from IPython.utils.warn import warn, error
34 35
35 36 #-----------------------------------------------------------------------------
36 37 # Utilities
37 38 #-----------------------------------------------------------------------------
38 39
39 40 # This is used as the pattern for calls to split_user_input.
40 41 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
41 42
42 43 def default_aliases():
43 44 # Make some aliases automatically
44 45 # Prepare list of shell aliases to auto-define
45 46 if os.name == 'posix':
46 47 default_aliases = ('mkdir mkdir', 'rmdir rmdir',
47 48 'mv mv -i','rm rm -i','cp cp -i',
48 49 'cat cat','less less','clear clear',
49 50 # a better ls
50 51 'ls ls -F',
51 52 # long ls
52 53 'll ls -lF')
53 54 # Extra ls aliases with color, which need special treatment on BSD
54 55 # variants
55 56 ls_extra = ( # color ls
56 57 'lc ls -F -o --color',
57 58 # ls normal files only
58 59 'lf ls -F -o --color %l | grep ^-',
59 60 # ls symbolic links
60 61 'lk ls -F -o --color %l | grep ^l',
61 62 # directories or links to directories,
62 63 'ldir ls -F -o --color %l | grep /$',
63 64 # things which are executable
64 65 'lx ls -F -o --color %l | grep ^-..x',
65 66 )
66 67 # The BSDs don't ship GNU ls, so they don't understand the
67 68 # --color switch out of the box
68 69 if 'bsd' in sys.platform:
69 70 ls_extra = ( # ls normal files only
70 71 'lf ls -lF | grep ^-',
71 72 # ls symbolic links
72 73 'lk ls -lF | grep ^l',
73 74 # directories or links to directories,
74 75 'ldir ls -lF | grep /$',
75 76 # things which are executable
76 77 'lx ls -lF | grep ^-..x',
77 78 )
78 79 default_aliases = default_aliases + ls_extra
79 80 elif os.name in ['nt','dos']:
80 81 default_aliases = ('ls dir /on',
81 82 'ddir dir /ad /on', 'ldir dir /ad /on',
82 83 'mkdir mkdir','rmdir rmdir','echo echo',
83 84 'ren ren','cls cls','copy copy')
84 85 else:
85 86 default_aliases = ()
86 87 return [s.split(None,1) for s in default_aliases]
87 88
88 89
89 90 class AliasError(Exception):
90 91 pass
91 92
92 93
93 94 class InvalidAliasError(AliasError):
94 95 pass
95 96
96 97
97 98 #-----------------------------------------------------------------------------
98 99 # Main AliasManager class
99 100 #-----------------------------------------------------------------------------
100 101
101 102
102 class AliasManager(Component):
103 class AliasManager(Configurable):
103 104
104 105 default_aliases = List(default_aliases(), config=True)
105 106 user_aliases = List(default_value=[], config=True)
107 shell = Instance('IPython.core.iplib.InteractiveShell')
106 108
107 def __init__(self, parent, config=None):
108 super(AliasManager, self).__init__(parent, config=config)
109 def __init__(self, shell, config=None):
110 super(AliasManager, self).__init__(config=config)
109 111 self.alias_table = {}
110 112 self.exclude_aliases()
111 113 self.init_aliases()
112
113 @auto_attr
114 def shell(self):
115 return Component.get_instances(
116 root=self.root,
117 klass='IPython.core.iplib.InteractiveShell')[0]
114 self.shell = shell
118 115
119 116 def __contains__(self, name):
120 117 if name in self.alias_table:
121 118 return True
122 119 else:
123 120 return False
124 121
125 122 @property
126 123 def aliases(self):
127 124 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
128 125
129 126 def exclude_aliases(self):
130 127 # set of things NOT to alias (keywords, builtins and some magics)
131 128 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
132 129 no_alias.update(set(keyword.kwlist))
133 130 no_alias.update(set(__builtin__.__dict__.keys()))
134 131 self.no_alias = no_alias
135 132
136 133 def init_aliases(self):
137 134 # Load default aliases
138 135 for name, cmd in self.default_aliases:
139 136 self.soft_define_alias(name, cmd)
140 137
141 138 # Load user aliases
142 139 for name, cmd in self.user_aliases:
143 140 self.soft_define_alias(name, cmd)
144 141
145 142 def clear_aliases(self):
146 143 self.alias_table.clear()
147 144
148 145 def soft_define_alias(self, name, cmd):
149 146 """Define an alias, but don't raise on an AliasError."""
150 147 try:
151 148 self.define_alias(name, cmd)
152 149 except AliasError, e:
153 150 error("Invalid alias: %s" % e)
154 151
155 152 def define_alias(self, name, cmd):
156 153 """Define a new alias after validating it.
157 154
158 155 This will raise an :exc:`AliasError` if there are validation
159 156 problems.
160 157 """
161 158 nargs = self.validate_alias(name, cmd)
162 159 self.alias_table[name] = (nargs, cmd)
163 160
164 161 def undefine_alias(self, name):
165 162 if self.alias_table.has_key(name):
166 163 del self.alias_table[name]
167 164
168 165 def validate_alias(self, name, cmd):
169 166 """Validate an alias and return the its number of arguments."""
170 167 if name in self.no_alias:
171 168 raise InvalidAliasError("The name %s can't be aliased "
172 169 "because it is a keyword or builtin." % name)
173 170 if not (isinstance(cmd, basestring)):
174 171 raise InvalidAliasError("An alias command must be a string, "
175 172 "got: %r" % name)
176 173 nargs = cmd.count('%s')
177 174 if nargs>0 and cmd.find('%l')>=0:
178 175 raise InvalidAliasError('The %s and %l specifiers are mutually '
179 176 'exclusive in alias definitions.')
180 177 return nargs
181 178
182 179 def call_alias(self, alias, rest=''):
183 180 """Call an alias given its name and the rest of the line."""
184 181 cmd = self.transform_alias(alias, rest)
185 182 try:
186 183 self.shell.system(cmd)
187 184 except:
188 185 self.shell.showtraceback()
189 186
190 187 def transform_alias(self, alias,rest=''):
191 188 """Transform alias to system command string."""
192 189 nargs, cmd = self.alias_table[alias]
193 190
194 191 if ' ' in cmd and os.path.isfile(cmd):
195 192 cmd = '"%s"' % cmd
196 193
197 194 # Expand the %l special to be the user's input line
198 195 if cmd.find('%l') >= 0:
199 196 cmd = cmd.replace('%l', rest)
200 197 rest = ''
201 198 if nargs==0:
202 199 # Simple, argument-less aliases
203 200 cmd = '%s %s' % (cmd, rest)
204 201 else:
205 202 # Handle aliases with positional arguments
206 203 args = rest.split(None, nargs)
207 204 if len(args) < nargs:
208 205 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
209 206 (alias, nargs, len(args)))
210 207 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
211 208 return cmd
212 209
213 210 def expand_alias(self, line):
214 211 """ Expand an alias in the command line
215 212
216 213 Returns the provided command line, possibly with the first word
217 214 (command) translated according to alias expansion rules.
218 215
219 216 [ipython]|16> _ip.expand_aliases("np myfile.txt")
220 217 <16> 'q:/opt/np/notepad++.exe myfile.txt'
221 218 """
222 219
223 220 pre,fn,rest = split_user_input(line)
224 221 res = pre + self.expand_aliases(fn, rest)
225 222 return res
226 223
227 224 def expand_aliases(self, fn, rest):
228 225 """Expand multiple levels of aliases:
229 226
230 227 if:
231 228
232 229 alias foo bar /tmp
233 230 alias baz foo
234 231
235 232 then:
236 233
237 234 baz huhhahhei -> bar /tmp huhhahhei
238 235
239 236 """
240 237 line = fn + " " + rest
241 238
242 239 done = set()
243 240 while 1:
244 241 pre,fn,rest = split_user_input(line, shell_line_split)
245 242 if fn in self.alias_table:
246 243 if fn in done:
247 244 warn("Cyclic alias definition, repeated '%s'" % fn)
248 245 return ""
249 246 done.add(fn)
250 247
251 248 l2 = self.transform_alias(fn, rest)
252 249 if l2 == line:
253 250 break
254 251 # ls -> ls -F should not recurse forever
255 252 if l2.split(None,1)[0] == line.split(None,1)[0]:
256 253 line = l2
257 254 break
258 255 line=l2
259 256 else:
260 257 break
261 258
262 259 return line
@@ -1,453 +1,453 b''
1 1 # encoding: utf-8
2 2 """
3 3 An application for IPython.
4 4
5 5 All top-level applications should use the classes in this module for
6 6 handling configuration and creating componenets.
7 7
8 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 11 Authors:
12 12
13 13 * Brian Granger
14 14 * Fernando Perez
15 15
16 16 Notes
17 17 -----
18 18 """
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Copyright (C) 2008-2009 The IPython Development Team
22 22 #
23 23 # Distributed under the terms of the BSD License. The full license is in
24 24 # the file COPYING, distributed as part of this software.
25 25 #-----------------------------------------------------------------------------
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Imports
29 29 #-----------------------------------------------------------------------------
30 30
31 31 import logging
32 32 import os
33 33 import sys
34 34
35 35 from IPython.core import release, crashhandler
36 36 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
37 37 from IPython.config.loader import (
38 38 PyFileConfigLoader,
39 39 ArgParseConfigLoader,
40 40 Config,
41 41 )
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Classes and functions
45 45 #-----------------------------------------------------------------------------
46 46
47 47 class ApplicationError(Exception):
48 48 pass
49 49
50 50
51 51 class BaseAppConfigLoader(ArgParseConfigLoader):
52 52 """Default command line options for IPython based applications."""
53 53
54 54 def _add_ipython_dir(self, parser):
55 55 """Add the --ipython-dir option to the parser."""
56 56 paa = parser.add_argument
57 57 paa('--ipython-dir',
58 58 dest='Global.ipython_dir',type=unicode,
59 59 help=
60 60 """Set to override default location of the IPython directory
61 61 IPYTHON_DIR, stored as Global.ipython_dir. This can also be
62 62 specified through the environment variable IPYTHON_DIR.""",
63 63 metavar='Global.ipython_dir')
64 64
65 65 def _add_log_level(self, parser):
66 66 """Add the --log-level option to the parser."""
67 67 paa = parser.add_argument
68 68 paa('--log-level',
69 69 dest="Global.log_level",type=int,
70 70 help='Set the log level (0,10,20,30,40,50). Default is 30.',
71 71 metavar='Global.log_level')
72 72
73 73 def _add_arguments(self):
74 74 self._add_ipython_dir(self.parser)
75 75 self._add_log_level(self.parser)
76 76
77 77
78 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 81 The configuration of an application can be done via three different Config
82 82 objects, which are loaded and ultimately merged into a single one used
83 83 from that point on by the app. These are:
84 84
85 85 1. default_config: internal defaults, implemented in code.
86 86 2. file_config: read from the filesystem.
87 87 3. command_line_config: read from the system's command line flags.
88 88
89 89 During initialization, 3 is actually read before 2, since at the
90 90 command-line one may override the location of the file to be read. But the
91 91 above is the order in which the merge is made.
92 92 """
93 93
94 94 name = u'ipython'
95 95 description = 'IPython: an enhanced interactive Python shell.'
96 96 #: Usage message printed by argparse. If None, auto-generate
97 97 usage = None
98 98 #: The command line config loader. Subclass of ArgParseConfigLoader.
99 99 command_line_loader = BaseAppConfigLoader
100 100 #: The name of the config file to load, determined at runtime
101 101 config_file_name = None
102 102 #: The name of the default config file. Track separately from the actual
103 103 #: name because some logic happens only if we aren't using the default.
104 104 default_config_file_name = u'ipython_config.py'
105 105 default_log_level = logging.WARN
106 106 #: Set by --profile option
107 107 profile_name = None
108 108 #: User's ipython directory, typically ~/.ipython/
109 109 ipython_dir = None
110 110 #: Internal defaults, implemented in code.
111 111 default_config = None
112 112 #: Read from the filesystem.
113 113 file_config = None
114 114 #: Read from the system's command line flags.
115 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 117 master_config = None
118 118 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
119 119 argv = None
120 120 #: extra arguments computed by the command-line loader
121 121 extra_args = None
122 122 #: The class to use as the crash handler.
123 123 crash_handler_class = crashhandler.CrashHandler
124 124
125 125 # Private attributes
126 126 _exiting = False
127 127 _initialized = False
128 128
129 129 def __init__(self, argv=None):
130 130 self.argv = sys.argv[1:] if argv is None else argv
131 131 self.init_logger()
132 132
133 133 def init_logger(self):
134 134 self.log = logging.getLogger(self.__class__.__name__)
135 135 # This is used as the default until the command line arguments are read.
136 136 self.log.setLevel(self.default_log_level)
137 137 self._log_handler = logging.StreamHandler()
138 138 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
139 139 self._log_handler.setFormatter(self._log_formatter)
140 140 self.log.addHandler(self._log_handler)
141 141
142 142 def _set_log_level(self, level):
143 143 self.log.setLevel(level)
144 144
145 145 def _get_log_level(self):
146 146 return self.log.level
147 147
148 148 log_level = property(_get_log_level, _set_log_level)
149 149
150 150 def initialize(self):
151 151 """Initialize the application.
152 152
153 153 Loads all configuration information and sets all application state, but
154 154 does not start any relevant processing (typically some kind of event
155 155 loop).
156 156
157 157 Once this method has been called, the application is flagged as
158 158 initialized and the method becomes a no-op."""
159 159
160 160 if self._initialized:
161 161 return
162 162
163 163 # The first part is protected with an 'attempt' wrapper, that will log
164 164 # failures with the basic system traceback machinery. Once our crash
165 165 # handler is in place, we can let any subsequent exception propagate,
166 166 # as our handler will log it with much better detail than the default.
167 167 self.attempt(self.create_crash_handler)
168 168
169 169 # Configuration phase
170 170 # Default config (internally hardwired in application code)
171 171 self.create_default_config()
172 172 self.log_default_config()
173 173 self.set_default_config_log_level()
174 174
175 175 # Command-line config
176 176 self.pre_load_command_line_config()
177 177 self.load_command_line_config()
178 178 self.set_command_line_config_log_level()
179 179 self.post_load_command_line_config()
180 180 self.log_command_line_config()
181 181
182 182 # Find resources needed for filesystem access, using information from
183 183 # the above two
184 184 self.find_ipython_dir()
185 185 self.find_resources()
186 186 self.find_config_file_name()
187 187 self.find_config_file_paths()
188 188
189 189 # File-based config
190 190 self.pre_load_file_config()
191 191 self.load_file_config()
192 192 self.set_file_config_log_level()
193 193 self.post_load_file_config()
194 194 self.log_file_config()
195 195
196 196 # Merge all config objects into a single one the app can then use
197 197 self.merge_configs()
198 198 self.log_master_config()
199 199
200 200 # Construction phase
201 201 self.pre_construct()
202 202 self.construct()
203 203 self.post_construct()
204 204
205 205 # Done, flag as such and
206 206 self._initialized = True
207 207
208 208 def start(self):
209 209 """Start the application."""
210 210 self.initialize()
211 211 self.start_app()
212 212
213 213 #-------------------------------------------------------------------------
214 214 # Various stages of Application creation
215 215 #-------------------------------------------------------------------------
216 216
217 217 def create_crash_handler(self):
218 218 """Create a crash handler, typically setting sys.excepthook to it."""
219 219 self.crash_handler = self.crash_handler_class(self)
220 220 sys.excepthook = self.crash_handler
221 221
222 222 def create_default_config(self):
223 223 """Create defaults that can't be set elsewhere.
224 224
225 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
227 not a HasTraits or Component) are not set in this way. Instead
226 of Configurables. But, defaults the top-level Application (which is
227 not a HasTraits or Configurables) are not set in this way. Instead
228 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 231 c = Config()
232 232 c.Global.ipython_dir = get_ipython_dir()
233 233 c.Global.log_level = self.log_level
234 234 self.default_config = c
235 235
236 236 def log_default_config(self):
237 237 self.log.debug('Default config loaded:')
238 238 self.log.debug(repr(self.default_config))
239 239
240 240 def set_default_config_log_level(self):
241 241 try:
242 242 self.log_level = self.default_config.Global.log_level
243 243 except AttributeError:
244 244 # Fallback to the default_log_level class attribute
245 245 pass
246 246
247 247 def create_command_line_config(self):
248 248 """Create and return a command line config loader."""
249 249 return self.command_line_loader(
250 250 self.argv,
251 251 description=self.description,
252 252 version=release.version,
253 253 usage=self.usage
254 254 )
255 255
256 256 def pre_load_command_line_config(self):
257 257 """Do actions just before loading the command line config."""
258 258 pass
259 259
260 260 def load_command_line_config(self):
261 261 """Load the command line config."""
262 262 loader = self.create_command_line_config()
263 263 self.command_line_config = loader.load_config()
264 264 self.extra_args = loader.get_extra_args()
265 265
266 266 def set_command_line_config_log_level(self):
267 267 try:
268 268 self.log_level = self.command_line_config.Global.log_level
269 269 except AttributeError:
270 270 pass
271 271
272 272 def post_load_command_line_config(self):
273 273 """Do actions just after loading the command line config."""
274 274 pass
275 275
276 276 def log_command_line_config(self):
277 277 self.log.debug("Command line config loaded:")
278 278 self.log.debug(repr(self.command_line_config))
279 279
280 280 def find_ipython_dir(self):
281 281 """Set the IPython directory.
282 282
283 283 This sets ``self.ipython_dir``, but the actual value that is passed to
284 284 the application is kept in either ``self.default_config`` or
285 285 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
286 286 ``sys.path`` so config files there can be referenced by other config
287 287 files.
288 288 """
289 289
290 290 try:
291 291 self.ipython_dir = self.command_line_config.Global.ipython_dir
292 292 except AttributeError:
293 293 self.ipython_dir = self.default_config.Global.ipython_dir
294 294 sys.path.append(os.path.abspath(self.ipython_dir))
295 295 if not os.path.isdir(self.ipython_dir):
296 296 os.makedirs(self.ipython_dir, mode=0777)
297 297 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
298 298
299 299 def find_resources(self):
300 300 """Find other resources that need to be in place.
301 301
302 302 Things like cluster directories need to be in place to find the
303 303 config file. These happen right after the IPython directory has
304 304 been set.
305 305 """
306 306 pass
307 307
308 308 def find_config_file_name(self):
309 309 """Find the config file name for this application.
310 310
311 311 This must set ``self.config_file_name`` to the filename of the
312 312 config file to use (just the filename). The search paths for the
313 313 config file are set in :meth:`find_config_file_paths` and then passed
314 314 to the config file loader where they are resolved to an absolute path.
315 315
316 316 If a profile has been set at the command line, this will resolve it.
317 317 """
318 318 try:
319 319 self.config_file_name = self.command_line_config.Global.config_file
320 320 except AttributeError:
321 321 pass
322 322 else:
323 323 return
324 324
325 325 try:
326 326 self.profile_name = self.command_line_config.Global.profile
327 327 except AttributeError:
328 328 # Just use the default as there is no profile
329 329 self.config_file_name = self.default_config_file_name
330 330 else:
331 331 # Use the default config file name and profile name if set
332 332 # to determine the used config file name.
333 333 name_parts = self.default_config_file_name.split('.')
334 334 name_parts.insert(1, u'_' + self.profile_name + u'.')
335 335 self.config_file_name = ''.join(name_parts)
336 336
337 337 def find_config_file_paths(self):
338 338 """Set the search paths for resolving the config file.
339 339
340 340 This must set ``self.config_file_paths`` to a sequence of search
341 341 paths to pass to the config file loader.
342 342 """
343 343 # Include our own profiles directory last, so that users can still find
344 344 # our shipped copies of builtin profiles even if they don't have them
345 345 # in their local ipython directory.
346 346 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
347 347 self.config_file_paths = (os.getcwd(), self.ipython_dir, prof_dir)
348 348
349 349 def pre_load_file_config(self):
350 350 """Do actions before the config file is loaded."""
351 351 pass
352 352
353 353 def load_file_config(self):
354 354 """Load the config file.
355 355
356 356 This tries to load the config file from disk. If successful, the
357 357 ``CONFIG_FILE`` config variable is set to the resolved config file
358 358 location. If not successful, an empty config is used.
359 359 """
360 360 self.log.debug("Attempting to load config file: %s" %
361 361 self.config_file_name)
362 362 loader = PyFileConfigLoader(self.config_file_name,
363 363 path=self.config_file_paths)
364 364 try:
365 365 self.file_config = loader.load_config()
366 366 self.file_config.Global.config_file = loader.full_filename
367 367 except IOError:
368 368 # Only warn if the default config file was NOT being used.
369 369 if not self.config_file_name==self.default_config_file_name:
370 370 self.log.warn("Config file not found, skipping: %s" %
371 371 self.config_file_name, exc_info=True)
372 372 self.file_config = Config()
373 373 except:
374 374 self.log.warn("Error loading config file: %s" %
375 375 self.config_file_name, exc_info=True)
376 376 self.file_config = Config()
377 377
378 378 def set_file_config_log_level(self):
379 379 # We need to keeep self.log_level updated. But we only use the value
380 380 # of the file_config if a value was not specified at the command
381 381 # line, because the command line overrides everything.
382 382 if not hasattr(self.command_line_config.Global, 'log_level'):
383 383 try:
384 384 self.log_level = self.file_config.Global.log_level
385 385 except AttributeError:
386 386 pass # Use existing value
387 387
388 388 def post_load_file_config(self):
389 389 """Do actions after the config file is loaded."""
390 390 pass
391 391
392 392 def log_file_config(self):
393 393 if hasattr(self.file_config.Global, 'config_file'):
394 394 self.log.debug("Config file loaded: %s" %
395 395 self.file_config.Global.config_file)
396 396 self.log.debug(repr(self.file_config))
397 397
398 398 def merge_configs(self):
399 399 """Merge the default, command line and file config objects."""
400 400 config = Config()
401 401 config._merge(self.default_config)
402 402 config._merge(self.file_config)
403 403 config._merge(self.command_line_config)
404 404
405 405 # XXX fperez - propose to Brian we rename master_config to simply
406 406 # config, I think this is going to be heavily used in examples and
407 407 # application code and the name is shorter/easier to find/remember.
408 408 # For now, just alias it...
409 409 self.master_config = config
410 410 self.config = config
411 411
412 412 def log_master_config(self):
413 413 self.log.debug("Master config created:")
414 414 self.log.debug(repr(self.master_config))
415 415
416 416 def pre_construct(self):
417 417 """Do actions after the config has been built, but before construct."""
418 418 pass
419 419
420 420 def construct(self):
421 """Construct the main components that make up this app."""
422 self.log.debug("Constructing components for application")
421 """Construct the main objects that make up this app."""
422 self.log.debug("Constructing main objects for application")
423 423
424 424 def post_construct(self):
425 425 """Do actions after construct, but before starting the app."""
426 426 pass
427 427
428 428 def start_app(self):
429 429 """Actually start the app."""
430 430 self.log.debug("Starting application")
431 431
432 432 #-------------------------------------------------------------------------
433 433 # Utility methods
434 434 #-------------------------------------------------------------------------
435 435
436 436 def exit(self, exit_status=0):
437 437 if self._exiting:
438 438 pass
439 439 else:
440 440 self.log.debug("Exiting application: %s" % self.name)
441 441 self._exiting = True
442 442 sys.exit(exit_status)
443 443
444 444 def attempt(self, func):
445 445 try:
446 446 func()
447 447 except SystemExit:
448 448 raise
449 449 except:
450 450 self.log.critical("Aborting application: %s" % self.name,
451 451 exc_info=True)
452 452 self.exit(0)
453 453
@@ -1,118 +1,115 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 A context manager for managing things injected into :mod:`__builtin__`.
5 5
6 6 Authors:
7 7
8 8 * Brian Granger
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2009 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import __builtin__
23 23
24 from IPython.core.component import Component
24 from IPython.config.configurable import Configurable
25 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 30 # Classes and functions
31 31 #-----------------------------------------------------------------------------
32 32
33 33
34 34 class __BuiltinUndefined(object): pass
35 35 BuiltinUndefined = __BuiltinUndefined()
36 36
37 37
38 class BuiltinTrap(Component):
38 class BuiltinTrap(Configurable):
39 39
40 def __init__(self, parent):
41 super(BuiltinTrap, self).__init__(parent, None, None)
40 shell = Instance('IPython.core.iplib.InteractiveShell')
41
42 def __init__(self, shell):
43 super(BuiltinTrap, self).__init__(None)
42 44 self._orig_builtins = {}
43 45 # We define this to track if a single BuiltinTrap is nested.
44 46 # Only turn off the trap when the outermost call to __exit__ is made.
45 47 self._nested_level = 0
46
47 @auto_attr
48 def shell(self):
49 return Component.get_instances(
50 root=self.root,
51 klass='IPython.core.iplib.InteractiveShell')[0]
48 self.shell = shell
52 49
53 50 def __enter__(self):
54 51 if self._nested_level == 0:
55 52 self.set()
56 53 self._nested_level += 1
57 54 # I return self, so callers can use add_builtin in a with clause.
58 55 return self
59 56
60 57 def __exit__(self, type, value, traceback):
61 58 if self._nested_level == 1:
62 59 self.unset()
63 60 self._nested_level -= 1
64 61 # Returning False will cause exceptions to propagate
65 62 return False
66 63
67 64 def add_builtin(self, key, value):
68 65 """Add a builtin and save the original."""
69 66 orig = __builtin__.__dict__.get(key, BuiltinUndefined)
70 67 self._orig_builtins[key] = orig
71 68 __builtin__.__dict__[key] = value
72 69
73 70 def remove_builtin(self, key):
74 71 """Remove an added builtin and re-set the original."""
75 72 try:
76 73 orig = self._orig_builtins.pop(key)
77 74 except KeyError:
78 75 pass
79 76 else:
80 77 if orig is BuiltinUndefined:
81 78 del __builtin__.__dict__[key]
82 79 else:
83 80 __builtin__.__dict__[key] = orig
84 81
85 82 def set(self):
86 83 """Store ipython references in the __builtin__ namespace."""
87 84 self.add_builtin('exit', Quitter(self.shell, 'exit'))
88 85 self.add_builtin('quit', Quitter(self.shell, 'quit'))
89 86 self.add_builtin('get_ipython', self.shell.get_ipython)
90 87
91 88 # Recursive reload function
92 89 try:
93 90 from IPython.lib import deepreload
94 91 if self.shell.deep_reload:
95 92 self.add_builtin('reload', deepreload.reload)
96 93 else:
97 94 self.add_builtin('dreload', deepreload.reload)
98 95 del deepreload
99 96 except ImportError:
100 97 pass
101 98
102 99 # Keep in the builtins a flag for when IPython is active. We set it
103 100 # with setdefault so that multiple nested IPythons don't clobber one
104 101 # another. Each will increase its value by one upon being activated,
105 102 # which also gives us a way to determine the nesting level.
106 103 __builtin__.__dict__.setdefault('__IPYTHON__active',0)
107 104
108 105 def unset(self):
109 106 """Remove any builtins which might have been added by add_builtins, or
110 107 restore overwritten ones to their previous values."""
111 108 for key in self._orig_builtins.keys():
112 109 self.remove_builtin(key)
113 110 self._orig_builtins.clear()
114 111 self._builtins_added = False
115 112 try:
116 113 del __builtin__.__dict__['__IPYTHON__active']
117 114 except KeyError:
118 115 pass
@@ -1,75 +1,69 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 A context manager for handling sys.displayhook.
5 5
6 6 Authors:
7 7
8 8 * Robert Kern
9 9 * Brian Granger
10 10 """
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2008-2009 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import sys
24 24
25 from IPython.core.component import Component
25 from IPython.config.configurable import Configurable
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Classes and functions
29 29 #-----------------------------------------------------------------------------
30 30
31 31
32 class DisplayTrap(Component):
32 class DisplayTrap(Configurable):
33 33 """Object to manage sys.displayhook.
34 34
35 35 This came from IPython.core.kernel.display_hook, but is simplified
36 36 (no callbacks or formatters) until more of the core is refactored.
37 37 """
38 38
39 def __init__(self, parent, hook):
40 super(DisplayTrap, self).__init__(parent, None, None)
39 def __init__(self, hook):
40 super(DisplayTrap, self).__init__(None)
41 41 self.hook = hook
42 42 self.old_hook = None
43 43 # We define this to track if a single BuiltinTrap is nested.
44 44 # Only turn off the trap when the outermost call to __exit__ is made.
45 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 47 def __enter__(self):
54 48 if self._nested_level == 0:
55 49 self.set()
56 50 self._nested_level += 1
57 51 return self
58 52
59 53 def __exit__(self, type, value, traceback):
60 54 if self._nested_level == 1:
61 55 self.unset()
62 56 self._nested_level -= 1
63 57 # Returning False will cause exceptions to propagate
64 58 return False
65 59
66 60 def set(self):
67 61 """Set the hook."""
68 62 if sys.displayhook is not self.hook:
69 63 self.old_hook = sys.displayhook
70 64 sys.displayhook = self.hook
71 65
72 66 def unset(self):
73 67 """Unset the hook."""
74 68 sys.displayhook = self.old_hook
75 69
@@ -1,36 +1,30 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 This module is *completely* deprecated and should no longer be used for
5 5 any purpose. Currently, we have a few parts of the core that have
6 6 not been componentized and thus, still rely on this module. When everything
7 7 has been made into a component, this module will be sent to deathrow.
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2008-2009 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Classes and functions
23 23 #-----------------------------------------------------------------------------
24 24
25 25
26 26 def get():
27 """Get the most recently created InteractiveShell instance."""
27 """Get the global InteractiveShell instance."""
28 28 from IPython.core.iplib import InteractiveShell
29 insts = InteractiveShell.get_instances()
30 if len(insts)==0:
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
29 return InteractiveShell.instance()
30
@@ -1,665 +1,665 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The :class:`~IPython.core.application.Application` object for the command
5 5 line :command:`ipython` program.
6 6
7 7 Authors
8 8 -------
9 9
10 10 * Brian Granger
11 11 * Fernando Perez
12 12 """
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Copyright (C) 2008-2010 The IPython Development Team
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-----------------------------------------------------------------------------
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Imports
23 23 #-----------------------------------------------------------------------------
24 24
25 25 from __future__ import absolute_import
26 26
27 27 import logging
28 28 import os
29 29 import sys
30 30
31 31 from IPython.core import release
32 32 from IPython.core.crashhandler import CrashHandler
33 33 from IPython.core.application import Application, BaseAppConfigLoader
34 34 from IPython.core.iplib import InteractiveShell
35 35 from IPython.config.loader import (
36 36 Config,
37 37 PyFileConfigLoader
38 38 )
39 39 from IPython.lib import inputhook
40 40 from IPython.utils.path import filefind, get_ipython_dir
41 41 from . import usage
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Globals, utilities and helpers
45 45 #-----------------------------------------------------------------------------
46 46
47 47 #: The default config file name for this application.
48 48 default_config_file_name = u'ipython_config.py'
49 49
50 50
51 51 class IPAppConfigLoader(BaseAppConfigLoader):
52 52
53 53 def _add_arguments(self):
54 54 super(IPAppConfigLoader, self)._add_arguments()
55 55 paa = self.parser.add_argument
56 56 paa('-p',
57 57 '--profile', dest='Global.profile', type=unicode,
58 58 help=
59 59 """The string name of the ipython profile to be used. Assume that your
60 60 config file is ipython_config-<name>.py (looks in current dir first,
61 61 then in IPYTHON_DIR). This is a quick way to keep and load multiple
62 62 config files for different tasks, especially if include your basic one
63 63 in your more specialized ones. You can keep a basic
64 64 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
65 65 include this one and load extra things for particular tasks.""",
66 66 metavar='Global.profile')
67 67 paa('--config-file',
68 68 dest='Global.config_file', type=unicode,
69 69 help=
70 70 """Set the config file name to override default. Normally IPython
71 71 loads ipython_config.py (from current directory) or
72 72 IPYTHON_DIR/ipython_config.py. If the loading of your config file
73 73 fails, IPython starts with a bare bones configuration (no modules
74 74 loaded at all).""",
75 75 metavar='Global.config_file')
76 76 paa('--autocall',
77 77 dest='InteractiveShell.autocall', type=int,
78 78 help=
79 79 """Make IPython automatically call any callable object even if you
80 80 didn't type explicit parentheses. For example, 'str 43' becomes
81 81 'str(43)' automatically. The value can be '0' to disable the feature,
82 82 '1' for 'smart' autocall, where it is not applied if there are no more
83 83 arguments on the line, and '2' for 'full' autocall, where all callable
84 84 objects are automatically called (even if no arguments are present).
85 85 The default is '1'.""",
86 86 metavar='InteractiveShell.autocall')
87 87 paa('--autoindent',
88 88 action='store_true', dest='InteractiveShell.autoindent',
89 89 help='Turn on autoindenting.')
90 90 paa('--no-autoindent',
91 91 action='store_false', dest='InteractiveShell.autoindent',
92 92 help='Turn off autoindenting.')
93 93 paa('--automagic',
94 94 action='store_true', dest='InteractiveShell.automagic',
95 95 help=
96 96 """Turn on the auto calling of magic commands. Type %%magic at the
97 97 IPython prompt for more information.""")
98 98 paa('--no-automagic',
99 99 action='store_false', dest='InteractiveShell.automagic',
100 100 help='Turn off the auto calling of magic commands.')
101 101 paa('--autoedit-syntax',
102 102 action='store_true', dest='InteractiveShell.autoedit_syntax',
103 103 help='Turn on auto editing of files with syntax errors.')
104 104 paa('--no-autoedit-syntax',
105 105 action='store_false', dest='InteractiveShell.autoedit_syntax',
106 106 help='Turn off auto editing of files with syntax errors.')
107 107 paa('--banner',
108 108 action='store_true', dest='Global.display_banner',
109 109 help='Display a banner upon starting IPython.')
110 110 paa('--no-banner',
111 111 action='store_false', dest='Global.display_banner',
112 112 help="Don't display a banner upon starting IPython.")
113 113 paa('--cache-size',
114 114 type=int, dest='InteractiveShell.cache_size',
115 115 help=
116 116 """Set the size of the output cache. The default is 1000, you can
117 117 change it permanently in your config file. Setting it to 0 completely
118 118 disables the caching system, and the minimum value accepted is 20 (if
119 119 you provide a value less than 20, it is reset to 0 and a warning is
120 120 issued). This limit is defined because otherwise you'll spend more
121 121 time re-flushing a too small cache than working""",
122 122 metavar='InteractiveShell.cache_size')
123 123 paa('--classic',
124 124 action='store_true', dest='Global.classic',
125 125 help="Gives IPython a similar feel to the classic Python prompt.")
126 126 paa('--colors',
127 127 type=str, dest='InteractiveShell.colors',
128 128 help="Set the color scheme (NoColor, Linux, and LightBG).",
129 129 metavar='InteractiveShell.colors')
130 130 paa('--color-info',
131 131 action='store_true', dest='InteractiveShell.color_info',
132 132 help=
133 133 """IPython can display information about objects via a set of func-
134 134 tions, and optionally can use colors for this, syntax highlighting
135 135 source code and various other elements. However, because this
136 136 information is passed through a pager (like 'less') and many pagers get
137 137 confused with color codes, this option is off by default. You can test
138 138 it and turn it on permanently in your ipython_config.py file if it
139 139 works for you. Test it and turn it on permanently if it works with
140 140 your system. The magic function %%color_info allows you to toggle this
141 141 inter- actively for testing.""")
142 142 paa('--no-color-info',
143 143 action='store_false', dest='InteractiveShell.color_info',
144 144 help="Disable using colors for info related things.")
145 145 paa('--confirm-exit',
146 146 action='store_true', dest='InteractiveShell.confirm_exit',
147 147 help=
148 148 """Set to confirm when you try to exit IPython with an EOF (Control-D
149 149 in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or
150 150 '%%Exit', you can force a direct exit without any confirmation.""")
151 151 paa('--no-confirm-exit',
152 152 action='store_false', dest='InteractiveShell.confirm_exit',
153 153 help="Don't prompt the user when exiting.")
154 154 paa('--deep-reload',
155 155 action='store_true', dest='InteractiveShell.deep_reload',
156 156 help=
157 157 """Enable deep (recursive) reloading by default. IPython can use the
158 158 deep_reload module which reloads changes in modules recursively (it
159 159 replaces the reload() function, so you don't need to change anything to
160 160 use it). deep_reload() forces a full reload of modules whose code may
161 161 have changed, which the default reload() function does not. When
162 162 deep_reload is off, IPython will use the normal reload(), but
163 163 deep_reload will still be available as dreload(). This fea- ture is off
164 164 by default [which means that you have both normal reload() and
165 165 dreload()].""")
166 166 paa('--no-deep-reload',
167 167 action='store_false', dest='InteractiveShell.deep_reload',
168 168 help="Disable deep (recursive) reloading by default.")
169 169 paa('--editor',
170 170 type=str, dest='InteractiveShell.editor',
171 171 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
172 172 metavar='InteractiveShell.editor')
173 173 paa('--log','-l',
174 174 action='store_true', dest='InteractiveShell.logstart',
175 175 help="Start logging to the default log file (./ipython_log.py).")
176 176 paa('--logfile','-lf',
177 177 type=unicode, dest='InteractiveShell.logfile',
178 178 help="Start logging to logfile with this name.",
179 179 metavar='InteractiveShell.logfile')
180 180 paa('--log-append','-la',
181 181 type=unicode, dest='InteractiveShell.logappend',
182 182 help="Start logging to the given file in append mode.",
183 183 metavar='InteractiveShell.logfile')
184 184 paa('--pdb',
185 185 action='store_true', dest='InteractiveShell.pdb',
186 186 help="Enable auto calling the pdb debugger after every exception.")
187 187 paa('--no-pdb',
188 188 action='store_false', dest='InteractiveShell.pdb',
189 189 help="Disable auto calling the pdb debugger after every exception.")
190 190 paa('--pprint',
191 191 action='store_true', dest='InteractiveShell.pprint',
192 192 help="Enable auto pretty printing of results.")
193 193 paa('--no-pprint',
194 194 action='store_false', dest='InteractiveShell.pprint',
195 195 help="Disable auto auto pretty printing of results.")
196 196 paa('--prompt-in1','-pi1',
197 197 type=str, dest='InteractiveShell.prompt_in1',
198 198 help=
199 199 """Set the main input prompt ('In [\#]: '). Note that if you are using
200 200 numbered prompts, the number is represented with a '\#' in the string.
201 201 Don't forget to quote strings with spaces embedded in them. Most
202 202 bash-like escapes can be used to customize IPython's prompts, as well
203 203 as a few additional ones which are IPython-spe- cific. All valid
204 204 prompt escapes are described in detail in the Customization section of
205 205 the IPython manual.""",
206 206 metavar='InteractiveShell.prompt_in1')
207 207 paa('--prompt-in2','-pi2',
208 208 type=str, dest='InteractiveShell.prompt_in2',
209 209 help=
210 210 """Set the secondary input prompt (' .\D.: '). Similar to the previous
211 211 option, but used for the continuation prompts. The special sequence
212 212 '\D' is similar to '\#', but with all digits replaced by dots (so you
213 213 can have your continuation prompt aligned with your input prompt).
214 214 Default: ' .\D.: ' (note three spaces at the start for alignment with
215 215 'In [\#]')""",
216 216 metavar='InteractiveShell.prompt_in2')
217 217 paa('--prompt-out','-po',
218 218 type=str, dest='InteractiveShell.prompt_out',
219 219 help="Set the output prompt ('Out[\#]:')",
220 220 metavar='InteractiveShell.prompt_out')
221 221 paa('--quick',
222 222 action='store_true', dest='Global.quick',
223 223 help="Enable quick startup with no config files.")
224 224 paa('--readline',
225 225 action='store_true', dest='InteractiveShell.readline_use',
226 226 help="Enable readline for command line usage.")
227 227 paa('--no-readline',
228 228 action='store_false', dest='InteractiveShell.readline_use',
229 229 help="Disable readline for command line usage.")
230 230 paa('--screen-length','-sl',
231 231 type=int, dest='InteractiveShell.screen_length',
232 232 help=
233 233 """Number of lines of your screen, used to control printing of very
234 234 long strings. Strings longer than this number of lines will be sent
235 235 through a pager instead of directly printed. The default value for
236 236 this is 0, which means IPython will auto-detect your screen size every
237 237 time it needs to print certain potentially long strings (this doesn't
238 238 change the behavior of the 'print' keyword, it's only triggered
239 239 internally). If for some reason this isn't working well (it needs
240 240 curses support), specify it yourself. Otherwise don't change the
241 241 default.""",
242 242 metavar='InteractiveShell.screen_length')
243 243 paa('--separate-in','-si',
244 244 type=str, dest='InteractiveShell.separate_in',
245 245 help="Separator before input prompts. Default '\\n'.",
246 246 metavar='InteractiveShell.separate_in')
247 247 paa('--separate-out','-so',
248 248 type=str, dest='InteractiveShell.separate_out',
249 249 help="Separator before output prompts. Default 0 (nothing).",
250 250 metavar='InteractiveShell.separate_out')
251 251 paa('--separate-out2','-so2',
252 252 type=str, dest='InteractiveShell.separate_out2',
253 253 help="Separator after output prompts. Default 0 (nonight).",
254 254 metavar='InteractiveShell.separate_out2')
255 255 paa('--no-sep',
256 256 action='store_true', dest='Global.nosep',
257 257 help="Eliminate all spacing between prompts.")
258 258 paa('--term-title',
259 259 action='store_true', dest='InteractiveShell.term_title',
260 260 help="Enable auto setting the terminal title.")
261 261 paa('--no-term-title',
262 262 action='store_false', dest='InteractiveShell.term_title',
263 263 help="Disable auto setting the terminal title.")
264 264 paa('--xmode',
265 265 type=str, dest='InteractiveShell.xmode',
266 266 help=
267 267 """Exception reporting mode ('Plain','Context','Verbose'). Plain:
268 268 similar to python's normal traceback printing. Context: prints 5 lines
269 269 of context source code around each line in the traceback. Verbose:
270 270 similar to Context, but additionally prints the variables currently
271 271 visible where the exception happened (shortening their strings if too
272 272 long). This can potentially be very slow, if you happen to have a huge
273 273 data structure whose string representation is complex to compute.
274 274 Your computer may appear to freeze for a while with cpu usage at 100%%.
275 275 If this occurs, you can cancel the traceback with Ctrl-C (maybe hitting
276 276 it more than once).
277 277 """,
278 278 metavar='InteractiveShell.xmode')
279 279 paa('--ext',
280 280 type=str, dest='Global.extra_extension',
281 281 help="The dotted module name of an IPython extension to load.",
282 282 metavar='Global.extra_extension')
283 283 paa('-c',
284 284 type=str, dest='Global.code_to_run',
285 285 help="Execute the given command string.",
286 286 metavar='Global.code_to_run')
287 287 paa('-i',
288 288 action='store_true', dest='Global.force_interact',
289 289 help=
290 290 "If running code from the command line, become interactive afterwards.")
291 291
292 292 # Options to start with GUI control enabled from the beginning
293 293 paa('--gui',
294 294 type=str, dest='Global.gui',
295 295 help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
296 296 metavar='gui-mode')
297 297 paa('--pylab','-pylab',
298 298 type=str, dest='Global.pylab',
299 299 nargs='?', const='auto', metavar='gui-mode',
300 300 help="Pre-load matplotlib and numpy for interactive use. "+
301 301 "If no value is given, the gui backend is matplotlib's, else use "+
302 302 "one of: ['tk', 'qt', 'wx', 'gtk'].")
303 303
304 304 # Legacy GUI options. Leave them in for backwards compatibility, but the
305 305 # 'thread' names are really a misnomer now.
306 306 paa('--wthread', '-wthread',
307 307 action='store_true', dest='Global.wthread',
308 308 help=
309 309 """Enable wxPython event loop integration. (DEPRECATED, use --gui wx)""")
310 310 paa('--q4thread', '--qthread', '-q4thread', '-qthread',
311 311 action='store_true', dest='Global.q4thread',
312 312 help=
313 313 """Enable Qt4 event loop integration. Qt3 is no longer supported.
314 314 (DEPRECATED, use --gui qt)""")
315 315 paa('--gthread', '-gthread',
316 316 action='store_true', dest='Global.gthread',
317 317 help=
318 318 """Enable GTK event loop integration. (DEPRECATED, use --gui gtk)""")
319 319
320 320
321 321 #-----------------------------------------------------------------------------
322 322 # Crash handler for this application
323 323 #-----------------------------------------------------------------------------
324 324
325 325
326 326 _message_template = """\
327 327 Oops, $self.app_name crashed. We do our best to make it stable, but...
328 328
329 329 A crash report was automatically generated with the following information:
330 330 - A verbatim copy of the crash traceback.
331 331 - A copy of your input history during this session.
332 332 - Data on your current $self.app_name configuration.
333 333
334 334 It was left in the file named:
335 335 \t'$self.crash_report_fname'
336 336 If you can email this file to the developers, the information in it will help
337 337 them in understanding and correcting the problem.
338 338
339 339 You can mail it to: $self.contact_name at $self.contact_email
340 340 with the subject '$self.app_name Crash Report'.
341 341
342 342 If you want to do it now, the following command will work (under Unix):
343 343 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
344 344
345 345 To ensure accurate tracking of this issue, please file a report about it at:
346 346 $self.bug_tracker
347 347 """
348 348
349 349 class IPAppCrashHandler(CrashHandler):
350 350 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
351 351
352 352 message_template = _message_template
353 353
354 354 def __init__(self, app):
355 355 contact_name = release.authors['Fernando'][0]
356 356 contact_email = release.authors['Fernando'][1]
357 357 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
358 358 super(IPAppCrashHandler,self).__init__(
359 359 app, contact_name, contact_email, bug_tracker
360 360 )
361 361
362 362 def make_report(self,traceback):
363 363 """Return a string containing a crash report."""
364 364
365 365 sec_sep = self.section_sep
366 366 # Start with parent report
367 367 report = [super(IPAppCrashHandler, self).make_report(traceback)]
368 368 # Add interactive-specific info we may have
369 369 rpt_add = report.append
370 370 try:
371 371 rpt_add(sec_sep+"History of session input:")
372 372 for line in self.app.shell.user_ns['_ih']:
373 373 rpt_add(line)
374 374 rpt_add('\n*** Last line of input (may not be in above history):\n')
375 375 rpt_add(self.app.shell._last_input_line+'\n')
376 376 except:
377 377 pass
378 378
379 379 return ''.join(report)
380 380
381 381
382 382 #-----------------------------------------------------------------------------
383 383 # Main classes and functions
384 384 #-----------------------------------------------------------------------------
385 385
386 386 class IPythonApp(Application):
387 387 name = u'ipython'
388 388 #: argparse formats better the 'usage' than the 'description' field
389 389 description = None
390 390 usage = usage.cl_usage
391 391 command_line_loader = IPAppConfigLoader
392 392 default_config_file_name = default_config_file_name
393 393 crash_handler_class = IPAppCrashHandler
394 394
395 395 def create_default_config(self):
396 396 super(IPythonApp, self).create_default_config()
397 397 # Eliminate multiple lookups
398 398 Global = self.default_config.Global
399 399
400 400 # Set all default values
401 401 Global.display_banner = True
402 402
403 403 # If the -c flag is given or a file is given to run at the cmd line
404 404 # like "ipython foo.py", normally we exit without starting the main
405 405 # loop. The force_interact config variable allows a user to override
406 406 # this and interact. It is also set by the -i cmd line flag, just
407 407 # like Python.
408 408 Global.force_interact = False
409 409
410 410 # By default always interact by starting the IPython mainloop.
411 411 Global.interact = True
412 412
413 413 # No GUI integration by default
414 414 Global.gui = False
415 415 # Pylab off by default
416 416 Global.pylab = False
417 417
418 418 # Deprecated versions of gui support that used threading, we support
419 419 # them just for bacwards compatibility as an alternate spelling for
420 420 # '--gui X'
421 421 Global.qthread = False
422 422 Global.q4thread = False
423 423 Global.wthread = False
424 424 Global.gthread = False
425 425
426 426 def load_file_config(self):
427 427 if hasattr(self.command_line_config.Global, 'quick'):
428 428 if self.command_line_config.Global.quick:
429 429 self.file_config = Config()
430 430 return
431 431 super(IPythonApp, self).load_file_config()
432 432
433 433 def post_load_file_config(self):
434 434 if hasattr(self.command_line_config.Global, 'extra_extension'):
435 435 if not hasattr(self.file_config.Global, 'extensions'):
436 436 self.file_config.Global.extensions = []
437 437 self.file_config.Global.extensions.append(
438 438 self.command_line_config.Global.extra_extension)
439 439 del self.command_line_config.Global.extra_extension
440 440
441 441 def pre_construct(self):
442 442 config = self.master_config
443 443
444 444 if hasattr(config.Global, 'classic'):
445 445 if config.Global.classic:
446 446 config.InteractiveShell.cache_size = 0
447 447 config.InteractiveShell.pprint = 0
448 448 config.InteractiveShell.prompt_in1 = '>>> '
449 449 config.InteractiveShell.prompt_in2 = '... '
450 450 config.InteractiveShell.prompt_out = ''
451 451 config.InteractiveShell.separate_in = \
452 452 config.InteractiveShell.separate_out = \
453 453 config.InteractiveShell.separate_out2 = ''
454 454 config.InteractiveShell.colors = 'NoColor'
455 455 config.InteractiveShell.xmode = 'Plain'
456 456
457 457 if hasattr(config.Global, 'nosep'):
458 458 if config.Global.nosep:
459 459 config.InteractiveShell.separate_in = \
460 460 config.InteractiveShell.separate_out = \
461 461 config.InteractiveShell.separate_out2 = ''
462 462
463 463 # if there is code of files to run from the cmd line, don't interact
464 464 # unless the -i flag (Global.force_interact) is true.
465 465 code_to_run = config.Global.get('code_to_run','')
466 466 file_to_run = False
467 467 if self.extra_args and self.extra_args[0]:
468 468 file_to_run = True
469 469 if file_to_run or code_to_run:
470 470 if not config.Global.force_interact:
471 471 config.Global.interact = False
472 472
473 473 def construct(self):
474 474 # I am a little hesitant to put these into InteractiveShell itself.
475 475 # But that might be the place for them
476 476 sys.path.insert(0, '')
477 477
478 # Create an InteractiveShell instance
479 self.shell = InteractiveShell(None, self.master_config)
478 # Create an InteractiveShell instance.
479 self.shell = InteractiveShell.instance(config=self.master_config)
480 480
481 481 def post_construct(self):
482 482 """Do actions after construct, but before starting the app."""
483 483 config = self.master_config
484 484
485 485 # shell.display_banner should always be False for the terminal
486 486 # based app, because we call shell.show_banner() by hand below
487 487 # so the banner shows *before* all extension loading stuff.
488 488 self.shell.display_banner = False
489 489 if config.Global.display_banner and \
490 490 config.Global.interact:
491 491 self.shell.show_banner()
492 492
493 493 # Make sure there is a space below the banner.
494 494 if self.log_level <= logging.INFO: print
495 495
496 496 # Now a variety of things that happen after the banner is printed.
497 497 self._enable_gui_pylab()
498 498 self._load_extensions()
499 499 self._run_exec_lines()
500 500 self._run_exec_files()
501 501 self._run_cmd_line_code()
502 502
503 503 def _enable_gui_pylab(self):
504 504 """Enable GUI event loop integration, taking pylab into account."""
505 505 Global = self.master_config.Global
506 506
507 507 # Select which gui to use
508 508 if Global.gui:
509 509 gui = Global.gui
510 510 # The following are deprecated, but there's likely to be a lot of use
511 511 # of this form out there, so we might as well support it for now. But
512 512 # the --gui option above takes precedence.
513 513 elif Global.wthread:
514 514 gui = inputhook.GUI_WX
515 515 elif Global.qthread:
516 516 gui = inputhook.GUI_QT
517 517 elif Global.gthread:
518 518 gui = inputhook.GUI_GTK
519 519 else:
520 520 gui = None
521 521
522 522 # Using --pylab will also require gui activation, though which toolkit
523 523 # to use may be chosen automatically based on mpl configuration.
524 524 if Global.pylab:
525 525 activate = self.shell.enable_pylab
526 526 if Global.pylab == 'auto':
527 527 gui = None
528 528 else:
529 529 gui = Global.pylab
530 530 else:
531 531 # Enable only GUI integration, no pylab
532 532 activate = inputhook.enable_gui
533 533
534 534 if gui or Global.pylab:
535 535 try:
536 536 self.log.info("Enabling GUI event loop integration, "
537 537 "toolkit=%s, pylab=%s" % (gui, Global.pylab) )
538 538 activate(gui)
539 539 except:
540 540 self.log.warn("Error in enabling GUI event loop integration:")
541 541 self.shell.showtraceback()
542 542
543 543 def _load_extensions(self):
544 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 547 the extensions listed in ``self.master_config.Global.extensions``.
548 548 """
549 549 try:
550 550 if hasattr(self.master_config.Global, 'extensions'):
551 551 self.log.debug("Loading IPython extensions...")
552 552 extensions = self.master_config.Global.extensions
553 553 for ext in extensions:
554 554 try:
555 555 self.log.info("Loading IPython extension: %s" % ext)
556 self.shell.load_extension(ext)
556 self.shell.extension_manager.load_extension(ext)
557 557 except:
558 558 self.log.warn("Error in loading extension: %s" % ext)
559 559 self.shell.showtraceback()
560 560 except:
561 561 self.log.warn("Unknown error in loading extensions:")
562 562 self.shell.showtraceback()
563 563
564 564 def _run_exec_lines(self):
565 565 """Run lines of code in Global.exec_lines in the user's namespace."""
566 566 try:
567 567 if hasattr(self.master_config.Global, 'exec_lines'):
568 568 self.log.debug("Running code from Global.exec_lines...")
569 569 exec_lines = self.master_config.Global.exec_lines
570 570 for line in exec_lines:
571 571 try:
572 572 self.log.info("Running code in user namespace: %s" %
573 573 line)
574 574 self.shell.runlines(line)
575 575 except:
576 576 self.log.warn("Error in executing line in user "
577 577 "namespace: %s" % line)
578 578 self.shell.showtraceback()
579 579 except:
580 580 self.log.warn("Unknown error in handling Global.exec_lines:")
581 581 self.shell.showtraceback()
582 582
583 583 def _exec_file(self, fname):
584 584 full_filename = filefind(fname, [u'.', self.ipython_dir])
585 585 if os.path.isfile(full_filename):
586 586 if full_filename.endswith(u'.py'):
587 587 self.log.info("Running file in user namespace: %s" %
588 588 full_filename)
589 589 # Ensure that __file__ is always defined to match Python behavior
590 590 self.shell.user_ns['__file__'] = fname
591 591 try:
592 592 self.shell.safe_execfile(full_filename, self.shell.user_ns)
593 593 finally:
594 594 del self.shell.user_ns['__file__']
595 595 elif full_filename.endswith('.ipy'):
596 596 self.log.info("Running file in user namespace: %s" %
597 597 full_filename)
598 598 self.shell.safe_execfile_ipy(full_filename)
599 599 else:
600 600 self.log.warn("File does not have a .py or .ipy extension: <%s>"
601 601 % full_filename)
602 602 def _run_exec_files(self):
603 603 try:
604 604 if hasattr(self.master_config.Global, 'exec_files'):
605 605 self.log.debug("Running files in Global.exec_files...")
606 606 exec_files = self.master_config.Global.exec_files
607 607 for fname in exec_files:
608 608 self._exec_file(fname)
609 609 except:
610 610 self.log.warn("Unknown error in handling Global.exec_files:")
611 611 self.shell.showtraceback()
612 612
613 613 def _run_cmd_line_code(self):
614 614 if hasattr(self.master_config.Global, 'code_to_run'):
615 615 line = self.master_config.Global.code_to_run
616 616 try:
617 617 self.log.info("Running code given at command line (-c): %s" %
618 618 line)
619 619 self.shell.runlines(line)
620 620 except:
621 621 self.log.warn("Error in executing line in user namespace: %s" %
622 622 line)
623 623 self.shell.showtraceback()
624 624 return
625 625 # Like Python itself, ignore the second if the first of these is present
626 626 try:
627 627 fname = self.extra_args[0]
628 628 except:
629 629 pass
630 630 else:
631 631 try:
632 632 self._exec_file(fname)
633 633 except:
634 634 self.log.warn("Error in executing file in user namespace: %s" %
635 635 fname)
636 636 self.shell.showtraceback()
637 637
638 638 def start_app(self):
639 639 if self.master_config.Global.interact:
640 640 self.log.debug("Starting IPython's mainloop...")
641 641 self.shell.mainloop()
642 642 else:
643 643 self.log.debug("IPython not interactive, start_app is no-op...")
644 644
645 645
646 646 def load_default_config(ipython_dir=None):
647 647 """Load the default config file from the default ipython_dir.
648 648
649 649 This is useful for embedded shells.
650 650 """
651 651 if ipython_dir is None:
652 652 ipython_dir = get_ipython_dir()
653 653 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
654 654 config = cl.load_config()
655 655 return config
656 656
657 657
658 658 def launch_new_instance():
659 659 """Create and run a full blown IPython instance"""
660 660 app = IPythonApp()
661 661 app.start()
662 662
663 663
664 664 if __name__ == '__main__':
665 665 launch_new_instance()
@@ -1,2582 +1,2511 b''
1 1 # -*- coding: utf-8 -*-
2 """
3 Main IPython Component
4 """
2 """Main IPython class."""
5 3
6 4 #-----------------------------------------------------------------------------
7 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
8 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 9 # Distributed under the terms of the BSD License. The full license is in
12 10 # the file COPYING, distributed as part of this software.
13 11 #-----------------------------------------------------------------------------
14 12
15 13 #-----------------------------------------------------------------------------
16 14 # Imports
17 15 #-----------------------------------------------------------------------------
18 16
19 17 from __future__ import with_statement
20 18 from __future__ import absolute_import
21 19
22 20 import __builtin__
23 21 import bdb
24 22 import codeop
25 23 import exceptions
26 24 import new
27 25 import os
28 26 import re
29 27 import string
30 28 import sys
31 29 import tempfile
32 30 from contextlib import nested
33 31
34 32 from IPython.core import debugger, oinspect
35 33 from IPython.core import history as ipcorehist
36 34 from IPython.core import prefilter
37 35 from IPython.core import shadowns
38 36 from IPython.core import ultratb
39 37 from IPython.core.alias import AliasManager
40 38 from IPython.core.builtin_trap import BuiltinTrap
41 from IPython.core.component import Component
39 from IPython.config.configurable import Configurable
42 40 from IPython.core.display_trap import DisplayTrap
43 41 from IPython.core.error import TryNext, UsageError
42 from IPython.core.extensions import ExtensionManager
44 43 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
45 44 from IPython.core.logger import Logger
46 45 from IPython.core.magic import Magic
47 46 from IPython.core.prefilter import PrefilterManager
48 47 from IPython.core.prompts import CachedOutput
49 48 from IPython.core.usage import interactive_usage, default_banner
50 49 import IPython.core.hooks
51 50 from IPython.external.Itpl import ItplNS
52 51 from IPython.lib.inputhook import enable_gui
53 52 from IPython.lib.backgroundjobs import BackgroundJobManager
54 53 from IPython.lib.pylabtools import pylab_activate
55 54 from IPython.utils import PyColorize
56 55 from IPython.utils import pickleshare
57 56 from IPython.utils.doctestreload import doctest_reload
58 57 from IPython.utils.ipstruct import Struct
59 58 from IPython.utils.io import Term, ask_yes_no
60 59 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
61 60 from IPython.utils.process import (
62 61 abbrev_cwd,
63 62 getoutput,
64 63 getoutputerror
65 64 )
66 65 # import IPython.utils.rlineimpl as readline
67 66 from IPython.utils.strdispatch import StrDispatch
68 67 from IPython.utils.syspathcontext import prepended_to_syspath
69 68 from IPython.utils.terminal import toggle_set_term_title, set_term_title
70 69 from IPython.utils.warn import warn, error, fatal
71 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 74 # from IPython.utils import growl
76 75 # growl.start("IPython")
77 76
78 77 #-----------------------------------------------------------------------------
79 78 # Globals
80 79 #-----------------------------------------------------------------------------
81 80
82 81 # store the builtin raw_input globally, and use this always, in case user code
83 82 # overwrites it (like wx.py.PyShell does)
84 83 raw_input_original = raw_input
85 84
86 85 # compiled regexps for autoindent management
87 86 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
88 87
89 88 #-----------------------------------------------------------------------------
90 89 # Utilities
91 90 #-----------------------------------------------------------------------------
92 91
93 92 ini_spaces_re = re.compile(r'^(\s+)')
94 93
95 94
96 95 def num_ini_spaces(strng):
97 96 """Return the number of initial spaces in a string"""
98 97
99 98 ini_spaces = ini_spaces_re.match(strng)
100 99 if ini_spaces:
101 100 return ini_spaces.end()
102 101 else:
103 102 return 0
104 103
105 104
106 105 def softspace(file, newvalue):
107 106 """Copied from code.py, to remove the dependency"""
108 107
109 108 oldvalue = 0
110 109 try:
111 110 oldvalue = file.softspace
112 111 except AttributeError:
113 112 pass
114 113 try:
115 114 file.softspace = newvalue
116 115 except (AttributeError, TypeError):
117 116 # "attribute-less object" or "read-only attributes"
118 117 pass
119 118 return oldvalue
120 119
121 120
122 121 def no_op(*a, **kw): pass
123 122
124 123 class SpaceInInput(exceptions.Exception): pass
125 124
126 125 class Bunch: pass
127 126
128 127 class InputList(list):
129 128 """Class to store user input.
130 129
131 130 It's basically a list, but slices return a string instead of a list, thus
132 131 allowing things like (assuming 'In' is an instance):
133 132
134 133 exec In[4:7]
135 134
136 135 or
137 136
138 137 exec In[5:9] + In[14] + In[21:25]"""
139 138
140 139 def __getslice__(self,i,j):
141 140 return ''.join(list.__getslice__(self,i,j))
142 141
143 142
144 143 class SyntaxTB(ultratb.ListTB):
145 144 """Extension which holds some state: the last exception value"""
146 145
147 146 def __init__(self,color_scheme = 'NoColor'):
148 147 ultratb.ListTB.__init__(self,color_scheme)
149 148 self.last_syntax_error = None
150 149
151 150 def __call__(self, etype, value, elist):
152 151 self.last_syntax_error = value
153 152 ultratb.ListTB.__call__(self,etype,value,elist)
154 153
155 154 def clear_err_state(self):
156 155 """Return the current error state and clear it"""
157 156 e = self.last_syntax_error
158 157 self.last_syntax_error = None
159 158 return e
160 159
161 160
162 161 def get_default_editor():
163 162 try:
164 163 ed = os.environ['EDITOR']
165 164 except KeyError:
166 165 if os.name == 'posix':
167 166 ed = 'vi' # the only one guaranteed to be there!
168 167 else:
169 168 ed = 'notepad' # same in Windows!
170 169 return ed
171 170
172 171
173 172 def get_default_colors():
174 173 if sys.platform=='darwin':
175 174 return "LightBG"
176 175 elif os.name=='nt':
177 176 return 'Linux'
178 177 else:
179 178 return 'Linux'
180 179
181 180
182 181 class SeparateStr(Str):
183 182 """A Str subclass to validate separate_in, separate_out, etc.
184 183
185 184 This is a Str based trait that converts '0'->'' and '\\n'->'\n'.
186 185 """
187 186
188 187 def validate(self, obj, value):
189 188 if value == '0': value = ''
190 189 value = value.replace('\\n','\n')
191 190 return super(SeparateStr, self).validate(obj, value)
192 191
193 192
194 193 #-----------------------------------------------------------------------------
195 194 # Main IPython class
196 195 #-----------------------------------------------------------------------------
197 196
198 197
199 class InteractiveShell(Component, Magic):
198 class InteractiveShell(Configurable, Magic):
200 199 """An enhanced, interactive shell for Python."""
201 200
202 201 autocall = Enum((0,1,2), default_value=1, config=True)
203 202 autoedit_syntax = CBool(False, config=True)
204 203 autoindent = CBool(True, config=True)
205 204 automagic = CBool(True, config=True)
206 205 banner = Str('')
207 206 banner1 = Str(default_banner, config=True)
208 207 banner2 = Str('', config=True)
209 208 cache_size = Int(1000, config=True)
210 209 color_info = CBool(True, config=True)
211 210 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
212 211 default_value=get_default_colors(), config=True)
213 212 confirm_exit = CBool(True, config=True)
214 213 debug = CBool(False, config=True)
215 214 deep_reload = CBool(False, config=True)
216 215 # This display_banner only controls whether or not self.show_banner()
217 216 # is called when mainloop/interact are called. The default is False
218 217 # because for the terminal based application, the banner behavior
219 218 # is controlled by Global.display_banner, which IPythonApp looks at
220 219 # to determine if *it* should call show_banner() by hand or not.
221 220 display_banner = CBool(False) # This isn't configurable!
222 221 embedded = CBool(False)
223 222 embedded_active = CBool(False)
224 223 editor = Str(get_default_editor(), config=True)
225 224 filename = Str("<ipython console>")
226 225 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
227 226 logstart = CBool(False, config=True)
228 227 logfile = Str('', config=True)
229 228 logappend = Str('', config=True)
230 229 object_info_string_level = Enum((0,1,2), default_value=0,
231 230 config=True)
232 231 pager = Str('less', config=True)
233 232 pdb = CBool(False, config=True)
234 233 pprint = CBool(True, config=True)
235 234 profile = Str('', config=True)
236 235 prompt_in1 = Str('In [\\#]: ', config=True)
237 236 prompt_in2 = Str(' .\\D.: ', config=True)
238 237 prompt_out = Str('Out[\\#]: ', config=True)
239 238 prompts_pad_left = CBool(True, config=True)
240 239 quiet = CBool(False, config=True)
241 240
242 241 readline_use = CBool(True, config=True)
243 242 readline_merge_completions = CBool(True, config=True)
244 243 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
245 244 readline_remove_delims = Str('-/~', config=True)
246 245 readline_parse_and_bind = List([
247 246 'tab: complete',
248 247 '"\C-l": clear-screen',
249 248 'set show-all-if-ambiguous on',
250 249 '"\C-o": tab-insert',
251 250 '"\M-i": " "',
252 251 '"\M-o": "\d\d\d\d"',
253 252 '"\M-I": "\d\d\d\d"',
254 253 '"\C-r": reverse-search-history',
255 254 '"\C-s": forward-search-history',
256 255 '"\C-p": history-search-backward',
257 256 '"\C-n": history-search-forward',
258 257 '"\e[A": history-search-backward',
259 258 '"\e[B": history-search-forward',
260 259 '"\C-k": kill-line',
261 260 '"\C-u": unix-line-discard',
262 261 ], allow_none=False, config=True)
263 262
264 263 screen_length = Int(0, config=True)
265 264
266 265 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
267 266 separate_in = SeparateStr('\n', config=True)
268 267 separate_out = SeparateStr('', config=True)
269 268 separate_out2 = SeparateStr('', config=True)
270 269
271 270 system_header = Str('IPython system call: ', config=True)
272 271 system_verbose = CBool(False, config=True)
273 272 term_title = CBool(False, config=True)
274 273 wildcards_case_sensitive = CBool(True, config=True)
275 274 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
276 275 default_value='Context', config=True)
277 276
278 277 autoexec = List(allow_none=False)
279 278
280 279 # class attribute to indicate whether the class supports threads or not.
281 280 # Subclasses with thread support should override this as needed.
282 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 291 user_ns=None, user_global_ns=None,
286 292 banner1=None, banner2=None, display_banner=None,
287 293 custom_exceptions=((),None)):
288 294
289 295 # This is where traits with a config_key argument are updated
290 296 # from the values on config.
291 super(InteractiveShell, self).__init__(parent, config=config)
297 super(InteractiveShell, self).__init__(config=config)
292 298
293 299 # These are relatively independent and stateless
294 300 self.init_ipython_dir(ipython_dir)
295 301 self.init_instance_attrs()
296 302 self.init_term_title()
297 303 self.init_usage(usage)
298 304 self.init_banner(banner1, banner2, display_banner)
299 305
300 306 # Create namespaces (user_ns, user_global_ns, etc.)
301 307 self.init_create_namespaces(user_ns, user_global_ns)
302 308 # This has to be done after init_create_namespaces because it uses
303 309 # something in self.user_ns, but before init_sys_modules, which
304 310 # is the first thing to modify sys.
305 311 self.save_sys_module_state()
306 312 self.init_sys_modules()
307 313
308 314 self.init_history()
309 315 self.init_encoding()
310 316 self.init_prefilter()
311 317
312 318 Magic.__init__(self, self)
313 319
314 320 self.init_syntax_highlighting()
315 321 self.init_hooks()
316 322 self.init_pushd_popd_magic()
317 323 self.init_traceback_handlers(custom_exceptions)
318 324 self.init_user_ns()
319 325 self.init_logger()
320 326 self.init_alias()
321 327 self.init_builtins()
322 328
323 329 # pre_config_initialization
324 330 self.init_shadow_hist()
325 331
326 332 # The next section should contain averything that was in ipmaker.
327 333 self.init_logstart()
328 334
329 335 # The following was in post_config_initialization
330 336 self.init_inspector()
331 337 self.init_readline()
332 338 self.init_prompts()
333 339 self.init_displayhook()
334 340 self.init_reload_doctest()
335 341 self.init_magics()
336 342 self.init_pdb()
343 self.init_extension_manager()
337 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 357 def get_ipython(self):
340 358 """Return the currently running IPython instance."""
341 359 return self
342 360
343 361 #-------------------------------------------------------------------------
344 362 # Trait changed handlers
345 363 #-------------------------------------------------------------------------
346 364
347 365 def _banner1_changed(self):
348 366 self.compute_banner()
349 367
350 368 def _banner2_changed(self):
351 369 self.compute_banner()
352 370
353 371 def _ipython_dir_changed(self, name, new):
354 372 if not os.path.isdir(new):
355 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 375 @property
364 376 def usable_screen_length(self):
365 377 if self.screen_length == 0:
366 378 return 0
367 379 else:
368 380 num_lines_bot = self.separate_in.count('\n')+1
369 381 return self.screen_length - num_lines_bot
370 382
371 383 def _term_title_changed(self, name, new_value):
372 384 self.init_term_title()
373 385
374 386 def set_autoindent(self,value=None):
375 387 """Set the autoindent flag, checking for readline support.
376 388
377 389 If called with no arguments, it acts as a toggle."""
378 390
379 391 if not self.has_readline:
380 392 if os.name == 'posix':
381 393 warn("The auto-indent feature requires the readline library")
382 394 self.autoindent = 0
383 395 return
384 396 if value is None:
385 397 self.autoindent = not self.autoindent
386 398 else:
387 399 self.autoindent = value
388 400
389 401 #-------------------------------------------------------------------------
390 402 # init_* methods called by __init__
391 403 #-------------------------------------------------------------------------
392 404
393 405 def init_ipython_dir(self, ipython_dir):
394 406 if ipython_dir is not None:
395 407 self.ipython_dir = ipython_dir
396 408 self.config.Global.ipython_dir = self.ipython_dir
397 409 return
398 410
399 411 if hasattr(self.config.Global, 'ipython_dir'):
400 412 self.ipython_dir = self.config.Global.ipython_dir
401 413 else:
402 414 self.ipython_dir = get_ipython_dir()
403 415
404 416 # All children can just read this
405 417 self.config.Global.ipython_dir = self.ipython_dir
406 418
407 419 def init_instance_attrs(self):
408 420 self.jobs = BackgroundJobManager()
409 421 self.more = False
410 422
411 423 # command compiler
412 424 self.compile = codeop.CommandCompiler()
413 425
414 426 # User input buffer
415 427 self.buffer = []
416 428
417 429 # Make an empty namespace, which extension writers can rely on both
418 430 # existing and NEVER being used by ipython itself. This gives them a
419 431 # convenient location for storing additional information and state
420 432 # their extensions may require, without fear of collisions with other
421 433 # ipython names that may develop later.
422 434 self.meta = Struct()
423 435
424 436 # Object variable to store code object waiting execution. This is
425 437 # used mainly by the multithreaded shells, but it can come in handy in
426 438 # other situations. No need to use a Queue here, since it's a single
427 439 # item which gets cleared once run.
428 440 self.code_to_run = None
429 441
430 442 # Flag to mark unconditional exit
431 443 self.exit_now = False
432 444
433 445 # Temporary files used for various purposes. Deleted at exit.
434 446 self.tempfiles = []
435 447
436 448 # Keep track of readline usage (later set by init_readline)
437 449 self.has_readline = False
438 450
439 451 # keep track of where we started running (mainly for crash post-mortem)
440 452 # This is not being used anywhere currently.
441 453 self.starting_dir = os.getcwd()
442 454
443 455 # Indentation management
444 456 self.indent_current_nsp = 0
445 457
446 458 def init_term_title(self):
447 459 # Enable or disable the terminal title.
448 460 if self.term_title:
449 461 toggle_set_term_title(True)
450 462 set_term_title('IPython: ' + abbrev_cwd())
451 463 else:
452 464 toggle_set_term_title(False)
453 465
454 466 def init_usage(self, usage=None):
455 467 if usage is None:
456 468 self.usage = interactive_usage
457 469 else:
458 470 self.usage = usage
459 471
460 472 def init_encoding(self):
461 473 # Get system encoding at startup time. Certain terminals (like Emacs
462 474 # under Win32 have it set to None, and we need to have a known valid
463 475 # encoding to use in the raw_input() method
464 476 try:
465 477 self.stdin_encoding = sys.stdin.encoding or 'ascii'
466 478 except AttributeError:
467 479 self.stdin_encoding = 'ascii'
468 480
469 481 def init_syntax_highlighting(self):
470 482 # Python source parser/formatter for syntax highlighting
471 483 pyformat = PyColorize.Parser().format
472 484 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
473 485
474 486 def init_pushd_popd_magic(self):
475 487 # for pushd/popd management
476 488 try:
477 489 self.home_dir = get_home_dir()
478 490 except HomeDirError, msg:
479 491 fatal(msg)
480 492
481 493 self.dir_stack = []
482 494
483 495 def init_logger(self):
484 496 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
485 497 # local shortcut, this is used a LOT
486 498 self.log = self.logger.log
487 499
488 500 def init_logstart(self):
489 501 if self.logappend:
490 502 self.magic_logstart(self.logappend + ' append')
491 503 elif self.logfile:
492 504 self.magic_logstart(self.logfile)
493 505 elif self.logstart:
494 506 self.magic_logstart()
495 507
496 508 def init_builtins(self):
497 509 self.builtin_trap = BuiltinTrap(self)
498 510
499 511 def init_inspector(self):
500 512 # Object inspector
501 513 self.inspector = oinspect.Inspector(oinspect.InspectColors,
502 514 PyColorize.ANSICodeColors,
503 515 'NoColor',
504 516 self.object_info_string_level)
505 517
506 518 def init_prompts(self):
507 519 # Initialize cache, set in/out prompts and printing system
508 520 self.outputcache = CachedOutput(self,
509 521 self.cache_size,
510 522 self.pprint,
511 523 input_sep = self.separate_in,
512 524 output_sep = self.separate_out,
513 525 output_sep2 = self.separate_out2,
514 526 ps1 = self.prompt_in1,
515 527 ps2 = self.prompt_in2,
516 528 ps_out = self.prompt_out,
517 529 pad_left = self.prompts_pad_left)
518 530
519 531 # user may have over-ridden the default print hook:
520 532 try:
521 533 self.outputcache.__class__.display = self.hooks.display
522 534 except AttributeError:
523 535 pass
524 536
525 537 def init_displayhook(self):
526 self.display_trap = DisplayTrap(self, self.outputcache)
538 self.display_trap = DisplayTrap(self.outputcache)
527 539
528 540 def init_reload_doctest(self):
529 541 # Do a proper resetting of doctest, including the necessary displayhook
530 542 # monkeypatching
531 543 try:
532 544 doctest_reload()
533 545 except ImportError:
534 546 warn("doctest module does not exist.")
535 547
536 548 #-------------------------------------------------------------------------
537 549 # Things related to the banner
538 550 #-------------------------------------------------------------------------
539 551
540 552 def init_banner(self, banner1, banner2, display_banner):
541 553 if banner1 is not None:
542 554 self.banner1 = banner1
543 555 if banner2 is not None:
544 556 self.banner2 = banner2
545 557 if display_banner is not None:
546 558 self.display_banner = display_banner
547 559 self.compute_banner()
548 560
549 561 def show_banner(self, banner=None):
550 562 if banner is None:
551 563 banner = self.banner
552 564 self.write(banner)
553 565
554 566 def compute_banner(self):
555 567 self.banner = self.banner1 + '\n'
556 568 if self.profile:
557 569 self.banner += '\nIPython profile: %s\n' % self.profile
558 570 if self.banner2:
559 571 self.banner += '\n' + self.banner2 + '\n'
560 572
561 573 #-------------------------------------------------------------------------
562 574 # Things related to injections into the sys module
563 575 #-------------------------------------------------------------------------
564 576
565 577 def save_sys_module_state(self):
566 578 """Save the state of hooks in the sys module.
567 579
568 580 This has to be called after self.user_ns is created.
569 581 """
570 582 self._orig_sys_module_state = {}
571 583 self._orig_sys_module_state['stdin'] = sys.stdin
572 584 self._orig_sys_module_state['stdout'] = sys.stdout
573 585 self._orig_sys_module_state['stderr'] = sys.stderr
574 586 self._orig_sys_module_state['excepthook'] = sys.excepthook
575 587 try:
576 588 self._orig_sys_modules_main_name = self.user_ns['__name__']
577 589 except KeyError:
578 590 pass
579 591
580 592 def restore_sys_module_state(self):
581 593 """Restore the state of the sys module."""
582 594 try:
583 595 for k, v in self._orig_sys_module_state.items():
584 596 setattr(sys, k, v)
585 597 except AttributeError:
586 598 pass
587 599 try:
588 600 delattr(sys, 'ipcompleter')
589 601 except AttributeError:
590 602 pass
591 603 # Reset what what done in self.init_sys_modules
592 604 try:
593 605 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
594 606 except (AttributeError, KeyError):
595 607 pass
596 608
597 609 #-------------------------------------------------------------------------
598 610 # Things related to hooks
599 611 #-------------------------------------------------------------------------
600 612
601 613 def init_hooks(self):
602 614 # hooks holds pointers used for user-side customizations
603 615 self.hooks = Struct()
604 616
605 617 self.strdispatchers = {}
606 618
607 619 # Set all default hooks, defined in the IPython.hooks module.
608 620 hooks = IPython.core.hooks
609 621 for hook_name in hooks.__all__:
610 622 # default hooks have priority 100, i.e. low; user hooks should have
611 623 # 0-100 priority
612 624 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
613 625
614 626 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
615 627 """set_hook(name,hook) -> sets an internal IPython hook.
616 628
617 629 IPython exposes some of its internal API as user-modifiable hooks. By
618 630 adding your function to one of these hooks, you can modify IPython's
619 631 behavior to call at runtime your own routines."""
620 632
621 633 # At some point in the future, this should validate the hook before it
622 634 # accepts it. Probably at least check that the hook takes the number
623 635 # of args it's supposed to.
624 636
625 637 f = new.instancemethod(hook,self,self.__class__)
626 638
627 639 # check if the hook is for strdispatcher first
628 640 if str_key is not None:
629 641 sdp = self.strdispatchers.get(name, StrDispatch())
630 642 sdp.add_s(str_key, f, priority )
631 643 self.strdispatchers[name] = sdp
632 644 return
633 645 if re_key is not None:
634 646 sdp = self.strdispatchers.get(name, StrDispatch())
635 647 sdp.add_re(re.compile(re_key), f, priority )
636 648 self.strdispatchers[name] = sdp
637 649 return
638 650
639 651 dp = getattr(self.hooks, name, None)
640 652 if name not in IPython.core.hooks.__all__:
641 653 print "Warning! Hook '%s' is not one of %s" % (name, IPython.core.hooks.__all__ )
642 654 if not dp:
643 655 dp = IPython.core.hooks.CommandChainDispatcher()
644 656
645 657 try:
646 658 dp.add(f,priority)
647 659 except AttributeError:
648 660 # it was not commandchain, plain old func - replace
649 661 dp = f
650 662
651 663 setattr(self.hooks,name, dp)
652 664
653 665 #-------------------------------------------------------------------------
654 666 # Things related to the "main" module
655 667 #-------------------------------------------------------------------------
656 668
657 669 def new_main_mod(self,ns=None):
658 670 """Return a new 'main' module object for user code execution.
659 671 """
660 672 main_mod = self._user_main_module
661 673 init_fakemod_dict(main_mod,ns)
662 674 return main_mod
663 675
664 676 def cache_main_mod(self,ns,fname):
665 677 """Cache a main module's namespace.
666 678
667 679 When scripts are executed via %run, we must keep a reference to the
668 680 namespace of their __main__ module (a FakeModule instance) around so
669 681 that Python doesn't clear it, rendering objects defined therein
670 682 useless.
671 683
672 684 This method keeps said reference in a private dict, keyed by the
673 685 absolute path of the module object (which corresponds to the script
674 686 path). This way, for multiple executions of the same script we only
675 687 keep one copy of the namespace (the last one), thus preventing memory
676 688 leaks from old references while allowing the objects from the last
677 689 execution to be accessible.
678 690
679 691 Note: we can not allow the actual FakeModule instances to be deleted,
680 692 because of how Python tears down modules (it hard-sets all their
681 693 references to None without regard for reference counts). This method
682 694 must therefore make a *copy* of the given namespace, to allow the
683 695 original module's __dict__ to be cleared and reused.
684 696
685 697
686 698 Parameters
687 699 ----------
688 700 ns : a namespace (a dict, typically)
689 701
690 702 fname : str
691 703 Filename associated with the namespace.
692 704
693 705 Examples
694 706 --------
695 707
696 708 In [10]: import IPython
697 709
698 710 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
699 711
700 712 In [12]: IPython.__file__ in _ip._main_ns_cache
701 713 Out[12]: True
702 714 """
703 715 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
704 716
705 717 def clear_main_mod_cache(self):
706 718 """Clear the cache of main modules.
707 719
708 720 Mainly for use by utilities like %reset.
709 721
710 722 Examples
711 723 --------
712 724
713 725 In [15]: import IPython
714 726
715 727 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
716 728
717 729 In [17]: len(_ip._main_ns_cache) > 0
718 730 Out[17]: True
719 731
720 732 In [18]: _ip.clear_main_mod_cache()
721 733
722 734 In [19]: len(_ip._main_ns_cache) == 0
723 735 Out[19]: True
724 736 """
725 737 self._main_ns_cache.clear()
726 738
727 739 #-------------------------------------------------------------------------
728 740 # Things related to debugging
729 741 #-------------------------------------------------------------------------
730 742
731 743 def init_pdb(self):
732 744 # Set calling of pdb on exceptions
733 745 # self.call_pdb is a property
734 746 self.call_pdb = self.pdb
735 747
736 748 def _get_call_pdb(self):
737 749 return self._call_pdb
738 750
739 751 def _set_call_pdb(self,val):
740 752
741 753 if val not in (0,1,False,True):
742 754 raise ValueError,'new call_pdb value must be boolean'
743 755
744 756 # store value in instance
745 757 self._call_pdb = val
746 758
747 759 # notify the actual exception handlers
748 760 self.InteractiveTB.call_pdb = val
749 761 if self.isthreaded:
750 762 try:
751 763 self.sys_excepthook.call_pdb = val
752 764 except:
753 765 warn('Failed to activate pdb for threaded exception handler')
754 766
755 767 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
756 768 'Control auto-activation of pdb at exceptions')
757 769
758 770 def debugger(self,force=False):
759 771 """Call the pydb/pdb debugger.
760 772
761 773 Keywords:
762 774
763 775 - force(False): by default, this routine checks the instance call_pdb
764 776 flag and does not actually invoke the debugger if the flag is false.
765 777 The 'force' option forces the debugger to activate even if the flag
766 778 is false.
767 779 """
768 780
769 781 if not (force or self.call_pdb):
770 782 return
771 783
772 784 if not hasattr(sys,'last_traceback'):
773 785 error('No traceback has been produced, nothing to debug.')
774 786 return
775 787
776 788 # use pydb if available
777 789 if debugger.has_pydb:
778 790 from pydb import pm
779 791 else:
780 792 # fallback to our internal debugger
781 793 pm = lambda : self.InteractiveTB.debugger(force=True)
782 794 self.history_saving_wrapper(pm)()
783 795
784 796 #-------------------------------------------------------------------------
785 797 # Things related to IPython's various namespaces
786 798 #-------------------------------------------------------------------------
787 799
788 800 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
789 801 # Create the namespace where the user will operate. user_ns is
790 802 # normally the only one used, and it is passed to the exec calls as
791 803 # the locals argument. But we do carry a user_global_ns namespace
792 804 # given as the exec 'globals' argument, This is useful in embedding
793 805 # situations where the ipython shell opens in a context where the
794 806 # distinction between locals and globals is meaningful. For
795 807 # non-embedded contexts, it is just the same object as the user_ns dict.
796 808
797 809 # FIXME. For some strange reason, __builtins__ is showing up at user
798 810 # level as a dict instead of a module. This is a manual fix, but I
799 811 # should really track down where the problem is coming from. Alex
800 812 # Schmolck reported this problem first.
801 813
802 814 # A useful post by Alex Martelli on this topic:
803 815 # Re: inconsistent value from __builtins__
804 816 # Von: Alex Martelli <aleaxit@yahoo.com>
805 817 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
806 818 # Gruppen: comp.lang.python
807 819
808 820 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
809 821 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
810 822 # > <type 'dict'>
811 823 # > >>> print type(__builtins__)
812 824 # > <type 'module'>
813 825 # > Is this difference in return value intentional?
814 826
815 827 # Well, it's documented that '__builtins__' can be either a dictionary
816 828 # or a module, and it's been that way for a long time. Whether it's
817 829 # intentional (or sensible), I don't know. In any case, the idea is
818 830 # that if you need to access the built-in namespace directly, you
819 831 # should start with "import __builtin__" (note, no 's') which will
820 832 # definitely give you a module. Yeah, it's somewhat confusing:-(.
821 833
822 834 # These routines return properly built dicts as needed by the rest of
823 835 # the code, and can also be used by extension writers to generate
824 836 # properly initialized namespaces.
825 837 user_ns, user_global_ns = self.make_user_namespaces(user_ns, user_global_ns)
826 838
827 839 # Assign namespaces
828 840 # This is the namespace where all normal user variables live
829 841 self.user_ns = user_ns
830 842 self.user_global_ns = user_global_ns
831 843
832 844 # An auxiliary namespace that checks what parts of the user_ns were
833 845 # loaded at startup, so we can list later only variables defined in
834 846 # actual interactive use. Since it is always a subset of user_ns, it
835 847 # doesn't need to be separately tracked in the ns_table.
836 848 self.user_ns_hidden = {}
837 849
838 850 # A namespace to keep track of internal data structures to prevent
839 851 # them from cluttering user-visible stuff. Will be updated later
840 852 self.internal_ns = {}
841 853
842 854 # Now that FakeModule produces a real module, we've run into a nasty
843 855 # problem: after script execution (via %run), the module where the user
844 856 # code ran is deleted. Now that this object is a true module (needed
845 857 # so docetst and other tools work correctly), the Python module
846 858 # teardown mechanism runs over it, and sets to None every variable
847 859 # present in that module. Top-level references to objects from the
848 860 # script survive, because the user_ns is updated with them. However,
849 861 # calling functions defined in the script that use other things from
850 862 # the script will fail, because the function's closure had references
851 863 # to the original objects, which are now all None. So we must protect
852 864 # these modules from deletion by keeping a cache.
853 865 #
854 866 # To avoid keeping stale modules around (we only need the one from the
855 867 # last run), we use a dict keyed with the full path to the script, so
856 868 # only the last version of the module is held in the cache. Note,
857 869 # however, that we must cache the module *namespace contents* (their
858 870 # __dict__). Because if we try to cache the actual modules, old ones
859 871 # (uncached) could be destroyed while still holding references (such as
860 872 # those held by GUI objects that tend to be long-lived)>
861 873 #
862 874 # The %reset command will flush this cache. See the cache_main_mod()
863 875 # and clear_main_mod_cache() methods for details on use.
864 876
865 877 # This is the cache used for 'main' namespaces
866 878 self._main_ns_cache = {}
867 879 # And this is the single instance of FakeModule whose __dict__ we keep
868 880 # copying and clearing for reuse on each %run
869 881 self._user_main_module = FakeModule()
870 882
871 883 # A table holding all the namespaces IPython deals with, so that
872 884 # introspection facilities can search easily.
873 885 self.ns_table = {'user':user_ns,
874 886 'user_global':user_global_ns,
875 887 'internal':self.internal_ns,
876 888 'builtin':__builtin__.__dict__
877 889 }
878 890
879 891 # Similarly, track all namespaces where references can be held and that
880 892 # we can safely clear (so it can NOT include builtin). This one can be
881 893 # a simple list.
882 894 self.ns_refs_table = [ user_ns, user_global_ns, self.user_ns_hidden,
883 895 self.internal_ns, self._main_ns_cache ]
884 896
885 897 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
886 898 """Return a valid local and global user interactive namespaces.
887 899
888 900 This builds a dict with the minimal information needed to operate as a
889 901 valid IPython user namespace, which you can pass to the various
890 902 embedding classes in ipython. The default implementation returns the
891 903 same dict for both the locals and the globals to allow functions to
892 904 refer to variables in the namespace. Customized implementations can
893 905 return different dicts. The locals dictionary can actually be anything
894 906 following the basic mapping protocol of a dict, but the globals dict
895 907 must be a true dict, not even a subclass. It is recommended that any
896 908 custom object for the locals namespace synchronize with the globals
897 909 dict somehow.
898 910
899 911 Raises TypeError if the provided globals namespace is not a true dict.
900 912
901 913 Parameters
902 914 ----------
903 915 user_ns : dict-like, optional
904 916 The current user namespace. The items in this namespace should
905 917 be included in the output. If None, an appropriate blank
906 918 namespace should be created.
907 919 user_global_ns : dict, optional
908 920 The current user global namespace. The items in this namespace
909 921 should be included in the output. If None, an appropriate
910 922 blank namespace should be created.
911 923
912 924 Returns
913 925 -------
914 926 A pair of dictionary-like object to be used as the local namespace
915 927 of the interpreter and a dict to be used as the global namespace.
916 928 """
917 929
918 930
919 931 # We must ensure that __builtin__ (without the final 's') is always
920 932 # available and pointing to the __builtin__ *module*. For more details:
921 933 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
922 934
923 935 if user_ns is None:
924 936 # Set __name__ to __main__ to better match the behavior of the
925 937 # normal interpreter.
926 938 user_ns = {'__name__' :'__main__',
927 939 '__builtin__' : __builtin__,
928 940 '__builtins__' : __builtin__,
929 941 }
930 942 else:
931 943 user_ns.setdefault('__name__','__main__')
932 944 user_ns.setdefault('__builtin__',__builtin__)
933 945 user_ns.setdefault('__builtins__',__builtin__)
934 946
935 947 if user_global_ns is None:
936 948 user_global_ns = user_ns
937 949 if type(user_global_ns) is not dict:
938 950 raise TypeError("user_global_ns must be a true dict; got %r"
939 951 % type(user_global_ns))
940 952
941 953 return user_ns, user_global_ns
942 954
943 955 def init_sys_modules(self):
944 956 # We need to insert into sys.modules something that looks like a
945 957 # module but which accesses the IPython namespace, for shelve and
946 958 # pickle to work interactively. Normally they rely on getting
947 959 # everything out of __main__, but for embedding purposes each IPython
948 960 # instance has its own private namespace, so we can't go shoving
949 961 # everything into __main__.
950 962
951 963 # note, however, that we should only do this for non-embedded
952 964 # ipythons, which really mimic the __main__.__dict__ with their own
953 965 # namespace. Embedded instances, on the other hand, should not do
954 966 # this because they need to manage the user local/global namespaces
955 967 # only, but they live within a 'normal' __main__ (meaning, they
956 968 # shouldn't overtake the execution environment of the script they're
957 969 # embedded in).
958 970
959 971 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
960 972
961 973 try:
962 974 main_name = self.user_ns['__name__']
963 975 except KeyError:
964 976 raise KeyError('user_ns dictionary MUST have a "__name__" key')
965 977 else:
966 978 sys.modules[main_name] = FakeModule(self.user_ns)
967 979
968 980 def init_user_ns(self):
969 981 """Initialize all user-visible namespaces to their minimum defaults.
970 982
971 983 Certain history lists are also initialized here, as they effectively
972 984 act as user namespaces.
973 985
974 986 Notes
975 987 -----
976 988 All data structures here are only filled in, they are NOT reset by this
977 989 method. If they were not empty before, data will simply be added to
978 990 therm.
979 991 """
980 992 # This function works in two parts: first we put a few things in
981 993 # user_ns, and we sync that contents into user_ns_hidden so that these
982 994 # initial variables aren't shown by %who. After the sync, we add the
983 995 # rest of what we *do* want the user to see with %who even on a new
984 996 # session (probably nothing, so theye really only see their own stuff)
985 997
986 998 # The user dict must *always* have a __builtin__ reference to the
987 999 # Python standard __builtin__ namespace, which must be imported.
988 1000 # This is so that certain operations in prompt evaluation can be
989 1001 # reliably executed with builtins. Note that we can NOT use
990 1002 # __builtins__ (note the 's'), because that can either be a dict or a
991 1003 # module, and can even mutate at runtime, depending on the context
992 1004 # (Python makes no guarantees on it). In contrast, __builtin__ is
993 1005 # always a module object, though it must be explicitly imported.
994 1006
995 1007 # For more details:
996 1008 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
997 1009 ns = dict(__builtin__ = __builtin__)
998 1010
999 1011 # Put 'help' in the user namespace
1000 1012 try:
1001 1013 from site import _Helper
1002 1014 ns['help'] = _Helper()
1003 1015 except ImportError:
1004 1016 warn('help() not available - check site.py')
1005 1017
1006 1018 # make global variables for user access to the histories
1007 1019 ns['_ih'] = self.input_hist
1008 1020 ns['_oh'] = self.output_hist
1009 1021 ns['_dh'] = self.dir_hist
1010 1022
1011 1023 ns['_sh'] = shadowns
1012 1024
1013 1025 # user aliases to input and output histories. These shouldn't show up
1014 1026 # in %who, as they can have very large reprs.
1015 1027 ns['In'] = self.input_hist
1016 1028 ns['Out'] = self.output_hist
1017 1029
1018 1030 # Store myself as the public api!!!
1019 1031 ns['get_ipython'] = self.get_ipython
1020 1032
1021 1033 # Sync what we've added so far to user_ns_hidden so these aren't seen
1022 1034 # by %who
1023 1035 self.user_ns_hidden.update(ns)
1024 1036
1025 1037 # Anything put into ns now would show up in %who. Think twice before
1026 1038 # putting anything here, as we really want %who to show the user their
1027 1039 # stuff, not our variables.
1028 1040
1029 1041 # Finally, update the real user's namespace
1030 1042 self.user_ns.update(ns)
1031 1043
1032 1044
1033 1045 def reset(self):
1034 1046 """Clear all internal namespaces.
1035 1047
1036 1048 Note that this is much more aggressive than %reset, since it clears
1037 1049 fully all namespaces, as well as all input/output lists.
1038 1050 """
1039 1051 for ns in self.ns_refs_table:
1040 1052 ns.clear()
1041 1053
1042 1054 self.alias_manager.clear_aliases()
1043 1055
1044 1056 # Clear input and output histories
1045 1057 self.input_hist[:] = []
1046 1058 self.input_hist_raw[:] = []
1047 1059 self.output_hist.clear()
1048 1060
1049 1061 # Restore the user namespaces to minimal usability
1050 1062 self.init_user_ns()
1051 1063
1052 1064 # Restore the default and user aliases
1053 1065 self.alias_manager.init_aliases()
1054 1066
1055 1067 def reset_selective(self, regex=None):
1056 1068 """Clear selective variables from internal namespaces based on a specified regular expression.
1057 1069
1058 1070 Parameters
1059 1071 ----------
1060 1072 regex : string or compiled pattern, optional
1061 1073 A regular expression pattern that will be used in searching variable names in the users
1062 1074 namespaces.
1063 1075 """
1064 1076 if regex is not None:
1065 1077 try:
1066 1078 m = re.compile(regex)
1067 1079 except TypeError:
1068 1080 raise TypeError('regex must be a string or compiled pattern')
1069 1081 # Search for keys in each namespace that match the given regex
1070 1082 # If a match is found, delete the key/value pair.
1071 1083 for ns in self.ns_refs_table:
1072 1084 for var in ns:
1073 1085 if m.search(var):
1074 1086 del ns[var]
1075 1087
1076 1088 def push(self, variables, interactive=True):
1077 1089 """Inject a group of variables into the IPython user namespace.
1078 1090
1079 1091 Parameters
1080 1092 ----------
1081 1093 variables : dict, str or list/tuple of str
1082 1094 The variables to inject into the user's namespace. If a dict,
1083 1095 a simple update is done. If a str, the string is assumed to
1084 1096 have variable names separated by spaces. A list/tuple of str
1085 1097 can also be used to give the variable names. If just the variable
1086 1098 names are give (list/tuple/str) then the variable values looked
1087 1099 up in the callers frame.
1088 1100 interactive : bool
1089 1101 If True (default), the variables will be listed with the ``who``
1090 1102 magic.
1091 1103 """
1092 1104 vdict = None
1093 1105
1094 1106 # We need a dict of name/value pairs to do namespace updates.
1095 1107 if isinstance(variables, dict):
1096 1108 vdict = variables
1097 1109 elif isinstance(variables, (basestring, list, tuple)):
1098 1110 if isinstance(variables, basestring):
1099 1111 vlist = variables.split()
1100 1112 else:
1101 1113 vlist = variables
1102 1114 vdict = {}
1103 1115 cf = sys._getframe(1)
1104 1116 for name in vlist:
1105 1117 try:
1106 1118 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1107 1119 except:
1108 1120 print ('Could not get variable %s from %s' %
1109 1121 (name,cf.f_code.co_name))
1110 1122 else:
1111 1123 raise ValueError('variables must be a dict/str/list/tuple')
1112 1124
1113 1125 # Propagate variables to user namespace
1114 1126 self.user_ns.update(vdict)
1115 1127
1116 1128 # And configure interactive visibility
1117 1129 config_ns = self.user_ns_hidden
1118 1130 if interactive:
1119 1131 for name, val in vdict.iteritems():
1120 1132 config_ns.pop(name, None)
1121 1133 else:
1122 1134 for name,val in vdict.iteritems():
1123 1135 config_ns[name] = val
1124 1136
1125 1137 #-------------------------------------------------------------------------
1126 1138 # Things related to history management
1127 1139 #-------------------------------------------------------------------------
1128 1140
1129 1141 def init_history(self):
1130 1142 # List of input with multi-line handling.
1131 1143 self.input_hist = InputList()
1132 1144 # This one will hold the 'raw' input history, without any
1133 1145 # pre-processing. This will allow users to retrieve the input just as
1134 1146 # it was exactly typed in by the user, with %hist -r.
1135 1147 self.input_hist_raw = InputList()
1136 1148
1137 1149 # list of visited directories
1138 1150 try:
1139 1151 self.dir_hist = [os.getcwd()]
1140 1152 except OSError:
1141 1153 self.dir_hist = []
1142 1154
1143 1155 # dict of output history
1144 1156 self.output_hist = {}
1145 1157
1146 1158 # Now the history file
1147 1159 if self.profile:
1148 1160 histfname = 'history-%s' % self.profile
1149 1161 else:
1150 1162 histfname = 'history'
1151 1163 self.histfile = os.path.join(self.ipython_dir, histfname)
1152 1164
1153 1165 # Fill the history zero entry, user counter starts at 1
1154 1166 self.input_hist.append('\n')
1155 1167 self.input_hist_raw.append('\n')
1156 1168
1157 1169 def init_shadow_hist(self):
1158 1170 try:
1159 1171 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1160 1172 except exceptions.UnicodeDecodeError:
1161 1173 print "Your ipython_dir can't be decoded to unicode!"
1162 1174 print "Please set HOME environment variable to something that"
1163 1175 print r"only has ASCII characters, e.g. c:\home"
1164 1176 print "Now it is", self.ipython_dir
1165 1177 sys.exit()
1166 1178 self.shadowhist = ipcorehist.ShadowHist(self.db)
1167 1179
1168 1180 def savehist(self):
1169 1181 """Save input history to a file (via readline library)."""
1170 1182
1171 1183 try:
1172 1184 self.readline.write_history_file(self.histfile)
1173 1185 except:
1174 1186 print 'Unable to save IPython command history to file: ' + \
1175 1187 `self.histfile`
1176 1188
1177 1189 def reloadhist(self):
1178 1190 """Reload the input history from disk file."""
1179 1191
1180 1192 try:
1181 1193 self.readline.clear_history()
1182 1194 self.readline.read_history_file(self.shell.histfile)
1183 1195 except AttributeError:
1184 1196 pass
1185 1197
1186 1198 def history_saving_wrapper(self, func):
1187 1199 """ Wrap func for readline history saving
1188 1200
1189 1201 Convert func into callable that saves & restores
1190 1202 history around the call """
1191 1203
1192 1204 if self.has_readline:
1193 1205 from IPython.utils import rlineimpl as readline
1194 1206 else:
1195 1207 return func
1196 1208
1197 1209 def wrapper():
1198 1210 self.savehist()
1199 1211 try:
1200 1212 func()
1201 1213 finally:
1202 1214 readline.read_history_file(self.histfile)
1203 1215 return wrapper
1204 1216
1205 1217 #-------------------------------------------------------------------------
1206 1218 # Things related to exception handling and tracebacks (not debugging)
1207 1219 #-------------------------------------------------------------------------
1208 1220
1209 1221 def init_traceback_handlers(self, custom_exceptions):
1210 1222 # Syntax error handler.
1211 1223 self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
1212 1224
1213 1225 # The interactive one is initialized with an offset, meaning we always
1214 1226 # want to remove the topmost item in the traceback, which is our own
1215 1227 # internal code. Valid modes: ['Plain','Context','Verbose']
1216 1228 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1217 1229 color_scheme='NoColor',
1218 1230 tb_offset = 1)
1219 1231
1220 1232 # The instance will store a pointer to the system-wide exception hook,
1221 1233 # so that runtime code (such as magics) can access it. This is because
1222 1234 # during the read-eval loop, it may get temporarily overwritten.
1223 1235 self.sys_excepthook = sys.excepthook
1224 1236
1225 1237 # and add any custom exception handlers the user may have specified
1226 1238 self.set_custom_exc(*custom_exceptions)
1227 1239
1228 1240 # Set the exception mode
1229 1241 self.InteractiveTB.set_mode(mode=self.xmode)
1230 1242
1231 1243 def set_custom_exc(self,exc_tuple,handler):
1232 1244 """set_custom_exc(exc_tuple,handler)
1233 1245
1234 1246 Set a custom exception handler, which will be called if any of the
1235 1247 exceptions in exc_tuple occur in the mainloop (specifically, in the
1236 1248 runcode() method.
1237 1249
1238 1250 Inputs:
1239 1251
1240 1252 - exc_tuple: a *tuple* of valid exceptions to call the defined
1241 1253 handler for. It is very important that you use a tuple, and NOT A
1242 1254 LIST here, because of the way Python's except statement works. If
1243 1255 you only want to trap a single exception, use a singleton tuple:
1244 1256
1245 1257 exc_tuple == (MyCustomException,)
1246 1258
1247 1259 - handler: this must be defined as a function with the following
1248 1260 basic interface: def my_handler(self,etype,value,tb).
1249 1261
1250 1262 This will be made into an instance method (via new.instancemethod)
1251 1263 of IPython itself, and it will be called if any of the exceptions
1252 1264 listed in the exc_tuple are caught. If the handler is None, an
1253 1265 internal basic one is used, which just prints basic info.
1254 1266
1255 1267 WARNING: by putting in your own exception handler into IPython's main
1256 1268 execution loop, you run a very good chance of nasty crashes. This
1257 1269 facility should only be used if you really know what you are doing."""
1258 1270
1259 1271 assert type(exc_tuple)==type(()) , \
1260 1272 "The custom exceptions must be given AS A TUPLE."
1261 1273
1262 1274 def dummy_handler(self,etype,value,tb):
1263 1275 print '*** Simple custom exception handler ***'
1264 1276 print 'Exception type :',etype
1265 1277 print 'Exception value:',value
1266 1278 print 'Traceback :',tb
1267 1279 print 'Source code :','\n'.join(self.buffer)
1268 1280
1269 1281 if handler is None: handler = dummy_handler
1270 1282
1271 1283 self.CustomTB = new.instancemethod(handler,self,self.__class__)
1272 1284 self.custom_exceptions = exc_tuple
1273 1285
1274 1286 def excepthook(self, etype, value, tb):
1275 1287 """One more defense for GUI apps that call sys.excepthook.
1276 1288
1277 1289 GUI frameworks like wxPython trap exceptions and call
1278 1290 sys.excepthook themselves. I guess this is a feature that
1279 1291 enables them to keep running after exceptions that would
1280 1292 otherwise kill their mainloop. This is a bother for IPython
1281 1293 which excepts to catch all of the program exceptions with a try:
1282 1294 except: statement.
1283 1295
1284 1296 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1285 1297 any app directly invokes sys.excepthook, it will look to the user like
1286 1298 IPython crashed. In order to work around this, we can disable the
1287 1299 CrashHandler and replace it with this excepthook instead, which prints a
1288 1300 regular traceback using our InteractiveTB. In this fashion, apps which
1289 1301 call sys.excepthook will generate a regular-looking exception from
1290 1302 IPython, and the CrashHandler will only be triggered by real IPython
1291 1303 crashes.
1292 1304
1293 1305 This hook should be used sparingly, only in places which are not likely
1294 1306 to be true IPython errors.
1295 1307 """
1296 1308 self.showtraceback((etype,value,tb),tb_offset=0)
1297 1309
1298 1310 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1299 1311 exception_only=False):
1300 1312 """Display the exception that just occurred.
1301 1313
1302 1314 If nothing is known about the exception, this is the method which
1303 1315 should be used throughout the code for presenting user tracebacks,
1304 1316 rather than directly invoking the InteractiveTB object.
1305 1317
1306 1318 A specific showsyntaxerror() also exists, but this method can take
1307 1319 care of calling it if needed, so unless you are explicitly catching a
1308 1320 SyntaxError exception, don't try to analyze the stack manually and
1309 1321 simply call this method."""
1310 1322
1311 1323 try:
1312 1324 if exc_tuple is None:
1313 1325 etype, value, tb = sys.exc_info()
1314 1326 else:
1315 1327 etype, value, tb = exc_tuple
1316 1328
1317 1329 if etype is None:
1318 1330 if hasattr(sys, 'last_type'):
1319 1331 etype, value, tb = sys.last_type, sys.last_value, \
1320 1332 sys.last_traceback
1321 1333 else:
1322 1334 self.write('No traceback available to show.\n')
1323 1335 return
1324 1336
1325 1337 if etype is SyntaxError:
1326 1338 # Though this won't be called by syntax errors in the input
1327 1339 # line, there may be SyntaxError cases whith imported code.
1328 1340 self.showsyntaxerror(filename)
1329 1341 elif etype is UsageError:
1330 1342 print "UsageError:", value
1331 1343 else:
1332 1344 # WARNING: these variables are somewhat deprecated and not
1333 1345 # necessarily safe to use in a threaded environment, but tools
1334 1346 # like pdb depend on their existence, so let's set them. If we
1335 1347 # find problems in the field, we'll need to revisit their use.
1336 1348 sys.last_type = etype
1337 1349 sys.last_value = value
1338 1350 sys.last_traceback = tb
1339 1351
1340 1352 if etype in self.custom_exceptions:
1341 1353 self.CustomTB(etype,value,tb)
1342 1354 else:
1343 1355 if exception_only:
1344 1356 m = ('An exception has occurred, use %tb to see the '
1345 1357 'full traceback.')
1346 1358 print m
1347 1359 self.InteractiveTB.show_exception_only(etype, value)
1348 1360 else:
1349 1361 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1350 1362 if self.InteractiveTB.call_pdb:
1351 1363 # pdb mucks up readline, fix it back
1352 1364 self.set_completer()
1353 1365
1354 1366 except KeyboardInterrupt:
1355 1367 self.write("\nKeyboardInterrupt\n")
1356 1368
1357 1369
1358 1370 def showsyntaxerror(self, filename=None):
1359 1371 """Display the syntax error that just occurred.
1360 1372
1361 1373 This doesn't display a stack trace because there isn't one.
1362 1374
1363 1375 If a filename is given, it is stuffed in the exception instead
1364 1376 of what was there before (because Python's parser always uses
1365 1377 "<string>" when reading from a string).
1366 1378 """
1367 1379 etype, value, last_traceback = sys.exc_info()
1368 1380
1369 1381 # See note about these variables in showtraceback() above
1370 1382 sys.last_type = etype
1371 1383 sys.last_value = value
1372 1384 sys.last_traceback = last_traceback
1373 1385
1374 1386 if filename and etype is SyntaxError:
1375 1387 # Work hard to stuff the correct filename in the exception
1376 1388 try:
1377 1389 msg, (dummy_filename, lineno, offset, line) = value
1378 1390 except:
1379 1391 # Not the format we expect; leave it alone
1380 1392 pass
1381 1393 else:
1382 1394 # Stuff in the right filename
1383 1395 try:
1384 1396 # Assume SyntaxError is a class exception
1385 1397 value = SyntaxError(msg, (filename, lineno, offset, line))
1386 1398 except:
1387 1399 # If that failed, assume SyntaxError is a string
1388 1400 value = msg, (filename, lineno, offset, line)
1389 1401 self.SyntaxTB(etype,value,[])
1390 1402
1391 1403 def edit_syntax_error(self):
1392 1404 """The bottom half of the syntax error handler called in the main loop.
1393 1405
1394 1406 Loop until syntax error is fixed or user cancels.
1395 1407 """
1396 1408
1397 1409 while self.SyntaxTB.last_syntax_error:
1398 1410 # copy and clear last_syntax_error
1399 1411 err = self.SyntaxTB.clear_err_state()
1400 1412 if not self._should_recompile(err):
1401 1413 return
1402 1414 try:
1403 1415 # may set last_syntax_error again if a SyntaxError is raised
1404 1416 self.safe_execfile(err.filename,self.user_ns)
1405 1417 except:
1406 1418 self.showtraceback()
1407 1419 else:
1408 1420 try:
1409 1421 f = file(err.filename)
1410 1422 try:
1411 1423 # This should be inside a display_trap block and I
1412 1424 # think it is.
1413 1425 sys.displayhook(f.read())
1414 1426 finally:
1415 1427 f.close()
1416 1428 except:
1417 1429 self.showtraceback()
1418 1430
1419 1431 def _should_recompile(self,e):
1420 1432 """Utility routine for edit_syntax_error"""
1421 1433
1422 1434 if e.filename in ('<ipython console>','<input>','<string>',
1423 1435 '<console>','<BackgroundJob compilation>',
1424 1436 None):
1425 1437
1426 1438 return False
1427 1439 try:
1428 1440 if (self.autoedit_syntax and
1429 1441 not self.ask_yes_no('Return to editor to correct syntax error? '
1430 1442 '[Y/n] ','y')):
1431 1443 return False
1432 1444 except EOFError:
1433 1445 return False
1434 1446
1435 1447 def int0(x):
1436 1448 try:
1437 1449 return int(x)
1438 1450 except TypeError:
1439 1451 return 0
1440 1452 # always pass integer line and offset values to editor hook
1441 1453 try:
1442 1454 self.hooks.fix_error_editor(e.filename,
1443 1455 int0(e.lineno),int0(e.offset),e.msg)
1444 1456 except TryNext:
1445 1457 warn('Could not open editor')
1446 1458 return False
1447 1459 return True
1448 1460
1449 1461 #-------------------------------------------------------------------------
1450 1462 # Things related to tab completion
1451 1463 #-------------------------------------------------------------------------
1452 1464
1453 1465 def complete(self, text):
1454 1466 """Return a sorted list of all possible completions on text.
1455 1467
1456 1468 Inputs:
1457 1469
1458 1470 - text: a string of text to be completed on.
1459 1471
1460 1472 This is a wrapper around the completion mechanism, similar to what
1461 1473 readline does at the command line when the TAB key is hit. By
1462 1474 exposing it as a method, it can be used by other non-readline
1463 1475 environments (such as GUIs) for text completion.
1464 1476
1465 1477 Simple usage example:
1466 1478
1467 1479 In [7]: x = 'hello'
1468 1480
1469 1481 In [8]: x
1470 1482 Out[8]: 'hello'
1471 1483
1472 1484 In [9]: print x
1473 1485 hello
1474 1486
1475 1487 In [10]: _ip.complete('x.l')
1476 1488 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1477 1489 """
1478 1490
1479 1491 # Inject names into __builtin__ so we can complete on the added names.
1480 1492 with self.builtin_trap:
1481 1493 complete = self.Completer.complete
1482 1494 state = 0
1483 1495 # use a dict so we get unique keys, since ipyhton's multiple
1484 1496 # completers can return duplicates. When we make 2.4 a requirement,
1485 1497 # start using sets instead, which are faster.
1486 1498 comps = {}
1487 1499 while True:
1488 1500 newcomp = complete(text,state,line_buffer=text)
1489 1501 if newcomp is None:
1490 1502 break
1491 1503 comps[newcomp] = 1
1492 1504 state += 1
1493 1505 outcomps = comps.keys()
1494 1506 outcomps.sort()
1495 1507 #print "T:",text,"OC:",outcomps # dbg
1496 1508 #print "vars:",self.user_ns.keys()
1497 1509 return outcomps
1498 1510
1499 1511 def set_custom_completer(self,completer,pos=0):
1500 1512 """Adds a new custom completer function.
1501 1513
1502 1514 The position argument (defaults to 0) is the index in the completers
1503 1515 list where you want the completer to be inserted."""
1504 1516
1505 1517 newcomp = new.instancemethod(completer,self.Completer,
1506 1518 self.Completer.__class__)
1507 1519 self.Completer.matchers.insert(pos,newcomp)
1508 1520
1509 1521 def set_completer(self):
1510 1522 """Reset readline's completer to be our own."""
1511 1523 self.readline.set_completer(self.Completer.complete)
1512 1524
1513 1525 def set_completer_frame(self, frame=None):
1514 1526 """Set the frame of the completer."""
1515 1527 if frame:
1516 1528 self.Completer.namespace = frame.f_locals
1517 1529 self.Completer.global_namespace = frame.f_globals
1518 1530 else:
1519 1531 self.Completer.namespace = self.user_ns
1520 1532 self.Completer.global_namespace = self.user_global_ns
1521 1533
1522 1534 #-------------------------------------------------------------------------
1523 1535 # Things related to readline
1524 1536 #-------------------------------------------------------------------------
1525 1537
1526 1538 def init_readline(self):
1527 1539 """Command history completion/saving/reloading."""
1528 1540
1529 1541 if self.readline_use:
1530 1542 import IPython.utils.rlineimpl as readline
1531 1543
1532 1544 self.rl_next_input = None
1533 1545 self.rl_do_indent = False
1534 1546
1535 1547 if not self.readline_use or not readline.have_readline:
1536 1548 self.has_readline = False
1537 1549 self.readline = None
1538 1550 # Set a number of methods that depend on readline to be no-op
1539 1551 self.savehist = no_op
1540 1552 self.reloadhist = no_op
1541 1553 self.set_completer = no_op
1542 1554 self.set_custom_completer = no_op
1543 1555 self.set_completer_frame = no_op
1544 1556 warn('Readline services not available or not loaded.')
1545 1557 else:
1546 1558 self.has_readline = True
1547 1559 self.readline = readline
1548 1560 sys.modules['readline'] = readline
1549 1561 import atexit
1550 1562 from IPython.core.completer import IPCompleter
1551 1563 self.Completer = IPCompleter(self,
1552 1564 self.user_ns,
1553 1565 self.user_global_ns,
1554 1566 self.readline_omit__names,
1555 1567 self.alias_manager.alias_table)
1556 1568 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1557 1569 self.strdispatchers['complete_command'] = sdisp
1558 1570 self.Completer.custom_completers = sdisp
1559 1571 # Platform-specific configuration
1560 1572 if os.name == 'nt':
1561 1573 self.readline_startup_hook = readline.set_pre_input_hook
1562 1574 else:
1563 1575 self.readline_startup_hook = readline.set_startup_hook
1564 1576
1565 1577 # Load user's initrc file (readline config)
1566 1578 # Or if libedit is used, load editrc.
1567 1579 inputrc_name = os.environ.get('INPUTRC')
1568 1580 if inputrc_name is None:
1569 1581 home_dir = get_home_dir()
1570 1582 if home_dir is not None:
1571 1583 inputrc_name = '.inputrc'
1572 1584 if readline.uses_libedit:
1573 1585 inputrc_name = '.editrc'
1574 1586 inputrc_name = os.path.join(home_dir, inputrc_name)
1575 1587 if os.path.isfile(inputrc_name):
1576 1588 try:
1577 1589 readline.read_init_file(inputrc_name)
1578 1590 except:
1579 1591 warn('Problems reading readline initialization file <%s>'
1580 1592 % inputrc_name)
1581 1593
1582 1594 # save this in sys so embedded copies can restore it properly
1583 1595 sys.ipcompleter = self.Completer.complete
1584 1596 self.set_completer()
1585 1597
1586 1598 # Configure readline according to user's prefs
1587 1599 # This is only done if GNU readline is being used. If libedit
1588 1600 # is being used (as on Leopard) the readline config is
1589 1601 # not run as the syntax for libedit is different.
1590 1602 if not readline.uses_libedit:
1591 1603 for rlcommand in self.readline_parse_and_bind:
1592 1604 #print "loading rl:",rlcommand # dbg
1593 1605 readline.parse_and_bind(rlcommand)
1594 1606
1595 1607 # Remove some chars from the delimiters list. If we encounter
1596 1608 # unicode chars, discard them.
1597 1609 delims = readline.get_completer_delims().encode("ascii", "ignore")
1598 1610 delims = delims.translate(string._idmap,
1599 1611 self.readline_remove_delims)
1600 1612 readline.set_completer_delims(delims)
1601 1613 # otherwise we end up with a monster history after a while:
1602 1614 readline.set_history_length(1000)
1603 1615 try:
1604 1616 #print '*** Reading readline history' # dbg
1605 1617 readline.read_history_file(self.histfile)
1606 1618 except IOError:
1607 1619 pass # It doesn't exist yet.
1608 1620
1609 1621 atexit.register(self.atexit_operations)
1610 1622 del atexit
1611 1623
1612 1624 # Configure auto-indent for all platforms
1613 1625 self.set_autoindent(self.autoindent)
1614 1626
1615 1627 def set_next_input(self, s):
1616 1628 """ Sets the 'default' input string for the next command line.
1617 1629
1618 1630 Requires readline.
1619 1631
1620 1632 Example:
1621 1633
1622 1634 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1623 1635 [D:\ipython]|2> Hello Word_ # cursor is here
1624 1636 """
1625 1637
1626 1638 self.rl_next_input = s
1627 1639
1628 1640 def pre_readline(self):
1629 1641 """readline hook to be used at the start of each line.
1630 1642
1631 1643 Currently it handles auto-indent only."""
1632 1644
1633 1645 #debugx('self.indent_current_nsp','pre_readline:')
1634 1646
1635 1647 if self.rl_do_indent:
1636 1648 self.readline.insert_text(self._indent_current_str())
1637 1649 if self.rl_next_input is not None:
1638 1650 self.readline.insert_text(self.rl_next_input)
1639 1651 self.rl_next_input = None
1640 1652
1641 1653 def _indent_current_str(self):
1642 1654 """return the current level of indentation as a string"""
1643 1655 return self.indent_current_nsp * ' '
1644 1656
1645 1657 #-------------------------------------------------------------------------
1646 1658 # Things related to magics
1647 1659 #-------------------------------------------------------------------------
1648 1660
1649 1661 def init_magics(self):
1650 1662 # Set user colors (don't do it in the constructor above so that it
1651 1663 # doesn't crash if colors option is invalid)
1652 1664 self.magic_colors(self.colors)
1653 1665 # History was moved to a separate module
1654 1666 from . import history
1655 1667 history.init_ipython(self)
1656 1668
1657 1669 def magic(self,arg_s):
1658 1670 """Call a magic function by name.
1659 1671
1660 1672 Input: a string containing the name of the magic function to call and any
1661 1673 additional arguments to be passed to the magic.
1662 1674
1663 1675 magic('name -opt foo bar') is equivalent to typing at the ipython
1664 1676 prompt:
1665 1677
1666 1678 In[1]: %name -opt foo bar
1667 1679
1668 1680 To call a magic without arguments, simply use magic('name').
1669 1681
1670 1682 This provides a proper Python function to call IPython's magics in any
1671 1683 valid Python code you can type at the interpreter, including loops and
1672 1684 compound statements.
1673 1685 """
1674 1686 args = arg_s.split(' ',1)
1675 1687 magic_name = args[0]
1676 1688 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1677 1689
1678 1690 try:
1679 1691 magic_args = args[1]
1680 1692 except IndexError:
1681 1693 magic_args = ''
1682 1694 fn = getattr(self,'magic_'+magic_name,None)
1683 1695 if fn is None:
1684 1696 error("Magic function `%s` not found." % magic_name)
1685 1697 else:
1686 1698 magic_args = self.var_expand(magic_args,1)
1687 1699 with nested(self.builtin_trap,):
1688 1700 result = fn(magic_args)
1689 1701 return result
1690 1702
1691 1703 def define_magic(self, magicname, func):
1692 1704 """Expose own function as magic function for ipython
1693 1705
1694 1706 def foo_impl(self,parameter_s=''):
1695 1707 'My very own magic!. (Use docstrings, IPython reads them).'
1696 1708 print 'Magic function. Passed parameter is between < >:'
1697 1709 print '<%s>' % parameter_s
1698 1710 print 'The self object is:',self
1699 1711
1700 1712 self.define_magic('foo',foo_impl)
1701 1713 """
1702 1714
1703 1715 import new
1704 1716 im = new.instancemethod(func,self, self.__class__)
1705 1717 old = getattr(self, "magic_" + magicname, None)
1706 1718 setattr(self, "magic_" + magicname, im)
1707 1719 return old
1708 1720
1709 1721 #-------------------------------------------------------------------------
1710 1722 # Things related to macros
1711 1723 #-------------------------------------------------------------------------
1712 1724
1713 1725 def define_macro(self, name, themacro):
1714 1726 """Define a new macro
1715 1727
1716 1728 Parameters
1717 1729 ----------
1718 1730 name : str
1719 1731 The name of the macro.
1720 1732 themacro : str or Macro
1721 1733 The action to do upon invoking the macro. If a string, a new
1722 1734 Macro object is created by passing the string to it.
1723 1735 """
1724 1736
1725 1737 from IPython.core import macro
1726 1738
1727 1739 if isinstance(themacro, basestring):
1728 1740 themacro = macro.Macro(themacro)
1729 1741 if not isinstance(themacro, macro.Macro):
1730 1742 raise ValueError('A macro must be a string or a Macro instance.')
1731 1743 self.user_ns[name] = themacro
1732 1744
1733 1745 #-------------------------------------------------------------------------
1734 1746 # Things related to the running of system commands
1735 1747 #-------------------------------------------------------------------------
1736 1748
1737 1749 def system(self, cmd):
1738 1750 """Make a system call, using IPython."""
1739 1751 return self.hooks.shell_hook(self.var_expand(cmd, depth=2))
1740 1752
1741 1753 #-------------------------------------------------------------------------
1742 1754 # Things related to aliases
1743 1755 #-------------------------------------------------------------------------
1744 1756
1745 1757 def init_alias(self):
1746 1758 self.alias_manager = AliasManager(self, config=self.config)
1747 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 1769 # Things related to the running of code
1751 1770 #-------------------------------------------------------------------------
1752 1771
1753 1772 def ex(self, cmd):
1754 1773 """Execute a normal python statement in user namespace."""
1755 1774 with nested(self.builtin_trap,):
1756 1775 exec cmd in self.user_global_ns, self.user_ns
1757 1776
1758 1777 def ev(self, expr):
1759 1778 """Evaluate python expression expr in user namespace.
1760 1779
1761 1780 Returns the result of evaluation
1762 1781 """
1763 1782 with nested(self.builtin_trap,):
1764 1783 return eval(expr, self.user_global_ns, self.user_ns)
1765 1784
1766 1785 def mainloop(self, display_banner=None):
1767 1786 """Start the mainloop.
1768 1787
1769 1788 If an optional banner argument is given, it will override the
1770 1789 internally created default banner.
1771 1790 """
1772 1791
1773 1792 with nested(self.builtin_trap, self.display_trap):
1774 1793
1775 1794 # if you run stuff with -c <cmd>, raw hist is not updated
1776 1795 # ensure that it's in sync
1777 1796 if len(self.input_hist) != len (self.input_hist_raw):
1778 1797 self.input_hist_raw = InputList(self.input_hist)
1779 1798
1780 1799 while 1:
1781 1800 try:
1782 1801 self.interact(display_banner=display_banner)
1783 1802 #self.interact_with_readline()
1784 1803 # XXX for testing of a readline-decoupled repl loop, call
1785 1804 # interact_with_readline above
1786 1805 break
1787 1806 except KeyboardInterrupt:
1788 1807 # this should not be necessary, but KeyboardInterrupt
1789 1808 # handling seems rather unpredictable...
1790 1809 self.write("\nKeyboardInterrupt in interact()\n")
1791 1810
1792 1811 def interact_prompt(self):
1793 1812 """ Print the prompt (in read-eval-print loop)
1794 1813
1795 1814 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1796 1815 used in standard IPython flow.
1797 1816 """
1798 1817 if self.more:
1799 1818 try:
1800 1819 prompt = self.hooks.generate_prompt(True)
1801 1820 except:
1802 1821 self.showtraceback()
1803 1822 if self.autoindent:
1804 1823 self.rl_do_indent = True
1805 1824
1806 1825 else:
1807 1826 try:
1808 1827 prompt = self.hooks.generate_prompt(False)
1809 1828 except:
1810 1829 self.showtraceback()
1811 1830 self.write(prompt)
1812 1831
1813 1832 def interact_handle_input(self,line):
1814 1833 """ Handle the input line (in read-eval-print loop)
1815 1834
1816 1835 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1817 1836 used in standard IPython flow.
1818 1837 """
1819 1838 if line.lstrip() == line:
1820 1839 self.shadowhist.add(line.strip())
1821 1840 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1822 1841
1823 1842 if line.strip():
1824 1843 if self.more:
1825 1844 self.input_hist_raw[-1] += '%s\n' % line
1826 1845 else:
1827 1846 self.input_hist_raw.append('%s\n' % line)
1828 1847
1829 1848
1830 1849 self.more = self.push_line(lineout)
1831 1850 if (self.SyntaxTB.last_syntax_error and
1832 1851 self.autoedit_syntax):
1833 1852 self.edit_syntax_error()
1834 1853
1835 1854 def interact_with_readline(self):
1836 1855 """ Demo of using interact_handle_input, interact_prompt
1837 1856
1838 1857 This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
1839 1858 it should work like this.
1840 1859 """
1841 1860 self.readline_startup_hook(self.pre_readline)
1842 1861 while not self.exit_now:
1843 1862 self.interact_prompt()
1844 1863 if self.more:
1845 1864 self.rl_do_indent = True
1846 1865 else:
1847 1866 self.rl_do_indent = False
1848 1867 line = raw_input_original().decode(self.stdin_encoding)
1849 1868 self.interact_handle_input(line)
1850 1869
1851 1870 def interact(self, display_banner=None):
1852 1871 """Closely emulate the interactive Python console."""
1853 1872
1854 1873 # batch run -> do not interact
1855 1874 if self.exit_now:
1856 1875 return
1857 1876
1858 1877 if display_banner is None:
1859 1878 display_banner = self.display_banner
1860 1879 if display_banner:
1861 1880 self.show_banner()
1862 1881
1863 1882 more = 0
1864 1883
1865 1884 # Mark activity in the builtins
1866 1885 __builtin__.__dict__['__IPYTHON__active'] += 1
1867 1886
1868 1887 if self.has_readline:
1869 1888 self.readline_startup_hook(self.pre_readline)
1870 1889 # exit_now is set by a call to %Exit or %Quit, through the
1871 1890 # ask_exit callback.
1872 1891
1873 1892 while not self.exit_now:
1874 1893 self.hooks.pre_prompt_hook()
1875 1894 if more:
1876 1895 try:
1877 1896 prompt = self.hooks.generate_prompt(True)
1878 1897 except:
1879 1898 self.showtraceback()
1880 1899 if self.autoindent:
1881 1900 self.rl_do_indent = True
1882 1901
1883 1902 else:
1884 1903 try:
1885 1904 prompt = self.hooks.generate_prompt(False)
1886 1905 except:
1887 1906 self.showtraceback()
1888 1907 try:
1889 1908 line = self.raw_input(prompt, more)
1890 1909 if self.exit_now:
1891 1910 # quick exit on sys.std[in|out] close
1892 1911 break
1893 1912 if self.autoindent:
1894 1913 self.rl_do_indent = False
1895 1914
1896 1915 except KeyboardInterrupt:
1897 1916 #double-guard against keyboardinterrupts during kbdint handling
1898 1917 try:
1899 1918 self.write('\nKeyboardInterrupt\n')
1900 1919 self.resetbuffer()
1901 1920 # keep cache in sync with the prompt counter:
1902 1921 self.outputcache.prompt_count -= 1
1903 1922
1904 1923 if self.autoindent:
1905 1924 self.indent_current_nsp = 0
1906 1925 more = 0
1907 1926 except KeyboardInterrupt:
1908 1927 pass
1909 1928 except EOFError:
1910 1929 if self.autoindent:
1911 1930 self.rl_do_indent = False
1912 1931 if self.has_readline:
1913 1932 self.readline_startup_hook(None)
1914 1933 self.write('\n')
1915 1934 self.exit()
1916 1935 except bdb.BdbQuit:
1917 1936 warn('The Python debugger has exited with a BdbQuit exception.\n'
1918 1937 'Because of how pdb handles the stack, it is impossible\n'
1919 1938 'for IPython to properly format this particular exception.\n'
1920 1939 'IPython will resume normal operation.')
1921 1940 except:
1922 1941 # exceptions here are VERY RARE, but they can be triggered
1923 1942 # asynchronously by signal handlers, for example.
1924 1943 self.showtraceback()
1925 1944 else:
1926 1945 more = self.push_line(line)
1927 1946 if (self.SyntaxTB.last_syntax_error and
1928 1947 self.autoedit_syntax):
1929 1948 self.edit_syntax_error()
1930 1949
1931 1950 # We are off again...
1932 1951 __builtin__.__dict__['__IPYTHON__active'] -= 1
1933 1952
1934 1953 # Turn off the exit flag, so the mainloop can be restarted if desired
1935 1954 self.exit_now = False
1936 1955
1937 1956 def safe_execfile(self, fname, *where, **kw):
1938 1957 """A safe version of the builtin execfile().
1939 1958
1940 1959 This version will never throw an exception, but instead print
1941 1960 helpful error messages to the screen. This only works on pure
1942 1961 Python files with the .py extension.
1943 1962
1944 1963 Parameters
1945 1964 ----------
1946 1965 fname : string
1947 1966 The name of the file to be executed.
1948 1967 where : tuple
1949 1968 One or two namespaces, passed to execfile() as (globals,locals).
1950 1969 If only one is given, it is passed as both.
1951 1970 exit_ignore : bool (False)
1952 1971 If True, then silence SystemExit for non-zero status (it is always
1953 1972 silenced for zero status, as it is so common).
1954 1973 """
1955 1974 kw.setdefault('exit_ignore', False)
1956 1975
1957 1976 fname = os.path.abspath(os.path.expanduser(fname))
1958 1977
1959 1978 # Make sure we have a .py file
1960 1979 if not fname.endswith('.py'):
1961 1980 warn('File must end with .py to be run using execfile: <%s>' % fname)
1962 1981
1963 1982 # Make sure we can open the file
1964 1983 try:
1965 1984 with open(fname) as thefile:
1966 1985 pass
1967 1986 except:
1968 1987 warn('Could not open file <%s> for safe execution.' % fname)
1969 1988 return
1970 1989
1971 1990 # Find things also in current directory. This is needed to mimic the
1972 1991 # behavior of running a script from the system command line, where
1973 1992 # Python inserts the script's directory into sys.path
1974 1993 dname = os.path.dirname(fname)
1975 1994
1976 1995 with prepended_to_syspath(dname):
1977 1996 try:
1978 1997 execfile(fname,*where)
1979 1998 except SystemExit, status:
1980 1999 # If the call was made with 0 or None exit status (sys.exit(0)
1981 2000 # or sys.exit() ), don't bother showing a traceback, as both of
1982 2001 # these are considered normal by the OS:
1983 2002 # > python -c'import sys;sys.exit(0)'; echo $?
1984 2003 # 0
1985 2004 # > python -c'import sys;sys.exit()'; echo $?
1986 2005 # 0
1987 2006 # For other exit status, we show the exception unless
1988 2007 # explicitly silenced, but only in short form.
1989 2008 if status.code not in (0, None) and not kw['exit_ignore']:
1990 2009 self.showtraceback(exception_only=True)
1991 2010 except:
1992 2011 self.showtraceback()
1993 2012
1994 2013 def safe_execfile_ipy(self, fname):
1995 2014 """Like safe_execfile, but for .ipy files with IPython syntax.
1996 2015
1997 2016 Parameters
1998 2017 ----------
1999 2018 fname : str
2000 2019 The name of the file to execute. The filename must have a
2001 2020 .ipy extension.
2002 2021 """
2003 2022 fname = os.path.abspath(os.path.expanduser(fname))
2004 2023
2005 2024 # Make sure we have a .py file
2006 2025 if not fname.endswith('.ipy'):
2007 2026 warn('File must end with .py to be run using execfile: <%s>' % fname)
2008 2027
2009 2028 # Make sure we can open the file
2010 2029 try:
2011 2030 with open(fname) as thefile:
2012 2031 pass
2013 2032 except:
2014 2033 warn('Could not open file <%s> for safe execution.' % fname)
2015 2034 return
2016 2035
2017 2036 # Find things also in current directory. This is needed to mimic the
2018 2037 # behavior of running a script from the system command line, where
2019 2038 # Python inserts the script's directory into sys.path
2020 2039 dname = os.path.dirname(fname)
2021 2040
2022 2041 with prepended_to_syspath(dname):
2023 2042 try:
2024 2043 with open(fname) as thefile:
2025 2044 script = thefile.read()
2026 2045 # self.runlines currently captures all exceptions
2027 2046 # raise in user code. It would be nice if there were
2028 2047 # versions of runlines, execfile that did raise, so
2029 2048 # we could catch the errors.
2030 2049 self.runlines(script, clean=True)
2031 2050 except:
2032 2051 self.showtraceback()
2033 2052 warn('Unknown failure executing file: <%s>' % fname)
2034 2053
2035 2054 def _is_secondary_block_start(self, s):
2036 2055 if not s.endswith(':'):
2037 2056 return False
2038 2057 if (s.startswith('elif') or
2039 2058 s.startswith('else') or
2040 2059 s.startswith('except') or
2041 2060 s.startswith('finally')):
2042 2061 return True
2043 2062
2044 2063 def cleanup_ipy_script(self, script):
2045 2064 """Make a script safe for self.runlines()
2046 2065
2047 2066 Currently, IPython is lines based, with blocks being detected by
2048 2067 empty lines. This is a problem for block based scripts that may
2049 2068 not have empty lines after blocks. This script adds those empty
2050 2069 lines to make scripts safe for running in the current line based
2051 2070 IPython.
2052 2071 """
2053 2072 res = []
2054 2073 lines = script.splitlines()
2055 2074 level = 0
2056 2075
2057 2076 for l in lines:
2058 2077 lstripped = l.lstrip()
2059 2078 stripped = l.strip()
2060 2079 if not stripped:
2061 2080 continue
2062 2081 newlevel = len(l) - len(lstripped)
2063 2082 if level > 0 and newlevel == 0 and \
2064 2083 not self._is_secondary_block_start(stripped):
2065 2084 # add empty line
2066 2085 res.append('')
2067 2086 res.append(l)
2068 2087 level = newlevel
2069 2088
2070 2089 return '\n'.join(res) + '\n'
2071 2090
2072 2091 def runlines(self, lines, clean=False):
2073 2092 """Run a string of one or more lines of source.
2074 2093
2075 2094 This method is capable of running a string containing multiple source
2076 2095 lines, as if they had been entered at the IPython prompt. Since it
2077 2096 exposes IPython's processing machinery, the given strings can contain
2078 2097 magic calls (%magic), special shell access (!cmd), etc.
2079 2098 """
2080 2099
2081 2100 if isinstance(lines, (list, tuple)):
2082 2101 lines = '\n'.join(lines)
2083 2102
2084 2103 if clean:
2085 2104 lines = self.cleanup_ipy_script(lines)
2086 2105
2087 2106 # We must start with a clean buffer, in case this is run from an
2088 2107 # interactive IPython session (via a magic, for example).
2089 2108 self.resetbuffer()
2090 2109 lines = lines.splitlines()
2091 2110 more = 0
2092 2111
2093 2112 with nested(self.builtin_trap, self.display_trap):
2094 2113 for line in lines:
2095 2114 # skip blank lines so we don't mess up the prompt counter, but do
2096 2115 # NOT skip even a blank line if we are in a code block (more is
2097 2116 # true)
2098 2117
2099 2118 if line or more:
2100 2119 # push to raw history, so hist line numbers stay in sync
2101 2120 self.input_hist_raw.append("# " + line + "\n")
2102 2121 prefiltered = self.prefilter_manager.prefilter_lines(line,more)
2103 2122 more = self.push_line(prefiltered)
2104 2123 # IPython's runsource returns None if there was an error
2105 2124 # compiling the code. This allows us to stop processing right
2106 2125 # away, so the user gets the error message at the right place.
2107 2126 if more is None:
2108 2127 break
2109 2128 else:
2110 2129 self.input_hist_raw.append("\n")
2111 2130 # final newline in case the input didn't have it, so that the code
2112 2131 # actually does get executed
2113 2132 if more:
2114 2133 self.push_line('\n')
2115 2134
2116 2135 def runsource(self, source, filename='<input>', symbol='single'):
2117 2136 """Compile and run some source in the interpreter.
2118 2137
2119 2138 Arguments are as for compile_command().
2120 2139
2121 2140 One several things can happen:
2122 2141
2123 2142 1) The input is incorrect; compile_command() raised an
2124 2143 exception (SyntaxError or OverflowError). A syntax traceback
2125 2144 will be printed by calling the showsyntaxerror() method.
2126 2145
2127 2146 2) The input is incomplete, and more input is required;
2128 2147 compile_command() returned None. Nothing happens.
2129 2148
2130 2149 3) The input is complete; compile_command() returned a code
2131 2150 object. The code is executed by calling self.runcode() (which
2132 2151 also handles run-time exceptions, except for SystemExit).
2133 2152
2134 2153 The return value is:
2135 2154
2136 2155 - True in case 2
2137 2156
2138 2157 - False in the other cases, unless an exception is raised, where
2139 2158 None is returned instead. This can be used by external callers to
2140 2159 know whether to continue feeding input or not.
2141 2160
2142 2161 The return value can be used to decide whether to use sys.ps1 or
2143 2162 sys.ps2 to prompt the next line."""
2144 2163
2145 2164 # if the source code has leading blanks, add 'if 1:\n' to it
2146 2165 # this allows execution of indented pasted code. It is tempting
2147 2166 # to add '\n' at the end of source to run commands like ' a=1'
2148 2167 # directly, but this fails for more complicated scenarios
2149 2168 source=source.encode(self.stdin_encoding)
2150 2169 if source[:1] in [' ', '\t']:
2151 2170 source = 'if 1:\n%s' % source
2152 2171
2153 2172 try:
2154 2173 code = self.compile(source,filename,symbol)
2155 2174 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2156 2175 # Case 1
2157 2176 self.showsyntaxerror(filename)
2158 2177 return None
2159 2178
2160 2179 if code is None:
2161 2180 # Case 2
2162 2181 return True
2163 2182
2164 2183 # Case 3
2165 2184 # We store the code object so that threaded shells and
2166 2185 # custom exception handlers can access all this info if needed.
2167 2186 # The source corresponding to this can be obtained from the
2168 2187 # buffer attribute as '\n'.join(self.buffer).
2169 2188 self.code_to_run = code
2170 2189 # now actually execute the code object
2171 2190 if self.runcode(code) == 0:
2172 2191 return False
2173 2192 else:
2174 2193 return None
2175 2194
2176 2195 def runcode(self,code_obj):
2177 2196 """Execute a code object.
2178 2197
2179 2198 When an exception occurs, self.showtraceback() is called to display a
2180 2199 traceback.
2181 2200
2182 2201 Return value: a flag indicating whether the code to be run completed
2183 2202 successfully:
2184 2203
2185 2204 - 0: successful execution.
2186 2205 - 1: an error occurred.
2187 2206 """
2188 2207
2189 2208 # Set our own excepthook in case the user code tries to call it
2190 2209 # directly, so that the IPython crash handler doesn't get triggered
2191 2210 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2192 2211
2193 2212 # we save the original sys.excepthook in the instance, in case config
2194 2213 # code (such as magics) needs access to it.
2195 2214 self.sys_excepthook = old_excepthook
2196 2215 outflag = 1 # happens in more places, so it's easier as default
2197 2216 try:
2198 2217 try:
2199 2218 self.hooks.pre_runcode_hook()
2200 2219 exec code_obj in self.user_global_ns, self.user_ns
2201 2220 finally:
2202 2221 # Reset our crash handler in place
2203 2222 sys.excepthook = old_excepthook
2204 2223 except SystemExit:
2205 2224 self.resetbuffer()
2206 2225 self.showtraceback(exception_only=True)
2207 2226 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2208 2227 except self.custom_exceptions:
2209 2228 etype,value,tb = sys.exc_info()
2210 2229 self.CustomTB(etype,value,tb)
2211 2230 except:
2212 2231 self.showtraceback()
2213 2232 else:
2214 2233 outflag = 0
2215 2234 if softspace(sys.stdout, 0):
2216 2235 print
2217 2236 # Flush out code object which has been run (and source)
2218 2237 self.code_to_run = None
2219 2238 return outflag
2220 2239
2221 2240 def push_line(self, line):
2222 2241 """Push a line to the interpreter.
2223 2242
2224 2243 The line should not have a trailing newline; it may have
2225 2244 internal newlines. The line is appended to a buffer and the
2226 2245 interpreter's runsource() method is called with the
2227 2246 concatenated contents of the buffer as source. If this
2228 2247 indicates that the command was executed or invalid, the buffer
2229 2248 is reset; otherwise, the command is incomplete, and the buffer
2230 2249 is left as it was after the line was appended. The return
2231 2250 value is 1 if more input is required, 0 if the line was dealt
2232 2251 with in some way (this is the same as runsource()).
2233 2252 """
2234 2253
2235 2254 # autoindent management should be done here, and not in the
2236 2255 # interactive loop, since that one is only seen by keyboard input. We
2237 2256 # need this done correctly even for code run via runlines (which uses
2238 2257 # push).
2239 2258
2240 2259 #print 'push line: <%s>' % line # dbg
2241 2260 for subline in line.splitlines():
2242 2261 self._autoindent_update(subline)
2243 2262 self.buffer.append(line)
2244 2263 more = self.runsource('\n'.join(self.buffer), self.filename)
2245 2264 if not more:
2246 2265 self.resetbuffer()
2247 2266 return more
2248 2267
2249 2268 def _autoindent_update(self,line):
2250 2269 """Keep track of the indent level."""
2251 2270
2252 2271 #debugx('line')
2253 2272 #debugx('self.indent_current_nsp')
2254 2273 if self.autoindent:
2255 2274 if line:
2256 2275 inisp = num_ini_spaces(line)
2257 2276 if inisp < self.indent_current_nsp:
2258 2277 self.indent_current_nsp = inisp
2259 2278
2260 2279 if line[-1] == ':':
2261 2280 self.indent_current_nsp += 4
2262 2281 elif dedent_re.match(line):
2263 2282 self.indent_current_nsp -= 4
2264 2283 else:
2265 2284 self.indent_current_nsp = 0
2266 2285
2267 2286 def resetbuffer(self):
2268 2287 """Reset the input buffer."""
2269 2288 self.buffer[:] = []
2270 2289
2271 2290 def raw_input(self,prompt='',continue_prompt=False):
2272 2291 """Write a prompt and read a line.
2273 2292
2274 2293 The returned line does not include the trailing newline.
2275 2294 When the user enters the EOF key sequence, EOFError is raised.
2276 2295
2277 2296 Optional inputs:
2278 2297
2279 2298 - prompt(''): a string to be printed to prompt the user.
2280 2299
2281 2300 - continue_prompt(False): whether this line is the first one or a
2282 2301 continuation in a sequence of inputs.
2283 2302 """
2284 2303 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2285 2304
2286 2305 # Code run by the user may have modified the readline completer state.
2287 2306 # We must ensure that our completer is back in place.
2288 2307
2289 2308 if self.has_readline:
2290 2309 self.set_completer()
2291 2310
2292 2311 try:
2293 2312 line = raw_input_original(prompt).decode(self.stdin_encoding)
2294 2313 except ValueError:
2295 2314 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
2296 2315 " or sys.stdout.close()!\nExiting IPython!")
2297 2316 self.ask_exit()
2298 2317 return ""
2299 2318
2300 2319 # Try to be reasonably smart about not re-indenting pasted input more
2301 2320 # than necessary. We do this by trimming out the auto-indent initial
2302 2321 # spaces, if the user's actual input started itself with whitespace.
2303 2322 #debugx('self.buffer[-1]')
2304 2323
2305 2324 if self.autoindent:
2306 2325 if num_ini_spaces(line) > self.indent_current_nsp:
2307 2326 line = line[self.indent_current_nsp:]
2308 2327 self.indent_current_nsp = 0
2309 2328
2310 2329 # store the unfiltered input before the user has any chance to modify
2311 2330 # it.
2312 2331 if line.strip():
2313 2332 if continue_prompt:
2314 2333 self.input_hist_raw[-1] += '%s\n' % line
2315 2334 if self.has_readline and self.readline_use:
2316 2335 try:
2317 2336 histlen = self.readline.get_current_history_length()
2318 2337 if histlen > 1:
2319 2338 newhist = self.input_hist_raw[-1].rstrip()
2320 2339 self.readline.remove_history_item(histlen-1)
2321 2340 self.readline.replace_history_item(histlen-2,
2322 2341 newhist.encode(self.stdin_encoding))
2323 2342 except AttributeError:
2324 2343 pass # re{move,place}_history_item are new in 2.4.
2325 2344 else:
2326 2345 self.input_hist_raw.append('%s\n' % line)
2327 2346 # only entries starting at first column go to shadow history
2328 2347 if line.lstrip() == line:
2329 2348 self.shadowhist.add(line.strip())
2330 2349 elif not continue_prompt:
2331 2350 self.input_hist_raw.append('\n')
2332 2351 try:
2333 2352 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2334 2353 except:
2335 2354 # blanket except, in case a user-defined prefilter crashes, so it
2336 2355 # can't take all of ipython with it.
2337 2356 self.showtraceback()
2338 2357 return ''
2339 2358 else:
2340 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 2362 # Things related to the prefilter
2434 2363 #-------------------------------------------------------------------------
2435 2364
2436 2365 def init_prefilter(self):
2437 2366 self.prefilter_manager = PrefilterManager(self, config=self.config)
2438 2367 # Ultimately this will be refactored in the new interpreter code, but
2439 2368 # for now, we should expose the main prefilter method (there's legacy
2440 2369 # code out there that may rely on this).
2441 2370 self.prefilter = self.prefilter_manager.prefilter_lines
2442 2371
2443 2372 #-------------------------------------------------------------------------
2444 2373 # Utilities
2445 2374 #-------------------------------------------------------------------------
2446 2375
2447 2376 def getoutput(self, cmd):
2448 2377 return getoutput(self.var_expand(cmd,depth=2),
2449 2378 header=self.system_header,
2450 2379 verbose=self.system_verbose)
2451 2380
2452 2381 def getoutputerror(self, cmd):
2453 2382 return getoutputerror(self.var_expand(cmd,depth=2),
2454 2383 header=self.system_header,
2455 2384 verbose=self.system_verbose)
2456 2385
2457 2386 def var_expand(self,cmd,depth=0):
2458 2387 """Expand python variables in a string.
2459 2388
2460 2389 The depth argument indicates how many frames above the caller should
2461 2390 be walked to look for the local namespace where to expand variables.
2462 2391
2463 2392 The global namespace for expansion is always the user's interactive
2464 2393 namespace.
2465 2394 """
2466 2395
2467 2396 return str(ItplNS(cmd,
2468 2397 self.user_ns, # globals
2469 2398 # Skip our own frame in searching for locals:
2470 2399 sys._getframe(depth+1).f_locals # locals
2471 2400 ))
2472 2401
2473 2402 def mktempfile(self,data=None):
2474 2403 """Make a new tempfile and return its filename.
2475 2404
2476 2405 This makes a call to tempfile.mktemp, but it registers the created
2477 2406 filename internally so ipython cleans it up at exit time.
2478 2407
2479 2408 Optional inputs:
2480 2409
2481 2410 - data(None): if data is given, it gets written out to the temp file
2482 2411 immediately, and the file is closed again."""
2483 2412
2484 2413 filename = tempfile.mktemp('.py','ipython_edit_')
2485 2414 self.tempfiles.append(filename)
2486 2415
2487 2416 if data:
2488 2417 tmp_file = open(filename,'w')
2489 2418 tmp_file.write(data)
2490 2419 tmp_file.close()
2491 2420 return filename
2492 2421
2493 2422 def write(self,data):
2494 2423 """Write a string to the default output"""
2495 2424 Term.cout.write(data)
2496 2425
2497 2426 def write_err(self,data):
2498 2427 """Write a string to the default error output"""
2499 2428 Term.cerr.write(data)
2500 2429
2501 2430 def ask_yes_no(self,prompt,default=True):
2502 2431 if self.quiet:
2503 2432 return True
2504 2433 return ask_yes_no(prompt,default)
2505 2434
2506 2435 #-------------------------------------------------------------------------
2507 2436 # Things related to GUI support and pylab
2508 2437 #-------------------------------------------------------------------------
2509 2438
2510 2439 def enable_pylab(self, gui=None):
2511 2440 """Activate pylab support at runtime.
2512 2441
2513 2442 This turns on support for matplotlib, preloads into the interactive
2514 2443 namespace all of numpy and pylab, and configures IPython to correcdtly
2515 2444 interact with the GUI event loop. The GUI backend to be used can be
2516 2445 optionally selected with the optional :param:`gui` argument.
2517 2446
2518 2447 Parameters
2519 2448 ----------
2520 2449 gui : optional, string
2521 2450
2522 2451 If given, dictates the choice of matplotlib GUI backend to use
2523 2452 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
2524 2453 'gtk'), otherwise we use the default chosen by matplotlib (as
2525 2454 dictated by the matplotlib build-time options plus the user's
2526 2455 matplotlibrc configuration file).
2527 2456 """
2528 2457 # We want to prevent the loading of pylab to pollute the user's
2529 2458 # namespace as shown by the %who* magics, so we execute the activation
2530 2459 # code in an empty namespace, and we update *both* user_ns and
2531 2460 # user_ns_hidden with this information.
2532 2461 ns = {}
2533 2462 gui = pylab_activate(ns, gui)
2534 2463 self.user_ns.update(ns)
2535 2464 self.user_ns_hidden.update(ns)
2536 2465 # Now we must activate the gui pylab wants to use, and fix %run to take
2537 2466 # plot updates into account
2538 2467 enable_gui(gui)
2539 2468 self.magic_run = self._pylab_magic_run
2540 2469
2541 2470 #-------------------------------------------------------------------------
2542 2471 # Things related to IPython exiting
2543 2472 #-------------------------------------------------------------------------
2544 2473
2545 2474 def ask_exit(self):
2546 2475 """ Ask the shell to exit. Can be overiden and used as a callback. """
2547 2476 self.exit_now = True
2548 2477
2549 2478 def exit(self):
2550 2479 """Handle interactive exit.
2551 2480
2552 2481 This method calls the ask_exit callback."""
2553 2482 if self.confirm_exit:
2554 2483 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
2555 2484 self.ask_exit()
2556 2485 else:
2557 2486 self.ask_exit()
2558 2487
2559 2488 def atexit_operations(self):
2560 2489 """This will be executed at the time of exit.
2561 2490
2562 2491 Saving of persistent data should be performed here.
2563 2492 """
2564 2493 self.savehist()
2565 2494
2566 2495 # Cleanup all tempfiles left around
2567 2496 for tfile in self.tempfiles:
2568 2497 try:
2569 2498 os.unlink(tfile)
2570 2499 except OSError:
2571 2500 pass
2572 2501
2573 2502 # Clear all user namespaces to release all references cleanly.
2574 2503 self.reset()
2575 2504
2576 2505 # Run user hooks
2577 2506 self.hooks.shutdown_hook()
2578 2507
2579 2508 def cleanup(self):
2580 2509 self.restore_sys_module_state()
2581 2510
2582 2511
1 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 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 Prefiltering components.
5 5
6 6 Prefilters transform user input before it is exec'd by Python. These
7 7 transforms are used to implement additional syntax such as !ls and %magic.
8 8
9 9 Authors:
10 10
11 11 * Brian Granger
12 12 * Fernando Perez
13 13 * Dan Milstein
14 14 * Ville Vainio
15 15 """
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Copyright (C) 2008-2009 The IPython Development Team
19 19 #
20 20 # Distributed under the terms of the BSD License. The full license is in
21 21 # the file COPYING, distributed as part of this software.
22 22 #-----------------------------------------------------------------------------
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Imports
26 26 #-----------------------------------------------------------------------------
27 27
28 28 import __builtin__
29 29 import codeop
30 30 import re
31 31
32 32 from IPython.core.alias import AliasManager
33 33 from IPython.core.autocall import IPyAutocall
34 from IPython.core.component import Component
34 from IPython.config.configurable import Configurable
35 35 from IPython.core.splitinput import split_user_input
36 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 39 from IPython.utils.io import Term
40 40 from IPython.utils.text import make_quoted_expr
41 41 from IPython.utils.autoattr import auto_attr
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Global utilities, errors and constants
45 45 #-----------------------------------------------------------------------------
46 46
47 47 # Warning, these cannot be changed unless various regular expressions
48 48 # are updated in a number of places. Not great, but at least we told you.
49 49 ESC_SHELL = '!'
50 50 ESC_SH_CAP = '!!'
51 51 ESC_HELP = '?'
52 52 ESC_MAGIC = '%'
53 53 ESC_QUOTE = ','
54 54 ESC_QUOTE2 = ';'
55 55 ESC_PAREN = '/'
56 56
57 57
58 58 class PrefilterError(Exception):
59 59 pass
60 60
61 61
62 62 # RegExp to identify potential function names
63 63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
64 64
65 65 # RegExp to exclude strings with this start from autocalling. In
66 66 # particular, all binary operators should be excluded, so that if foo is
67 67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
68 68 # characters '!=()' don't need to be checked for, as the checkPythonChars
69 69 # routine explicitely does so, to catch direct calls and rebindings of
70 70 # existing names.
71 71
72 72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
73 73 # it affects the rest of the group in square brackets.
74 74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
75 75 r'|^is |^not |^in |^and |^or ')
76 76
77 77 # try to catch also methods for stuff in lists/tuples/dicts: off
78 78 # (experimental). For this to work, the line_split regexp would need
79 79 # to be modified so it wouldn't break things at '['. That line is
80 80 # nasty enough that I shouldn't change it until I can test it _well_.
81 81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
82 82
83 83
84 84 # Handler Check Utilities
85 85 def is_shadowed(identifier, ip):
86 86 """Is the given identifier defined in one of the namespaces which shadow
87 87 the alias and magic namespaces? Note that an identifier is different
88 88 than ifun, because it can not contain a '.' character."""
89 89 # This is much safer than calling ofind, which can change state
90 90 return (identifier in ip.user_ns \
91 91 or identifier in ip.internal_ns \
92 92 or identifier in ip.ns_table['builtin'])
93 93
94 94
95 95 #-----------------------------------------------------------------------------
96 96 # The LineInfo class used throughout
97 97 #-----------------------------------------------------------------------------
98 98
99 99
100 100 class LineInfo(object):
101 101 """A single line of input and associated info.
102 102
103 103 Includes the following as properties:
104 104
105 105 line
106 106 The original, raw line
107 107
108 108 continue_prompt
109 109 Is this line a continuation in a sequence of multiline input?
110 110
111 111 pre
112 112 The initial esc character or whitespace.
113 113
114 114 pre_char
115 115 The escape character(s) in pre or the empty string if there isn't one.
116 116 Note that '!!' is a possible value for pre_char. Otherwise it will
117 117 always be a single character.
118 118
119 119 pre_whitespace
120 120 The leading whitespace from pre if it exists. If there is a pre_char,
121 121 this is just ''.
122 122
123 123 ifun
124 124 The 'function part', which is basically the maximal initial sequence
125 125 of valid python identifiers and the '.' character. This is what is
126 126 checked for alias and magic transformations, used for auto-calling,
127 127 etc.
128 128
129 129 the_rest
130 130 Everything else on the line.
131 131 """
132 132 def __init__(self, line, continue_prompt):
133 133 self.line = line
134 134 self.continue_prompt = continue_prompt
135 135 self.pre, self.ifun, self.the_rest = split_user_input(line)
136 136
137 137 self.pre_char = self.pre.strip()
138 138 if self.pre_char:
139 139 self.pre_whitespace = '' # No whitespace allowd before esc chars
140 140 else:
141 141 self.pre_whitespace = self.pre
142 142
143 143 self._oinfo = None
144 144
145 145 def ofind(self, ip):
146 146 """Do a full, attribute-walking lookup of the ifun in the various
147 147 namespaces for the given IPython InteractiveShell instance.
148 148
149 149 Return a dict with keys: found,obj,ospace,ismagic
150 150
151 151 Note: can cause state changes because of calling getattr, but should
152 152 only be run if autocall is on and if the line hasn't matched any
153 153 other, less dangerous handlers.
154 154
155 155 Does cache the results of the call, so can be called multiple times
156 156 without worrying about *further* damaging state.
157 157 """
158 158 if not self._oinfo:
159 159 # ip.shell._ofind is actually on the Magic class!
160 160 self._oinfo = ip.shell._ofind(self.ifun)
161 161 return self._oinfo
162 162
163 163 def __str__(self):
164 164 return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest)
165 165
166 166
167 167 #-----------------------------------------------------------------------------
168 168 # Main Prefilter manager
169 169 #-----------------------------------------------------------------------------
170 170
171 171
172 class PrefilterManager(Component):
172 class PrefilterManager(Configurable):
173 173 """Main prefilter component.
174 174
175 175 The IPython prefilter is run on all user input before it is run. The
176 176 prefilter consumes lines of input and produces transformed lines of
177 177 input.
178 178
179 179 The iplementation consists of two phases:
180 180
181 181 1. Transformers
182 182 2. Checkers and handlers
183 183
184 184 Over time, we plan on deprecating the checkers and handlers and doing
185 185 everything in the transformers.
186 186
187 187 The transformers are instances of :class:`PrefilterTransformer` and have
188 188 a single method :meth:`transform` that takes a line and returns a
189 189 transformed line. The transformation can be accomplished using any
190 190 tool, but our current ones use regular expressions for speed. We also
191 191 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
192 192
193 193 After all the transformers have been run, the line is fed to the checkers,
194 194 which are instances of :class:`PrefilterChecker`. The line is passed to
195 195 the :meth:`check` method, which either returns `None` or a
196 196 :class:`PrefilterHandler` instance. If `None` is returned, the other
197 197 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
198 198 the line is passed to the :meth:`handle` method of the returned
199 199 handler and no further checkers are tried.
200 200
201 201 Both transformers and checkers have a `priority` attribute, that determines
202 202 the order in which they are called. Smaller priorities are tried first.
203 203
204 204 Both transformers and checkers also have `enabled` attribute, which is
205 205 a boolean that determines if the instance is used.
206 206
207 207 Users or developers can change the priority or enabled attribute of
208 208 transformers or checkers, but they must call the :meth:`sort_checkers`
209 209 or :meth:`sort_transformers` method after changing the priority.
210 210 """
211 211
212 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 super(PrefilterManager, self).__init__(parent, config=config)
215 def __init__(self, shell, config=None):
216 super(PrefilterManager, self).__init__(config=config)
217 self.shell = shell
216 218 self.init_transformers()
217 219 self.init_handlers()
218 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 223 # API for managing transformers
228 224 #-------------------------------------------------------------------------
229 225
230 226 def init_transformers(self):
231 227 """Create the default transformers."""
232 228 self._transformers = []
233 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 232 def sort_transformers(self):
237 233 """Sort the transformers by priority.
238 234
239 235 This must be called after the priority of a transformer is changed.
240 236 The :meth:`register_transformer` method calls this automatically.
241 237 """
242 238 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
243 239
244 240 @property
245 241 def transformers(self):
246 242 """Return a list of checkers, sorted by priority."""
247 243 return self._transformers
248 244
249 245 def register_transformer(self, transformer):
250 246 """Register a transformer instance."""
251 247 if transformer not in self._transformers:
252 248 self._transformers.append(transformer)
253 249 self.sort_transformers()
254 250
255 251 def unregister_transformer(self, transformer):
256 252 """Unregister a transformer instance."""
257 253 if transformer in self._transformers:
258 254 self._transformers.remove(transformer)
259 255
260 256 #-------------------------------------------------------------------------
261 257 # API for managing checkers
262 258 #-------------------------------------------------------------------------
263 259
264 260 def init_checkers(self):
265 261 """Create the default checkers."""
266 262 self._checkers = []
267 263 for checker in _default_checkers:
268 checker(self, config=self.config)
264 checker(self.shell, self, config=self.config)
269 265
270 266 def sort_checkers(self):
271 267 """Sort the checkers by priority.
272 268
273 269 This must be called after the priority of a checker is changed.
274 270 The :meth:`register_checker` method calls this automatically.
275 271 """
276 272 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
277 273
278 274 @property
279 275 def checkers(self):
280 276 """Return a list of checkers, sorted by priority."""
281 277 return self._checkers
282 278
283 279 def register_checker(self, checker):
284 280 """Register a checker instance."""
285 281 if checker not in self._checkers:
286 282 self._checkers.append(checker)
287 283 self.sort_checkers()
288 284
289 285 def unregister_checker(self, checker):
290 286 """Unregister a checker instance."""
291 287 if checker in self._checkers:
292 288 self._checkers.remove(checker)
293 289
294 290 #-------------------------------------------------------------------------
295 291 # API for managing checkers
296 292 #-------------------------------------------------------------------------
297 293
298 294 def init_handlers(self):
299 295 """Create the default handlers."""
300 296 self._handlers = {}
301 297 self._esc_handlers = {}
302 298 for handler in _default_handlers:
303 handler(self, config=self.config)
299 handler(self.shell, self, config=self.config)
304 300
305 301 @property
306 302 def handlers(self):
307 303 """Return a dict of all the handlers."""
308 304 return self._handlers
309 305
310 306 def register_handler(self, name, handler, esc_strings):
311 307 """Register a handler instance by name with esc_strings."""
312 308 self._handlers[name] = handler
313 309 for esc_str in esc_strings:
314 310 self._esc_handlers[esc_str] = handler
315 311
316 312 def unregister_handler(self, name, handler, esc_strings):
317 313 """Unregister a handler instance by name with esc_strings."""
318 314 try:
319 315 del self._handlers[name]
320 316 except KeyError:
321 317 pass
322 318 for esc_str in esc_strings:
323 319 h = self._esc_handlers.get(esc_str)
324 320 if h is handler:
325 321 del self._esc_handlers[esc_str]
326 322
327 323 def get_handler_by_name(self, name):
328 324 """Get a handler by its name."""
329 325 return self._handlers.get(name)
330 326
331 327 def get_handler_by_esc(self, esc_str):
332 328 """Get a handler by its escape string."""
333 329 return self._esc_handlers.get(esc_str)
334 330
335 331 #-------------------------------------------------------------------------
336 332 # Main prefiltering API
337 333 #-------------------------------------------------------------------------
338 334
339 335 def prefilter_line_info(self, line_info):
340 336 """Prefilter a line that has been converted to a LineInfo object.
341 337
342 338 This implements the checker/handler part of the prefilter pipe.
343 339 """
344 340 # print "prefilter_line_info: ", line_info
345 341 handler = self.find_handler(line_info)
346 342 return handler.handle(line_info)
347 343
348 344 def find_handler(self, line_info):
349 345 """Find a handler for the line_info by trying checkers."""
350 346 for checker in self.checkers:
351 347 if checker.enabled:
352 348 handler = checker.check(line_info)
353 349 if handler:
354 350 return handler
355 351 return self.get_handler_by_name('normal')
356 352
357 353 def transform_line(self, line, continue_prompt):
358 354 """Calls the enabled transformers in order of increasing priority."""
359 355 for transformer in self.transformers:
360 356 if transformer.enabled:
361 357 line = transformer.transform(line, continue_prompt)
362 358 return line
363 359
364 360 def prefilter_line(self, line, continue_prompt=False):
365 361 """Prefilter a single input line as text.
366 362
367 363 This method prefilters a single line of text by calling the
368 364 transformers and then the checkers/handlers.
369 365 """
370 366
371 367 # print "prefilter_line: ", line, continue_prompt
372 368 # All handlers *must* return a value, even if it's blank ('').
373 369
374 370 # Lines are NOT logged here. Handlers should process the line as
375 371 # needed, update the cache AND log it (so that the input cache array
376 372 # stays synced).
377 373
378 374 # save the line away in case we crash, so the post-mortem handler can
379 375 # record it
380 376 self.shell._last_input_line = line
381 377
382 378 if not line:
383 379 # Return immediately on purely empty lines, so that if the user
384 380 # previously typed some whitespace that started a continuation
385 381 # prompt, he can break out of that loop with just an empty line.
386 382 # This is how the default python prompt works.
387 383
388 384 # Only return if the accumulated input buffer was just whitespace!
389 385 if ''.join(self.shell.buffer).isspace():
390 386 self.shell.buffer[:] = []
391 387 return ''
392 388
393 389 # At this point, we invoke our transformers.
394 390 if not continue_prompt or (continue_prompt and self.multi_line_specials):
395 391 line = self.transform_line(line, continue_prompt)
396 392
397 393 # Now we compute line_info for the checkers and handlers
398 394 line_info = LineInfo(line, continue_prompt)
399 395
400 396 # the input history needs to track even empty lines
401 397 stripped = line.strip()
402 398
403 399 normal_handler = self.get_handler_by_name('normal')
404 400 if not stripped:
405 401 if not continue_prompt:
406 402 self.shell.outputcache.prompt_count -= 1
407 403
408 404 return normal_handler.handle(line_info)
409 405
410 406 # special handlers are only allowed for single line statements
411 407 if continue_prompt and not self.multi_line_specials:
412 408 return normal_handler.handle(line_info)
413 409
414 410 prefiltered = self.prefilter_line_info(line_info)
415 411 # print "prefiltered line: %r" % prefiltered
416 412 return prefiltered
417 413
418 414 def prefilter_lines(self, lines, continue_prompt=False):
419 415 """Prefilter multiple input lines of text.
420 416
421 417 This is the main entry point for prefiltering multiple lines of
422 418 input. This simply calls :meth:`prefilter_line` for each line of
423 419 input.
424 420
425 421 This covers cases where there are multiple lines in the user entry,
426 422 which is the case when the user goes back to a multiline history
427 423 entry and presses enter.
428 424 """
429 425 llines = lines.rstrip('\n').split('\n')
430 426 # We can get multiple lines in one shot, where multiline input 'blends'
431 427 # into one line, in cases like recalling from the readline history
432 428 # buffer. We need to make sure that in such cases, we correctly
433 429 # communicate downstream which line is first and which are continuation
434 430 # ones.
435 431 if len(llines) > 1:
436 432 out = '\n'.join([self.prefilter_line(line, lnum>0)
437 433 for lnum, line in enumerate(llines) ])
438 434 else:
439 435 out = self.prefilter_line(llines[0], continue_prompt)
440 436
441 437 return out
442 438
443 439 #-----------------------------------------------------------------------------
444 440 # Prefilter transformers
445 441 #-----------------------------------------------------------------------------
446 442
447 443
448 class PrefilterTransformer(Component):
444 class PrefilterTransformer(Configurable):
449 445 """Transform a line of user input."""
450 446
451 447 priority = Int(100, config=True)
452 shell = Any
453 prefilter_manager = Any
448 # Transformers don't currently use shell or prefilter_manager, but as we
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 452 enabled = Bool(True, config=True)
455 453
456 def __init__(self, parent, config=None):
457 super(PrefilterTransformer, self).__init__(parent, config=config)
454 def __init__(self, shell, prefilter_manager, config=None):
455 super(PrefilterTransformer, self).__init__(config=config)
456 self.shell = shell
457 self.prefilter_manager = prefilter_manager
458 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 460 def transform(self, line, continue_prompt):
471 461 """Transform a line, returning the new one."""
472 462 return None
473 463
474 464 def __repr__(self):
475 465 return "<%s(priority=%r, enabled=%r)>" % (
476 466 self.__class__.__name__, self.priority, self.enabled)
477 467
478 468
479 469 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
480 470 r'\s*=\s*!(?P<cmd>.*)')
481 471
482 472
483 473 class AssignSystemTransformer(PrefilterTransformer):
484 474 """Handle the `files = !ls` syntax."""
485 475
486 476 priority = Int(100, config=True)
487 477
488 478 def transform(self, line, continue_prompt):
489 479 m = _assign_system_re.match(line)
490 480 if m is not None:
491 481 cmd = m.group('cmd')
492 482 lhs = m.group('lhs')
493 483 expr = make_quoted_expr("sc -l =%s" % cmd)
494 484 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
495 485 return new_line
496 486 return line
497 487
498 488
499 489 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
500 490 r'\s*=\s*%(?P<cmd>.*)')
501 491
502 492 class AssignMagicTransformer(PrefilterTransformer):
503 493 """Handle the `a = %who` syntax."""
504 494
505 495 priority = Int(200, config=True)
506 496
507 497 def transform(self, line, continue_prompt):
508 498 m = _assign_magic_re.match(line)
509 499 if m is not None:
510 500 cmd = m.group('cmd')
511 501 lhs = m.group('lhs')
512 502 expr = make_quoted_expr(cmd)
513 503 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
514 504 return new_line
515 505 return line
516 506
517 507
518 508 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
519 509
520 510 class PyPromptTransformer(PrefilterTransformer):
521 511 """Handle inputs that start with '>>> ' syntax."""
522 512
523 513 priority = Int(50, config=True)
524 514
525 515 def transform(self, line, continue_prompt):
526 516
527 517 if not line or line.isspace() or line.strip() == '...':
528 518 # This allows us to recognize multiple input prompts separated by
529 519 # blank lines and pasted in a single chunk, very common when
530 520 # pasting doctests or long tutorial passages.
531 521 return ''
532 522 m = _classic_prompt_re.match(line)
533 523 if m:
534 524 return line[len(m.group(0)):]
535 525 else:
536 526 return line
537 527
538 528
539 529 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
540 530
541 531 class IPyPromptTransformer(PrefilterTransformer):
542 532 """Handle inputs that start classic IPython prompt syntax."""
543 533
544 534 priority = Int(50, config=True)
545 535
546 536 def transform(self, line, continue_prompt):
547 537
548 538 if not line or line.isspace() or line.strip() == '...':
549 539 # This allows us to recognize multiple input prompts separated by
550 540 # blank lines and pasted in a single chunk, very common when
551 541 # pasting doctests or long tutorial passages.
552 542 return ''
553 543 m = _ipy_prompt_re.match(line)
554 544 if m:
555 545 return line[len(m.group(0)):]
556 546 else:
557 547 return line
558 548
559 549 #-----------------------------------------------------------------------------
560 550 # Prefilter checkers
561 551 #-----------------------------------------------------------------------------
562 552
563 553
564 class PrefilterChecker(Component):
554 class PrefilterChecker(Configurable):
565 555 """Inspect an input line and return a handler for that line."""
566 556
567 557 priority = Int(100, config=True)
568 shell = Any
569 prefilter_manager = Any
558 shell = Instance('IPython.core.iplib.InteractiveShell')
559 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
570 560 enabled = Bool(True, config=True)
571 561
572 def __init__(self, parent, config=None):
573 super(PrefilterChecker, self).__init__(parent, config=config)
562 def __init__(self, shell, prefilter_manager, config=None):
563 super(PrefilterChecker, self).__init__(config=config)
564 self.shell = shell
565 self.prefilter_manager = prefilter_manager
574 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 568 def check(self, line_info):
587 569 """Inspect line_info and return a handler instance or None."""
588 570 return None
589 571
590 572 def __repr__(self):
591 573 return "<%s(priority=%r, enabled=%r)>" % (
592 574 self.__class__.__name__, self.priority, self.enabled)
593 575
594 576
595 577 class EmacsChecker(PrefilterChecker):
596 578
597 579 priority = Int(100, config=True)
598 580 enabled = Bool(False, config=True)
599 581
600 582 def check(self, line_info):
601 583 "Emacs ipython-mode tags certain input lines."
602 584 if line_info.line.endswith('# PYTHON-MODE'):
603 585 return self.prefilter_manager.get_handler_by_name('emacs')
604 586 else:
605 587 return None
606 588
607 589
608 590 class ShellEscapeChecker(PrefilterChecker):
609 591
610 592 priority = Int(200, config=True)
611 593
612 594 def check(self, line_info):
613 595 if line_info.line.lstrip().startswith(ESC_SHELL):
614 596 return self.prefilter_manager.get_handler_by_name('shell')
615 597
616 598
617 599 class IPyAutocallChecker(PrefilterChecker):
618 600
619 601 priority = Int(300, config=True)
620 602
621 603 def check(self, line_info):
622 604 "Instances of IPyAutocall in user_ns get autocalled immediately"
623 605 obj = self.shell.user_ns.get(line_info.ifun, None)
624 606 if isinstance(obj, IPyAutocall):
625 607 obj.set_ip(self.shell)
626 608 return self.prefilter_manager.get_handler_by_name('auto')
627 609 else:
628 610 return None
629 611
630 612
631 613 class MultiLineMagicChecker(PrefilterChecker):
632 614
633 615 priority = Int(400, config=True)
634 616
635 617 def check(self, line_info):
636 618 "Allow ! and !! in multi-line statements if multi_line_specials is on"
637 619 # Note that this one of the only places we check the first character of
638 620 # ifun and *not* the pre_char. Also note that the below test matches
639 621 # both ! and !!.
640 622 if line_info.continue_prompt \
641 623 and self.prefilter_manager.multi_line_specials:
642 624 if line_info.ifun.startswith(ESC_MAGIC):
643 625 return self.prefilter_manager.get_handler_by_name('magic')
644 626 else:
645 627 return None
646 628
647 629
648 630 class EscCharsChecker(PrefilterChecker):
649 631
650 632 priority = Int(500, config=True)
651 633
652 634 def check(self, line_info):
653 635 """Check for escape character and return either a handler to handle it,
654 636 or None if there is no escape char."""
655 637 if line_info.line[-1] == ESC_HELP \
656 638 and line_info.pre_char != ESC_SHELL \
657 639 and line_info.pre_char != ESC_SH_CAP:
658 640 # the ? can be at the end, but *not* for either kind of shell escape,
659 641 # because a ? can be a vaild final char in a shell cmd
660 642 return self.prefilter_manager.get_handler_by_name('help')
661 643 else:
662 644 # This returns None like it should if no handler exists
663 645 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
664 646
665 647
666 648 class AssignmentChecker(PrefilterChecker):
667 649
668 650 priority = Int(600, config=True)
669 651
670 652 def check(self, line_info):
671 653 """Check to see if user is assigning to a var for the first time, in
672 654 which case we want to avoid any sort of automagic / autocall games.
673 655
674 656 This allows users to assign to either alias or magic names true python
675 657 variables (the magic/alias systems always take second seat to true
676 658 python code). E.g. ls='hi', or ls,that=1,2"""
677 659 if line_info.the_rest:
678 660 if line_info.the_rest[0] in '=,':
679 661 return self.prefilter_manager.get_handler_by_name('normal')
680 662 else:
681 663 return None
682 664
683 665
684 666 class AutoMagicChecker(PrefilterChecker):
685 667
686 668 priority = Int(700, config=True)
687 669
688 670 def check(self, line_info):
689 671 """If the ifun is magic, and automagic is on, run it. Note: normal,
690 672 non-auto magic would already have been triggered via '%' in
691 673 check_esc_chars. This just checks for automagic. Also, before
692 674 triggering the magic handler, make sure that there is nothing in the
693 675 user namespace which could shadow it."""
694 676 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
695 677 return None
696 678
697 679 # We have a likely magic method. Make sure we should actually call it.
698 680 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
699 681 return None
700 682
701 683 head = line_info.ifun.split('.',1)[0]
702 684 if is_shadowed(head, self.shell):
703 685 return None
704 686
705 687 return self.prefilter_manager.get_handler_by_name('magic')
706 688
707 689
708 690 class AliasChecker(PrefilterChecker):
709 691
710 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 694 def check(self, line_info):
717 695 "Check if the initital identifier on the line is an alias."
718 696 # Note: aliases can not contain '.'
719 697 head = line_info.ifun.split('.',1)[0]
720 if line_info.ifun not in self.alias_manager \
721 or head not in self.alias_manager \
698 if line_info.ifun not in self.shell.alias_manager \
699 or head not in self.shell.alias_manager \
722 700 or is_shadowed(head, self.shell):
723 701 return None
724 702
725 703 return self.prefilter_manager.get_handler_by_name('alias')
726 704
727 705
728 706 class PythonOpsChecker(PrefilterChecker):
729 707
730 708 priority = Int(900, config=True)
731 709
732 710 def check(self, line_info):
733 711 """If the 'rest' of the line begins with a function call or pretty much
734 712 any python operator, we should simply execute the line (regardless of
735 713 whether or not there's a possible autocall expansion). This avoids
736 714 spurious (and very confusing) geattr() accesses."""
737 715 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
738 716 return self.prefilter_manager.get_handler_by_name('normal')
739 717 else:
740 718 return None
741 719
742 720
743 721 class AutocallChecker(PrefilterChecker):
744 722
745 723 priority = Int(1000, config=True)
746 724
747 725 def check(self, line_info):
748 726 "Check if the initial word/function is callable and autocall is on."
749 727 if not self.shell.autocall:
750 728 return None
751 729
752 730 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
753 731 if not oinfo['found']:
754 732 return None
755 733
756 734 if callable(oinfo['obj']) \
757 735 and (not re_exclude_auto.match(line_info.the_rest)) \
758 736 and re_fun_name.match(line_info.ifun):
759 737 return self.prefilter_manager.get_handler_by_name('auto')
760 738 else:
761 739 return None
762 740
763 741
764 742 #-----------------------------------------------------------------------------
765 743 # Prefilter handlers
766 744 #-----------------------------------------------------------------------------
767 745
768 746
769 class PrefilterHandler(Component):
747 class PrefilterHandler(Configurable):
770 748
771 749 handler_name = Str('normal')
772 750 esc_strings = List([])
773 shell = Any
774 prefilter_manager = Any
751 shell = Instance('IPython.core.iplib.InteractiveShell')
752 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
775 753
776 def __init__(self, parent, config=None):
777 super(PrefilterHandler, self).__init__(parent, config=config)
754 def __init__(self, shell, prefilter_manager, config=None):
755 super(PrefilterHandler, self).__init__(config=config)
756 self.shell = shell
757 self.prefilter_manager = prefilter_manager
778 758 self.prefilter_manager.register_handler(
779 759 self.handler_name,
780 760 self,
781 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 764 def handle(self, line_info):
795 765 # print "normal: ", line_info
796 766 """Handle normal input lines. Use as a template for handlers."""
797 767
798 768 # With autoindent on, we need some way to exit the input loop, and I
799 769 # don't want to force the user to have to backspace all the way to
800 770 # clear the line. The rule will be in this case, that either two
801 771 # lines of pure whitespace in a row, or a line of pure whitespace but
802 772 # of a size different to the indent level, will exit the input loop.
803 773 line = line_info.line
804 774 continue_prompt = line_info.continue_prompt
805 775
806 776 if (continue_prompt and
807 777 self.shell.autoindent and
808 778 line.isspace() and
809 779
810 780 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2
811 781 or
812 782 not self.shell.buffer
813 783 or
814 784 (self.shell.buffer[-1]).isspace()
815 785 )
816 786 ):
817 787 line = ''
818 788
819 789 self.shell.log(line, line, continue_prompt)
820 790 return line
821 791
822 792 def __str__(self):
823 793 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
824 794
825 795
826 796 class AliasHandler(PrefilterHandler):
827 797
828 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 800 def handle(self, line_info):
835 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 803 # pre is needed, because it carries the leading whitespace. Otherwise
838 804 # aliases won't work in indented sections.
839 805 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
840 806 make_quoted_expr(transformed))
841 807
842 808 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
843 809 return line_out
844 810
845 811
846 812 class ShellEscapeHandler(PrefilterHandler):
847 813
848 814 handler_name = Str('shell')
849 815 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
850 816
851 817 def handle(self, line_info):
852 818 """Execute the line in a shell, empty return value"""
853 819 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
854 820
855 821 line = line_info.line
856 822 if line.lstrip().startswith(ESC_SH_CAP):
857 823 # rewrite LineInfo's line, ifun and the_rest to properly hold the
858 824 # call to %sx and the actual command to be executed, so
859 825 # handle_magic can work correctly. Note that this works even if
860 826 # the line is indented, so it handles multi_line_specials
861 827 # properly.
862 828 new_rest = line.lstrip()[2:]
863 829 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
864 830 line_info.ifun = 'sx'
865 831 line_info.the_rest = new_rest
866 832 return magic_handler.handle(line_info)
867 833 else:
868 834 cmd = line.lstrip().lstrip(ESC_SHELL)
869 835 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
870 836 make_quoted_expr(cmd))
871 837 # update cache/log and return
872 838 self.shell.log(line, line_out, line_info.continue_prompt)
873 839 return line_out
874 840
875 841
876 842 class MagicHandler(PrefilterHandler):
877 843
878 844 handler_name = Str('magic')
879 845 esc_strings = List([ESC_MAGIC])
880 846
881 847 def handle(self, line_info):
882 848 """Execute magic functions."""
883 849 ifun = line_info.ifun
884 850 the_rest = line_info.the_rest
885 851 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
886 852 make_quoted_expr(ifun + " " + the_rest))
887 853 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
888 854 return cmd
889 855
890 856
891 857 class AutoHandler(PrefilterHandler):
892 858
893 859 handler_name = Str('auto')
894 860 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
895 861
896 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 864 line = line_info.line
899 865 ifun = line_info.ifun
900 866 the_rest = line_info.the_rest
901 867 pre = line_info.pre
902 868 continue_prompt = line_info.continue_prompt
903 869 obj = line_info.ofind(self)['obj']
904 870 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
905 871
906 872 # This should only be active for single-line input!
907 873 if continue_prompt:
908 874 self.shell.log(line,line,continue_prompt)
909 875 return line
910 876
911 877 force_auto = isinstance(obj, IPyAutocall)
912 878 auto_rewrite = True
913 879
914 880 if pre == ESC_QUOTE:
915 881 # Auto-quote splitting on whitespace
916 882 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
917 883 elif pre == ESC_QUOTE2:
918 884 # Auto-quote whole string
919 885 newcmd = '%s("%s")' % (ifun,the_rest)
920 886 elif pre == ESC_PAREN:
921 887 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
922 888 else:
923 889 # Auto-paren.
924 890 # We only apply it to argument-less calls if the autocall
925 891 # parameter is set to 2. We only need to check that autocall is <
926 892 # 2, since this function isn't called unless it's at least 1.
927 893 if not the_rest and (self.shell.autocall < 2) and not force_auto:
928 894 newcmd = '%s %s' % (ifun,the_rest)
929 895 auto_rewrite = False
930 896 else:
931 897 if not force_auto and the_rest.startswith('['):
932 898 if hasattr(obj,'__getitem__'):
933 899 # Don't autocall in this case: item access for an object
934 900 # which is BOTH callable and implements __getitem__.
935 901 newcmd = '%s %s' % (ifun,the_rest)
936 902 auto_rewrite = False
937 903 else:
938 904 # if the object doesn't support [] access, go ahead and
939 905 # autocall
940 906 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
941 907 elif the_rest.endswith(';'):
942 908 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
943 909 else:
944 910 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
945 911
946 912 if auto_rewrite:
947 913 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
948 914
949 915 try:
950 916 # plain ascii works better w/ pyreadline, on some machines, so
951 917 # we use it and only print uncolored rewrite if we have unicode
952 918 rw = str(rw)
953 919 print >>Term.cout, rw
954 920 except UnicodeEncodeError:
955 921 print "-------------->" + newcmd
956 922
957 923 # log what is now valid Python, not the actual user input (without the
958 924 # final newline)
959 925 self.shell.log(line,newcmd,continue_prompt)
960 926 return newcmd
961 927
962 928
963 929 class HelpHandler(PrefilterHandler):
964 930
965 931 handler_name = Str('help')
966 932 esc_strings = List([ESC_HELP])
967 933
968 934 def handle(self, line_info):
969 935 """Try to get some help for the object.
970 936
971 937 obj? or ?obj -> basic information.
972 938 obj?? or ??obj -> more details.
973 939 """
974 940 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
975 941 line = line_info.line
976 942 # We need to make sure that we don't process lines which would be
977 943 # otherwise valid python, such as "x=1 # what?"
978 944 try:
979 945 codeop.compile_command(line)
980 946 except SyntaxError:
981 947 # We should only handle as help stuff which is NOT valid syntax
982 948 if line[0]==ESC_HELP:
983 949 line = line[1:]
984 950 elif line[-1]==ESC_HELP:
985 951 line = line[:-1]
986 952 self.shell.log(line, '#?'+line, line_info.continue_prompt)
987 953 if line:
988 954 #print 'line:<%r>' % line # dbg
989 955 self.shell.magic_pinfo(line)
990 956 else:
991 957 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
992 958 return '' # Empty string is needed here!
993 959 except:
994 960 raise
995 961 # Pass any other exceptions through to the normal handler
996 962 return normal_handler.handle(line_info)
997 963 else:
998 964 # If the code compiles ok, we should handle it normally
999 965 return normal_handler.handle(line_info)
1000 966
1001 967
1002 968 class EmacsHandler(PrefilterHandler):
1003 969
1004 970 handler_name = Str('emacs')
1005 971 esc_strings = List([])
1006 972
1007 973 def handle(self, line_info):
1008 974 """Handle input lines marked by python-mode."""
1009 975
1010 976 # Currently, nothing is done. Later more functionality can be added
1011 977 # here if needed.
1012 978
1013 979 # The input cache shouldn't be updated
1014 980 return line_info.line
1015 981
1016 982
1017 983 #-----------------------------------------------------------------------------
1018 984 # Defaults
1019 985 #-----------------------------------------------------------------------------
1020 986
1021 987
1022 988 _default_transformers = [
1023 989 AssignSystemTransformer,
1024 990 AssignMagicTransformer,
1025 991 PyPromptTransformer,
1026 992 IPyPromptTransformer,
1027 993 ]
1028 994
1029 995 _default_checkers = [
1030 996 EmacsChecker,
1031 997 ShellEscapeChecker,
1032 998 IPyAutocallChecker,
1033 999 MultiLineMagicChecker,
1034 1000 EscCharsChecker,
1035 1001 AssignmentChecker,
1036 1002 AutoMagicChecker,
1037 1003 AliasChecker,
1038 1004 PythonOpsChecker,
1039 1005 AutocallChecker
1040 1006 ]
1041 1007
1042 1008 _default_handlers = [
1043 1009 PrefilterHandler,
1044 1010 AliasHandler,
1045 1011 ShellEscapeHandler,
1046 1012 MagicHandler,
1047 1013 AutoHandler,
1048 1014 HelpHandler,
1049 1015 EmacsHandler
1050 1016 ]
@@ -1,101 +1,101 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 Simple tests for :mod:`IPython.extensions.pretty`.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from unittest import TestCase
19 19
20 20 from IPython.core.component import Component, masquerade_as
21 21 from IPython.core.iplib import InteractiveShell
22 22 from IPython.extensions import pretty as pretty_ext
23 23 from IPython.external import pretty
24 24 from IPython.testing import decorators as dec
25 25 from IPython.testing import tools as tt
26 26 from IPython.utils.traitlets import Bool
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Tests
30 30 #-----------------------------------------------------------------------------
31 31
32 32 class InteractiveShellStub(Component):
33 33 pprint = Bool(True)
34 34
35 35 class A(object):
36 36 pass
37 37
38 38 def a_pprinter(o, p, c):
39 39 return p.text("<A>")
40 40
41 41 class TestPrettyResultDisplay(TestCase):
42 42
43 43 def setUp(self):
44 44 self.ip = InteractiveShellStub(None)
45 45 # This allows our stub to be retrieved instead of the real
46 46 # InteractiveShell
47 47 masquerade_as(self.ip, InteractiveShell)
48 48 self.prd = pretty_ext.PrettyResultDisplay(self.ip,
49 49 name='pretty_result_display')
50 50
51 51 def test_for_type(self):
52 52 self.prd.for_type(A, a_pprinter)
53 53 a = A()
54 54 result = pretty.pretty(a)
55 55 self.assertEquals(result, "<A>")
56 56
57 57 ipy_src = """
58 58 class A(object):
59 59 def __repr__(self):
60 60 return 'A()'
61 61
62 62 class B(object):
63 63 def __repr__(self):
64 64 return 'B()'
65 65
66 66 a = A()
67 67 b = B()
68 68
69 69 def a_pretty_printer(obj, p, cycle):
70 70 p.text('<A>')
71 71
72 72 def b_pretty_printer(obj, p, cycle):
73 73 p.text('<B>')
74 74
75 75
76 76 a
77 77 b
78 78
79 79 ip = get_ipython()
80 prd = ip.load_extension('pretty')
80 prd = ip.extension_manager.load_extension('pretty')
81 81 prd.for_type(A, a_pretty_printer)
82 82 prd.for_type_by_name(B.__module__, B.__name__, b_pretty_printer)
83 83
84 84 a
85 85 b
86 86 """
87 87 ipy_out = """
88 88 A()
89 89 B()
90 90 <A>
91 91 <B>
92 92 """
93 93
94 94 class TestPrettyInteractively(tt.TempFileMixin):
95 95
96 96 # XXX Unfortunately, ipexec_validate fails under win32. If someone helps
97 97 # us write a win32-compatible version, we can reactivate this test.
98 98 @dec.skip_win32
99 99 def test_printers(self):
100 100 self.mktmp(ipy_src, '.ipy')
101 101 tt.ipexec_validate(self.fname, ipy_out)
@@ -1,539 +1,539 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The IPython cluster directory
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import with_statement
19 19
20 20 import os
21 21 import shutil
22 22 import sys
23 23 import warnings
24 24
25 25 from twisted.python import log
26 26
27 27 from IPython.config.loader import PyFileConfigLoader
28 28 from IPython.core.application import Application, BaseAppConfigLoader
29 from IPython.core.component import Component
29 from IPython.config.configurable import Configurable
30 30 from IPython.core.crashhandler import CrashHandler
31 31 from IPython.core import release
32 32 from IPython.utils.path import (
33 33 get_ipython_package_dir,
34 34 expand_path
35 35 )
36 36 from IPython.utils.traitlets import Unicode
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Warnings control
40 40 #-----------------------------------------------------------------------------
41 41 # Twisted generates annoying warnings with Python 2.6, as will do other code
42 42 # that imports 'sets' as of today
43 43 warnings.filterwarnings('ignore', 'the sets module is deprecated',
44 44 DeprecationWarning )
45 45
46 46 # This one also comes from Twisted
47 47 warnings.filterwarnings('ignore', 'the sha module is deprecated',
48 48 DeprecationWarning)
49 49
50 50 #-----------------------------------------------------------------------------
51 51 # Module errors
52 52 #-----------------------------------------------------------------------------
53 53
54 54 class ClusterDirError(Exception):
55 55 pass
56 56
57 57
58 58 class PIDFileError(Exception):
59 59 pass
60 60
61 61
62 62 #-----------------------------------------------------------------------------
63 63 # Class for managing cluster directories
64 64 #-----------------------------------------------------------------------------
65 65
66 class ClusterDir(Component):
66 class ClusterDir(Configurable):
67 67 """An object to manage the cluster directory and its resources.
68 68
69 69 The cluster directory is used by :command:`ipcontroller`,
70 70 :command:`ipcontroller` and :command:`ipcontroller` to manage the
71 71 configuration, logging and security of these applications.
72 72
73 73 This object knows how to find, create and manage these directories. This
74 74 should be used by any code that want's to handle cluster directories.
75 75 """
76 76
77 77 security_dir_name = Unicode('security')
78 78 log_dir_name = Unicode('log')
79 79 pid_dir_name = Unicode('pid')
80 80 security_dir = Unicode(u'')
81 81 log_dir = Unicode(u'')
82 82 pid_dir = Unicode(u'')
83 83 location = Unicode(u'')
84 84
85 85 def __init__(self, location):
86 86 super(ClusterDir, self).__init__(None)
87 87 self.location = location
88 88
89 89 def _location_changed(self, name, old, new):
90 90 if not os.path.isdir(new):
91 91 os.makedirs(new)
92 92 self.security_dir = os.path.join(new, self.security_dir_name)
93 93 self.log_dir = os.path.join(new, self.log_dir_name)
94 94 self.pid_dir = os.path.join(new, self.pid_dir_name)
95 95 self.check_dirs()
96 96
97 97 def _log_dir_changed(self, name, old, new):
98 98 self.check_log_dir()
99 99
100 100 def check_log_dir(self):
101 101 if not os.path.isdir(self.log_dir):
102 102 os.mkdir(self.log_dir)
103 103
104 104 def _security_dir_changed(self, name, old, new):
105 105 self.check_security_dir()
106 106
107 107 def check_security_dir(self):
108 108 if not os.path.isdir(self.security_dir):
109 109 os.mkdir(self.security_dir, 0700)
110 110 os.chmod(self.security_dir, 0700)
111 111
112 112 def _pid_dir_changed(self, name, old, new):
113 113 self.check_pid_dir()
114 114
115 115 def check_pid_dir(self):
116 116 if not os.path.isdir(self.pid_dir):
117 117 os.mkdir(self.pid_dir, 0700)
118 118 os.chmod(self.pid_dir, 0700)
119 119
120 120 def check_dirs(self):
121 121 self.check_security_dir()
122 122 self.check_log_dir()
123 123 self.check_pid_dir()
124 124
125 125 def load_config_file(self, filename):
126 126 """Load a config file from the top level of the cluster dir.
127 127
128 128 Parameters
129 129 ----------
130 130 filename : unicode or str
131 131 The filename only of the config file that must be located in
132 132 the top-level of the cluster directory.
133 133 """
134 134 loader = PyFileConfigLoader(filename, self.location)
135 135 return loader.load_config()
136 136
137 137 def copy_config_file(self, config_file, path=None, overwrite=False):
138 138 """Copy a default config file into the active cluster directory.
139 139
140 140 Default configuration files are kept in :mod:`IPython.config.default`.
141 141 This function moves these from that location to the working cluster
142 142 directory.
143 143 """
144 144 if path is None:
145 145 import IPython.config.default
146 146 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
147 147 path = os.path.sep.join(path)
148 148 src = os.path.join(path, config_file)
149 149 dst = os.path.join(self.location, config_file)
150 150 if not os.path.isfile(dst) or overwrite:
151 151 shutil.copy(src, dst)
152 152
153 153 def copy_all_config_files(self, path=None, overwrite=False):
154 154 """Copy all config files into the active cluster directory."""
155 155 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
156 156 u'ipcluster_config.py']:
157 157 self.copy_config_file(f, path=path, overwrite=overwrite)
158 158
159 159 @classmethod
160 160 def create_cluster_dir(csl, cluster_dir):
161 161 """Create a new cluster directory given a full path.
162 162
163 163 Parameters
164 164 ----------
165 165 cluster_dir : str
166 166 The full path to the cluster directory. If it does exist, it will
167 167 be used. If not, it will be created.
168 168 """
169 169 return ClusterDir(cluster_dir)
170 170
171 171 @classmethod
172 172 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
173 173 """Create a cluster dir by profile name and path.
174 174
175 175 Parameters
176 176 ----------
177 177 path : str
178 178 The path (directory) to put the cluster directory in.
179 179 profile : str
180 180 The name of the profile. The name of the cluster directory will
181 181 be "cluster_<profile>".
182 182 """
183 183 if not os.path.isdir(path):
184 184 raise ClusterDirError('Directory not found: %s' % path)
185 185 cluster_dir = os.path.join(path, u'cluster_' + profile)
186 186 return ClusterDir(cluster_dir)
187 187
188 188 @classmethod
189 189 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
190 190 """Find an existing cluster dir by profile name, return its ClusterDir.
191 191
192 192 This searches through a sequence of paths for a cluster dir. If it
193 193 is not found, a :class:`ClusterDirError` exception will be raised.
194 194
195 195 The search path algorithm is:
196 196 1. ``os.getcwd()``
197 197 2. ``ipython_dir``
198 198 3. The directories found in the ":" separated
199 199 :env:`IPCLUSTER_DIR_PATH` environment variable.
200 200
201 201 Parameters
202 202 ----------
203 203 ipython_dir : unicode or str
204 204 The IPython directory to use.
205 205 profile : unicode or str
206 206 The name of the profile. The name of the cluster directory
207 207 will be "cluster_<profile>".
208 208 """
209 209 dirname = u'cluster_' + profile
210 210 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
211 211 if cluster_dir_paths:
212 212 cluster_dir_paths = cluster_dir_paths.split(':')
213 213 else:
214 214 cluster_dir_paths = []
215 215 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
216 216 for p in paths:
217 217 cluster_dir = os.path.join(p, dirname)
218 218 if os.path.isdir(cluster_dir):
219 219 return ClusterDir(cluster_dir)
220 220 else:
221 221 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
222 222
223 223 @classmethod
224 224 def find_cluster_dir(cls, cluster_dir):
225 225 """Find/create a cluster dir and return its ClusterDir.
226 226
227 227 This will create the cluster directory if it doesn't exist.
228 228
229 229 Parameters
230 230 ----------
231 231 cluster_dir : unicode or str
232 232 The path of the cluster directory. This is expanded using
233 233 :func:`IPython.utils.genutils.expand_path`.
234 234 """
235 235 cluster_dir = expand_path(cluster_dir)
236 236 if not os.path.isdir(cluster_dir):
237 237 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
238 238 return ClusterDir(cluster_dir)
239 239
240 240
241 241 #-----------------------------------------------------------------------------
242 242 # Command line options
243 243 #-----------------------------------------------------------------------------
244 244
245 245 class ClusterDirConfigLoader(BaseAppConfigLoader):
246 246
247 247 def _add_cluster_profile(self, parser):
248 248 paa = parser.add_argument
249 249 paa('-p', '--profile',
250 250 dest='Global.profile',type=unicode,
251 251 help=
252 252 """The string name of the profile to be used. This determines the name
253 253 of the cluster dir as: cluster_<profile>. The default profile is named
254 254 'default'. The cluster directory is resolve this way if the
255 255 --cluster-dir option is not used.""",
256 256 metavar='Global.profile')
257 257
258 258 def _add_cluster_dir(self, parser):
259 259 paa = parser.add_argument
260 260 paa('--cluster-dir',
261 261 dest='Global.cluster_dir',type=unicode,
262 262 help="""Set the cluster dir. This overrides the logic used by the
263 263 --profile option.""",
264 264 metavar='Global.cluster_dir')
265 265
266 266 def _add_work_dir(self, parser):
267 267 paa = parser.add_argument
268 268 paa('--work-dir',
269 269 dest='Global.work_dir',type=unicode,
270 270 help='Set the working dir for the process.',
271 271 metavar='Global.work_dir')
272 272
273 273 def _add_clean_logs(self, parser):
274 274 paa = parser.add_argument
275 275 paa('--clean-logs',
276 276 dest='Global.clean_logs', action='store_true',
277 277 help='Delete old log flies before starting.')
278 278
279 279 def _add_no_clean_logs(self, parser):
280 280 paa = parser.add_argument
281 281 paa('--no-clean-logs',
282 282 dest='Global.clean_logs', action='store_false',
283 283 help="Don't Delete old log flies before starting.")
284 284
285 285 def _add_arguments(self):
286 286 super(ClusterDirConfigLoader, self)._add_arguments()
287 287 self._add_cluster_profile(self.parser)
288 288 self._add_cluster_dir(self.parser)
289 289 self._add_work_dir(self.parser)
290 290 self._add_clean_logs(self.parser)
291 291 self._add_no_clean_logs(self.parser)
292 292
293 293
294 294 #-----------------------------------------------------------------------------
295 295 # Crash handler for this application
296 296 #-----------------------------------------------------------------------------
297 297
298 298
299 299 _message_template = """\
300 300 Oops, $self.app_name crashed. We do our best to make it stable, but...
301 301
302 302 A crash report was automatically generated with the following information:
303 303 - A verbatim copy of the crash traceback.
304 304 - Data on your current $self.app_name configuration.
305 305
306 306 It was left in the file named:
307 307 \t'$self.crash_report_fname'
308 308 If you can email this file to the developers, the information in it will help
309 309 them in understanding and correcting the problem.
310 310
311 311 You can mail it to: $self.contact_name at $self.contact_email
312 312 with the subject '$self.app_name Crash Report'.
313 313
314 314 If you want to do it now, the following command will work (under Unix):
315 315 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
316 316
317 317 To ensure accurate tracking of this issue, please file a report about it at:
318 318 $self.bug_tracker
319 319 """
320 320
321 321 class ClusterDirCrashHandler(CrashHandler):
322 322 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
323 323
324 324 message_template = _message_template
325 325
326 326 def __init__(self, app):
327 327 contact_name = release.authors['Brian'][0]
328 328 contact_email = release.authors['Brian'][1]
329 329 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
330 330 super(ClusterDirCrashHandler,self).__init__(
331 331 app, contact_name, contact_email, bug_tracker
332 332 )
333 333
334 334
335 335 #-----------------------------------------------------------------------------
336 336 # Main application
337 337 #-----------------------------------------------------------------------------
338 338
339 339 class ApplicationWithClusterDir(Application):
340 340 """An application that puts everything into a cluster directory.
341 341
342 342 Instead of looking for things in the ipython_dir, this type of application
343 343 will use its own private directory called the "cluster directory"
344 344 for things like config files, log files, etc.
345 345
346 346 The cluster directory is resolved as follows:
347 347
348 348 * If the ``--cluster-dir`` option is given, it is used.
349 349 * If ``--cluster-dir`` is not given, the application directory is
350 350 resolve using the profile name as ``cluster_<profile>``. The search
351 351 path for this directory is then i) cwd if it is found there
352 352 and ii) in ipython_dir otherwise.
353 353
354 354 The config file for the application is to be put in the cluster
355 355 dir and named the value of the ``config_file_name`` class attribute.
356 356 """
357 357
358 358 command_line_loader = ClusterDirConfigLoader
359 359 crash_handler_class = ClusterDirCrashHandler
360 360 auto_create_cluster_dir = True
361 361
362 362 def create_default_config(self):
363 363 super(ApplicationWithClusterDir, self).create_default_config()
364 364 self.default_config.Global.profile = u'default'
365 365 self.default_config.Global.cluster_dir = u''
366 366 self.default_config.Global.work_dir = os.getcwd()
367 367 self.default_config.Global.log_to_file = False
368 368 self.default_config.Global.clean_logs = False
369 369
370 370 def find_resources(self):
371 371 """This resolves the cluster directory.
372 372
373 373 This tries to find the cluster directory and if successful, it will
374 374 have done:
375 375 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
376 376 the application.
377 377 * Sets ``self.cluster_dir`` attribute of the application and config
378 378 objects.
379 379
380 380 The algorithm used for this is as follows:
381 381 1. Try ``Global.cluster_dir``.
382 382 2. Try using ``Global.profile``.
383 383 3. If both of these fail and ``self.auto_create_cluster_dir`` is
384 384 ``True``, then create the new cluster dir in the IPython directory.
385 385 4. If all fails, then raise :class:`ClusterDirError`.
386 386 """
387 387
388 388 try:
389 389 cluster_dir = self.command_line_config.Global.cluster_dir
390 390 except AttributeError:
391 391 cluster_dir = self.default_config.Global.cluster_dir
392 392 cluster_dir = expand_path(cluster_dir)
393 393 try:
394 394 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
395 395 except ClusterDirError:
396 396 pass
397 397 else:
398 398 self.log.info('Using existing cluster dir: %s' % \
399 399 self.cluster_dir_obj.location
400 400 )
401 401 self.finish_cluster_dir()
402 402 return
403 403
404 404 try:
405 405 self.profile = self.command_line_config.Global.profile
406 406 except AttributeError:
407 407 self.profile = self.default_config.Global.profile
408 408 try:
409 409 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
410 410 self.ipython_dir, self.profile)
411 411 except ClusterDirError:
412 412 pass
413 413 else:
414 414 self.log.info('Using existing cluster dir: %s' % \
415 415 self.cluster_dir_obj.location
416 416 )
417 417 self.finish_cluster_dir()
418 418 return
419 419
420 420 if self.auto_create_cluster_dir:
421 421 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
422 422 self.ipython_dir, self.profile
423 423 )
424 424 self.log.info('Creating new cluster dir: %s' % \
425 425 self.cluster_dir_obj.location
426 426 )
427 427 self.finish_cluster_dir()
428 428 else:
429 429 raise ClusterDirError('Could not find a valid cluster directory.')
430 430
431 431 def finish_cluster_dir(self):
432 432 # Set the cluster directory
433 433 self.cluster_dir = self.cluster_dir_obj.location
434 434
435 435 # These have to be set because they could be different from the one
436 436 # that we just computed. Because command line has the highest
437 437 # priority, this will always end up in the master_config.
438 438 self.default_config.Global.cluster_dir = self.cluster_dir
439 439 self.command_line_config.Global.cluster_dir = self.cluster_dir
440 440
441 441 def find_config_file_name(self):
442 442 """Find the config file name for this application."""
443 443 # For this type of Application it should be set as a class attribute.
444 444 if not hasattr(self, 'default_config_file_name'):
445 445 self.log.critical("No config filename found")
446 446 else:
447 447 self.config_file_name = self.default_config_file_name
448 448
449 449 def find_config_file_paths(self):
450 450 # Set the search path to to the cluster directory. We should NOT
451 451 # include IPython.config.default here as the default config files
452 452 # are ALWAYS automatically moved to the cluster directory.
453 453 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
454 454 self.config_file_paths = (self.cluster_dir,)
455 455
456 456 def pre_construct(self):
457 457 # The log and security dirs were set earlier, but here we put them
458 458 # into the config and log them.
459 459 config = self.master_config
460 460 sdir = self.cluster_dir_obj.security_dir
461 461 self.security_dir = config.Global.security_dir = sdir
462 462 ldir = self.cluster_dir_obj.log_dir
463 463 self.log_dir = config.Global.log_dir = ldir
464 464 pdir = self.cluster_dir_obj.pid_dir
465 465 self.pid_dir = config.Global.pid_dir = pdir
466 466 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
467 467 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
468 468 # Change to the working directory. We do this just before construct
469 469 # is called so all the components there have the right working dir.
470 470 self.to_work_dir()
471 471
472 472 def to_work_dir(self):
473 473 wd = self.master_config.Global.work_dir
474 474 if unicode(wd) != unicode(os.getcwd()):
475 475 os.chdir(wd)
476 476 self.log.info("Changing to working dir: %s" % wd)
477 477
478 478 def start_logging(self):
479 479 # Remove old log files
480 480 if self.master_config.Global.clean_logs:
481 481 log_dir = self.master_config.Global.log_dir
482 482 for f in os.listdir(log_dir):
483 483 if f.startswith(self.name + u'-') and f.endswith('.log'):
484 484 os.remove(os.path.join(log_dir, f))
485 485 # Start logging to the new log file
486 486 if self.master_config.Global.log_to_file:
487 487 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
488 488 logfile = os.path.join(self.log_dir, log_filename)
489 489 open_log_file = open(logfile, 'w')
490 490 else:
491 491 open_log_file = sys.stdout
492 492 log.startLogging(open_log_file)
493 493
494 494 def write_pid_file(self, overwrite=False):
495 495 """Create a .pid file in the pid_dir with my pid.
496 496
497 497 This must be called after pre_construct, which sets `self.pid_dir`.
498 498 This raises :exc:`PIDFileError` if the pid file exists already.
499 499 """
500 500 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
501 501 if os.path.isfile(pid_file):
502 502 pid = self.get_pid_from_file()
503 503 if not overwrite:
504 504 raise PIDFileError(
505 505 'The pid file [%s] already exists. \nThis could mean that this '
506 506 'server is already running with [pid=%s].' % (pid_file, pid)
507 507 )
508 508 with open(pid_file, 'w') as f:
509 509 self.log.info("Creating pid file: %s" % pid_file)
510 510 f.write(repr(os.getpid())+'\n')
511 511
512 512 def remove_pid_file(self):
513 513 """Remove the pid file.
514 514
515 515 This should be called at shutdown by registering a callback with
516 516 :func:`reactor.addSystemEventTrigger`. This needs to return
517 517 ``None``.
518 518 """
519 519 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
520 520 if os.path.isfile(pid_file):
521 521 try:
522 522 self.log.info("Removing pid file: %s" % pid_file)
523 523 os.remove(pid_file)
524 524 except:
525 525 self.log.warn("Error removing the pid file: %s" % pid_file)
526 526
527 527 def get_pid_from_file(self):
528 528 """Get the pid from the pid file.
529 529
530 530 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
531 531 """
532 532 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
533 533 if os.path.isfile(pid_file):
534 534 with open(pid_file, 'r') as f:
535 535 pid = int(f.read().strip())
536 536 return pid
537 537 else:
538 538 raise PIDFileError('pid file not found: %s' % pid_file)
539 539
@@ -1,79 +1,79 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 A class for creating a Twisted service that is configured using IPython's
5 5 configuration system.
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2008-2009 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 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 24 # Code
25 25 #-----------------------------------------------------------------------------
26 26
27 27
28 28 class IConfiguredObjectFactory(zi.Interface):
29 29 """I am a component that creates a configured object.
30 30
31 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 35 def __init__(config):
36 36 """Get ready to configure the object using config."""
37 37
38 38 def create():
39 39 """Return an instance of the configured object."""
40 40
41 41
42 class ConfiguredObjectFactory(Component):
42 class ConfiguredObjectFactory(Configurable):
43 43
44 44 zi.implements(IConfiguredObjectFactory)
45 45
46 46 def __init__(self, config):
47 super(ConfiguredObjectFactory, self).__init__(None, config=config)
47 super(ConfiguredObjectFactory, self).__init__(config=config)
48 48
49 49 def create(self):
50 50 raise NotImplementedError('create must be implemented in a subclass')
51 51
52 52
53 53 class IAdaptedConfiguredObjectFactory(zi.Interface):
54 54 """I am a component that adapts and configures an object.
55 55
56 56 This class is useful if you have the adapt an instance and configure it.
57 57 """
58 58
59 59 def __init__(config, adaptee=None):
60 60 """Get ready to adapt adaptee and then configure it using config."""
61 61
62 62 def create():
63 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 68 # zi.implements(IAdaptedConfiguredObjectFactory)
69 69
70 70 def __init__(self, config, adaptee):
71 71 # print
72 72 # print "config pre:", config
73 super(AdaptedConfiguredObjectFactory, self).__init__(None, config=config)
73 super(AdaptedConfiguredObjectFactory, self).__init__(config=config)
74 74 # print
75 75 # print "config post:", config
76 76 self.adaptee = adaptee
77 77
78 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 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 Foolscap related utilities.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import with_statement
19 19
20 20 import os
21 21 import tempfile
22 22
23 23 from twisted.internet import reactor, defer
24 24 from twisted.python import log
25 25
26 26 import foolscap
27 27 try:
28 28 from foolscap.api import Tub, UnauthenticatedTub
29 29 except ImportError:
30 30 from foolscap import Tub, UnauthenticatedTub
31 31
32 32 from IPython.config.loader import Config
33 33 from IPython.kernel.configobjfactory import AdaptedConfiguredObjectFactory
34 34 from IPython.kernel.error import SecurityError
35 35
36 36 from IPython.utils.importstring import import_item
37 37 from IPython.utils.path import expand_path
38 38 from IPython.utils.traitlets import Int, Str, Bool, Instance
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Code
42 42 #-----------------------------------------------------------------------------
43 43
44 44
45 45 # We do this so if a user doesn't have OpenSSL installed, it will try to use
46 46 # an UnauthenticatedTub. But, they will still run into problems if they
47 47 # try to use encrypted furls.
48 48 try:
49 49 import OpenSSL
50 50 except:
51 51 Tub = UnauthenticatedTub
52 52 have_crypto = False
53 53 else:
54 54 have_crypto = True
55 55
56 56
57 57 class FURLError(Exception):
58 58 pass
59 59
60 60
61 61 def check_furl_file_security(furl_file, secure):
62 62 """Remove the old furl_file if changing security modes."""
63 63 furl_file = expand_path(furl_file)
64 64 if os.path.isfile(furl_file):
65 65 with open(furl_file, 'r') as f:
66 66 oldfurl = f.read().strip()
67 67 if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure):
68 68 os.remove(furl_file)
69 69
70 70
71 71 def is_secure(furl):
72 72 """Is the given FURL secure or not."""
73 73 if is_valid_furl(furl):
74 74 if furl.startswith("pb://"):
75 75 return True
76 76 elif furl.startswith("pbu://"):
77 77 return False
78 78 else:
79 79 raise FURLError("invalid FURL: %s" % furl)
80 80
81 81
82 82 def is_valid_furl(furl):
83 83 """Is the str a valid FURL or not."""
84 84 if isinstance(furl, str):
85 85 if furl.startswith("pb://") or furl.startswith("pbu://"):
86 86 return True
87 87 else:
88 88 return False
89 89 else:
90 90 return False
91 91
92 92
93 93 def is_valid_furl_file(furl_or_file):
94 94 """See if furl_or_file exists and contains a valid FURL.
95 95
96 96 This doesn't try to read the contents because often we have to validate
97 97 FURL files that are created, but don't yet have a FURL written to them.
98 98 """
99 99 if isinstance(furl_or_file, (str, unicode)):
100 100 path, furl_filename = os.path.split(furl_or_file)
101 101 if os.path.isdir(path) and furl_filename.endswith('.furl'):
102 102 return True
103 103 return False
104 104
105 105
106 106 def find_furl(furl_or_file):
107 107 """Find, validate and return a FURL in a string or file.
108 108
109 109 This calls :func:`IPython.utils.path.expand_path` on the argument to
110 110 properly handle ``~`` and ``$`` variables in the path.
111 111 """
112 112 if is_valid_furl(furl_or_file):
113 113 return furl_or_file
114 114 furl_or_file = expand_path(furl_or_file)
115 115 if is_valid_furl_file(furl_or_file):
116 116 with open(furl_or_file, 'r') as f:
117 117 furl = f.read().strip()
118 118 if is_valid_furl(furl):
119 119 return furl
120 120 raise FURLError("Not a valid FURL or FURL file: %r" % furl_or_file)
121 121
122 122
123 123 def is_valid_furl_or_file(furl_or_file):
124 124 """Validate a FURL or a FURL file.
125 125
126 126 If ``furl_or_file`` looks like a file, we simply make sure its directory
127 127 exists and that it has a ``.furl`` file extension. We don't try to see
128 128 if the FURL file exists or to read its contents. This is useful for
129 129 cases where auto re-connection is being used.
130 130 """
131 131 if is_valid_furl(furl_or_file) or is_valid_furl_file(furl_or_file):
132 132 return True
133 133 else:
134 134 return False
135 135
136 136
137 137 def validate_furl_or_file(furl_or_file):
138 138 """Like :func:`is_valid_furl_or_file`, but raises an error."""
139 139 if not is_valid_furl_or_file(furl_or_file):
140 140 raise FURLError('Not a valid FURL or FURL file: %r' % furl_or_file)
141 141
142 142
143 143 def get_temp_furlfile(filename):
144 144 """Return a temporary FURL file."""
145 145 return tempfile.mktemp(dir=os.path.dirname(filename),
146 146 prefix=os.path.basename(filename))
147 147
148 148
149 149 def make_tub(ip, port, secure, cert_file):
150 150 """Create a listening tub given an ip, port, and cert_file location.
151 151
152 152 Parameters
153 153 ----------
154 154 ip : str
155 155 The ip address or hostname that the tub should listen on.
156 156 Empty means all interfaces.
157 157 port : int
158 158 The port that the tub should listen on. A value of 0 means
159 159 pick a random port
160 160 secure: bool
161 161 Will the connection be secure (in the Foolscap sense).
162 162 cert_file: str
163 163 A filename of a file to be used for theSSL certificate.
164 164
165 165 Returns
166 166 -------
167 167 A tub, listener tuple.
168 168 """
169 169 if secure:
170 170 if have_crypto:
171 171 tub = Tub(certFile=cert_file)
172 172 else:
173 173 raise SecurityError("OpenSSL/pyOpenSSL is not available, so we "
174 174 "can't run in secure mode. Try running without "
175 175 "security using 'ipcontroller -xy'.")
176 176 else:
177 177 tub = UnauthenticatedTub()
178 178
179 179 # Set the strport based on the ip and port and start listening
180 180 if ip == '':
181 181 strport = "tcp:%i" % port
182 182 else:
183 183 strport = "tcp:%i:interface=%s" % (port, ip)
184 184 log.msg("Starting listener with [secure=%r] on: %s" % (secure, strport))
185 185 listener = tub.listenOn(strport)
186 186
187 187 return tub, listener
188 188
189 189
190 190 class FCServiceFactory(AdaptedConfiguredObjectFactory):
191 191 """This class creates a tub with various services running in it.
192 192
193 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.
195 This class is a subclass of :class:`IPython.core.component.Component`
196 so the IPython configuration and component system are used.
194 instance that has a number of Foolscap references registered in it. This
195 class is a subclass of :class:`IPython.config.configurable.Configurable`
196 so the IPython configuration system is used.
197 197
198 198 Attributes
199 199 ----------
200 200 interfaces : Config
201 201 A Config instance whose values are sub-Config objects having two
202 202 keys: furl_file and interface_chain.
203 203
204 204 The other attributes are the standard ones for Foolscap.
205 205 """
206 206
207 207 ip = Str('', config=True)
208 208 port = Int(0, config=True)
209 209 secure = Bool(True, config=True)
210 210 cert_file = Str('', config=True)
211 211 location = Str('', config=True)
212 212 reuse_furls = Bool(False, config=True)
213 213 interfaces = Instance(klass=Config, kw={}, allow_none=False, config=True)
214 214
215 215 def __init__(self, config, adaptee):
216 216 super(FCServiceFactory, self).__init__(config, adaptee)
217 217 self._check_reuse_furls()
218 218
219 219 def _ip_changed(self, name, old, new):
220 220 if new == 'localhost' or new == '127.0.0.1':
221 221 self.location = '127.0.0.1'
222 222
223 223 def _check_reuse_furls(self):
224 224 furl_files = [i.furl_file for i in self.interfaces.values()]
225 225 for ff in furl_files:
226 226 fullfile = self._get_security_file(ff)
227 227 if self.reuse_furls:
228 228 if self.port==0:
229 229 raise FURLError("You are trying to reuse the FURL file "
230 230 "for this connection, but the port for this connection "
231 231 "is set to 0 (autoselect). To reuse the FURL file "
232 232 "you need to specify specific port to listen on."
233 233 )
234 234 else:
235 235 log.msg("Reusing FURL file: %s" % fullfile)
236 236 else:
237 237 if os.path.isfile(fullfile):
238 238 log.msg("Removing old FURL file: %s" % fullfile)
239 239 os.remove(fullfile)
240 240
241 241 def _get_security_file(self, filename):
242 242 return os.path.join(self.config.Global.security_dir, filename)
243 243
244 244 def create(self):
245 245 """Create and return the Foolscap tub with everything running."""
246 246
247 247 self.tub, self.listener = make_tub(
248 248 self.ip, self.port, self.secure,
249 249 self._get_security_file(self.cert_file)
250 250 )
251 251 # log.msg("Interfaces to register [%r]: %r" % \
252 252 # (self.__class__, self.interfaces))
253 253 if not self.secure:
254 254 log.msg("WARNING: running with no security: %s" % \
255 255 self.__class__.__name__)
256 256 reactor.callWhenRunning(self.set_location_and_register)
257 257 return self.tub
258 258
259 259 def set_location_and_register(self):
260 260 """Set the location for the tub and return a deferred."""
261 261
262 262 if self.location == '':
263 263 d = self.tub.setLocationAutomatically()
264 264 else:
265 265 d = defer.maybeDeferred(self.tub.setLocation,
266 266 "%s:%i" % (self.location, self.listener.getPortnum()))
267 267 self.adapt_to_interfaces(d)
268 268
269 269 def adapt_to_interfaces(self, d):
270 270 """Run through the interfaces, adapt and register."""
271 271
272 272 for ifname, ifconfig in self.interfaces.iteritems():
273 273 ff = self._get_security_file(ifconfig.furl_file)
274 274 log.msg("Adapting [%s] to interface: %s" % \
275 275 (self.adaptee.__class__.__name__, ifname))
276 276 log.msg("Saving FURL for interface [%s] to file: %s" % (ifname, ff))
277 277 check_furl_file_security(ff, self.secure)
278 278 adaptee = self.adaptee
279 279 for i in ifconfig.interface_chain:
280 280 adaptee = import_item(i)(adaptee)
281 281 d.addCallback(self.register, adaptee, furl_file=ff)
282 282
283 283 def register(self, empty, ref, furl_file):
284 284 """Register the reference with the FURL file.
285 285
286 286 The FURL file is created and then moved to make sure that when the
287 287 file appears, the buffer has been flushed and the file closed. This
288 288 is not done if we are re-using FURLS however.
289 289 """
290 290 if self.reuse_furls:
291 291 self.tub.registerReference(ref, furlFile=furl_file)
292 292 else:
293 293 temp_furl_file = get_temp_furlfile(furl_file)
294 294 self.tub.registerReference(ref, furlFile=temp_furl_file)
295 295 os.rename(temp_furl_file, furl_file)
296 296
@@ -1,835 +1,835 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 Facilities for launching IPython processes asynchronously.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 import os
19 19 import re
20 20 import sys
21 21
22 from IPython.core.component import Component
22 from IPython.config.configurable import Configurable
23 23 from IPython.external import Itpl
24 24 from IPython.utils.traitlets import Str, Int, List, Unicode
25 25 from IPython.utils.path import get_ipython_module_path
26 26 from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError
27 27 from IPython.kernel.twistedutil import (
28 28 gatherBoth,
29 29 make_deferred,
30 30 sleep_deferred
31 31 )
32 32 from IPython.kernel.winhpcjob import (
33 33 IPControllerTask, IPEngineTask,
34 34 IPControllerJob, IPEngineSetJob
35 35 )
36 36
37 37 from twisted.internet import reactor, defer
38 38 from twisted.internet.defer import inlineCallbacks
39 39 from twisted.internet.protocol import ProcessProtocol
40 40 from twisted.internet.utils import getProcessOutput
41 41 from twisted.internet.error import ProcessDone, ProcessTerminated
42 42 from twisted.python import log
43 43 from twisted.python.failure import Failure
44 44
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Paths to the kernel apps
48 48 #-----------------------------------------------------------------------------
49 49
50 50
51 51 ipcluster_cmd_argv = pycmd2argv(get_ipython_module_path(
52 52 'IPython.kernel.ipclusterapp'
53 53 ))
54 54
55 55 ipengine_cmd_argv = pycmd2argv(get_ipython_module_path(
56 56 'IPython.kernel.ipengineapp'
57 57 ))
58 58
59 59 ipcontroller_cmd_argv = pycmd2argv(get_ipython_module_path(
60 60 'IPython.kernel.ipcontrollerapp'
61 61 ))
62 62
63 63 #-----------------------------------------------------------------------------
64 64 # Base launchers and errors
65 65 #-----------------------------------------------------------------------------
66 66
67 67
68 68 class LauncherError(Exception):
69 69 pass
70 70
71 71
72 72 class ProcessStateError(LauncherError):
73 73 pass
74 74
75 75
76 76 class UnknownStatus(LauncherError):
77 77 pass
78 78
79 79
80 class BaseLauncher(Component):
80 class BaseLauncher(Configurable):
81 81 """An asbtraction for starting, stopping and signaling a process."""
82 82
83 83 # In all of the launchers, the work_dir is where child processes will be
84 84 # run. This will usually be the cluster_dir, but may not be. any work_dir
85 85 # passed into the __init__ method will override the config value.
86 86 # This should not be used to set the work_dir for the actual engine
87 87 # and controller. Instead, use their own config files or the
88 88 # controller_args, engine_args attributes of the launchers to add
89 89 # the --work-dir option.
90 90 work_dir = Unicode(u'')
91 91
92 def __init__(self, work_dir, parent=None, name=None, config=None):
93 super(BaseLauncher, self).__init__(parent, name, config)
92 def __init__(self, work_dir, config=None):
93 super(BaseLauncher, self).__init__(config)
94 94 self.work_dir = work_dir
95 95 self.state = 'before' # can be before, running, after
96 96 self.stop_deferreds = []
97 97 self.start_data = None
98 98 self.stop_data = None
99 99
100 100 @property
101 101 def args(self):
102 102 """A list of cmd and args that will be used to start the process.
103 103
104 104 This is what is passed to :func:`spawnProcess` and the first element
105 105 will be the process name.
106 106 """
107 107 return self.find_args()
108 108
109 109 def find_args(self):
110 110 """The ``.args`` property calls this to find the args list.
111 111
112 112 Subcommand should implement this to construct the cmd and args.
113 113 """
114 114 raise NotImplementedError('find_args must be implemented in a subclass')
115 115
116 116 @property
117 117 def arg_str(self):
118 118 """The string form of the program arguments."""
119 119 return ' '.join(self.args)
120 120
121 121 @property
122 122 def running(self):
123 123 """Am I running."""
124 124 if self.state == 'running':
125 125 return True
126 126 else:
127 127 return False
128 128
129 129 def start(self):
130 130 """Start the process.
131 131
132 132 This must return a deferred that fires with information about the
133 133 process starting (like a pid, job id, etc.).
134 134 """
135 135 return defer.fail(
136 136 Failure(NotImplementedError(
137 137 'start must be implemented in a subclass')
138 138 )
139 139 )
140 140
141 141 def stop(self):
142 142 """Stop the process and notify observers of stopping.
143 143
144 144 This must return a deferred that fires with information about the
145 145 processing stopping, like errors that occur while the process is
146 146 attempting to be shut down. This deferred won't fire when the process
147 147 actually stops. To observe the actual process stopping, see
148 148 :func:`observe_stop`.
149 149 """
150 150 return defer.fail(
151 151 Failure(NotImplementedError(
152 152 'stop must be implemented in a subclass')
153 153 )
154 154 )
155 155
156 156 def observe_stop(self):
157 157 """Get a deferred that will fire when the process stops.
158 158
159 159 The deferred will fire with data that contains information about
160 160 the exit status of the process.
161 161 """
162 162 if self.state=='after':
163 163 return defer.succeed(self.stop_data)
164 164 else:
165 165 d = defer.Deferred()
166 166 self.stop_deferreds.append(d)
167 167 return d
168 168
169 169 def notify_start(self, data):
170 170 """Call this to trigger startup actions.
171 171
172 172 This logs the process startup and sets the state to 'running'. It is
173 173 a pass-through so it can be used as a callback.
174 174 """
175 175
176 176 log.msg('Process %r started: %r' % (self.args[0], data))
177 177 self.start_data = data
178 178 self.state = 'running'
179 179 return data
180 180
181 181 def notify_stop(self, data):
182 182 """Call this to trigger process stop actions.
183 183
184 184 This logs the process stopping and sets the state to 'after'. Call
185 185 this to trigger all the deferreds from :func:`observe_stop`."""
186 186
187 187 log.msg('Process %r stopped: %r' % (self.args[0], data))
188 188 self.stop_data = data
189 189 self.state = 'after'
190 190 for i in range(len(self.stop_deferreds)):
191 191 d = self.stop_deferreds.pop()
192 192 d.callback(data)
193 193 return data
194 194
195 195 def signal(self, sig):
196 196 """Signal the process.
197 197
198 198 Return a semi-meaningless deferred after signaling the process.
199 199
200 200 Parameters
201 201 ----------
202 202 sig : str or int
203 203 'KILL', 'INT', etc., or any signal number
204 204 """
205 205 return defer.fail(
206 206 Failure(NotImplementedError(
207 207 'signal must be implemented in a subclass')
208 208 )
209 209 )
210 210
211 211
212 212 #-----------------------------------------------------------------------------
213 213 # Local process launchers
214 214 #-----------------------------------------------------------------------------
215 215
216 216
217 217 class LocalProcessLauncherProtocol(ProcessProtocol):
218 218 """A ProcessProtocol to go with the LocalProcessLauncher."""
219 219
220 220 def __init__(self, process_launcher):
221 221 self.process_launcher = process_launcher
222 222 self.pid = None
223 223
224 224 def connectionMade(self):
225 225 self.pid = self.transport.pid
226 226 self.process_launcher.notify_start(self.transport.pid)
227 227
228 228 def processEnded(self, status):
229 229 value = status.value
230 230 if isinstance(value, ProcessDone):
231 231 self.process_launcher.notify_stop(
232 232 {'exit_code':0,
233 233 'signal':None,
234 234 'status':None,
235 235 'pid':self.pid
236 236 }
237 237 )
238 238 elif isinstance(value, ProcessTerminated):
239 239 self.process_launcher.notify_stop(
240 240 {'exit_code':value.exitCode,
241 241 'signal':value.signal,
242 242 'status':value.status,
243 243 'pid':self.pid
244 244 }
245 245 )
246 246 else:
247 247 raise UnknownStatus("Unknown exit status, this is probably a "
248 248 "bug in Twisted")
249 249
250 250 def outReceived(self, data):
251 251 log.msg(data)
252 252
253 253 def errReceived(self, data):
254 254 log.err(data)
255 255
256 256
257 257 class LocalProcessLauncher(BaseLauncher):
258 258 """Start and stop an external process in an asynchronous manner.
259 259
260 260 This will launch the external process with a working directory of
261 261 ``self.work_dir``.
262 262 """
263 263
264 264 # This is used to to construct self.args, which is passed to
265 265 # spawnProcess.
266 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 269 super(LocalProcessLauncher, self).__init__(
270 work_dir, parent, name, config
270 work_dir, config
271 271 )
272 272 self.process_protocol = None
273 273 self.start_deferred = None
274 274
275 275 def find_args(self):
276 276 return self.cmd_and_args
277 277
278 278 def start(self):
279 279 if self.state == 'before':
280 280 self.process_protocol = LocalProcessLauncherProtocol(self)
281 281 self.start_deferred = defer.Deferred()
282 282 self.process_transport = reactor.spawnProcess(
283 283 self.process_protocol,
284 284 str(self.args[0]), # twisted expects these to be str, not unicode
285 285 [str(a) for a in self.args], # str expected, not unicode
286 286 env=os.environ,
287 287 path=self.work_dir # start in the work_dir
288 288 )
289 289 return self.start_deferred
290 290 else:
291 291 s = 'The process was already started and has state: %r' % self.state
292 292 return defer.fail(ProcessStateError(s))
293 293
294 294 def notify_start(self, data):
295 295 super(LocalProcessLauncher, self).notify_start(data)
296 296 self.start_deferred.callback(data)
297 297
298 298 def stop(self):
299 299 return self.interrupt_then_kill()
300 300
301 301 @make_deferred
302 302 def signal(self, sig):
303 303 if self.state == 'running':
304 304 self.process_transport.signalProcess(sig)
305 305
306 306 @inlineCallbacks
307 307 def interrupt_then_kill(self, delay=2.0):
308 308 """Send INT, wait a delay and then send KILL."""
309 309 yield self.signal('INT')
310 310 yield sleep_deferred(delay)
311 311 yield self.signal('KILL')
312 312
313 313
314 314 class LocalControllerLauncher(LocalProcessLauncher):
315 315 """Launch a controller as a regular external process."""
316 316
317 317 controller_cmd = List(ipcontroller_cmd_argv, config=True)
318 318 # Command line arguments to ipcontroller.
319 319 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
320 320
321 321 def find_args(self):
322 322 return self.controller_cmd + self.controller_args
323 323
324 324 def start(self, cluster_dir):
325 325 """Start the controller by cluster_dir."""
326 326 self.controller_args.extend(['--cluster-dir', cluster_dir])
327 327 self.cluster_dir = unicode(cluster_dir)
328 328 log.msg("Starting LocalControllerLauncher: %r" % self.args)
329 329 return super(LocalControllerLauncher, self).start()
330 330
331 331
332 332 class LocalEngineLauncher(LocalProcessLauncher):
333 333 """Launch a single engine as a regular externall process."""
334 334
335 335 engine_cmd = List(ipengine_cmd_argv, config=True)
336 336 # Command line arguments for ipengine.
337 337 engine_args = List(
338 338 ['--log-to-file','--log-level', '40'], config=True
339 339 )
340 340
341 341 def find_args(self):
342 342 return self.engine_cmd + self.engine_args
343 343
344 344 def start(self, cluster_dir):
345 345 """Start the engine by cluster_dir."""
346 346 self.engine_args.extend(['--cluster-dir', cluster_dir])
347 347 self.cluster_dir = unicode(cluster_dir)
348 348 return super(LocalEngineLauncher, self).start()
349 349
350 350
351 351 class LocalEngineSetLauncher(BaseLauncher):
352 352 """Launch a set of engines as regular external processes."""
353 353
354 354 # Command line arguments for ipengine.
355 355 engine_args = List(
356 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 360 super(LocalEngineSetLauncher, self).__init__(
361 work_dir, parent, name, config
361 work_dir, config
362 362 )
363 363 self.launchers = []
364 364
365 365 def start(self, n, cluster_dir):
366 366 """Start n engines by profile or cluster_dir."""
367 367 self.cluster_dir = unicode(cluster_dir)
368 368 dlist = []
369 369 for i in range(n):
370 el = LocalEngineLauncher(self.work_dir, self)
370 el = LocalEngineLauncher(self.work_dir, self.config)
371 371 # Copy the engine args over to each engine launcher.
372 372 import copy
373 373 el.engine_args = copy.deepcopy(self.engine_args)
374 374 d = el.start(cluster_dir)
375 375 if i==0:
376 376 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
377 377 self.launchers.append(el)
378 378 dlist.append(d)
379 379 # The consumeErrors here could be dangerous
380 380 dfinal = gatherBoth(dlist, consumeErrors=True)
381 381 dfinal.addCallback(self.notify_start)
382 382 return dfinal
383 383
384 384 def find_args(self):
385 385 return ['engine set']
386 386
387 387 def signal(self, sig):
388 388 dlist = []
389 389 for el in self.launchers:
390 390 d = el.signal(sig)
391 391 dlist.append(d)
392 392 dfinal = gatherBoth(dlist, consumeErrors=True)
393 393 return dfinal
394 394
395 395 def interrupt_then_kill(self, delay=1.0):
396 396 dlist = []
397 397 for el in self.launchers:
398 398 d = el.interrupt_then_kill(delay)
399 399 dlist.append(d)
400 400 dfinal = gatherBoth(dlist, consumeErrors=True)
401 401 return dfinal
402 402
403 403 def stop(self):
404 404 return self.interrupt_then_kill()
405 405
406 406 def observe_stop(self):
407 407 dlist = [el.observe_stop() for el in self.launchers]
408 408 dfinal = gatherBoth(dlist, consumeErrors=False)
409 409 dfinal.addCallback(self.notify_stop)
410 410 return dfinal
411 411
412 412
413 413 #-----------------------------------------------------------------------------
414 414 # MPIExec launchers
415 415 #-----------------------------------------------------------------------------
416 416
417 417
418 418 class MPIExecLauncher(LocalProcessLauncher):
419 419 """Launch an external process using mpiexec."""
420 420
421 421 # The mpiexec command to use in starting the process.
422 422 mpi_cmd = List(['mpiexec'], config=True)
423 423 # The command line arguments to pass to mpiexec.
424 424 mpi_args = List([], config=True)
425 425 # The program to start using mpiexec.
426 426 program = List(['date'], config=True)
427 427 # The command line argument to the program.
428 428 program_args = List([], config=True)
429 429 # The number of instances of the program to start.
430 430 n = Int(1, config=True)
431 431
432 432 def find_args(self):
433 433 """Build self.args using all the fields."""
434 434 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
435 435 self.program + self.program_args
436 436
437 437 def start(self, n):
438 438 """Start n instances of the program using mpiexec."""
439 439 self.n = n
440 440 return super(MPIExecLauncher, self).start()
441 441
442 442
443 443 class MPIExecControllerLauncher(MPIExecLauncher):
444 444 """Launch a controller using mpiexec."""
445 445
446 446 controller_cmd = List(ipcontroller_cmd_argv, config=True)
447 447 # Command line arguments to ipcontroller.
448 448 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
449 449 n = Int(1, config=False)
450 450
451 451 def start(self, cluster_dir):
452 452 """Start the controller by cluster_dir."""
453 453 self.controller_args.extend(['--cluster-dir', cluster_dir])
454 454 self.cluster_dir = unicode(cluster_dir)
455 455 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
456 456 return super(MPIExecControllerLauncher, self).start(1)
457 457
458 458 def find_args(self):
459 459 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
460 460 self.controller_cmd + self.controller_args
461 461
462 462
463 463 class MPIExecEngineSetLauncher(MPIExecLauncher):
464 464
465 465 engine_cmd = List(ipengine_cmd_argv, config=True)
466 466 # Command line arguments for ipengine.
467 467 engine_args = List(
468 468 ['--log-to-file','--log-level', '40'], config=True
469 469 )
470 470 n = Int(1, config=True)
471 471
472 472 def start(self, n, cluster_dir):
473 473 """Start n engines by profile or cluster_dir."""
474 474 self.engine_args.extend(['--cluster-dir', cluster_dir])
475 475 self.cluster_dir = unicode(cluster_dir)
476 476 self.n = n
477 477 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
478 478 return super(MPIExecEngineSetLauncher, self).start(n)
479 479
480 480 def find_args(self):
481 481 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
482 482 self.engine_cmd + self.engine_args
483 483
484 484
485 485 #-----------------------------------------------------------------------------
486 486 # SSH launchers
487 487 #-----------------------------------------------------------------------------
488 488
489 489 # TODO: Get SSH Launcher working again.
490 490
491 491 class SSHLauncher(BaseLauncher):
492 492 """A minimal launcher for ssh.
493 493
494 494 To be useful this will probably have to be extended to use the ``sshx``
495 495 idea for environment variables. There could be other things this needs
496 496 as well.
497 497 """
498 498
499 499 ssh_cmd = List(['ssh'], config=True)
500 500 ssh_args = List([], config=True)
501 501 program = List(['date'], config=True)
502 502 program_args = List([], config=True)
503 503 hostname = Str('', config=True)
504 504 user = Str('', config=True)
505 505 location = Str('')
506 506
507 507 def _hostname_changed(self, name, old, new):
508 508 self.location = '%s@%s' % (self.user, new)
509 509
510 510 def _user_changed(self, name, old, new):
511 511 self.location = '%s@%s' % (new, self.hostname)
512 512
513 513 def find_args(self):
514 514 return self.ssh_cmd + self.ssh_args + [self.location] + \
515 515 self.program + self.program_args
516 516
517 517 def start(self, n, hostname=None, user=None):
518 518 if hostname is not None:
519 519 self.hostname = hostname
520 520 if user is not None:
521 521 self.user = user
522 522 return super(SSHLauncher, self).start()
523 523
524 524
525 525 class SSHControllerLauncher(SSHLauncher):
526 526 pass
527 527
528 528
529 529 class SSHEngineSetLauncher(BaseLauncher):
530 530 pass
531 531
532 532
533 533 #-----------------------------------------------------------------------------
534 534 # Windows HPC Server 2008 scheduler launchers
535 535 #-----------------------------------------------------------------------------
536 536
537 537
538 538 # This is only used on Windows.
539 539 def find_job_cmd():
540 540 if os.name=='nt':
541 541 try:
542 542 return find_cmd('job')
543 543 except FindCmdError:
544 544 return 'job'
545 545 else:
546 546 return 'job'
547 547
548 548
549 549 class WindowsHPCLauncher(BaseLauncher):
550 550
551 551 # A regular expression used to get the job id from the output of the
552 552 # submit_command.
553 553 job_id_regexp = Str(r'\d+', config=True)
554 554 # The filename of the instantiated job script.
555 555 job_file_name = Unicode(u'ipython_job.xml', config=True)
556 556 # The full path to the instantiated job script. This gets made dynamically
557 557 # by combining the work_dir with the job_file_name.
558 558 job_file = Unicode(u'')
559 559 # The hostname of the scheduler to submit the job to
560 560 scheduler = Str('', config=True)
561 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 564 super(WindowsHPCLauncher, self).__init__(
565 work_dir, parent, name, config
565 work_dir, config
566 566 )
567 567
568 568 @property
569 569 def job_file(self):
570 570 return os.path.join(self.work_dir, self.job_file_name)
571 571
572 572 def write_job_file(self, n):
573 573 raise NotImplementedError("Implement write_job_file in a subclass.")
574 574
575 575 def find_args(self):
576 576 return ['job.exe']
577 577
578 578 def parse_job_id(self, output):
579 579 """Take the output of the submit command and return the job id."""
580 580 m = re.search(self.job_id_regexp, output)
581 581 if m is not None:
582 582 job_id = m.group()
583 583 else:
584 584 raise LauncherError("Job id couldn't be determined: %s" % output)
585 585 self.job_id = job_id
586 586 log.msg('Job started with job id: %r' % job_id)
587 587 return job_id
588 588
589 589 @inlineCallbacks
590 590 def start(self, n):
591 591 """Start n copies of the process using the Win HPC job scheduler."""
592 592 self.write_job_file(n)
593 593 args = [
594 594 'submit',
595 595 '/jobfile:%s' % self.job_file,
596 596 '/scheduler:%s' % self.scheduler
597 597 ]
598 598 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
599 599 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
600 600 output = yield getProcessOutput(str(self.job_cmd),
601 601 [str(a) for a in args],
602 602 env=dict((str(k),str(v)) for k,v in os.environ.items()),
603 603 path=self.work_dir
604 604 )
605 605 job_id = self.parse_job_id(output)
606 606 self.notify_start(job_id)
607 607 defer.returnValue(job_id)
608 608
609 609 @inlineCallbacks
610 610 def stop(self):
611 611 args = [
612 612 'cancel',
613 613 self.job_id,
614 614 '/scheduler:%s' % self.scheduler
615 615 ]
616 616 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
617 617 try:
618 618 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
619 619 output = yield getProcessOutput(str(self.job_cmd),
620 620 [str(a) for a in args],
621 621 env=dict((str(k),str(v)) for k,v in os.environ.items()),
622 622 path=self.work_dir
623 623 )
624 624 except:
625 625 output = 'The job already appears to be stoppped: %r' % self.job_id
626 626 self.notify_stop(output) # Pass the output of the kill cmd
627 627 defer.returnValue(output)
628 628
629 629
630 630 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
631 631
632 632 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
633 633 extra_args = List([], config=False)
634 634
635 635 def write_job_file(self, n):
636 636 job = IPControllerJob(self)
637 637
638 638 t = IPControllerTask(self)
639 639 # The tasks work directory is *not* the actual work directory of
640 640 # the controller. It is used as the base path for the stdout/stderr
641 641 # files that the scheduler redirects to.
642 642 t.work_directory = self.cluster_dir
643 643 # Add the --cluster-dir and from self.start().
644 644 t.controller_args.extend(self.extra_args)
645 645 job.add_task(t)
646 646
647 647 log.msg("Writing job description file: %s" % self.job_file)
648 648 job.write(self.job_file)
649 649
650 650 @property
651 651 def job_file(self):
652 652 return os.path.join(self.cluster_dir, self.job_file_name)
653 653
654 654 def start(self, cluster_dir):
655 655 """Start the controller by cluster_dir."""
656 656 self.extra_args = ['--cluster-dir', cluster_dir]
657 657 self.cluster_dir = unicode(cluster_dir)
658 658 return super(WindowsHPCControllerLauncher, self).start(1)
659 659
660 660
661 661 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
662 662
663 663 job_file_name = Unicode(u'ipengineset_job.xml', config=True)
664 664 extra_args = List([], config=False)
665 665
666 666 def write_job_file(self, n):
667 667 job = IPEngineSetJob(self)
668 668
669 669 for i in range(n):
670 670 t = IPEngineTask(self)
671 671 # The tasks work directory is *not* the actual work directory of
672 672 # the engine. It is used as the base path for the stdout/stderr
673 673 # files that the scheduler redirects to.
674 674 t.work_directory = self.cluster_dir
675 675 # Add the --cluster-dir and from self.start().
676 676 t.engine_args.extend(self.extra_args)
677 677 job.add_task(t)
678 678
679 679 log.msg("Writing job description file: %s" % self.job_file)
680 680 job.write(self.job_file)
681 681
682 682 @property
683 683 def job_file(self):
684 684 return os.path.join(self.cluster_dir, self.job_file_name)
685 685
686 686 def start(self, n, cluster_dir):
687 687 """Start the controller by cluster_dir."""
688 688 self.extra_args = ['--cluster-dir', cluster_dir]
689 689 self.cluster_dir = unicode(cluster_dir)
690 690 return super(WindowsHPCEngineSetLauncher, self).start(n)
691 691
692 692
693 693 #-----------------------------------------------------------------------------
694 694 # Batch (PBS) system launchers
695 695 #-----------------------------------------------------------------------------
696 696
697 697 # TODO: Get PBS launcher working again.
698 698
699 699 class BatchSystemLauncher(BaseLauncher):
700 700 """Launch an external process using a batch system.
701 701
702 702 This class is designed to work with UNIX batch systems like PBS, LSF,
703 703 GridEngine, etc. The overall model is that there are different commands
704 704 like qsub, qdel, etc. that handle the starting and stopping of the process.
705 705
706 706 This class also has the notion of a batch script. The ``batch_template``
707 707 attribute can be set to a string that is a template for the batch script.
708 708 This template is instantiated using Itpl. Thus the template can use
709 709 ${n} fot the number of instances. Subclasses can add additional variables
710 710 to the template dict.
711 711 """
712 712
713 713 # Subclasses must fill these in. See PBSEngineSet
714 714 # The name of the command line program used to submit jobs.
715 715 submit_command = Str('', config=True)
716 716 # The name of the command line program used to delete jobs.
717 717 delete_command = Str('', config=True)
718 718 # A regular expression used to get the job id from the output of the
719 719 # submit_command.
720 720 job_id_regexp = Str('', config=True)
721 721 # The string that is the batch script template itself.
722 722 batch_template = Str('', config=True)
723 723 # The filename of the instantiated batch script.
724 724 batch_file_name = Unicode(u'batch_script', config=True)
725 725 # The full path to the instantiated batch script.
726 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 729 super(BatchSystemLauncher, self).__init__(
730 work_dir, parent, name, config
730 work_dir, config
731 731 )
732 732 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
733 733 self.context = {}
734 734
735 735 def parse_job_id(self, output):
736 736 """Take the output of the submit command and return the job id."""
737 737 m = re.match(self.job_id_regexp, output)
738 738 if m is not None:
739 739 job_id = m.group()
740 740 else:
741 741 raise LauncherError("Job id couldn't be determined: %s" % output)
742 742 self.job_id = job_id
743 743 log.msg('Job started with job id: %r' % job_id)
744 744 return job_id
745 745
746 746 def write_batch_script(self, n):
747 747 """Instantiate and write the batch script to the work_dir."""
748 748 self.context['n'] = n
749 749 script_as_string = Itpl.itplns(self.batch_template, self.context)
750 750 log.msg('Writing instantiated batch script: %s' % self.batch_file)
751 751 f = open(self.batch_file, 'w')
752 752 f.write(script_as_string)
753 753 f.close()
754 754
755 755 @inlineCallbacks
756 756 def start(self, n):
757 757 """Start n copies of the process using a batch system."""
758 758 self.write_batch_script(n)
759 759 output = yield getProcessOutput(self.submit_command,
760 760 [self.batch_file], env=os.environ)
761 761 job_id = self.parse_job_id(output)
762 762 self.notify_start(job_id)
763 763 defer.returnValue(job_id)
764 764
765 765 @inlineCallbacks
766 766 def stop(self):
767 767 output = yield getProcessOutput(self.delete_command,
768 768 [self.job_id], env=os.environ
769 769 )
770 770 self.notify_stop(output) # Pass the output of the kill cmd
771 771 defer.returnValue(output)
772 772
773 773
774 774 class PBSLauncher(BatchSystemLauncher):
775 775 """A BatchSystemLauncher subclass for PBS."""
776 776
777 777 submit_command = Str('qsub', config=True)
778 778 delete_command = Str('qdel', config=True)
779 779 job_id_regexp = Str(r'\d+', config=True)
780 780 batch_template = Str('', config=True)
781 781 batch_file_name = Unicode(u'pbs_batch_script', config=True)
782 782 batch_file = Unicode(u'')
783 783
784 784
785 785 class PBSControllerLauncher(PBSLauncher):
786 786 """Launch a controller using PBS."""
787 787
788 788 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
789 789
790 790 def start(self, cluster_dir):
791 791 """Start the controller by profile or cluster_dir."""
792 792 # Here we save profile and cluster_dir in the context so they
793 793 # can be used in the batch script template as ${profile} and
794 794 # ${cluster_dir}
795 795 self.context['cluster_dir'] = cluster_dir
796 796 self.cluster_dir = unicode(cluster_dir)
797 797 log.msg("Starting PBSControllerLauncher: %r" % self.args)
798 798 return super(PBSControllerLauncher, self).start(1)
799 799
800 800
801 801 class PBSEngineSetLauncher(PBSLauncher):
802 802
803 803 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
804 804
805 805 def start(self, n, cluster_dir):
806 806 """Start n engines by profile or cluster_dir."""
807 807 self.program_args.extend(['--cluster-dir', cluster_dir])
808 808 self.cluster_dir = unicode(cluster_dir)
809 809 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
810 810 return super(PBSEngineSetLauncher, self).start(n)
811 811
812 812
813 813 #-----------------------------------------------------------------------------
814 814 # A launcher for ipcluster itself!
815 815 #-----------------------------------------------------------------------------
816 816
817 817
818 818 class IPClusterLauncher(LocalProcessLauncher):
819 819 """Launch the ipcluster program in an external process."""
820 820
821 821 ipcluster_cmd = List(ipcluster_cmd_argv, config=True)
822 822 # Command line arguments to pass to ipcluster.
823 823 ipcluster_args = List(
824 824 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
825 825 ipcluster_subcommand = Str('start')
826 826 ipcluster_n = Int(2)
827 827
828 828 def find_args(self):
829 829 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
830 830 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
831 831
832 832 def start(self):
833 833 log.msg("Starting ipcluster: %r" % self.args)
834 834 return super(IPClusterLauncher, self).start()
835 835
@@ -1,316 +1,316 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 Job and task components for writing .xml files that the Windows HPC Server
5 5 2008 can use to start jobs.
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2008-2009 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from __future__ import with_statement
20 20
21 21 import os
22 22 import re
23 23 import uuid
24 24
25 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 28 from IPython.utils.traitlets import (
29 29 Str, Int, List, Instance,
30 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 38 def as_str(value):
39 39 if isinstance(value, str):
40 40 return value
41 41 elif isinstance(value, bool):
42 42 if value:
43 43 return 'true'
44 44 else:
45 45 return 'false'
46 46 elif isinstance(value, (int, float)):
47 47 return repr(value)
48 48 else:
49 49 return value
50 50
51 51
52 52 def indent(elem, level=0):
53 53 i = "\n" + level*" "
54 54 if len(elem):
55 55 if not elem.text or not elem.text.strip():
56 56 elem.text = i + " "
57 57 if not elem.tail or not elem.tail.strip():
58 58 elem.tail = i
59 59 for elem in elem:
60 60 indent(elem, level+1)
61 61 if not elem.tail or not elem.tail.strip():
62 62 elem.tail = i
63 63 else:
64 64 if level and (not elem.tail or not elem.tail.strip()):
65 65 elem.tail = i
66 66
67 67
68 68 def find_username():
69 69 domain = os.environ.get('USERDOMAIN')
70 70 username = os.environ.get('USERNAME','')
71 71 if domain is None:
72 72 return username
73 73 else:
74 74 return '%s\\%s' % (domain, username)
75 75
76 76
77 class WinHPCJob(Component):
77 class WinHPCJob(Configurable):
78 78
79 79 job_id = Str('')
80 80 job_name = Str('MyJob', config=True)
81 81 min_cores = Int(1, config=True)
82 82 max_cores = Int(1, config=True)
83 83 min_sockets = Int(1, config=True)
84 84 max_sockets = Int(1, config=True)
85 85 min_nodes = Int(1, config=True)
86 86 max_nodes = Int(1, config=True)
87 87 unit_type = Str("Core", config=True)
88 88 auto_calculate_min = Bool(True, config=True)
89 89 auto_calculate_max = Bool(True, config=True)
90 90 run_until_canceled = Bool(False, config=True)
91 91 is_exclusive = Bool(False, config=True)
92 92 username = Str(find_username(), config=True)
93 93 job_type = Str('Batch', config=True)
94 94 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
95 95 default_value='Highest', config=True)
96 96 requested_nodes = Str('', config=True)
97 97 project = Str('IPython', config=True)
98 98 xmlns = Str('http://schemas.microsoft.com/HPCS2008/scheduler/')
99 99 version = Str("2.000")
100 100 tasks = List([])
101 101
102 102 @property
103 103 def owner(self):
104 104 return self.username
105 105
106 106 def _write_attr(self, root, attr, key):
107 107 s = as_str(getattr(self, attr, ''))
108 108 if s:
109 109 root.set(key, s)
110 110
111 111 def as_element(self):
112 112 # We have to add _A_ type things to get the right order than
113 113 # the MSFT XML parser expects.
114 114 root = ET.Element('Job')
115 115 self._write_attr(root, 'version', '_A_Version')
116 116 self._write_attr(root, 'job_name', '_B_Name')
117 117 self._write_attr(root, 'unit_type', '_C_UnitType')
118 118 self._write_attr(root, 'min_cores', '_D_MinCores')
119 119 self._write_attr(root, 'max_cores', '_E_MaxCores')
120 120 self._write_attr(root, 'min_sockets', '_F_MinSockets')
121 121 self._write_attr(root, 'max_sockets', '_G_MaxSockets')
122 122 self._write_attr(root, 'min_nodes', '_H_MinNodes')
123 123 self._write_attr(root, 'max_nodes', '_I_MaxNodes')
124 124 self._write_attr(root, 'run_until_canceled', '_J_RunUntilCanceled')
125 125 self._write_attr(root, 'is_exclusive', '_K_IsExclusive')
126 126 self._write_attr(root, 'username', '_L_UserName')
127 127 self._write_attr(root, 'job_type', '_M_JobType')
128 128 self._write_attr(root, 'priority', '_N_Priority')
129 129 self._write_attr(root, 'requested_nodes', '_O_RequestedNodes')
130 130 self._write_attr(root, 'auto_calculate_max', '_P_AutoCalculateMax')
131 131 self._write_attr(root, 'auto_calculate_min', '_Q_AutoCalculateMin')
132 132 self._write_attr(root, 'project', '_R_Project')
133 133 self._write_attr(root, 'owner', '_S_Owner')
134 134 self._write_attr(root, 'xmlns', '_T_xmlns')
135 135 dependencies = ET.SubElement(root, "Dependencies")
136 136 etasks = ET.SubElement(root, "Tasks")
137 137 for t in self.tasks:
138 138 etasks.append(t.as_element())
139 139 return root
140 140
141 141 def tostring(self):
142 142 """Return the string representation of the job description XML."""
143 143 root = self.as_element()
144 144 indent(root)
145 145 txt = ET.tostring(root, encoding="utf-8")
146 146 # Now remove the tokens used to order the attributes.
147 147 txt = re.sub(r'_[A-Z]_','',txt)
148 148 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
149 149 return txt
150 150
151 151 def write(self, filename):
152 152 """Write the XML job description to a file."""
153 153 txt = self.tostring()
154 154 with open(filename, 'w') as f:
155 155 f.write(txt)
156 156
157 157 def add_task(self, task):
158 158 """Add a task to the job.
159 159
160 160 Parameters
161 161 ----------
162 162 task : :class:`WinHPCTask`
163 163 The task object to add.
164 164 """
165 165 self.tasks.append(task)
166 166
167 167
168 class WinHPCTask(Component):
168 class WinHPCTask(Configurable):
169 169
170 170 task_id = Str('')
171 171 task_name = Str('')
172 172 version = Str("2.000")
173 173 min_cores = Int(1, config=True)
174 174 max_cores = Int(1, config=True)
175 175 min_sockets = Int(1, config=True)
176 176 max_sockets = Int(1, config=True)
177 177 min_nodes = Int(1, config=True)
178 178 max_nodes = Int(1, config=True)
179 179 unit_type = Str("Core", config=True)
180 180 command_line = CStr('', config=True)
181 181 work_directory = CStr('', config=True)
182 182 is_rerunnaable = Bool(True, config=True)
183 183 std_out_file_path = CStr('', config=True)
184 184 std_err_file_path = CStr('', config=True)
185 185 is_parametric = Bool(False, config=True)
186 186 environment_variables = Instance(dict, args=(), config=True)
187 187
188 188 def _write_attr(self, root, attr, key):
189 189 s = as_str(getattr(self, attr, ''))
190 190 if s:
191 191 root.set(key, s)
192 192
193 193 def as_element(self):
194 194 root = ET.Element('Task')
195 195 self._write_attr(root, 'version', '_A_Version')
196 196 self._write_attr(root, 'task_name', '_B_Name')
197 197 self._write_attr(root, 'min_cores', '_C_MinCores')
198 198 self._write_attr(root, 'max_cores', '_D_MaxCores')
199 199 self._write_attr(root, 'min_sockets', '_E_MinSockets')
200 200 self._write_attr(root, 'max_sockets', '_F_MaxSockets')
201 201 self._write_attr(root, 'min_nodes', '_G_MinNodes')
202 202 self._write_attr(root, 'max_nodes', '_H_MaxNodes')
203 203 self._write_attr(root, 'command_line', '_I_CommandLine')
204 204 self._write_attr(root, 'work_directory', '_J_WorkDirectory')
205 205 self._write_attr(root, 'is_rerunnaable', '_K_IsRerunnable')
206 206 self._write_attr(root, 'std_out_file_path', '_L_StdOutFilePath')
207 207 self._write_attr(root, 'std_err_file_path', '_M_StdErrFilePath')
208 208 self._write_attr(root, 'is_parametric', '_N_IsParametric')
209 209 self._write_attr(root, 'unit_type', '_O_UnitType')
210 210 root.append(self.get_env_vars())
211 211 return root
212 212
213 213 def get_env_vars(self):
214 214 env_vars = ET.Element('EnvironmentVariables')
215 215 for k, v in self.environment_variables.items():
216 216 variable = ET.SubElement(env_vars, "Variable")
217 217 name = ET.SubElement(variable, "Name")
218 218 name.text = k
219 219 value = ET.SubElement(variable, "Value")
220 220 value.text = v
221 221 return env_vars
222 222
223 223
224 224
225 225 # By declaring these, we can configure the controller and engine separately!
226 226
227 227 class IPControllerJob(WinHPCJob):
228 228 job_name = Str('IPController', config=False)
229 229 is_exclusive = Bool(False, config=True)
230 230 username = Str(find_username(), config=True)
231 231 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
232 232 default_value='Highest', config=True)
233 233 requested_nodes = Str('', config=True)
234 234 project = Str('IPython', config=True)
235 235
236 236
237 237 class IPEngineSetJob(WinHPCJob):
238 238 job_name = Str('IPEngineSet', config=False)
239 239 is_exclusive = Bool(False, config=True)
240 240 username = Str(find_username(), config=True)
241 241 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
242 242 default_value='Highest', config=True)
243 243 requested_nodes = Str('', config=True)
244 244 project = Str('IPython', config=True)
245 245
246 246
247 247 class IPControllerTask(WinHPCTask):
248 248
249 249 task_name = Str('IPController', config=True)
250 250 controller_cmd = List(['ipcontroller.exe'], config=True)
251 251 controller_args = List(['--log-to-file', '--log-level', '40'], config=True)
252 252 # I don't want these to be configurable
253 253 std_out_file_path = CStr('', config=False)
254 254 std_err_file_path = CStr('', config=False)
255 255 min_cores = Int(1, config=False)
256 256 max_cores = Int(1, config=False)
257 257 min_sockets = Int(1, config=False)
258 258 max_sockets = Int(1, config=False)
259 259 min_nodes = Int(1, config=False)
260 260 max_nodes = Int(1, config=False)
261 261 unit_type = Str("Core", config=False)
262 262 work_directory = CStr('', config=False)
263 263
264 def __init__(self, parent, name=None, config=None):
265 super(IPControllerTask, self).__init__(parent, name, config)
264 def __init__(self, config=None):
265 super(IPControllerTask, self).__init__(config)
266 266 the_uuid = uuid.uuid1()
267 267 self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid)
268 268 self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid)
269 269
270 270 @property
271 271 def command_line(self):
272 272 return ' '.join(self.controller_cmd + self.controller_args)
273 273
274 274
275 275 class IPEngineTask(WinHPCTask):
276 276
277 277 task_name = Str('IPEngine', config=True)
278 278 engine_cmd = List(['ipengine.exe'], config=True)
279 279 engine_args = List(['--log-to-file', '--log-level', '40'], config=True)
280 280 # I don't want these to be configurable
281 281 std_out_file_path = CStr('', config=False)
282 282 std_err_file_path = CStr('', config=False)
283 283 min_cores = Int(1, config=False)
284 284 max_cores = Int(1, config=False)
285 285 min_sockets = Int(1, config=False)
286 286 max_sockets = Int(1, config=False)
287 287 min_nodes = Int(1, config=False)
288 288 max_nodes = Int(1, config=False)
289 289 unit_type = Str("Core", config=False)
290 290 work_directory = CStr('', config=False)
291 291
292 def __init__(self, parent, name=None, config=None):
293 super(IPEngineTask,self).__init__(parent, name, config)
292 def __init__(self, config=None):
293 super(IPEngineTask,self).__init__(config)
294 294 the_uuid = uuid.uuid1()
295 295 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
296 296 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
297 297
298 298 @property
299 299 def command_line(self):
300 300 return ' '.join(self.engine_cmd + self.engine_args)
301 301
302 302
303 303 # j = WinHPCJob(None)
304 304 # j.job_name = 'IPCluster'
305 305 # j.username = 'GNET\\bgranger'
306 306 # j.requested_nodes = 'GREEN'
307 307 #
308 308 # t = WinHPCTask(None)
309 309 # t.task_name = 'Controller'
310 310 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
311 311 # t.work_directory = r"\\blue\domainusers$\bgranger\.ipython\cluster_default"
312 312 # t.std_out_file_path = 'controller-out.txt'
313 313 # t.std_err_file_path = 'controller-err.txt'
314 314 # t.environment_variables['PYTHONPATH'] = r"\\blue\domainusers$\bgranger\Python\Python25\Lib\site-packages"
315 315 # j.add_task(t)
316 316
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now