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