##// END OF EJS Templates
Adding support for HasTraits to take keyword arguments.
Brian Granger -
Show More
@@ -1,136 +1,139 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A base class for objects that are configurable.
4 A base class for objects that are configurable.
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2010 The IPython Development Team
13 # Copyright (C) 2008-2010 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 from copy import deepcopy
23 from copy import deepcopy
24 import datetime
24 import datetime
25 from weakref import WeakValueDictionary
25 from weakref import WeakValueDictionary
26
26
27 from IPython.utils.importstring import import_item
27 from IPython.utils.importstring import import_item
28 from loader import Config
28 from loader import Config
29 from IPython.utils.traitlets import HasTraits, Instance
29 from IPython.utils.traitlets import HasTraits, Instance
30
30
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Helper classes for Configurables
33 # Helper classes for Configurables
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36
36
37 class ConfigurableError(Exception):
37 class ConfigurableError(Exception):
38 pass
38 pass
39
39
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Configurable implementation
42 # Configurable implementation
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45
45
46 class Configurable(HasTraits):
46 class Configurable(HasTraits):
47
47
48 config = Instance(Config,(),{})
48 config = Instance(Config,(),{})
49 created = None
49 created = None
50
50
51 def __init__(self, config=None):
51 def __init__(self, **kwargs):
52 """Create a conigurable given a config config.
52 """Create a conigurable given a config config.
53
53
54 Parameters
54 Parameters
55 ----------
55 ----------
56 config : Config
56 config : Config
57 If this is empty, default values are used. If config is a
57 If this is empty, default values are used. If config is a
58 :class:`Config` instance, it will be used to configure the
58 :class:`Config` instance, it will be used to configure the
59 instance.
59 instance.
60
60
61 Notes
61 Notes
62 -----
62 -----
63 Subclasses of Configurable must call the :meth:`__init__` method of
63 Subclasses of Configurable must call the :meth:`__init__` method of
64 :class:`Configurable` *before* doing anything else and using
64 :class:`Configurable` *before* doing anything else and using
65 :func:`super`::
65 :func:`super`::
66
66
67 class MyConfigurable(Configurable):
67 class MyConfigurable(Configurable):
68 def __init__(self, config=None):
68 def __init__(self, config=None):
69 super(MyConfigurable, self).__init__(config)
69 super(MyConfigurable, self).__init__(config)
70 # Then any other code you need to finish initialization.
70 # Then any other code you need to finish initialization.
71
71
72 This ensures that instances will be configured properly.
72 This ensures that instances will be configured properly.
73 """
73 """
74 super(Configurable, self).__init__()
74 config = kwargs.pop('config', None)
75 if config is not None:
75 if config is not None:
76 # We used to deepcopy, but for now we are trying to just save
76 # We used to deepcopy, but for now we are trying to just save
77 # by reference. This *could* have side effects as all components
77 # by reference. This *could* have side effects as all components
78 # will share config. In fact, I did find such a side effect in
78 # will share config. In fact, I did find such a side effect in
79 # _config_changed below. If a config attribute value was a mutable type
79 # _config_changed below. If a config attribute value was a mutable type
80 # all instances of a component were getting the same copy, effectively
80 # all instances of a component were getting the same copy, effectively
81 # making that a class attribute.
81 # making that a class attribute.
82 # self.config = deepcopy(config)
82 # self.config = deepcopy(config)
83 self.config = config
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 self.created = datetime.datetime.now()
87 self.created = datetime.datetime.now()
85
88
86 #-------------------------------------------------------------------------
89 #-------------------------------------------------------------------------
87 # Static trait notifiations
90 # Static trait notifiations
88 #-------------------------------------------------------------------------
91 #-------------------------------------------------------------------------
89
92
90 def _config_changed(self, name, old, new):
93 def _config_changed(self, name, old, new):
91 """Update all the class traits having ``config=True`` as metadata.
94 """Update all the class traits having ``config=True`` as metadata.
92
95
93 For any class trait with a ``config`` metadata attribute that is
96 For any class trait with a ``config`` metadata attribute that is
94 ``True``, we update the trait with the value of the corresponding
97 ``True``, we update the trait with the value of the corresponding
95 config entry.
98 config entry.
96 """
99 """
97 # Get all traits with a config metadata entry that is True
100 # Get all traits with a config metadata entry that is True
98 traits = self.traits(config=True)
101 traits = self.traits(config=True)
99
102
100 # We auto-load config section for this class as well as any parent
103 # We auto-load config section for this class as well as any parent
101 # classes that are Configurable subclasses. This starts with Configurable
104 # classes that are Configurable subclasses. This starts with Configurable
102 # and works down the mro loading the config for each section.
105 # and works down the mro loading the config for each section.
103 section_names = [cls.__name__ for cls in \
106 section_names = [cls.__name__ for cls in \
104 reversed(self.__class__.__mro__) if
107 reversed(self.__class__.__mro__) if
105 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
108 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
106
109
107 for sname in section_names:
110 for sname in section_names:
108 # Don't do a blind getattr as that would cause the config to
111 # Don't do a blind getattr as that would cause the config to
109 # dynamically create the section with name self.__class__.__name__.
112 # dynamically create the section with name self.__class__.__name__.
110 if new._has_section(sname):
113 if new._has_section(sname):
111 my_config = new[sname]
114 my_config = new[sname]
112 for k, v in traits.items():
115 for k, v in traits.items():
113 # Don't allow traitlets with config=True to start with
116 # Don't allow traitlets with config=True to start with
114 # uppercase. Otherwise, they are confused with Config
117 # uppercase. Otherwise, they are confused with Config
115 # subsections. But, developers shouldn't have uppercase
118 # subsections. But, developers shouldn't have uppercase
116 # attributes anyways! (PEP 6)
119 # attributes anyways! (PEP 6)
117 if k[0].upper()==k[0] and not k.startswith('_'):
120 if k[0].upper()==k[0] and not k.startswith('_'):
118 raise ConfigurableError('Configurable traitlets with '
121 raise ConfigurableError('Configurable traitlets with '
119 'config=True must start with a lowercase so they are '
122 'config=True must start with a lowercase so they are '
120 'not confused with Config subsections: %s.%s' % \
123 'not confused with Config subsections: %s.%s' % \
121 (self.__class__.__name__, k))
124 (self.__class__.__name__, k))
122 try:
125 try:
123 # Here we grab the value from the config
126 # Here we grab the value from the config
124 # If k has the naming convention of a config
127 # If k has the naming convention of a config
125 # section, it will be auto created.
128 # section, it will be auto created.
126 config_value = my_config[k]
129 config_value = my_config[k]
127 except KeyError:
130 except KeyError:
128 pass
131 pass
129 else:
132 else:
130 # print "Setting %s.%s from %s.%s=%r" % \
133 # print "Setting %s.%s from %s.%s=%r" % \
131 # (self.__class__.__name__,k,sname,k,config_value)
134 # (self.__class__.__name__,k,sname,k,config_value)
132 # We have to do a deepcopy here if we don't deepcopy the entire
135 # We have to do a deepcopy here if we don't deepcopy the entire
133 # config object. If we don't, a mutable config_value will be
136 # config object. If we don't, a mutable config_value will be
134 # shared by all instances, effectively making it a class attribute.
137 # shared by all instances, effectively making it a class attribute.
135 setattr(self, k, deepcopy(config_value))
138 setattr(self, k, deepcopy(config_value))
136
139
@@ -1,95 +1,124 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Tests for IPython.config.configurable
4 Tests for IPython.config.configurable
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez (design help)
9 * Fernando Perez (design help)
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2010 The IPython Development Team
13 # Copyright (C) 2008-2010 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 from unittest import TestCase
23 from unittest import TestCase
24
24
25 from IPython.config.configurable import Configurable, ConfigurableError
25 from IPython.config.configurable import Configurable, ConfigurableError
26 from IPython.utils.traitlets import (
26 from IPython.utils.traitlets import (
27 TraitError, Int, Float, Str
27 TraitError, Int, Float, Str
28 )
28 )
29 from IPython.config.loader import Config
29 from IPython.config.loader import Config
30
30
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Test cases
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 class TestConfigurableConfig(TestCase):
53 class TestConfigurableConfig(TestCase):
38
54
39 def test_default(self):
55 def test_default(self):
40 c1 = Configurable()
56 c1 = Configurable()
41 c2 = Configurable(config=c1.config)
57 c2 = Configurable(config=c1.config)
42 c3 = Configurable(config=c2.config)
58 c3 = Configurable(config=c2.config)
43 self.assertEquals(c1.config, c2.config)
59 self.assertEquals(c1.config, c2.config)
44 self.assertEquals(c2.config, c3.config)
60 self.assertEquals(c2.config, c3.config)
45
61
46 def test_custom(self):
62 def test_custom(self):
47 config = Config()
63 config = Config()
48 config.foo = 'foo'
64 config.foo = 'foo'
49 config.bar = 'bar'
65 config.bar = 'bar'
50 c1 = Configurable(config=config)
66 c1 = Configurable(config=config)
51 c2 = Configurable(c1.config)
67 c2 = Configurable(config=c1.config)
52 c3 = Configurable(c2.config)
68 c3 = Configurable(config=c2.config)
53 self.assertEquals(c1.config, config)
69 self.assertEquals(c1.config, config)
54 self.assertEquals(c2.config, config)
70 self.assertEquals(c2.config, config)
55 self.assertEquals(c3.config, config)
71 self.assertEquals(c3.config, config)
56 # Test that copies are not made
72 # Test that copies are not made
57 self.assert_(c1.config is config)
73 self.assert_(c1.config is config)
58 self.assert_(c2.config is config)
74 self.assert_(c2.config is config)
59 self.assert_(c3.config is config)
75 self.assert_(c3.config is config)
60 self.assert_(c1.config is c2.config)
76 self.assert_(c1.config is c2.config)
61 self.assert_(c2.config is c3.config)
77 self.assert_(c2.config is c3.config)
62
78
63 def test_inheritance(self):
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 config = Config()
80 config = Config()
69 config.MyConfigurable.a = 2
81 config.MyConfigurable.a = 2
70 config.MyConfigurable.b = 2.0
82 config.MyConfigurable.b = 2.0
71 c1 = MyConfigurable(config=config)
83 c1 = MyConfigurable(config=config)
72 c2 = MyConfigurable(c1.config)
84 c2 = MyConfigurable(config=c1.config)
73 self.assertEquals(c1.a, config.MyConfigurable.a)
85 self.assertEquals(c1.a, config.MyConfigurable.a)
74 self.assertEquals(c1.b, config.MyConfigurable.b)
86 self.assertEquals(c1.b, config.MyConfigurable.b)
75 self.assertEquals(c2.a, config.MyConfigurable.a)
87 self.assertEquals(c2.a, config.MyConfigurable.a)
76 self.assertEquals(c2.b, config.MyConfigurable.b)
88 self.assertEquals(c2.b, config.MyConfigurable.b)
77
89
78 def test_parent(self):
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 config = Config()
91 config = Config()
86 config.Foo.a = 10
92 config.Foo.a = 10
87 config.Foo.b = "wow"
93 config.Foo.b = "wow"
88 config.Bar.b = 'later'
94 config.Bar.b = 'later'
89 config.Bar.c = 100.0
95 config.Bar.c = 100.0
90 f = Foo(config=config)
96 f = Foo(config=config)
91 b = Bar(f.config)
97 b = Bar(config=f.config)
92 self.assertEquals(f.a, 10)
98 self.assertEquals(f.a, 10)
93 self.assertEquals(f.b, 'wow')
99 self.assertEquals(f.b, 'wow')
94 self.assertEquals(b.b, 'gotit')
100 self.assertEquals(b.b, 'gotit')
95 self.assertEquals(b.c, 100.0)
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 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 System command aliases.
4 System command aliases.
5
5
6 Authors:
6 Authors:
7
7
8 * Fernando Perez
8 * Fernando Perez
9 * Brian Granger
9 * Brian Granger
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2009 The IPython Development Team
13 # Copyright (C) 2008-2009 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import __builtin__
23 import __builtin__
24 import keyword
24 import keyword
25 import os
25 import os
26 import re
26 import re
27 import sys
27 import sys
28
28
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.core.splitinput import split_user_input
30 from IPython.core.splitinput import split_user_input
31
31
32 from IPython.utils.traitlets import List, Instance
32 from IPython.utils.traitlets import List, Instance
33 from IPython.utils.autoattr import auto_attr
33 from IPython.utils.autoattr import auto_attr
34 from IPython.utils.warn import warn, error
34 from IPython.utils.warn import warn, error
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Utilities
37 # Utilities
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 # This is used as the pattern for calls to split_user_input.
40 # This is used as the pattern for calls to split_user_input.
41 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
41 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
42
42
43 def default_aliases():
43 def default_aliases():
44 # Make some aliases automatically
44 # Make some aliases automatically
45 # Prepare list of shell aliases to auto-define
45 # Prepare list of shell aliases to auto-define
46 if os.name == 'posix':
46 if os.name == 'posix':
47 default_aliases = ('mkdir mkdir', 'rmdir rmdir',
47 default_aliases = ('mkdir mkdir', 'rmdir rmdir',
48 'mv mv -i','rm rm -i','cp cp -i',
48 'mv mv -i','rm rm -i','cp cp -i',
49 'cat cat','less less','clear clear',
49 'cat cat','less less','clear clear',
50 # a better ls
50 # a better ls
51 'ls ls -F',
51 'ls ls -F',
52 # long ls
52 # long ls
53 'll ls -lF')
53 'll ls -lF')
54 # Extra ls aliases with color, which need special treatment on BSD
54 # Extra ls aliases with color, which need special treatment on BSD
55 # variants
55 # variants
56 ls_extra = ( # color ls
56 ls_extra = ( # color ls
57 'lc ls -F -o --color',
57 'lc ls -F -o --color',
58 # ls normal files only
58 # ls normal files only
59 'lf ls -F -o --color %l | grep ^-',
59 'lf ls -F -o --color %l | grep ^-',
60 # ls symbolic links
60 # ls symbolic links
61 'lk ls -F -o --color %l | grep ^l',
61 'lk ls -F -o --color %l | grep ^l',
62 # directories or links to directories,
62 # directories or links to directories,
63 'ldir ls -F -o --color %l | grep /$',
63 'ldir ls -F -o --color %l | grep /$',
64 # things which are executable
64 # things which are executable
65 'lx ls -F -o --color %l | grep ^-..x',
65 'lx ls -F -o --color %l | grep ^-..x',
66 )
66 )
67 # The BSDs don't ship GNU ls, so they don't understand the
67 # The BSDs don't ship GNU ls, so they don't understand the
68 # --color switch out of the box
68 # --color switch out of the box
69 if 'bsd' in sys.platform:
69 if 'bsd' in sys.platform:
70 ls_extra = ( # ls normal files only
70 ls_extra = ( # ls normal files only
71 'lf ls -lF | grep ^-',
71 'lf ls -lF | grep ^-',
72 # ls symbolic links
72 # ls symbolic links
73 'lk ls -lF | grep ^l',
73 'lk ls -lF | grep ^l',
74 # directories or links to directories,
74 # directories or links to directories,
75 'ldir ls -lF | grep /$',
75 'ldir ls -lF | grep /$',
76 # things which are executable
76 # things which are executable
77 'lx ls -lF | grep ^-..x',
77 'lx ls -lF | grep ^-..x',
78 )
78 )
79 default_aliases = default_aliases + ls_extra
79 default_aliases = default_aliases + ls_extra
80 elif os.name in ['nt','dos']:
80 elif os.name in ['nt','dos']:
81 default_aliases = ('ls dir /on',
81 default_aliases = ('ls dir /on',
82 'ddir dir /ad /on', 'ldir dir /ad /on',
82 'ddir dir /ad /on', 'ldir dir /ad /on',
83 'mkdir mkdir','rmdir rmdir','echo echo',
83 'mkdir mkdir','rmdir rmdir','echo echo',
84 'ren ren','cls cls','copy copy')
84 'ren ren','cls cls','copy copy')
85 else:
85 else:
86 default_aliases = ()
86 default_aliases = ()
87 return [s.split(None,1) for s in default_aliases]
87 return [s.split(None,1) for s in default_aliases]
88
88
89
89
90 class AliasError(Exception):
90 class AliasError(Exception):
91 pass
91 pass
92
92
93
93
94 class InvalidAliasError(AliasError):
94 class InvalidAliasError(AliasError):
95 pass
95 pass
96
96
97
97
98 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
99 # Main AliasManager class
99 # Main AliasManager class
100 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
101
101
102
102
103 class AliasManager(Configurable):
103 class AliasManager(Configurable):
104
104
105 default_aliases = List(default_aliases(), config=True)
105 default_aliases = List(default_aliases(), config=True)
106 user_aliases = List(default_value=[], config=True)
106 user_aliases = List(default_value=[], config=True)
107 shell = Instance('IPython.core.iplib.InteractiveShellABC')
107 shell = Instance('IPython.core.iplib.InteractiveShellABC')
108
108
109 def __init__(self, shell, config=None):
109 def __init__(self, shell=None, config=None):
110 super(AliasManager, self).__init__(config=config)
110 super(AliasManager, self).__init__(shell=shell, config=config)
111 self.alias_table = {}
111 self.alias_table = {}
112 self.exclude_aliases()
112 self.exclude_aliases()
113 self.init_aliases()
113 self.init_aliases()
114 self.shell = shell
115
114
116 def __contains__(self, name):
115 def __contains__(self, name):
117 if name in self.alias_table:
116 if name in self.alias_table:
118 return True
117 return True
119 else:
118 else:
120 return False
119 return False
121
120
122 @property
121 @property
123 def aliases(self):
122 def aliases(self):
124 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
123 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
125
124
126 def exclude_aliases(self):
125 def exclude_aliases(self):
127 # set of things NOT to alias (keywords, builtins and some magics)
126 # set of things NOT to alias (keywords, builtins and some magics)
128 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
127 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
129 no_alias.update(set(keyword.kwlist))
128 no_alias.update(set(keyword.kwlist))
130 no_alias.update(set(__builtin__.__dict__.keys()))
129 no_alias.update(set(__builtin__.__dict__.keys()))
131 self.no_alias = no_alias
130 self.no_alias = no_alias
132
131
133 def init_aliases(self):
132 def init_aliases(self):
134 # Load default aliases
133 # Load default aliases
135 for name, cmd in self.default_aliases:
134 for name, cmd in self.default_aliases:
136 self.soft_define_alias(name, cmd)
135 self.soft_define_alias(name, cmd)
137
136
138 # Load user aliases
137 # Load user aliases
139 for name, cmd in self.user_aliases:
138 for name, cmd in self.user_aliases:
140 self.soft_define_alias(name, cmd)
139 self.soft_define_alias(name, cmd)
141
140
142 def clear_aliases(self):
141 def clear_aliases(self):
143 self.alias_table.clear()
142 self.alias_table.clear()
144
143
145 def soft_define_alias(self, name, cmd):
144 def soft_define_alias(self, name, cmd):
146 """Define an alias, but don't raise on an AliasError."""
145 """Define an alias, but don't raise on an AliasError."""
147 try:
146 try:
148 self.define_alias(name, cmd)
147 self.define_alias(name, cmd)
149 except AliasError, e:
148 except AliasError, e:
150 error("Invalid alias: %s" % e)
149 error("Invalid alias: %s" % e)
151
150
152 def define_alias(self, name, cmd):
151 def define_alias(self, name, cmd):
153 """Define a new alias after validating it.
152 """Define a new alias after validating it.
154
153
155 This will raise an :exc:`AliasError` if there are validation
154 This will raise an :exc:`AliasError` if there are validation
156 problems.
155 problems.
157 """
156 """
158 nargs = self.validate_alias(name, cmd)
157 nargs = self.validate_alias(name, cmd)
159 self.alias_table[name] = (nargs, cmd)
158 self.alias_table[name] = (nargs, cmd)
160
159
161 def undefine_alias(self, name):
160 def undefine_alias(self, name):
162 if self.alias_table.has_key(name):
161 if self.alias_table.has_key(name):
163 del self.alias_table[name]
162 del self.alias_table[name]
164
163
165 def validate_alias(self, name, cmd):
164 def validate_alias(self, name, cmd):
166 """Validate an alias and return the its number of arguments."""
165 """Validate an alias and return the its number of arguments."""
167 if name in self.no_alias:
166 if name in self.no_alias:
168 raise InvalidAliasError("The name %s can't be aliased "
167 raise InvalidAliasError("The name %s can't be aliased "
169 "because it is a keyword or builtin." % name)
168 "because it is a keyword or builtin." % name)
170 if not (isinstance(cmd, basestring)):
169 if not (isinstance(cmd, basestring)):
171 raise InvalidAliasError("An alias command must be a string, "
170 raise InvalidAliasError("An alias command must be a string, "
172 "got: %r" % name)
171 "got: %r" % name)
173 nargs = cmd.count('%s')
172 nargs = cmd.count('%s')
174 if nargs>0 and cmd.find('%l')>=0:
173 if nargs>0 and cmd.find('%l')>=0:
175 raise InvalidAliasError('The %s and %l specifiers are mutually '
174 raise InvalidAliasError('The %s and %l specifiers are mutually '
176 'exclusive in alias definitions.')
175 'exclusive in alias definitions.')
177 return nargs
176 return nargs
178
177
179 def call_alias(self, alias, rest=''):
178 def call_alias(self, alias, rest=''):
180 """Call an alias given its name and the rest of the line."""
179 """Call an alias given its name and the rest of the line."""
181 cmd = self.transform_alias(alias, rest)
180 cmd = self.transform_alias(alias, rest)
182 try:
181 try:
183 self.shell.system(cmd)
182 self.shell.system(cmd)
184 except:
183 except:
185 self.shell.showtraceback()
184 self.shell.showtraceback()
186
185
187 def transform_alias(self, alias,rest=''):
186 def transform_alias(self, alias,rest=''):
188 """Transform alias to system command string."""
187 """Transform alias to system command string."""
189 nargs, cmd = self.alias_table[alias]
188 nargs, cmd = self.alias_table[alias]
190
189
191 if ' ' in cmd and os.path.isfile(cmd):
190 if ' ' in cmd and os.path.isfile(cmd):
192 cmd = '"%s"' % cmd
191 cmd = '"%s"' % cmd
193
192
194 # Expand the %l special to be the user's input line
193 # Expand the %l special to be the user's input line
195 if cmd.find('%l') >= 0:
194 if cmd.find('%l') >= 0:
196 cmd = cmd.replace('%l', rest)
195 cmd = cmd.replace('%l', rest)
197 rest = ''
196 rest = ''
198 if nargs==0:
197 if nargs==0:
199 # Simple, argument-less aliases
198 # Simple, argument-less aliases
200 cmd = '%s %s' % (cmd, rest)
199 cmd = '%s %s' % (cmd, rest)
201 else:
200 else:
202 # Handle aliases with positional arguments
201 # Handle aliases with positional arguments
203 args = rest.split(None, nargs)
202 args = rest.split(None, nargs)
204 if len(args) < nargs:
203 if len(args) < nargs:
205 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
204 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
206 (alias, nargs, len(args)))
205 (alias, nargs, len(args)))
207 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
206 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
208 return cmd
207 return cmd
209
208
210 def expand_alias(self, line):
209 def expand_alias(self, line):
211 """ Expand an alias in the command line
210 """ Expand an alias in the command line
212
211
213 Returns the provided command line, possibly with the first word
212 Returns the provided command line, possibly with the first word
214 (command) translated according to alias expansion rules.
213 (command) translated according to alias expansion rules.
215
214
216 [ipython]|16> _ip.expand_aliases("np myfile.txt")
215 [ipython]|16> _ip.expand_aliases("np myfile.txt")
217 <16> 'q:/opt/np/notepad++.exe myfile.txt'
216 <16> 'q:/opt/np/notepad++.exe myfile.txt'
218 """
217 """
219
218
220 pre,fn,rest = split_user_input(line)
219 pre,fn,rest = split_user_input(line)
221 res = pre + self.expand_aliases(fn, rest)
220 res = pre + self.expand_aliases(fn, rest)
222 return res
221 return res
223
222
224 def expand_aliases(self, fn, rest):
223 def expand_aliases(self, fn, rest):
225 """Expand multiple levels of aliases:
224 """Expand multiple levels of aliases:
226
225
227 if:
226 if:
228
227
229 alias foo bar /tmp
228 alias foo bar /tmp
230 alias baz foo
229 alias baz foo
231
230
232 then:
231 then:
233
232
234 baz huhhahhei -> bar /tmp huhhahhei
233 baz huhhahhei -> bar /tmp huhhahhei
235
234
236 """
235 """
237 line = fn + " " + rest
236 line = fn + " " + rest
238
237
239 done = set()
238 done = set()
240 while 1:
239 while 1:
241 pre,fn,rest = split_user_input(line, shell_line_split)
240 pre,fn,rest = split_user_input(line, shell_line_split)
242 if fn in self.alias_table:
241 if fn in self.alias_table:
243 if fn in done:
242 if fn in done:
244 warn("Cyclic alias definition, repeated '%s'" % fn)
243 warn("Cyclic alias definition, repeated '%s'" % fn)
245 return ""
244 return ""
246 done.add(fn)
245 done.add(fn)
247
246
248 l2 = self.transform_alias(fn, rest)
247 l2 = self.transform_alias(fn, rest)
249 if l2 == line:
248 if l2 == line:
250 break
249 break
251 # ls -> ls -F should not recurse forever
250 # ls -> ls -F should not recurse forever
252 if l2.split(None,1)[0] == line.split(None,1)[0]:
251 if l2.split(None,1)[0] == line.split(None,1)[0]:
253 line = l2
252 line = l2
254 break
253 break
255 line=l2
254 line=l2
256 else:
255 else:
257 break
256 break
258
257
259 return line
258 return line
@@ -1,115 +1,115 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A context manager for managing things injected into :mod:`__builtin__`.
4 A context manager for managing things injected into :mod:`__builtin__`.
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2009 The IPython Development Team
12 # Copyright (C) 2008-2009 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import __builtin__
22 import __builtin__
23
23
24 from IPython.config.configurable import Configurable
24 from IPython.config.configurable import Configurable
25 from IPython.core.quitter import Quitter
25 from IPython.core.quitter import Quitter
26
26
27 from IPython.utils.traitlets import Instance
27 from IPython.utils.traitlets import Instance
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Classes and functions
30 # Classes and functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33
33
34 class __BuiltinUndefined(object): pass
34 class __BuiltinUndefined(object): pass
35 BuiltinUndefined = __BuiltinUndefined()
35 BuiltinUndefined = __BuiltinUndefined()
36
36
37
37
38 class BuiltinTrap(Configurable):
38 class BuiltinTrap(Configurable):
39
39
40 shell = Instance('IPython.core.iplib.InteractiveShellABC')
40 shell = Instance('IPython.core.iplib.InteractiveShellABC')
41
41
42 def __init__(self, shell):
42 def __init__(self, shell=None):
43 super(BuiltinTrap, self).__init__(None)
43 super(BuiltinTrap, self).__init__(shell=shell, config=None)
44 self._orig_builtins = {}
44 self._orig_builtins = {}
45 # We define this to track if a single BuiltinTrap is nested.
45 # We define this to track if a single BuiltinTrap is nested.
46 # Only turn off the trap when the outermost call to __exit__ is made.
46 # Only turn off the trap when the outermost call to __exit__ is made.
47 self._nested_level = 0
47 self._nested_level = 0
48 self.shell = shell
48 self.shell = shell
49
49
50 def __enter__(self):
50 def __enter__(self):
51 if self._nested_level == 0:
51 if self._nested_level == 0:
52 self.set()
52 self.set()
53 self._nested_level += 1
53 self._nested_level += 1
54 # I return self, so callers can use add_builtin in a with clause.
54 # I return self, so callers can use add_builtin in a with clause.
55 return self
55 return self
56
56
57 def __exit__(self, type, value, traceback):
57 def __exit__(self, type, value, traceback):
58 if self._nested_level == 1:
58 if self._nested_level == 1:
59 self.unset()
59 self.unset()
60 self._nested_level -= 1
60 self._nested_level -= 1
61 # Returning False will cause exceptions to propagate
61 # Returning False will cause exceptions to propagate
62 return False
62 return False
63
63
64 def add_builtin(self, key, value):
64 def add_builtin(self, key, value):
65 """Add a builtin and save the original."""
65 """Add a builtin and save the original."""
66 orig = __builtin__.__dict__.get(key, BuiltinUndefined)
66 orig = __builtin__.__dict__.get(key, BuiltinUndefined)
67 self._orig_builtins[key] = orig
67 self._orig_builtins[key] = orig
68 __builtin__.__dict__[key] = value
68 __builtin__.__dict__[key] = value
69
69
70 def remove_builtin(self, key):
70 def remove_builtin(self, key):
71 """Remove an added builtin and re-set the original."""
71 """Remove an added builtin and re-set the original."""
72 try:
72 try:
73 orig = self._orig_builtins.pop(key)
73 orig = self._orig_builtins.pop(key)
74 except KeyError:
74 except KeyError:
75 pass
75 pass
76 else:
76 else:
77 if orig is BuiltinUndefined:
77 if orig is BuiltinUndefined:
78 del __builtin__.__dict__[key]
78 del __builtin__.__dict__[key]
79 else:
79 else:
80 __builtin__.__dict__[key] = orig
80 __builtin__.__dict__[key] = orig
81
81
82 def set(self):
82 def set(self):
83 """Store ipython references in the __builtin__ namespace."""
83 """Store ipython references in the __builtin__ namespace."""
84 self.add_builtin('exit', Quitter(self.shell, 'exit'))
84 self.add_builtin('exit', Quitter(self.shell, 'exit'))
85 self.add_builtin('quit', Quitter(self.shell, 'quit'))
85 self.add_builtin('quit', Quitter(self.shell, 'quit'))
86 self.add_builtin('get_ipython', self.shell.get_ipython)
86 self.add_builtin('get_ipython', self.shell.get_ipython)
87
87
88 # Recursive reload function
88 # Recursive reload function
89 try:
89 try:
90 from IPython.lib import deepreload
90 from IPython.lib import deepreload
91 if self.shell.deep_reload:
91 if self.shell.deep_reload:
92 self.add_builtin('reload', deepreload.reload)
92 self.add_builtin('reload', deepreload.reload)
93 else:
93 else:
94 self.add_builtin('dreload', deepreload.reload)
94 self.add_builtin('dreload', deepreload.reload)
95 del deepreload
95 del deepreload
96 except ImportError:
96 except ImportError:
97 pass
97 pass
98
98
99 # Keep in the builtins a flag for when IPython is active. We set it
99 # Keep in the builtins a flag for when IPython is active. We set it
100 # with setdefault so that multiple nested IPythons don't clobber one
100 # with setdefault so that multiple nested IPythons don't clobber one
101 # another. Each will increase its value by one upon being activated,
101 # another. Each will increase its value by one upon being activated,
102 # which also gives us a way to determine the nesting level.
102 # which also gives us a way to determine the nesting level.
103 __builtin__.__dict__.setdefault('__IPYTHON__active',0)
103 __builtin__.__dict__.setdefault('__IPYTHON__active',0)
104
104
105 def unset(self):
105 def unset(self):
106 """Remove any builtins which might have been added by add_builtins, or
106 """Remove any builtins which might have been added by add_builtins, or
107 restore overwritten ones to their previous values."""
107 restore overwritten ones to their previous values."""
108 for key in self._orig_builtins.keys():
108 for key in self._orig_builtins.keys():
109 self.remove_builtin(key)
109 self.remove_builtin(key)
110 self._orig_builtins.clear()
110 self._orig_builtins.clear()
111 self._builtins_added = False
111 self._builtins_added = False
112 try:
112 try:
113 del __builtin__.__dict__['__IPYTHON__active']
113 del __builtin__.__dict__['__IPYTHON__active']
114 except KeyError:
114 except KeyError:
115 pass
115 pass
@@ -1,69 +1,71 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A context manager for handling sys.displayhook.
4 A context manager for handling sys.displayhook.
5
5
6 Authors:
6 Authors:
7
7
8 * Robert Kern
8 * Robert Kern
9 * Brian Granger
9 * Brian Granger
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2009 The IPython Development Team
13 # Copyright (C) 2008-2009 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import sys
23 import sys
24
24
25 from IPython.config.configurable import Configurable
25 from IPython.config.configurable import Configurable
26 from IPython.utils.traitlets import Any
26
27
27 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
28 # Classes and functions
29 # Classes and functions
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30
31
31
32
32 class DisplayTrap(Configurable):
33 class DisplayTrap(Configurable):
33 """Object to manage sys.displayhook.
34 """Object to manage sys.displayhook.
34
35
35 This came from IPython.core.kernel.display_hook, but is simplified
36 This came from IPython.core.kernel.display_hook, but is simplified
36 (no callbacks or formatters) until more of the core is refactored.
37 (no callbacks or formatters) until more of the core is refactored.
37 """
38 """
38
39
39 def __init__(self, hook):
40 hook = Any
40 super(DisplayTrap, self).__init__(None)
41
41 self.hook = hook
42 def __init__(self, hook=None):
43 super(DisplayTrap, self).__init__(hook=hook, config=None)
42 self.old_hook = None
44 self.old_hook = None
43 # We define this to track if a single BuiltinTrap is nested.
45 # We define this to track if a single BuiltinTrap is nested.
44 # Only turn off the trap when the outermost call to __exit__ is made.
46 # Only turn off the trap when the outermost call to __exit__ is made.
45 self._nested_level = 0
47 self._nested_level = 0
46
48
47 def __enter__(self):
49 def __enter__(self):
48 if self._nested_level == 0:
50 if self._nested_level == 0:
49 self.set()
51 self.set()
50 self._nested_level += 1
52 self._nested_level += 1
51 return self
53 return self
52
54
53 def __exit__(self, type, value, traceback):
55 def __exit__(self, type, value, traceback):
54 if self._nested_level == 1:
56 if self._nested_level == 1:
55 self.unset()
57 self.unset()
56 self._nested_level -= 1
58 self._nested_level -= 1
57 # Returning False will cause exceptions to propagate
59 # Returning False will cause exceptions to propagate
58 return False
60 return False
59
61
60 def set(self):
62 def set(self):
61 """Set the hook."""
63 """Set the hook."""
62 if sys.displayhook is not self.hook:
64 if sys.displayhook is not self.hook:
63 self.old_hook = sys.displayhook
65 self.old_hook = sys.displayhook
64 sys.displayhook = self.hook
66 sys.displayhook = self.hook
65
67
66 def unset(self):
68 def unset(self):
67 """Unset the hook."""
69 """Unset the hook."""
68 sys.displayhook = self.old_hook
70 sys.displayhook = self.old_hook
69
71
@@ -1,126 +1,125 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A class for managing IPython extensions.
2 """A class for managing IPython extensions.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
10 # Copyright (C) 2010 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 import os
20 import os
21 import sys
21 import sys
22
22
23 from IPython.config.configurable import Configurable
23 from IPython.config.configurable import Configurable
24 from IPython.utils.traitlets import Instance
24 from IPython.utils.traitlets import Instance
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Main class
27 # Main class
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class ExtensionManager(Configurable):
30 class ExtensionManager(Configurable):
31 """A class to manage IPython extensions.
31 """A class to manage IPython extensions.
32
32
33 An IPython extension is an importable Python module that has
33 An IPython extension is an importable Python module that has
34 a function with the signature::
34 a function with the signature::
35
35
36 def load_ipython_extension(ipython):
36 def load_ipython_extension(ipython):
37 # Do things with ipython
37 # Do things with ipython
38
38
39 This function is called after your extension is imported and the
39 This function is called after your extension is imported and the
40 currently active :class:`InteractiveShell` instance is passed as
40 currently active :class:`InteractiveShell` instance is passed as
41 the only argument. You can do anything you want with IPython at
41 the only argument. You can do anything you want with IPython at
42 that point, including defining new magic and aliases, adding new
42 that point, including defining new magic and aliases, adding new
43 components, etc.
43 components, etc.
44
44
45 The :func:`load_ipython_extension` will be called again is you
45 The :func:`load_ipython_extension` will be called again is you
46 load or reload the extension again. It is up to the extension
46 load or reload the extension again. It is up to the extension
47 author to add code to manage that.
47 author to add code to manage that.
48
48
49 You can put your extension modules anywhere you want, as long as
49 You can put your extension modules anywhere you want, as long as
50 they can be imported by Python's standard import mechanism. However,
50 they can be imported by Python's standard import mechanism. However,
51 to make it easy to write extensions, you can also put your extensions
51 to make it easy to write extensions, you can also put your extensions
52 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
52 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
53 is added to ``sys.path`` automatically.
53 is added to ``sys.path`` automatically.
54 """
54 """
55
55
56 shell = Instance('IPython.core.iplib.InteractiveShellABC')
56 shell = Instance('IPython.core.iplib.InteractiveShellABC')
57
57
58 def __init__(self, shell, config=None):
58 def __init__(self, shell=None, config=None):
59 super(ExtensionManager, self).__init__(config=config)
59 super(ExtensionManager, self).__init__(shell=shell, config=config)
60 self.shell = shell
61 self.shell.on_trait_change(
60 self.shell.on_trait_change(
62 self._on_ipython_dir_changed, 'ipython_dir'
61 self._on_ipython_dir_changed, 'ipython_dir'
63 )
62 )
64
63
65 def __del__(self):
64 def __del__(self):
66 self.shell.on_trait_change(
65 self.shell.on_trait_change(
67 self._on_ipython_dir_changed, 'ipython_dir', remove=True
66 self._on_ipython_dir_changed, 'ipython_dir', remove=True
68 )
67 )
69
68
70 @property
69 @property
71 def ipython_extension_dir(self):
70 def ipython_extension_dir(self):
72 return os.path.join(self.shell.ipython_dir, u'extensions')
71 return os.path.join(self.shell.ipython_dir, u'extensions')
73
72
74 def _on_ipython_dir_changed(self):
73 def _on_ipython_dir_changed(self):
75 if not os.path.isdir(self.ipython_extension_dir):
74 if not os.path.isdir(self.ipython_extension_dir):
76 os.makedirs(self.ipython_extension_dir, mode = 0777)
75 os.makedirs(self.ipython_extension_dir, mode = 0777)
77
76
78 def load_extension(self, module_str):
77 def load_extension(self, module_str):
79 """Load an IPython extension by its module name.
78 """Load an IPython extension by its module name.
80
79
81 If :func:`load_ipython_extension` returns anything, this function
80 If :func:`load_ipython_extension` returns anything, this function
82 will return that object.
81 will return that object.
83 """
82 """
84 from IPython.utils.syspathcontext import prepended_to_syspath
83 from IPython.utils.syspathcontext import prepended_to_syspath
85
84
86 if module_str not in sys.modules:
85 if module_str not in sys.modules:
87 with prepended_to_syspath(self.ipython_extension_dir):
86 with prepended_to_syspath(self.ipython_extension_dir):
88 __import__(module_str)
87 __import__(module_str)
89 mod = sys.modules[module_str]
88 mod = sys.modules[module_str]
90 return self._call_load_ipython_extension(mod)
89 return self._call_load_ipython_extension(mod)
91
90
92 def unload_extension(self, module_str):
91 def unload_extension(self, module_str):
93 """Unload an IPython extension by its module name.
92 """Unload an IPython extension by its module name.
94
93
95 This function looks up the extension's name in ``sys.modules`` and
94 This function looks up the extension's name in ``sys.modules`` and
96 simply calls ``mod.unload_ipython_extension(self)``.
95 simply calls ``mod.unload_ipython_extension(self)``.
97 """
96 """
98 if module_str in sys.modules:
97 if module_str in sys.modules:
99 mod = sys.modules[module_str]
98 mod = sys.modules[module_str]
100 self._call_unload_ipython_extension(mod)
99 self._call_unload_ipython_extension(mod)
101
100
102 def reload_extension(self, module_str):
101 def reload_extension(self, module_str):
103 """Reload an IPython extension by calling reload.
102 """Reload an IPython extension by calling reload.
104
103
105 If the module has not been loaded before,
104 If the module has not been loaded before,
106 :meth:`InteractiveShell.load_extension` is called. Otherwise
105 :meth:`InteractiveShell.load_extension` is called. Otherwise
107 :func:`reload` is called and then the :func:`load_ipython_extension`
106 :func:`reload` is called and then the :func:`load_ipython_extension`
108 function of the module, if it exists is called.
107 function of the module, if it exists is called.
109 """
108 """
110 from IPython.utils.syspathcontext import prepended_to_syspath
109 from IPython.utils.syspathcontext import prepended_to_syspath
111
110
112 with prepended_to_syspath(self.ipython_extension_dir):
111 with prepended_to_syspath(self.ipython_extension_dir):
113 if module_str in sys.modules:
112 if module_str in sys.modules:
114 mod = sys.modules[module_str]
113 mod = sys.modules[module_str]
115 reload(mod)
114 reload(mod)
116 self._call_load_ipython_extension(mod)
115 self._call_load_ipython_extension(mod)
117 else:
116 else:
118 self.load_extension(module_str)
117 self.load_extension(module_str)
119
118
120 def _call_load_ipython_extension(self, mod):
119 def _call_load_ipython_extension(self, mod):
121 if hasattr(mod, 'load_ipython_extension'):
120 if hasattr(mod, 'load_ipython_extension'):
122 return mod.load_ipython_extension(self.shell)
121 return mod.load_ipython_extension(self.shell)
123
122
124 def _call_unload_ipython_extension(self, mod):
123 def _call_unload_ipython_extension(self, mod):
125 if hasattr(mod, 'unload_ipython_extension'):
124 if hasattr(mod, 'unload_ipython_extension'):
126 return mod.unload_ipython_extension(self.shell)
125 return mod.unload_ipython_extension(self.shell)
@@ -1,2523 +1,2523 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2010 The IPython Development Team
7 # Copyright (C) 2008-2010 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import with_statement
17 from __future__ import with_statement
18 from __future__ import absolute_import
18 from __future__ import absolute_import
19
19
20 import __builtin__
20 import __builtin__
21 import abc
21 import abc
22 import bdb
22 import bdb
23 import codeop
23 import codeop
24 import exceptions
24 import exceptions
25 import new
25 import new
26 import os
26 import os
27 import re
27 import re
28 import string
28 import string
29 import sys
29 import sys
30 import tempfile
30 import tempfile
31 from contextlib import nested
31 from contextlib import nested
32
32
33 from IPython.core import debugger, oinspect
33 from IPython.core import debugger, oinspect
34 from IPython.core import history as ipcorehist
34 from IPython.core import history as ipcorehist
35 from IPython.core import prefilter
35 from IPython.core import prefilter
36 from IPython.core import shadowns
36 from IPython.core import shadowns
37 from IPython.core import ultratb
37 from IPython.core import ultratb
38 from IPython.core.alias import AliasManager
38 from IPython.core.alias import AliasManager
39 from IPython.core.builtin_trap import BuiltinTrap
39 from IPython.core.builtin_trap import BuiltinTrap
40 from IPython.config.configurable import Configurable
40 from IPython.config.configurable import Configurable
41 from IPython.core.display_trap import DisplayTrap
41 from IPython.core.display_trap import DisplayTrap
42 from IPython.core.error import TryNext, UsageError
42 from IPython.core.error import TryNext, UsageError
43 from IPython.core.extensions import ExtensionManager
43 from IPython.core.extensions import ExtensionManager
44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
45 from IPython.core.logger import Logger
45 from IPython.core.logger import Logger
46 from IPython.core.magic import Magic
46 from IPython.core.magic import Magic
47 from IPython.core.plugin import PluginManager
47 from IPython.core.plugin import PluginManager
48 from IPython.core.prefilter import PrefilterManager
48 from IPython.core.prefilter import PrefilterManager
49 from IPython.core.prompts import CachedOutput
49 from IPython.core.prompts import CachedOutput
50 from IPython.core.usage import interactive_usage, default_banner
50 from IPython.core.usage import interactive_usage, default_banner
51 import IPython.core.hooks
51 import IPython.core.hooks
52 from IPython.external.Itpl import ItplNS
52 from IPython.external.Itpl import ItplNS
53 from IPython.lib.inputhook import enable_gui
53 from IPython.lib.inputhook import enable_gui
54 from IPython.lib.backgroundjobs import BackgroundJobManager
54 from IPython.lib.backgroundjobs import BackgroundJobManager
55 from IPython.lib.pylabtools import pylab_activate
55 from IPython.lib.pylabtools import pylab_activate
56 from IPython.utils import PyColorize
56 from IPython.utils import PyColorize
57 from IPython.utils import pickleshare
57 from IPython.utils import pickleshare
58 from IPython.utils.doctestreload import doctest_reload
58 from IPython.utils.doctestreload import doctest_reload
59 from IPython.utils.ipstruct import Struct
59 from IPython.utils.ipstruct import Struct
60 from IPython.utils.io import Term, ask_yes_no
60 from IPython.utils.io import Term, ask_yes_no
61 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
61 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
62 from IPython.utils.process import (
62 from IPython.utils.process import (
63 abbrev_cwd,
63 abbrev_cwd,
64 getoutput,
64 getoutput,
65 getoutputerror
65 getoutputerror
66 )
66 )
67 # import IPython.utils.rlineimpl as readline
67 # import IPython.utils.rlineimpl as readline
68 from IPython.utils.strdispatch import StrDispatch
68 from IPython.utils.strdispatch import StrDispatch
69 from IPython.utils.syspathcontext import prepended_to_syspath
69 from IPython.utils.syspathcontext import prepended_to_syspath
70 from IPython.utils.terminal import toggle_set_term_title, set_term_title
70 from IPython.utils.terminal import toggle_set_term_title, set_term_title
71 from IPython.utils.warn import warn, error, fatal
71 from IPython.utils.warn import warn, error, fatal
72 from IPython.utils.traitlets import (
72 from IPython.utils.traitlets import (
73 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode, Instance
73 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode, Instance
74 )
74 )
75
75
76 # from IPython.utils import growl
76 # from IPython.utils import growl
77 # growl.start("IPython")
77 # growl.start("IPython")
78
78
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80 # Globals
80 # Globals
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82
82
83 # store the builtin raw_input globally, and use this always, in case user code
83 # store the builtin raw_input globally, and use this always, in case user code
84 # overwrites it (like wx.py.PyShell does)
84 # overwrites it (like wx.py.PyShell does)
85 raw_input_original = raw_input
85 raw_input_original = raw_input
86
86
87 # compiled regexps for autoindent management
87 # compiled regexps for autoindent management
88 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
88 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
89
89
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91 # Utilities
91 # Utilities
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93
93
94 ini_spaces_re = re.compile(r'^(\s+)')
94 ini_spaces_re = re.compile(r'^(\s+)')
95
95
96
96
97 def num_ini_spaces(strng):
97 def num_ini_spaces(strng):
98 """Return the number of initial spaces in a string"""
98 """Return the number of initial spaces in a string"""
99
99
100 ini_spaces = ini_spaces_re.match(strng)
100 ini_spaces = ini_spaces_re.match(strng)
101 if ini_spaces:
101 if ini_spaces:
102 return ini_spaces.end()
102 return ini_spaces.end()
103 else:
103 else:
104 return 0
104 return 0
105
105
106
106
107 def softspace(file, newvalue):
107 def softspace(file, newvalue):
108 """Copied from code.py, to remove the dependency"""
108 """Copied from code.py, to remove the dependency"""
109
109
110 oldvalue = 0
110 oldvalue = 0
111 try:
111 try:
112 oldvalue = file.softspace
112 oldvalue = file.softspace
113 except AttributeError:
113 except AttributeError:
114 pass
114 pass
115 try:
115 try:
116 file.softspace = newvalue
116 file.softspace = newvalue
117 except (AttributeError, TypeError):
117 except (AttributeError, TypeError):
118 # "attribute-less object" or "read-only attributes"
118 # "attribute-less object" or "read-only attributes"
119 pass
119 pass
120 return oldvalue
120 return oldvalue
121
121
122
122
123 def no_op(*a, **kw): pass
123 def no_op(*a, **kw): pass
124
124
125 class SpaceInInput(exceptions.Exception): pass
125 class SpaceInInput(exceptions.Exception): pass
126
126
127 class Bunch: pass
127 class Bunch: pass
128
128
129 class InputList(list):
129 class InputList(list):
130 """Class to store user input.
130 """Class to store user input.
131
131
132 It's basically a list, but slices return a string instead of a list, thus
132 It's basically a list, but slices return a string instead of a list, thus
133 allowing things like (assuming 'In' is an instance):
133 allowing things like (assuming 'In' is an instance):
134
134
135 exec In[4:7]
135 exec In[4:7]
136
136
137 or
137 or
138
138
139 exec In[5:9] + In[14] + In[21:25]"""
139 exec In[5:9] + In[14] + In[21:25]"""
140
140
141 def __getslice__(self,i,j):
141 def __getslice__(self,i,j):
142 return ''.join(list.__getslice__(self,i,j))
142 return ''.join(list.__getslice__(self,i,j))
143
143
144
144
145 class SyntaxTB(ultratb.ListTB):
145 class SyntaxTB(ultratb.ListTB):
146 """Extension which holds some state: the last exception value"""
146 """Extension which holds some state: the last exception value"""
147
147
148 def __init__(self,color_scheme = 'NoColor'):
148 def __init__(self,color_scheme = 'NoColor'):
149 ultratb.ListTB.__init__(self,color_scheme)
149 ultratb.ListTB.__init__(self,color_scheme)
150 self.last_syntax_error = None
150 self.last_syntax_error = None
151
151
152 def __call__(self, etype, value, elist):
152 def __call__(self, etype, value, elist):
153 self.last_syntax_error = value
153 self.last_syntax_error = value
154 ultratb.ListTB.__call__(self,etype,value,elist)
154 ultratb.ListTB.__call__(self,etype,value,elist)
155
155
156 def clear_err_state(self):
156 def clear_err_state(self):
157 """Return the current error state and clear it"""
157 """Return the current error state and clear it"""
158 e = self.last_syntax_error
158 e = self.last_syntax_error
159 self.last_syntax_error = None
159 self.last_syntax_error = None
160 return e
160 return e
161
161
162
162
163 def get_default_editor():
163 def get_default_editor():
164 try:
164 try:
165 ed = os.environ['EDITOR']
165 ed = os.environ['EDITOR']
166 except KeyError:
166 except KeyError:
167 if os.name == 'posix':
167 if os.name == 'posix':
168 ed = 'vi' # the only one guaranteed to be there!
168 ed = 'vi' # the only one guaranteed to be there!
169 else:
169 else:
170 ed = 'notepad' # same in Windows!
170 ed = 'notepad' # same in Windows!
171 return ed
171 return ed
172
172
173
173
174 def get_default_colors():
174 def get_default_colors():
175 if sys.platform=='darwin':
175 if sys.platform=='darwin':
176 return "LightBG"
176 return "LightBG"
177 elif os.name=='nt':
177 elif os.name=='nt':
178 return 'Linux'
178 return 'Linux'
179 else:
179 else:
180 return 'Linux'
180 return 'Linux'
181
181
182
182
183 class SeparateStr(Str):
183 class SeparateStr(Str):
184 """A Str subclass to validate separate_in, separate_out, etc.
184 """A Str subclass to validate separate_in, separate_out, etc.
185
185
186 This is a Str based trait that converts '0'->'' and '\\n'->'\n'.
186 This is a Str based trait that converts '0'->'' and '\\n'->'\n'.
187 """
187 """
188
188
189 def validate(self, obj, value):
189 def validate(self, obj, value):
190 if value == '0': value = ''
190 if value == '0': value = ''
191 value = value.replace('\\n','\n')
191 value = value.replace('\\n','\n')
192 return super(SeparateStr, self).validate(obj, value)
192 return super(SeparateStr, self).validate(obj, value)
193
193
194
194
195 #-----------------------------------------------------------------------------
195 #-----------------------------------------------------------------------------
196 # Main IPython class
196 # Main IPython class
197 #-----------------------------------------------------------------------------
197 #-----------------------------------------------------------------------------
198
198
199
199
200 class InteractiveShell(Configurable, Magic):
200 class InteractiveShell(Configurable, Magic):
201 """An enhanced, interactive shell for Python."""
201 """An enhanced, interactive shell for Python."""
202
202
203 autocall = Enum((0,1,2), default_value=1, config=True)
203 autocall = Enum((0,1,2), default_value=1, config=True)
204 autoedit_syntax = CBool(False, config=True)
204 autoedit_syntax = CBool(False, config=True)
205 autoindent = CBool(True, config=True)
205 autoindent = CBool(True, config=True)
206 automagic = CBool(True, config=True)
206 automagic = CBool(True, config=True)
207 banner = Str('')
207 banner = Str('')
208 banner1 = Str(default_banner, config=True)
208 banner1 = Str(default_banner, config=True)
209 banner2 = Str('', config=True)
209 banner2 = Str('', config=True)
210 cache_size = Int(1000, config=True)
210 cache_size = Int(1000, config=True)
211 color_info = CBool(True, config=True)
211 color_info = CBool(True, config=True)
212 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
212 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
213 default_value=get_default_colors(), config=True)
213 default_value=get_default_colors(), config=True)
214 confirm_exit = CBool(True, config=True)
214 confirm_exit = CBool(True, config=True)
215 debug = CBool(False, config=True)
215 debug = CBool(False, config=True)
216 deep_reload = CBool(False, config=True)
216 deep_reload = CBool(False, config=True)
217 # This display_banner only controls whether or not self.show_banner()
217 # This display_banner only controls whether or not self.show_banner()
218 # is called when mainloop/interact are called. The default is False
218 # is called when mainloop/interact are called. The default is False
219 # because for the terminal based application, the banner behavior
219 # because for the terminal based application, the banner behavior
220 # is controlled by Global.display_banner, which IPythonApp looks at
220 # is controlled by Global.display_banner, which IPythonApp looks at
221 # to determine if *it* should call show_banner() by hand or not.
221 # to determine if *it* should call show_banner() by hand or not.
222 display_banner = CBool(False) # This isn't configurable!
222 display_banner = CBool(False) # This isn't configurable!
223 embedded = CBool(False)
223 embedded = CBool(False)
224 embedded_active = CBool(False)
224 embedded_active = CBool(False)
225 editor = Str(get_default_editor(), config=True)
225 editor = Str(get_default_editor(), config=True)
226 filename = Str("<ipython console>")
226 filename = Str("<ipython console>")
227 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
227 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
228 logstart = CBool(False, config=True)
228 logstart = CBool(False, config=True)
229 logfile = Str('', config=True)
229 logfile = Str('', config=True)
230 logappend = Str('', config=True)
230 logappend = Str('', config=True)
231 object_info_string_level = Enum((0,1,2), default_value=0,
231 object_info_string_level = Enum((0,1,2), default_value=0,
232 config=True)
232 config=True)
233 pager = Str('less', config=True)
233 pager = Str('less', config=True)
234 pdb = CBool(False, config=True)
234 pdb = CBool(False, config=True)
235 pprint = CBool(True, config=True)
235 pprint = CBool(True, config=True)
236 profile = Str('', config=True)
236 profile = Str('', config=True)
237 prompt_in1 = Str('In [\\#]: ', config=True)
237 prompt_in1 = Str('In [\\#]: ', config=True)
238 prompt_in2 = Str(' .\\D.: ', config=True)
238 prompt_in2 = Str(' .\\D.: ', config=True)
239 prompt_out = Str('Out[\\#]: ', config=True)
239 prompt_out = Str('Out[\\#]: ', config=True)
240 prompts_pad_left = CBool(True, config=True)
240 prompts_pad_left = CBool(True, config=True)
241 quiet = CBool(False, config=True)
241 quiet = CBool(False, config=True)
242
242
243 readline_use = CBool(True, config=True)
243 readline_use = CBool(True, config=True)
244 readline_merge_completions = CBool(True, config=True)
244 readline_merge_completions = CBool(True, config=True)
245 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
245 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
246 readline_remove_delims = Str('-/~', config=True)
246 readline_remove_delims = Str('-/~', config=True)
247 readline_parse_and_bind = List([
247 readline_parse_and_bind = List([
248 'tab: complete',
248 'tab: complete',
249 '"\C-l": clear-screen',
249 '"\C-l": clear-screen',
250 'set show-all-if-ambiguous on',
250 'set show-all-if-ambiguous on',
251 '"\C-o": tab-insert',
251 '"\C-o": tab-insert',
252 '"\M-i": " "',
252 '"\M-i": " "',
253 '"\M-o": "\d\d\d\d"',
253 '"\M-o": "\d\d\d\d"',
254 '"\M-I": "\d\d\d\d"',
254 '"\M-I": "\d\d\d\d"',
255 '"\C-r": reverse-search-history',
255 '"\C-r": reverse-search-history',
256 '"\C-s": forward-search-history',
256 '"\C-s": forward-search-history',
257 '"\C-p": history-search-backward',
257 '"\C-p": history-search-backward',
258 '"\C-n": history-search-forward',
258 '"\C-n": history-search-forward',
259 '"\e[A": history-search-backward',
259 '"\e[A": history-search-backward',
260 '"\e[B": history-search-forward',
260 '"\e[B": history-search-forward',
261 '"\C-k": kill-line',
261 '"\C-k": kill-line',
262 '"\C-u": unix-line-discard',
262 '"\C-u": unix-line-discard',
263 ], allow_none=False, config=True)
263 ], allow_none=False, config=True)
264
264
265 screen_length = Int(0, config=True)
265 screen_length = Int(0, config=True)
266
266
267 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
267 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
268 separate_in = SeparateStr('\n', config=True)
268 separate_in = SeparateStr('\n', config=True)
269 separate_out = SeparateStr('', config=True)
269 separate_out = SeparateStr('', config=True)
270 separate_out2 = SeparateStr('', config=True)
270 separate_out2 = SeparateStr('', config=True)
271
271
272 system_header = Str('IPython system call: ', config=True)
272 system_header = Str('IPython system call: ', config=True)
273 system_verbose = CBool(False, config=True)
273 system_verbose = CBool(False, config=True)
274 term_title = CBool(False, config=True)
274 term_title = CBool(False, config=True)
275 wildcards_case_sensitive = CBool(True, config=True)
275 wildcards_case_sensitive = CBool(True, config=True)
276 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
276 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
277 default_value='Context', config=True)
277 default_value='Context', config=True)
278
278
279 autoexec = List(allow_none=False)
279 autoexec = List(allow_none=False)
280
280
281 # class attribute to indicate whether the class supports threads or not.
281 # class attribute to indicate whether the class supports threads or not.
282 # Subclasses with thread support should override this as needed.
282 # Subclasses with thread support should override this as needed.
283 isthreaded = False
283 isthreaded = False
284
284
285 # Subcomponents of InteractiveShell
285 # Subcomponents of InteractiveShell
286 alias_manager = Instance('IPython.core.alias.AliasManager')
286 alias_manager = Instance('IPython.core.alias.AliasManager')
287 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
287 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
288 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
288 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
289 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
289 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
290 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
290 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
291 plugin_manager = Instance('IPython.core.plugin.PluginManager')
291 plugin_manager = Instance('IPython.core.plugin.PluginManager')
292
292
293 def __init__(self, config=None, ipython_dir=None, usage=None,
293 def __init__(self, config=None, ipython_dir=None, usage=None,
294 user_ns=None, user_global_ns=None,
294 user_ns=None, user_global_ns=None,
295 banner1=None, banner2=None, display_banner=None,
295 banner1=None, banner2=None, display_banner=None,
296 custom_exceptions=((),None)):
296 custom_exceptions=((),None)):
297
297
298 # This is where traits with a config_key argument are updated
298 # This is where traits with a config_key argument are updated
299 # from the values on config.
299 # from the values on config.
300 super(InteractiveShell, self).__init__(config=config)
300 super(InteractiveShell, self).__init__(config=config)
301
301
302 # These are relatively independent and stateless
302 # These are relatively independent and stateless
303 self.init_ipython_dir(ipython_dir)
303 self.init_ipython_dir(ipython_dir)
304 self.init_instance_attrs()
304 self.init_instance_attrs()
305 self.init_term_title()
305 self.init_term_title()
306 self.init_usage(usage)
306 self.init_usage(usage)
307 self.init_banner(banner1, banner2, display_banner)
307 self.init_banner(banner1, banner2, display_banner)
308
308
309 # Create namespaces (user_ns, user_global_ns, etc.)
309 # Create namespaces (user_ns, user_global_ns, etc.)
310 self.init_create_namespaces(user_ns, user_global_ns)
310 self.init_create_namespaces(user_ns, user_global_ns)
311 # This has to be done after init_create_namespaces because it uses
311 # This has to be done after init_create_namespaces because it uses
312 # something in self.user_ns, but before init_sys_modules, which
312 # something in self.user_ns, but before init_sys_modules, which
313 # is the first thing to modify sys.
313 # is the first thing to modify sys.
314 self.save_sys_module_state()
314 self.save_sys_module_state()
315 self.init_sys_modules()
315 self.init_sys_modules()
316
316
317 self.init_history()
317 self.init_history()
318 self.init_encoding()
318 self.init_encoding()
319 self.init_prefilter()
319 self.init_prefilter()
320
320
321 Magic.__init__(self, self)
321 Magic.__init__(self, self)
322
322
323 self.init_syntax_highlighting()
323 self.init_syntax_highlighting()
324 self.init_hooks()
324 self.init_hooks()
325 self.init_pushd_popd_magic()
325 self.init_pushd_popd_magic()
326 self.init_traceback_handlers(custom_exceptions)
326 self.init_traceback_handlers(custom_exceptions)
327 self.init_user_ns()
327 self.init_user_ns()
328 self.init_logger()
328 self.init_logger()
329 self.init_alias()
329 self.init_alias()
330 self.init_builtins()
330 self.init_builtins()
331
331
332 # pre_config_initialization
332 # pre_config_initialization
333 self.init_shadow_hist()
333 self.init_shadow_hist()
334
334
335 # The next section should contain averything that was in ipmaker.
335 # The next section should contain averything that was in ipmaker.
336 self.init_logstart()
336 self.init_logstart()
337
337
338 # The following was in post_config_initialization
338 # The following was in post_config_initialization
339 self.init_inspector()
339 self.init_inspector()
340 self.init_readline()
340 self.init_readline()
341 self.init_prompts()
341 self.init_prompts()
342 self.init_displayhook()
342 self.init_displayhook()
343 self.init_reload_doctest()
343 self.init_reload_doctest()
344 self.init_magics()
344 self.init_magics()
345 self.init_pdb()
345 self.init_pdb()
346 self.init_extension_manager()
346 self.init_extension_manager()
347 self.init_plugin_manager()
347 self.init_plugin_manager()
348 self.hooks.late_startup_hook()
348 self.hooks.late_startup_hook()
349
349
350 @classmethod
350 @classmethod
351 def instance(cls, *args, **kwargs):
351 def instance(cls, *args, **kwargs):
352 """Returns a global InteractiveShell instance."""
352 """Returns a global InteractiveShell instance."""
353 if not hasattr(cls, "_instance"):
353 if not hasattr(cls, "_instance"):
354 cls._instance = cls(*args, **kwargs)
354 cls._instance = cls(*args, **kwargs)
355 return cls._instance
355 return cls._instance
356
356
357 @classmethod
357 @classmethod
358 def initialized(cls):
358 def initialized(cls):
359 return hasattr(cls, "_instance")
359 return hasattr(cls, "_instance")
360
360
361 def get_ipython(self):
361 def get_ipython(self):
362 """Return the currently running IPython instance."""
362 """Return the currently running IPython instance."""
363 return self
363 return self
364
364
365 #-------------------------------------------------------------------------
365 #-------------------------------------------------------------------------
366 # Trait changed handlers
366 # Trait changed handlers
367 #-------------------------------------------------------------------------
367 #-------------------------------------------------------------------------
368
368
369 def _banner1_changed(self):
369 def _banner1_changed(self):
370 self.compute_banner()
370 self.compute_banner()
371
371
372 def _banner2_changed(self):
372 def _banner2_changed(self):
373 self.compute_banner()
373 self.compute_banner()
374
374
375 def _ipython_dir_changed(self, name, new):
375 def _ipython_dir_changed(self, name, new):
376 if not os.path.isdir(new):
376 if not os.path.isdir(new):
377 os.makedirs(new, mode = 0777)
377 os.makedirs(new, mode = 0777)
378
378
379 @property
379 @property
380 def usable_screen_length(self):
380 def usable_screen_length(self):
381 if self.screen_length == 0:
381 if self.screen_length == 0:
382 return 0
382 return 0
383 else:
383 else:
384 num_lines_bot = self.separate_in.count('\n')+1
384 num_lines_bot = self.separate_in.count('\n')+1
385 return self.screen_length - num_lines_bot
385 return self.screen_length - num_lines_bot
386
386
387 def _term_title_changed(self, name, new_value):
387 def _term_title_changed(self, name, new_value):
388 self.init_term_title()
388 self.init_term_title()
389
389
390 def set_autoindent(self,value=None):
390 def set_autoindent(self,value=None):
391 """Set the autoindent flag, checking for readline support.
391 """Set the autoindent flag, checking for readline support.
392
392
393 If called with no arguments, it acts as a toggle."""
393 If called with no arguments, it acts as a toggle."""
394
394
395 if not self.has_readline:
395 if not self.has_readline:
396 if os.name == 'posix':
396 if os.name == 'posix':
397 warn("The auto-indent feature requires the readline library")
397 warn("The auto-indent feature requires the readline library")
398 self.autoindent = 0
398 self.autoindent = 0
399 return
399 return
400 if value is None:
400 if value is None:
401 self.autoindent = not self.autoindent
401 self.autoindent = not self.autoindent
402 else:
402 else:
403 self.autoindent = value
403 self.autoindent = value
404
404
405 #-------------------------------------------------------------------------
405 #-------------------------------------------------------------------------
406 # init_* methods called by __init__
406 # init_* methods called by __init__
407 #-------------------------------------------------------------------------
407 #-------------------------------------------------------------------------
408
408
409 def init_ipython_dir(self, ipython_dir):
409 def init_ipython_dir(self, ipython_dir):
410 if ipython_dir is not None:
410 if ipython_dir is not None:
411 self.ipython_dir = ipython_dir
411 self.ipython_dir = ipython_dir
412 self.config.Global.ipython_dir = self.ipython_dir
412 self.config.Global.ipython_dir = self.ipython_dir
413 return
413 return
414
414
415 if hasattr(self.config.Global, 'ipython_dir'):
415 if hasattr(self.config.Global, 'ipython_dir'):
416 self.ipython_dir = self.config.Global.ipython_dir
416 self.ipython_dir = self.config.Global.ipython_dir
417 else:
417 else:
418 self.ipython_dir = get_ipython_dir()
418 self.ipython_dir = get_ipython_dir()
419
419
420 # All children can just read this
420 # All children can just read this
421 self.config.Global.ipython_dir = self.ipython_dir
421 self.config.Global.ipython_dir = self.ipython_dir
422
422
423 def init_instance_attrs(self):
423 def init_instance_attrs(self):
424 self.jobs = BackgroundJobManager()
424 self.jobs = BackgroundJobManager()
425 self.more = False
425 self.more = False
426
426
427 # command compiler
427 # command compiler
428 self.compile = codeop.CommandCompiler()
428 self.compile = codeop.CommandCompiler()
429
429
430 # User input buffer
430 # User input buffer
431 self.buffer = []
431 self.buffer = []
432
432
433 # Make an empty namespace, which extension writers can rely on both
433 # Make an empty namespace, which extension writers can rely on both
434 # existing and NEVER being used by ipython itself. This gives them a
434 # existing and NEVER being used by ipython itself. This gives them a
435 # convenient location for storing additional information and state
435 # convenient location for storing additional information and state
436 # their extensions may require, without fear of collisions with other
436 # their extensions may require, without fear of collisions with other
437 # ipython names that may develop later.
437 # ipython names that may develop later.
438 self.meta = Struct()
438 self.meta = Struct()
439
439
440 # Object variable to store code object waiting execution. This is
440 # Object variable to store code object waiting execution. This is
441 # used mainly by the multithreaded shells, but it can come in handy in
441 # used mainly by the multithreaded shells, but it can come in handy in
442 # other situations. No need to use a Queue here, since it's a single
442 # other situations. No need to use a Queue here, since it's a single
443 # item which gets cleared once run.
443 # item which gets cleared once run.
444 self.code_to_run = None
444 self.code_to_run = None
445
445
446 # Flag to mark unconditional exit
446 # Flag to mark unconditional exit
447 self.exit_now = False
447 self.exit_now = False
448
448
449 # Temporary files used for various purposes. Deleted at exit.
449 # Temporary files used for various purposes. Deleted at exit.
450 self.tempfiles = []
450 self.tempfiles = []
451
451
452 # Keep track of readline usage (later set by init_readline)
452 # Keep track of readline usage (later set by init_readline)
453 self.has_readline = False
453 self.has_readline = False
454
454
455 # keep track of where we started running (mainly for crash post-mortem)
455 # keep track of where we started running (mainly for crash post-mortem)
456 # This is not being used anywhere currently.
456 # This is not being used anywhere currently.
457 self.starting_dir = os.getcwd()
457 self.starting_dir = os.getcwd()
458
458
459 # Indentation management
459 # Indentation management
460 self.indent_current_nsp = 0
460 self.indent_current_nsp = 0
461
461
462 def init_term_title(self):
462 def init_term_title(self):
463 # Enable or disable the terminal title.
463 # Enable or disable the terminal title.
464 if self.term_title:
464 if self.term_title:
465 toggle_set_term_title(True)
465 toggle_set_term_title(True)
466 set_term_title('IPython: ' + abbrev_cwd())
466 set_term_title('IPython: ' + abbrev_cwd())
467 else:
467 else:
468 toggle_set_term_title(False)
468 toggle_set_term_title(False)
469
469
470 def init_usage(self, usage=None):
470 def init_usage(self, usage=None):
471 if usage is None:
471 if usage is None:
472 self.usage = interactive_usage
472 self.usage = interactive_usage
473 else:
473 else:
474 self.usage = usage
474 self.usage = usage
475
475
476 def init_encoding(self):
476 def init_encoding(self):
477 # Get system encoding at startup time. Certain terminals (like Emacs
477 # Get system encoding at startup time. Certain terminals (like Emacs
478 # under Win32 have it set to None, and we need to have a known valid
478 # under Win32 have it set to None, and we need to have a known valid
479 # encoding to use in the raw_input() method
479 # encoding to use in the raw_input() method
480 try:
480 try:
481 self.stdin_encoding = sys.stdin.encoding or 'ascii'
481 self.stdin_encoding = sys.stdin.encoding or 'ascii'
482 except AttributeError:
482 except AttributeError:
483 self.stdin_encoding = 'ascii'
483 self.stdin_encoding = 'ascii'
484
484
485 def init_syntax_highlighting(self):
485 def init_syntax_highlighting(self):
486 # Python source parser/formatter for syntax highlighting
486 # Python source parser/formatter for syntax highlighting
487 pyformat = PyColorize.Parser().format
487 pyformat = PyColorize.Parser().format
488 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
488 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
489
489
490 def init_pushd_popd_magic(self):
490 def init_pushd_popd_magic(self):
491 # for pushd/popd management
491 # for pushd/popd management
492 try:
492 try:
493 self.home_dir = get_home_dir()
493 self.home_dir = get_home_dir()
494 except HomeDirError, msg:
494 except HomeDirError, msg:
495 fatal(msg)
495 fatal(msg)
496
496
497 self.dir_stack = []
497 self.dir_stack = []
498
498
499 def init_logger(self):
499 def init_logger(self):
500 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
500 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
501 # local shortcut, this is used a LOT
501 # local shortcut, this is used a LOT
502 self.log = self.logger.log
502 self.log = self.logger.log
503
503
504 def init_logstart(self):
504 def init_logstart(self):
505 if self.logappend:
505 if self.logappend:
506 self.magic_logstart(self.logappend + ' append')
506 self.magic_logstart(self.logappend + ' append')
507 elif self.logfile:
507 elif self.logfile:
508 self.magic_logstart(self.logfile)
508 self.magic_logstart(self.logfile)
509 elif self.logstart:
509 elif self.logstart:
510 self.magic_logstart()
510 self.magic_logstart()
511
511
512 def init_builtins(self):
512 def init_builtins(self):
513 self.builtin_trap = BuiltinTrap(self)
513 self.builtin_trap = BuiltinTrap(shell=self)
514
514
515 def init_inspector(self):
515 def init_inspector(self):
516 # Object inspector
516 # Object inspector
517 self.inspector = oinspect.Inspector(oinspect.InspectColors,
517 self.inspector = oinspect.Inspector(oinspect.InspectColors,
518 PyColorize.ANSICodeColors,
518 PyColorize.ANSICodeColors,
519 'NoColor',
519 'NoColor',
520 self.object_info_string_level)
520 self.object_info_string_level)
521
521
522 def init_prompts(self):
522 def init_prompts(self):
523 # Initialize cache, set in/out prompts and printing system
523 # Initialize cache, set in/out prompts and printing system
524 self.outputcache = CachedOutput(self,
524 self.outputcache = CachedOutput(self,
525 self.cache_size,
525 self.cache_size,
526 self.pprint,
526 self.pprint,
527 input_sep = self.separate_in,
527 input_sep = self.separate_in,
528 output_sep = self.separate_out,
528 output_sep = self.separate_out,
529 output_sep2 = self.separate_out2,
529 output_sep2 = self.separate_out2,
530 ps1 = self.prompt_in1,
530 ps1 = self.prompt_in1,
531 ps2 = self.prompt_in2,
531 ps2 = self.prompt_in2,
532 ps_out = self.prompt_out,
532 ps_out = self.prompt_out,
533 pad_left = self.prompts_pad_left)
533 pad_left = self.prompts_pad_left)
534
534
535 # user may have over-ridden the default print hook:
535 # user may have over-ridden the default print hook:
536 try:
536 try:
537 self.outputcache.__class__.display = self.hooks.display
537 self.outputcache.__class__.display = self.hooks.display
538 except AttributeError:
538 except AttributeError:
539 pass
539 pass
540
540
541 def init_displayhook(self):
541 def init_displayhook(self):
542 self.display_trap = DisplayTrap(self.outputcache)
542 self.display_trap = DisplayTrap(hook=self.outputcache)
543
543
544 def init_reload_doctest(self):
544 def init_reload_doctest(self):
545 # Do a proper resetting of doctest, including the necessary displayhook
545 # Do a proper resetting of doctest, including the necessary displayhook
546 # monkeypatching
546 # monkeypatching
547 try:
547 try:
548 doctest_reload()
548 doctest_reload()
549 except ImportError:
549 except ImportError:
550 warn("doctest module does not exist.")
550 warn("doctest module does not exist.")
551
551
552 #-------------------------------------------------------------------------
552 #-------------------------------------------------------------------------
553 # Things related to the banner
553 # Things related to the banner
554 #-------------------------------------------------------------------------
554 #-------------------------------------------------------------------------
555
555
556 def init_banner(self, banner1, banner2, display_banner):
556 def init_banner(self, banner1, banner2, display_banner):
557 if banner1 is not None:
557 if banner1 is not None:
558 self.banner1 = banner1
558 self.banner1 = banner1
559 if banner2 is not None:
559 if banner2 is not None:
560 self.banner2 = banner2
560 self.banner2 = banner2
561 if display_banner is not None:
561 if display_banner is not None:
562 self.display_banner = display_banner
562 self.display_banner = display_banner
563 self.compute_banner()
563 self.compute_banner()
564
564
565 def show_banner(self, banner=None):
565 def show_banner(self, banner=None):
566 if banner is None:
566 if banner is None:
567 banner = self.banner
567 banner = self.banner
568 self.write(banner)
568 self.write(banner)
569
569
570 def compute_banner(self):
570 def compute_banner(self):
571 self.banner = self.banner1 + '\n'
571 self.banner = self.banner1 + '\n'
572 if self.profile:
572 if self.profile:
573 self.banner += '\nIPython profile: %s\n' % self.profile
573 self.banner += '\nIPython profile: %s\n' % self.profile
574 if self.banner2:
574 if self.banner2:
575 self.banner += '\n' + self.banner2 + '\n'
575 self.banner += '\n' + self.banner2 + '\n'
576
576
577 #-------------------------------------------------------------------------
577 #-------------------------------------------------------------------------
578 # Things related to injections into the sys module
578 # Things related to injections into the sys module
579 #-------------------------------------------------------------------------
579 #-------------------------------------------------------------------------
580
580
581 def save_sys_module_state(self):
581 def save_sys_module_state(self):
582 """Save the state of hooks in the sys module.
582 """Save the state of hooks in the sys module.
583
583
584 This has to be called after self.user_ns is created.
584 This has to be called after self.user_ns is created.
585 """
585 """
586 self._orig_sys_module_state = {}
586 self._orig_sys_module_state = {}
587 self._orig_sys_module_state['stdin'] = sys.stdin
587 self._orig_sys_module_state['stdin'] = sys.stdin
588 self._orig_sys_module_state['stdout'] = sys.stdout
588 self._orig_sys_module_state['stdout'] = sys.stdout
589 self._orig_sys_module_state['stderr'] = sys.stderr
589 self._orig_sys_module_state['stderr'] = sys.stderr
590 self._orig_sys_module_state['excepthook'] = sys.excepthook
590 self._orig_sys_module_state['excepthook'] = sys.excepthook
591 try:
591 try:
592 self._orig_sys_modules_main_name = self.user_ns['__name__']
592 self._orig_sys_modules_main_name = self.user_ns['__name__']
593 except KeyError:
593 except KeyError:
594 pass
594 pass
595
595
596 def restore_sys_module_state(self):
596 def restore_sys_module_state(self):
597 """Restore the state of the sys module."""
597 """Restore the state of the sys module."""
598 try:
598 try:
599 for k, v in self._orig_sys_module_state.items():
599 for k, v in self._orig_sys_module_state.items():
600 setattr(sys, k, v)
600 setattr(sys, k, v)
601 except AttributeError:
601 except AttributeError:
602 pass
602 pass
603 try:
603 try:
604 delattr(sys, 'ipcompleter')
604 delattr(sys, 'ipcompleter')
605 except AttributeError:
605 except AttributeError:
606 pass
606 pass
607 # Reset what what done in self.init_sys_modules
607 # Reset what what done in self.init_sys_modules
608 try:
608 try:
609 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
609 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
610 except (AttributeError, KeyError):
610 except (AttributeError, KeyError):
611 pass
611 pass
612
612
613 #-------------------------------------------------------------------------
613 #-------------------------------------------------------------------------
614 # Things related to hooks
614 # Things related to hooks
615 #-------------------------------------------------------------------------
615 #-------------------------------------------------------------------------
616
616
617 def init_hooks(self):
617 def init_hooks(self):
618 # hooks holds pointers used for user-side customizations
618 # hooks holds pointers used for user-side customizations
619 self.hooks = Struct()
619 self.hooks = Struct()
620
620
621 self.strdispatchers = {}
621 self.strdispatchers = {}
622
622
623 # Set all default hooks, defined in the IPython.hooks module.
623 # Set all default hooks, defined in the IPython.hooks module.
624 hooks = IPython.core.hooks
624 hooks = IPython.core.hooks
625 for hook_name in hooks.__all__:
625 for hook_name in hooks.__all__:
626 # default hooks have priority 100, i.e. low; user hooks should have
626 # default hooks have priority 100, i.e. low; user hooks should have
627 # 0-100 priority
627 # 0-100 priority
628 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
628 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
629
629
630 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
630 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
631 """set_hook(name,hook) -> sets an internal IPython hook.
631 """set_hook(name,hook) -> sets an internal IPython hook.
632
632
633 IPython exposes some of its internal API as user-modifiable hooks. By
633 IPython exposes some of its internal API as user-modifiable hooks. By
634 adding your function to one of these hooks, you can modify IPython's
634 adding your function to one of these hooks, you can modify IPython's
635 behavior to call at runtime your own routines."""
635 behavior to call at runtime your own routines."""
636
636
637 # At some point in the future, this should validate the hook before it
637 # At some point in the future, this should validate the hook before it
638 # accepts it. Probably at least check that the hook takes the number
638 # accepts it. Probably at least check that the hook takes the number
639 # of args it's supposed to.
639 # of args it's supposed to.
640
640
641 f = new.instancemethod(hook,self,self.__class__)
641 f = new.instancemethod(hook,self,self.__class__)
642
642
643 # check if the hook is for strdispatcher first
643 # check if the hook is for strdispatcher first
644 if str_key is not None:
644 if str_key is not None:
645 sdp = self.strdispatchers.get(name, StrDispatch())
645 sdp = self.strdispatchers.get(name, StrDispatch())
646 sdp.add_s(str_key, f, priority )
646 sdp.add_s(str_key, f, priority )
647 self.strdispatchers[name] = sdp
647 self.strdispatchers[name] = sdp
648 return
648 return
649 if re_key is not None:
649 if re_key is not None:
650 sdp = self.strdispatchers.get(name, StrDispatch())
650 sdp = self.strdispatchers.get(name, StrDispatch())
651 sdp.add_re(re.compile(re_key), f, priority )
651 sdp.add_re(re.compile(re_key), f, priority )
652 self.strdispatchers[name] = sdp
652 self.strdispatchers[name] = sdp
653 return
653 return
654
654
655 dp = getattr(self.hooks, name, None)
655 dp = getattr(self.hooks, name, None)
656 if name not in IPython.core.hooks.__all__:
656 if name not in IPython.core.hooks.__all__:
657 print "Warning! Hook '%s' is not one of %s" % (name, IPython.core.hooks.__all__ )
657 print "Warning! Hook '%s' is not one of %s" % (name, IPython.core.hooks.__all__ )
658 if not dp:
658 if not dp:
659 dp = IPython.core.hooks.CommandChainDispatcher()
659 dp = IPython.core.hooks.CommandChainDispatcher()
660
660
661 try:
661 try:
662 dp.add(f,priority)
662 dp.add(f,priority)
663 except AttributeError:
663 except AttributeError:
664 # it was not commandchain, plain old func - replace
664 # it was not commandchain, plain old func - replace
665 dp = f
665 dp = f
666
666
667 setattr(self.hooks,name, dp)
667 setattr(self.hooks,name, dp)
668
668
669 #-------------------------------------------------------------------------
669 #-------------------------------------------------------------------------
670 # Things related to the "main" module
670 # Things related to the "main" module
671 #-------------------------------------------------------------------------
671 #-------------------------------------------------------------------------
672
672
673 def new_main_mod(self,ns=None):
673 def new_main_mod(self,ns=None):
674 """Return a new 'main' module object for user code execution.
674 """Return a new 'main' module object for user code execution.
675 """
675 """
676 main_mod = self._user_main_module
676 main_mod = self._user_main_module
677 init_fakemod_dict(main_mod,ns)
677 init_fakemod_dict(main_mod,ns)
678 return main_mod
678 return main_mod
679
679
680 def cache_main_mod(self,ns,fname):
680 def cache_main_mod(self,ns,fname):
681 """Cache a main module's namespace.
681 """Cache a main module's namespace.
682
682
683 When scripts are executed via %run, we must keep a reference to the
683 When scripts are executed via %run, we must keep a reference to the
684 namespace of their __main__ module (a FakeModule instance) around so
684 namespace of their __main__ module (a FakeModule instance) around so
685 that Python doesn't clear it, rendering objects defined therein
685 that Python doesn't clear it, rendering objects defined therein
686 useless.
686 useless.
687
687
688 This method keeps said reference in a private dict, keyed by the
688 This method keeps said reference in a private dict, keyed by the
689 absolute path of the module object (which corresponds to the script
689 absolute path of the module object (which corresponds to the script
690 path). This way, for multiple executions of the same script we only
690 path). This way, for multiple executions of the same script we only
691 keep one copy of the namespace (the last one), thus preventing memory
691 keep one copy of the namespace (the last one), thus preventing memory
692 leaks from old references while allowing the objects from the last
692 leaks from old references while allowing the objects from the last
693 execution to be accessible.
693 execution to be accessible.
694
694
695 Note: we can not allow the actual FakeModule instances to be deleted,
695 Note: we can not allow the actual FakeModule instances to be deleted,
696 because of how Python tears down modules (it hard-sets all their
696 because of how Python tears down modules (it hard-sets all their
697 references to None without regard for reference counts). This method
697 references to None without regard for reference counts). This method
698 must therefore make a *copy* of the given namespace, to allow the
698 must therefore make a *copy* of the given namespace, to allow the
699 original module's __dict__ to be cleared and reused.
699 original module's __dict__ to be cleared and reused.
700
700
701
701
702 Parameters
702 Parameters
703 ----------
703 ----------
704 ns : a namespace (a dict, typically)
704 ns : a namespace (a dict, typically)
705
705
706 fname : str
706 fname : str
707 Filename associated with the namespace.
707 Filename associated with the namespace.
708
708
709 Examples
709 Examples
710 --------
710 --------
711
711
712 In [10]: import IPython
712 In [10]: import IPython
713
713
714 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
714 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
715
715
716 In [12]: IPython.__file__ in _ip._main_ns_cache
716 In [12]: IPython.__file__ in _ip._main_ns_cache
717 Out[12]: True
717 Out[12]: True
718 """
718 """
719 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
719 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
720
720
721 def clear_main_mod_cache(self):
721 def clear_main_mod_cache(self):
722 """Clear the cache of main modules.
722 """Clear the cache of main modules.
723
723
724 Mainly for use by utilities like %reset.
724 Mainly for use by utilities like %reset.
725
725
726 Examples
726 Examples
727 --------
727 --------
728
728
729 In [15]: import IPython
729 In [15]: import IPython
730
730
731 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
731 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
732
732
733 In [17]: len(_ip._main_ns_cache) > 0
733 In [17]: len(_ip._main_ns_cache) > 0
734 Out[17]: True
734 Out[17]: True
735
735
736 In [18]: _ip.clear_main_mod_cache()
736 In [18]: _ip.clear_main_mod_cache()
737
737
738 In [19]: len(_ip._main_ns_cache) == 0
738 In [19]: len(_ip._main_ns_cache) == 0
739 Out[19]: True
739 Out[19]: True
740 """
740 """
741 self._main_ns_cache.clear()
741 self._main_ns_cache.clear()
742
742
743 #-------------------------------------------------------------------------
743 #-------------------------------------------------------------------------
744 # Things related to debugging
744 # Things related to debugging
745 #-------------------------------------------------------------------------
745 #-------------------------------------------------------------------------
746
746
747 def init_pdb(self):
747 def init_pdb(self):
748 # Set calling of pdb on exceptions
748 # Set calling of pdb on exceptions
749 # self.call_pdb is a property
749 # self.call_pdb is a property
750 self.call_pdb = self.pdb
750 self.call_pdb = self.pdb
751
751
752 def _get_call_pdb(self):
752 def _get_call_pdb(self):
753 return self._call_pdb
753 return self._call_pdb
754
754
755 def _set_call_pdb(self,val):
755 def _set_call_pdb(self,val):
756
756
757 if val not in (0,1,False,True):
757 if val not in (0,1,False,True):
758 raise ValueError,'new call_pdb value must be boolean'
758 raise ValueError,'new call_pdb value must be boolean'
759
759
760 # store value in instance
760 # store value in instance
761 self._call_pdb = val
761 self._call_pdb = val
762
762
763 # notify the actual exception handlers
763 # notify the actual exception handlers
764 self.InteractiveTB.call_pdb = val
764 self.InteractiveTB.call_pdb = val
765 if self.isthreaded:
765 if self.isthreaded:
766 try:
766 try:
767 self.sys_excepthook.call_pdb = val
767 self.sys_excepthook.call_pdb = val
768 except:
768 except:
769 warn('Failed to activate pdb for threaded exception handler')
769 warn('Failed to activate pdb for threaded exception handler')
770
770
771 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
771 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
772 'Control auto-activation of pdb at exceptions')
772 'Control auto-activation of pdb at exceptions')
773
773
774 def debugger(self,force=False):
774 def debugger(self,force=False):
775 """Call the pydb/pdb debugger.
775 """Call the pydb/pdb debugger.
776
776
777 Keywords:
777 Keywords:
778
778
779 - force(False): by default, this routine checks the instance call_pdb
779 - force(False): by default, this routine checks the instance call_pdb
780 flag and does not actually invoke the debugger if the flag is false.
780 flag and does not actually invoke the debugger if the flag is false.
781 The 'force' option forces the debugger to activate even if the flag
781 The 'force' option forces the debugger to activate even if the flag
782 is false.
782 is false.
783 """
783 """
784
784
785 if not (force or self.call_pdb):
785 if not (force or self.call_pdb):
786 return
786 return
787
787
788 if not hasattr(sys,'last_traceback'):
788 if not hasattr(sys,'last_traceback'):
789 error('No traceback has been produced, nothing to debug.')
789 error('No traceback has been produced, nothing to debug.')
790 return
790 return
791
791
792 # use pydb if available
792 # use pydb if available
793 if debugger.has_pydb:
793 if debugger.has_pydb:
794 from pydb import pm
794 from pydb import pm
795 else:
795 else:
796 # fallback to our internal debugger
796 # fallback to our internal debugger
797 pm = lambda : self.InteractiveTB.debugger(force=True)
797 pm = lambda : self.InteractiveTB.debugger(force=True)
798 self.history_saving_wrapper(pm)()
798 self.history_saving_wrapper(pm)()
799
799
800 #-------------------------------------------------------------------------
800 #-------------------------------------------------------------------------
801 # Things related to IPython's various namespaces
801 # Things related to IPython's various namespaces
802 #-------------------------------------------------------------------------
802 #-------------------------------------------------------------------------
803
803
804 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
804 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
805 # Create the namespace where the user will operate. user_ns is
805 # Create the namespace where the user will operate. user_ns is
806 # normally the only one used, and it is passed to the exec calls as
806 # normally the only one used, and it is passed to the exec calls as
807 # the locals argument. But we do carry a user_global_ns namespace
807 # the locals argument. But we do carry a user_global_ns namespace
808 # given as the exec 'globals' argument, This is useful in embedding
808 # given as the exec 'globals' argument, This is useful in embedding
809 # situations where the ipython shell opens in a context where the
809 # situations where the ipython shell opens in a context where the
810 # distinction between locals and globals is meaningful. For
810 # distinction between locals and globals is meaningful. For
811 # non-embedded contexts, it is just the same object as the user_ns dict.
811 # non-embedded contexts, it is just the same object as the user_ns dict.
812
812
813 # FIXME. For some strange reason, __builtins__ is showing up at user
813 # FIXME. For some strange reason, __builtins__ is showing up at user
814 # level as a dict instead of a module. This is a manual fix, but I
814 # level as a dict instead of a module. This is a manual fix, but I
815 # should really track down where the problem is coming from. Alex
815 # should really track down where the problem is coming from. Alex
816 # Schmolck reported this problem first.
816 # Schmolck reported this problem first.
817
817
818 # A useful post by Alex Martelli on this topic:
818 # A useful post by Alex Martelli on this topic:
819 # Re: inconsistent value from __builtins__
819 # Re: inconsistent value from __builtins__
820 # Von: Alex Martelli <aleaxit@yahoo.com>
820 # Von: Alex Martelli <aleaxit@yahoo.com>
821 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
821 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
822 # Gruppen: comp.lang.python
822 # Gruppen: comp.lang.python
823
823
824 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
824 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
825 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
825 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
826 # > <type 'dict'>
826 # > <type 'dict'>
827 # > >>> print type(__builtins__)
827 # > >>> print type(__builtins__)
828 # > <type 'module'>
828 # > <type 'module'>
829 # > Is this difference in return value intentional?
829 # > Is this difference in return value intentional?
830
830
831 # Well, it's documented that '__builtins__' can be either a dictionary
831 # Well, it's documented that '__builtins__' can be either a dictionary
832 # or a module, and it's been that way for a long time. Whether it's
832 # or a module, and it's been that way for a long time. Whether it's
833 # intentional (or sensible), I don't know. In any case, the idea is
833 # intentional (or sensible), I don't know. In any case, the idea is
834 # that if you need to access the built-in namespace directly, you
834 # that if you need to access the built-in namespace directly, you
835 # should start with "import __builtin__" (note, no 's') which will
835 # should start with "import __builtin__" (note, no 's') which will
836 # definitely give you a module. Yeah, it's somewhat confusing:-(.
836 # definitely give you a module. Yeah, it's somewhat confusing:-(.
837
837
838 # These routines return properly built dicts as needed by the rest of
838 # These routines return properly built dicts as needed by the rest of
839 # the code, and can also be used by extension writers to generate
839 # the code, and can also be used by extension writers to generate
840 # properly initialized namespaces.
840 # properly initialized namespaces.
841 user_ns, user_global_ns = self.make_user_namespaces(user_ns, user_global_ns)
841 user_ns, user_global_ns = self.make_user_namespaces(user_ns, user_global_ns)
842
842
843 # Assign namespaces
843 # Assign namespaces
844 # This is the namespace where all normal user variables live
844 # This is the namespace where all normal user variables live
845 self.user_ns = user_ns
845 self.user_ns = user_ns
846 self.user_global_ns = user_global_ns
846 self.user_global_ns = user_global_ns
847
847
848 # An auxiliary namespace that checks what parts of the user_ns were
848 # An auxiliary namespace that checks what parts of the user_ns were
849 # loaded at startup, so we can list later only variables defined in
849 # loaded at startup, so we can list later only variables defined in
850 # actual interactive use. Since it is always a subset of user_ns, it
850 # actual interactive use. Since it is always a subset of user_ns, it
851 # doesn't need to be separately tracked in the ns_table.
851 # doesn't need to be separately tracked in the ns_table.
852 self.user_ns_hidden = {}
852 self.user_ns_hidden = {}
853
853
854 # A namespace to keep track of internal data structures to prevent
854 # A namespace to keep track of internal data structures to prevent
855 # them from cluttering user-visible stuff. Will be updated later
855 # them from cluttering user-visible stuff. Will be updated later
856 self.internal_ns = {}
856 self.internal_ns = {}
857
857
858 # Now that FakeModule produces a real module, we've run into a nasty
858 # Now that FakeModule produces a real module, we've run into a nasty
859 # problem: after script execution (via %run), the module where the user
859 # problem: after script execution (via %run), the module where the user
860 # code ran is deleted. Now that this object is a true module (needed
860 # code ran is deleted. Now that this object is a true module (needed
861 # so docetst and other tools work correctly), the Python module
861 # so docetst and other tools work correctly), the Python module
862 # teardown mechanism runs over it, and sets to None every variable
862 # teardown mechanism runs over it, and sets to None every variable
863 # present in that module. Top-level references to objects from the
863 # present in that module. Top-level references to objects from the
864 # script survive, because the user_ns is updated with them. However,
864 # script survive, because the user_ns is updated with them. However,
865 # calling functions defined in the script that use other things from
865 # calling functions defined in the script that use other things from
866 # the script will fail, because the function's closure had references
866 # the script will fail, because the function's closure had references
867 # to the original objects, which are now all None. So we must protect
867 # to the original objects, which are now all None. So we must protect
868 # these modules from deletion by keeping a cache.
868 # these modules from deletion by keeping a cache.
869 #
869 #
870 # To avoid keeping stale modules around (we only need the one from the
870 # To avoid keeping stale modules around (we only need the one from the
871 # last run), we use a dict keyed with the full path to the script, so
871 # last run), we use a dict keyed with the full path to the script, so
872 # only the last version of the module is held in the cache. Note,
872 # only the last version of the module is held in the cache. Note,
873 # however, that we must cache the module *namespace contents* (their
873 # however, that we must cache the module *namespace contents* (their
874 # __dict__). Because if we try to cache the actual modules, old ones
874 # __dict__). Because if we try to cache the actual modules, old ones
875 # (uncached) could be destroyed while still holding references (such as
875 # (uncached) could be destroyed while still holding references (such as
876 # those held by GUI objects that tend to be long-lived)>
876 # those held by GUI objects that tend to be long-lived)>
877 #
877 #
878 # The %reset command will flush this cache. See the cache_main_mod()
878 # The %reset command will flush this cache. See the cache_main_mod()
879 # and clear_main_mod_cache() methods for details on use.
879 # and clear_main_mod_cache() methods for details on use.
880
880
881 # This is the cache used for 'main' namespaces
881 # This is the cache used for 'main' namespaces
882 self._main_ns_cache = {}
882 self._main_ns_cache = {}
883 # And this is the single instance of FakeModule whose __dict__ we keep
883 # And this is the single instance of FakeModule whose __dict__ we keep
884 # copying and clearing for reuse on each %run
884 # copying and clearing for reuse on each %run
885 self._user_main_module = FakeModule()
885 self._user_main_module = FakeModule()
886
886
887 # A table holding all the namespaces IPython deals with, so that
887 # A table holding all the namespaces IPython deals with, so that
888 # introspection facilities can search easily.
888 # introspection facilities can search easily.
889 self.ns_table = {'user':user_ns,
889 self.ns_table = {'user':user_ns,
890 'user_global':user_global_ns,
890 'user_global':user_global_ns,
891 'internal':self.internal_ns,
891 'internal':self.internal_ns,
892 'builtin':__builtin__.__dict__
892 'builtin':__builtin__.__dict__
893 }
893 }
894
894
895 # Similarly, track all namespaces where references can be held and that
895 # Similarly, track all namespaces where references can be held and that
896 # we can safely clear (so it can NOT include builtin). This one can be
896 # we can safely clear (so it can NOT include builtin). This one can be
897 # a simple list.
897 # a simple list.
898 self.ns_refs_table = [ user_ns, user_global_ns, self.user_ns_hidden,
898 self.ns_refs_table = [ user_ns, user_global_ns, self.user_ns_hidden,
899 self.internal_ns, self._main_ns_cache ]
899 self.internal_ns, self._main_ns_cache ]
900
900
901 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
901 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
902 """Return a valid local and global user interactive namespaces.
902 """Return a valid local and global user interactive namespaces.
903
903
904 This builds a dict with the minimal information needed to operate as a
904 This builds a dict with the minimal information needed to operate as a
905 valid IPython user namespace, which you can pass to the various
905 valid IPython user namespace, which you can pass to the various
906 embedding classes in ipython. The default implementation returns the
906 embedding classes in ipython. The default implementation returns the
907 same dict for both the locals and the globals to allow functions to
907 same dict for both the locals and the globals to allow functions to
908 refer to variables in the namespace. Customized implementations can
908 refer to variables in the namespace. Customized implementations can
909 return different dicts. The locals dictionary can actually be anything
909 return different dicts. The locals dictionary can actually be anything
910 following the basic mapping protocol of a dict, but the globals dict
910 following the basic mapping protocol of a dict, but the globals dict
911 must be a true dict, not even a subclass. It is recommended that any
911 must be a true dict, not even a subclass. It is recommended that any
912 custom object for the locals namespace synchronize with the globals
912 custom object for the locals namespace synchronize with the globals
913 dict somehow.
913 dict somehow.
914
914
915 Raises TypeError if the provided globals namespace is not a true dict.
915 Raises TypeError if the provided globals namespace is not a true dict.
916
916
917 Parameters
917 Parameters
918 ----------
918 ----------
919 user_ns : dict-like, optional
919 user_ns : dict-like, optional
920 The current user namespace. The items in this namespace should
920 The current user namespace. The items in this namespace should
921 be included in the output. If None, an appropriate blank
921 be included in the output. If None, an appropriate blank
922 namespace should be created.
922 namespace should be created.
923 user_global_ns : dict, optional
923 user_global_ns : dict, optional
924 The current user global namespace. The items in this namespace
924 The current user global namespace. The items in this namespace
925 should be included in the output. If None, an appropriate
925 should be included in the output. If None, an appropriate
926 blank namespace should be created.
926 blank namespace should be created.
927
927
928 Returns
928 Returns
929 -------
929 -------
930 A pair of dictionary-like object to be used as the local namespace
930 A pair of dictionary-like object to be used as the local namespace
931 of the interpreter and a dict to be used as the global namespace.
931 of the interpreter and a dict to be used as the global namespace.
932 """
932 """
933
933
934
934
935 # We must ensure that __builtin__ (without the final 's') is always
935 # We must ensure that __builtin__ (without the final 's') is always
936 # available and pointing to the __builtin__ *module*. For more details:
936 # available and pointing to the __builtin__ *module*. For more details:
937 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
937 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
938
938
939 if user_ns is None:
939 if user_ns is None:
940 # Set __name__ to __main__ to better match the behavior of the
940 # Set __name__ to __main__ to better match the behavior of the
941 # normal interpreter.
941 # normal interpreter.
942 user_ns = {'__name__' :'__main__',
942 user_ns = {'__name__' :'__main__',
943 '__builtin__' : __builtin__,
943 '__builtin__' : __builtin__,
944 '__builtins__' : __builtin__,
944 '__builtins__' : __builtin__,
945 }
945 }
946 else:
946 else:
947 user_ns.setdefault('__name__','__main__')
947 user_ns.setdefault('__name__','__main__')
948 user_ns.setdefault('__builtin__',__builtin__)
948 user_ns.setdefault('__builtin__',__builtin__)
949 user_ns.setdefault('__builtins__',__builtin__)
949 user_ns.setdefault('__builtins__',__builtin__)
950
950
951 if user_global_ns is None:
951 if user_global_ns is None:
952 user_global_ns = user_ns
952 user_global_ns = user_ns
953 if type(user_global_ns) is not dict:
953 if type(user_global_ns) is not dict:
954 raise TypeError("user_global_ns must be a true dict; got %r"
954 raise TypeError("user_global_ns must be a true dict; got %r"
955 % type(user_global_ns))
955 % type(user_global_ns))
956
956
957 return user_ns, user_global_ns
957 return user_ns, user_global_ns
958
958
959 def init_sys_modules(self):
959 def init_sys_modules(self):
960 # We need to insert into sys.modules something that looks like a
960 # We need to insert into sys.modules something that looks like a
961 # module but which accesses the IPython namespace, for shelve and
961 # module but which accesses the IPython namespace, for shelve and
962 # pickle to work interactively. Normally they rely on getting
962 # pickle to work interactively. Normally they rely on getting
963 # everything out of __main__, but for embedding purposes each IPython
963 # everything out of __main__, but for embedding purposes each IPython
964 # instance has its own private namespace, so we can't go shoving
964 # instance has its own private namespace, so we can't go shoving
965 # everything into __main__.
965 # everything into __main__.
966
966
967 # note, however, that we should only do this for non-embedded
967 # note, however, that we should only do this for non-embedded
968 # ipythons, which really mimic the __main__.__dict__ with their own
968 # ipythons, which really mimic the __main__.__dict__ with their own
969 # namespace. Embedded instances, on the other hand, should not do
969 # namespace. Embedded instances, on the other hand, should not do
970 # this because they need to manage the user local/global namespaces
970 # this because they need to manage the user local/global namespaces
971 # only, but they live within a 'normal' __main__ (meaning, they
971 # only, but they live within a 'normal' __main__ (meaning, they
972 # shouldn't overtake the execution environment of the script they're
972 # shouldn't overtake the execution environment of the script they're
973 # embedded in).
973 # embedded in).
974
974
975 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
975 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
976
976
977 try:
977 try:
978 main_name = self.user_ns['__name__']
978 main_name = self.user_ns['__name__']
979 except KeyError:
979 except KeyError:
980 raise KeyError('user_ns dictionary MUST have a "__name__" key')
980 raise KeyError('user_ns dictionary MUST have a "__name__" key')
981 else:
981 else:
982 sys.modules[main_name] = FakeModule(self.user_ns)
982 sys.modules[main_name] = FakeModule(self.user_ns)
983
983
984 def init_user_ns(self):
984 def init_user_ns(self):
985 """Initialize all user-visible namespaces to their minimum defaults.
985 """Initialize all user-visible namespaces to their minimum defaults.
986
986
987 Certain history lists are also initialized here, as they effectively
987 Certain history lists are also initialized here, as they effectively
988 act as user namespaces.
988 act as user namespaces.
989
989
990 Notes
990 Notes
991 -----
991 -----
992 All data structures here are only filled in, they are NOT reset by this
992 All data structures here are only filled in, they are NOT reset by this
993 method. If they were not empty before, data will simply be added to
993 method. If they were not empty before, data will simply be added to
994 therm.
994 therm.
995 """
995 """
996 # This function works in two parts: first we put a few things in
996 # This function works in two parts: first we put a few things in
997 # user_ns, and we sync that contents into user_ns_hidden so that these
997 # user_ns, and we sync that contents into user_ns_hidden so that these
998 # initial variables aren't shown by %who. After the sync, we add the
998 # initial variables aren't shown by %who. After the sync, we add the
999 # rest of what we *do* want the user to see with %who even on a new
999 # rest of what we *do* want the user to see with %who even on a new
1000 # session (probably nothing, so theye really only see their own stuff)
1000 # session (probably nothing, so theye really only see their own stuff)
1001
1001
1002 # The user dict must *always* have a __builtin__ reference to the
1002 # The user dict must *always* have a __builtin__ reference to the
1003 # Python standard __builtin__ namespace, which must be imported.
1003 # Python standard __builtin__ namespace, which must be imported.
1004 # This is so that certain operations in prompt evaluation can be
1004 # This is so that certain operations in prompt evaluation can be
1005 # reliably executed with builtins. Note that we can NOT use
1005 # reliably executed with builtins. Note that we can NOT use
1006 # __builtins__ (note the 's'), because that can either be a dict or a
1006 # __builtins__ (note the 's'), because that can either be a dict or a
1007 # module, and can even mutate at runtime, depending on the context
1007 # module, and can even mutate at runtime, depending on the context
1008 # (Python makes no guarantees on it). In contrast, __builtin__ is
1008 # (Python makes no guarantees on it). In contrast, __builtin__ is
1009 # always a module object, though it must be explicitly imported.
1009 # always a module object, though it must be explicitly imported.
1010
1010
1011 # For more details:
1011 # For more details:
1012 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1012 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1013 ns = dict(__builtin__ = __builtin__)
1013 ns = dict(__builtin__ = __builtin__)
1014
1014
1015 # Put 'help' in the user namespace
1015 # Put 'help' in the user namespace
1016 try:
1016 try:
1017 from site import _Helper
1017 from site import _Helper
1018 ns['help'] = _Helper()
1018 ns['help'] = _Helper()
1019 except ImportError:
1019 except ImportError:
1020 warn('help() not available - check site.py')
1020 warn('help() not available - check site.py')
1021
1021
1022 # make global variables for user access to the histories
1022 # make global variables for user access to the histories
1023 ns['_ih'] = self.input_hist
1023 ns['_ih'] = self.input_hist
1024 ns['_oh'] = self.output_hist
1024 ns['_oh'] = self.output_hist
1025 ns['_dh'] = self.dir_hist
1025 ns['_dh'] = self.dir_hist
1026
1026
1027 ns['_sh'] = shadowns
1027 ns['_sh'] = shadowns
1028
1028
1029 # user aliases to input and output histories. These shouldn't show up
1029 # user aliases to input and output histories. These shouldn't show up
1030 # in %who, as they can have very large reprs.
1030 # in %who, as they can have very large reprs.
1031 ns['In'] = self.input_hist
1031 ns['In'] = self.input_hist
1032 ns['Out'] = self.output_hist
1032 ns['Out'] = self.output_hist
1033
1033
1034 # Store myself as the public api!!!
1034 # Store myself as the public api!!!
1035 ns['get_ipython'] = self.get_ipython
1035 ns['get_ipython'] = self.get_ipython
1036
1036
1037 # Sync what we've added so far to user_ns_hidden so these aren't seen
1037 # Sync what we've added so far to user_ns_hidden so these aren't seen
1038 # by %who
1038 # by %who
1039 self.user_ns_hidden.update(ns)
1039 self.user_ns_hidden.update(ns)
1040
1040
1041 # Anything put into ns now would show up in %who. Think twice before
1041 # Anything put into ns now would show up in %who. Think twice before
1042 # putting anything here, as we really want %who to show the user their
1042 # putting anything here, as we really want %who to show the user their
1043 # stuff, not our variables.
1043 # stuff, not our variables.
1044
1044
1045 # Finally, update the real user's namespace
1045 # Finally, update the real user's namespace
1046 self.user_ns.update(ns)
1046 self.user_ns.update(ns)
1047
1047
1048
1048
1049 def reset(self):
1049 def reset(self):
1050 """Clear all internal namespaces.
1050 """Clear all internal namespaces.
1051
1051
1052 Note that this is much more aggressive than %reset, since it clears
1052 Note that this is much more aggressive than %reset, since it clears
1053 fully all namespaces, as well as all input/output lists.
1053 fully all namespaces, as well as all input/output lists.
1054 """
1054 """
1055 for ns in self.ns_refs_table:
1055 for ns in self.ns_refs_table:
1056 ns.clear()
1056 ns.clear()
1057
1057
1058 self.alias_manager.clear_aliases()
1058 self.alias_manager.clear_aliases()
1059
1059
1060 # Clear input and output histories
1060 # Clear input and output histories
1061 self.input_hist[:] = []
1061 self.input_hist[:] = []
1062 self.input_hist_raw[:] = []
1062 self.input_hist_raw[:] = []
1063 self.output_hist.clear()
1063 self.output_hist.clear()
1064
1064
1065 # Restore the user namespaces to minimal usability
1065 # Restore the user namespaces to minimal usability
1066 self.init_user_ns()
1066 self.init_user_ns()
1067
1067
1068 # Restore the default and user aliases
1068 # Restore the default and user aliases
1069 self.alias_manager.init_aliases()
1069 self.alias_manager.init_aliases()
1070
1070
1071 def reset_selective(self, regex=None):
1071 def reset_selective(self, regex=None):
1072 """Clear selective variables from internal namespaces based on a specified regular expression.
1072 """Clear selective variables from internal namespaces based on a specified regular expression.
1073
1073
1074 Parameters
1074 Parameters
1075 ----------
1075 ----------
1076 regex : string or compiled pattern, optional
1076 regex : string or compiled pattern, optional
1077 A regular expression pattern that will be used in searching variable names in the users
1077 A regular expression pattern that will be used in searching variable names in the users
1078 namespaces.
1078 namespaces.
1079 """
1079 """
1080 if regex is not None:
1080 if regex is not None:
1081 try:
1081 try:
1082 m = re.compile(regex)
1082 m = re.compile(regex)
1083 except TypeError:
1083 except TypeError:
1084 raise TypeError('regex must be a string or compiled pattern')
1084 raise TypeError('regex must be a string or compiled pattern')
1085 # Search for keys in each namespace that match the given regex
1085 # Search for keys in each namespace that match the given regex
1086 # If a match is found, delete the key/value pair.
1086 # If a match is found, delete the key/value pair.
1087 for ns in self.ns_refs_table:
1087 for ns in self.ns_refs_table:
1088 for var in ns:
1088 for var in ns:
1089 if m.search(var):
1089 if m.search(var):
1090 del ns[var]
1090 del ns[var]
1091
1091
1092 def push(self, variables, interactive=True):
1092 def push(self, variables, interactive=True):
1093 """Inject a group of variables into the IPython user namespace.
1093 """Inject a group of variables into the IPython user namespace.
1094
1094
1095 Parameters
1095 Parameters
1096 ----------
1096 ----------
1097 variables : dict, str or list/tuple of str
1097 variables : dict, str or list/tuple of str
1098 The variables to inject into the user's namespace. If a dict,
1098 The variables to inject into the user's namespace. If a dict,
1099 a simple update is done. If a str, the string is assumed to
1099 a simple update is done. If a str, the string is assumed to
1100 have variable names separated by spaces. A list/tuple of str
1100 have variable names separated by spaces. A list/tuple of str
1101 can also be used to give the variable names. If just the variable
1101 can also be used to give the variable names. If just the variable
1102 names are give (list/tuple/str) then the variable values looked
1102 names are give (list/tuple/str) then the variable values looked
1103 up in the callers frame.
1103 up in the callers frame.
1104 interactive : bool
1104 interactive : bool
1105 If True (default), the variables will be listed with the ``who``
1105 If True (default), the variables will be listed with the ``who``
1106 magic.
1106 magic.
1107 """
1107 """
1108 vdict = None
1108 vdict = None
1109
1109
1110 # We need a dict of name/value pairs to do namespace updates.
1110 # We need a dict of name/value pairs to do namespace updates.
1111 if isinstance(variables, dict):
1111 if isinstance(variables, dict):
1112 vdict = variables
1112 vdict = variables
1113 elif isinstance(variables, (basestring, list, tuple)):
1113 elif isinstance(variables, (basestring, list, tuple)):
1114 if isinstance(variables, basestring):
1114 if isinstance(variables, basestring):
1115 vlist = variables.split()
1115 vlist = variables.split()
1116 else:
1116 else:
1117 vlist = variables
1117 vlist = variables
1118 vdict = {}
1118 vdict = {}
1119 cf = sys._getframe(1)
1119 cf = sys._getframe(1)
1120 for name in vlist:
1120 for name in vlist:
1121 try:
1121 try:
1122 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1122 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1123 except:
1123 except:
1124 print ('Could not get variable %s from %s' %
1124 print ('Could not get variable %s from %s' %
1125 (name,cf.f_code.co_name))
1125 (name,cf.f_code.co_name))
1126 else:
1126 else:
1127 raise ValueError('variables must be a dict/str/list/tuple')
1127 raise ValueError('variables must be a dict/str/list/tuple')
1128
1128
1129 # Propagate variables to user namespace
1129 # Propagate variables to user namespace
1130 self.user_ns.update(vdict)
1130 self.user_ns.update(vdict)
1131
1131
1132 # And configure interactive visibility
1132 # And configure interactive visibility
1133 config_ns = self.user_ns_hidden
1133 config_ns = self.user_ns_hidden
1134 if interactive:
1134 if interactive:
1135 for name, val in vdict.iteritems():
1135 for name, val in vdict.iteritems():
1136 config_ns.pop(name, None)
1136 config_ns.pop(name, None)
1137 else:
1137 else:
1138 for name,val in vdict.iteritems():
1138 for name,val in vdict.iteritems():
1139 config_ns[name] = val
1139 config_ns[name] = val
1140
1140
1141 #-------------------------------------------------------------------------
1141 #-------------------------------------------------------------------------
1142 # Things related to history management
1142 # Things related to history management
1143 #-------------------------------------------------------------------------
1143 #-------------------------------------------------------------------------
1144
1144
1145 def init_history(self):
1145 def init_history(self):
1146 # List of input with multi-line handling.
1146 # List of input with multi-line handling.
1147 self.input_hist = InputList()
1147 self.input_hist = InputList()
1148 # This one will hold the 'raw' input history, without any
1148 # This one will hold the 'raw' input history, without any
1149 # pre-processing. This will allow users to retrieve the input just as
1149 # pre-processing. This will allow users to retrieve the input just as
1150 # it was exactly typed in by the user, with %hist -r.
1150 # it was exactly typed in by the user, with %hist -r.
1151 self.input_hist_raw = InputList()
1151 self.input_hist_raw = InputList()
1152
1152
1153 # list of visited directories
1153 # list of visited directories
1154 try:
1154 try:
1155 self.dir_hist = [os.getcwd()]
1155 self.dir_hist = [os.getcwd()]
1156 except OSError:
1156 except OSError:
1157 self.dir_hist = []
1157 self.dir_hist = []
1158
1158
1159 # dict of output history
1159 # dict of output history
1160 self.output_hist = {}
1160 self.output_hist = {}
1161
1161
1162 # Now the history file
1162 # Now the history file
1163 if self.profile:
1163 if self.profile:
1164 histfname = 'history-%s' % self.profile
1164 histfname = 'history-%s' % self.profile
1165 else:
1165 else:
1166 histfname = 'history'
1166 histfname = 'history'
1167 self.histfile = os.path.join(self.ipython_dir, histfname)
1167 self.histfile = os.path.join(self.ipython_dir, histfname)
1168
1168
1169 # Fill the history zero entry, user counter starts at 1
1169 # Fill the history zero entry, user counter starts at 1
1170 self.input_hist.append('\n')
1170 self.input_hist.append('\n')
1171 self.input_hist_raw.append('\n')
1171 self.input_hist_raw.append('\n')
1172
1172
1173 def init_shadow_hist(self):
1173 def init_shadow_hist(self):
1174 try:
1174 try:
1175 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1175 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1176 except exceptions.UnicodeDecodeError:
1176 except exceptions.UnicodeDecodeError:
1177 print "Your ipython_dir can't be decoded to unicode!"
1177 print "Your ipython_dir can't be decoded to unicode!"
1178 print "Please set HOME environment variable to something that"
1178 print "Please set HOME environment variable to something that"
1179 print r"only has ASCII characters, e.g. c:\home"
1179 print r"only has ASCII characters, e.g. c:\home"
1180 print "Now it is", self.ipython_dir
1180 print "Now it is", self.ipython_dir
1181 sys.exit()
1181 sys.exit()
1182 self.shadowhist = ipcorehist.ShadowHist(self.db)
1182 self.shadowhist = ipcorehist.ShadowHist(self.db)
1183
1183
1184 def savehist(self):
1184 def savehist(self):
1185 """Save input history to a file (via readline library)."""
1185 """Save input history to a file (via readline library)."""
1186
1186
1187 try:
1187 try:
1188 self.readline.write_history_file(self.histfile)
1188 self.readline.write_history_file(self.histfile)
1189 except:
1189 except:
1190 print 'Unable to save IPython command history to file: ' + \
1190 print 'Unable to save IPython command history to file: ' + \
1191 `self.histfile`
1191 `self.histfile`
1192
1192
1193 def reloadhist(self):
1193 def reloadhist(self):
1194 """Reload the input history from disk file."""
1194 """Reload the input history from disk file."""
1195
1195
1196 try:
1196 try:
1197 self.readline.clear_history()
1197 self.readline.clear_history()
1198 self.readline.read_history_file(self.shell.histfile)
1198 self.readline.read_history_file(self.shell.histfile)
1199 except AttributeError:
1199 except AttributeError:
1200 pass
1200 pass
1201
1201
1202 def history_saving_wrapper(self, func):
1202 def history_saving_wrapper(self, func):
1203 """ Wrap func for readline history saving
1203 """ Wrap func for readline history saving
1204
1204
1205 Convert func into callable that saves & restores
1205 Convert func into callable that saves & restores
1206 history around the call """
1206 history around the call """
1207
1207
1208 if self.has_readline:
1208 if self.has_readline:
1209 from IPython.utils import rlineimpl as readline
1209 from IPython.utils import rlineimpl as readline
1210 else:
1210 else:
1211 return func
1211 return func
1212
1212
1213 def wrapper():
1213 def wrapper():
1214 self.savehist()
1214 self.savehist()
1215 try:
1215 try:
1216 func()
1216 func()
1217 finally:
1217 finally:
1218 readline.read_history_file(self.histfile)
1218 readline.read_history_file(self.histfile)
1219 return wrapper
1219 return wrapper
1220
1220
1221 #-------------------------------------------------------------------------
1221 #-------------------------------------------------------------------------
1222 # Things related to exception handling and tracebacks (not debugging)
1222 # Things related to exception handling and tracebacks (not debugging)
1223 #-------------------------------------------------------------------------
1223 #-------------------------------------------------------------------------
1224
1224
1225 def init_traceback_handlers(self, custom_exceptions):
1225 def init_traceback_handlers(self, custom_exceptions):
1226 # Syntax error handler.
1226 # Syntax error handler.
1227 self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
1227 self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
1228
1228
1229 # The interactive one is initialized with an offset, meaning we always
1229 # The interactive one is initialized with an offset, meaning we always
1230 # want to remove the topmost item in the traceback, which is our own
1230 # want to remove the topmost item in the traceback, which is our own
1231 # internal code. Valid modes: ['Plain','Context','Verbose']
1231 # internal code. Valid modes: ['Plain','Context','Verbose']
1232 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1232 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1233 color_scheme='NoColor',
1233 color_scheme='NoColor',
1234 tb_offset = 1)
1234 tb_offset = 1)
1235
1235
1236 # The instance will store a pointer to the system-wide exception hook,
1236 # The instance will store a pointer to the system-wide exception hook,
1237 # so that runtime code (such as magics) can access it. This is because
1237 # so that runtime code (such as magics) can access it. This is because
1238 # during the read-eval loop, it may get temporarily overwritten.
1238 # during the read-eval loop, it may get temporarily overwritten.
1239 self.sys_excepthook = sys.excepthook
1239 self.sys_excepthook = sys.excepthook
1240
1240
1241 # and add any custom exception handlers the user may have specified
1241 # and add any custom exception handlers the user may have specified
1242 self.set_custom_exc(*custom_exceptions)
1242 self.set_custom_exc(*custom_exceptions)
1243
1243
1244 # Set the exception mode
1244 # Set the exception mode
1245 self.InteractiveTB.set_mode(mode=self.xmode)
1245 self.InteractiveTB.set_mode(mode=self.xmode)
1246
1246
1247 def set_custom_exc(self,exc_tuple,handler):
1247 def set_custom_exc(self,exc_tuple,handler):
1248 """set_custom_exc(exc_tuple,handler)
1248 """set_custom_exc(exc_tuple,handler)
1249
1249
1250 Set a custom exception handler, which will be called if any of the
1250 Set a custom exception handler, which will be called if any of the
1251 exceptions in exc_tuple occur in the mainloop (specifically, in the
1251 exceptions in exc_tuple occur in the mainloop (specifically, in the
1252 runcode() method.
1252 runcode() method.
1253
1253
1254 Inputs:
1254 Inputs:
1255
1255
1256 - exc_tuple: a *tuple* of valid exceptions to call the defined
1256 - exc_tuple: a *tuple* of valid exceptions to call the defined
1257 handler for. It is very important that you use a tuple, and NOT A
1257 handler for. It is very important that you use a tuple, and NOT A
1258 LIST here, because of the way Python's except statement works. If
1258 LIST here, because of the way Python's except statement works. If
1259 you only want to trap a single exception, use a singleton tuple:
1259 you only want to trap a single exception, use a singleton tuple:
1260
1260
1261 exc_tuple == (MyCustomException,)
1261 exc_tuple == (MyCustomException,)
1262
1262
1263 - handler: this must be defined as a function with the following
1263 - handler: this must be defined as a function with the following
1264 basic interface: def my_handler(self,etype,value,tb).
1264 basic interface: def my_handler(self,etype,value,tb).
1265
1265
1266 This will be made into an instance method (via new.instancemethod)
1266 This will be made into an instance method (via new.instancemethod)
1267 of IPython itself, and it will be called if any of the exceptions
1267 of IPython itself, and it will be called if any of the exceptions
1268 listed in the exc_tuple are caught. If the handler is None, an
1268 listed in the exc_tuple are caught. If the handler is None, an
1269 internal basic one is used, which just prints basic info.
1269 internal basic one is used, which just prints basic info.
1270
1270
1271 WARNING: by putting in your own exception handler into IPython's main
1271 WARNING: by putting in your own exception handler into IPython's main
1272 execution loop, you run a very good chance of nasty crashes. This
1272 execution loop, you run a very good chance of nasty crashes. This
1273 facility should only be used if you really know what you are doing."""
1273 facility should only be used if you really know what you are doing."""
1274
1274
1275 assert type(exc_tuple)==type(()) , \
1275 assert type(exc_tuple)==type(()) , \
1276 "The custom exceptions must be given AS A TUPLE."
1276 "The custom exceptions must be given AS A TUPLE."
1277
1277
1278 def dummy_handler(self,etype,value,tb):
1278 def dummy_handler(self,etype,value,tb):
1279 print '*** Simple custom exception handler ***'
1279 print '*** Simple custom exception handler ***'
1280 print 'Exception type :',etype
1280 print 'Exception type :',etype
1281 print 'Exception value:',value
1281 print 'Exception value:',value
1282 print 'Traceback :',tb
1282 print 'Traceback :',tb
1283 print 'Source code :','\n'.join(self.buffer)
1283 print 'Source code :','\n'.join(self.buffer)
1284
1284
1285 if handler is None: handler = dummy_handler
1285 if handler is None: handler = dummy_handler
1286
1286
1287 self.CustomTB = new.instancemethod(handler,self,self.__class__)
1287 self.CustomTB = new.instancemethod(handler,self,self.__class__)
1288 self.custom_exceptions = exc_tuple
1288 self.custom_exceptions = exc_tuple
1289
1289
1290 def excepthook(self, etype, value, tb):
1290 def excepthook(self, etype, value, tb):
1291 """One more defense for GUI apps that call sys.excepthook.
1291 """One more defense for GUI apps that call sys.excepthook.
1292
1292
1293 GUI frameworks like wxPython trap exceptions and call
1293 GUI frameworks like wxPython trap exceptions and call
1294 sys.excepthook themselves. I guess this is a feature that
1294 sys.excepthook themselves. I guess this is a feature that
1295 enables them to keep running after exceptions that would
1295 enables them to keep running after exceptions that would
1296 otherwise kill their mainloop. This is a bother for IPython
1296 otherwise kill their mainloop. This is a bother for IPython
1297 which excepts to catch all of the program exceptions with a try:
1297 which excepts to catch all of the program exceptions with a try:
1298 except: statement.
1298 except: statement.
1299
1299
1300 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1300 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1301 any app directly invokes sys.excepthook, it will look to the user like
1301 any app directly invokes sys.excepthook, it will look to the user like
1302 IPython crashed. In order to work around this, we can disable the
1302 IPython crashed. In order to work around this, we can disable the
1303 CrashHandler and replace it with this excepthook instead, which prints a
1303 CrashHandler and replace it with this excepthook instead, which prints a
1304 regular traceback using our InteractiveTB. In this fashion, apps which
1304 regular traceback using our InteractiveTB. In this fashion, apps which
1305 call sys.excepthook will generate a regular-looking exception from
1305 call sys.excepthook will generate a regular-looking exception from
1306 IPython, and the CrashHandler will only be triggered by real IPython
1306 IPython, and the CrashHandler will only be triggered by real IPython
1307 crashes.
1307 crashes.
1308
1308
1309 This hook should be used sparingly, only in places which are not likely
1309 This hook should be used sparingly, only in places which are not likely
1310 to be true IPython errors.
1310 to be true IPython errors.
1311 """
1311 """
1312 self.showtraceback((etype,value,tb),tb_offset=0)
1312 self.showtraceback((etype,value,tb),tb_offset=0)
1313
1313
1314 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1314 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1315 exception_only=False):
1315 exception_only=False):
1316 """Display the exception that just occurred.
1316 """Display the exception that just occurred.
1317
1317
1318 If nothing is known about the exception, this is the method which
1318 If nothing is known about the exception, this is the method which
1319 should be used throughout the code for presenting user tracebacks,
1319 should be used throughout the code for presenting user tracebacks,
1320 rather than directly invoking the InteractiveTB object.
1320 rather than directly invoking the InteractiveTB object.
1321
1321
1322 A specific showsyntaxerror() also exists, but this method can take
1322 A specific showsyntaxerror() also exists, but this method can take
1323 care of calling it if needed, so unless you are explicitly catching a
1323 care of calling it if needed, so unless you are explicitly catching a
1324 SyntaxError exception, don't try to analyze the stack manually and
1324 SyntaxError exception, don't try to analyze the stack manually and
1325 simply call this method."""
1325 simply call this method."""
1326
1326
1327 try:
1327 try:
1328 if exc_tuple is None:
1328 if exc_tuple is None:
1329 etype, value, tb = sys.exc_info()
1329 etype, value, tb = sys.exc_info()
1330 else:
1330 else:
1331 etype, value, tb = exc_tuple
1331 etype, value, tb = exc_tuple
1332
1332
1333 if etype is None:
1333 if etype is None:
1334 if hasattr(sys, 'last_type'):
1334 if hasattr(sys, 'last_type'):
1335 etype, value, tb = sys.last_type, sys.last_value, \
1335 etype, value, tb = sys.last_type, sys.last_value, \
1336 sys.last_traceback
1336 sys.last_traceback
1337 else:
1337 else:
1338 self.write('No traceback available to show.\n')
1338 self.write('No traceback available to show.\n')
1339 return
1339 return
1340
1340
1341 if etype is SyntaxError:
1341 if etype is SyntaxError:
1342 # Though this won't be called by syntax errors in the input
1342 # Though this won't be called by syntax errors in the input
1343 # line, there may be SyntaxError cases whith imported code.
1343 # line, there may be SyntaxError cases whith imported code.
1344 self.showsyntaxerror(filename)
1344 self.showsyntaxerror(filename)
1345 elif etype is UsageError:
1345 elif etype is UsageError:
1346 print "UsageError:", value
1346 print "UsageError:", value
1347 else:
1347 else:
1348 # WARNING: these variables are somewhat deprecated and not
1348 # WARNING: these variables are somewhat deprecated and not
1349 # necessarily safe to use in a threaded environment, but tools
1349 # necessarily safe to use in a threaded environment, but tools
1350 # like pdb depend on their existence, so let's set them. If we
1350 # like pdb depend on their existence, so let's set them. If we
1351 # find problems in the field, we'll need to revisit their use.
1351 # find problems in the field, we'll need to revisit their use.
1352 sys.last_type = etype
1352 sys.last_type = etype
1353 sys.last_value = value
1353 sys.last_value = value
1354 sys.last_traceback = tb
1354 sys.last_traceback = tb
1355
1355
1356 if etype in self.custom_exceptions:
1356 if etype in self.custom_exceptions:
1357 self.CustomTB(etype,value,tb)
1357 self.CustomTB(etype,value,tb)
1358 else:
1358 else:
1359 if exception_only:
1359 if exception_only:
1360 m = ('An exception has occurred, use %tb to see the '
1360 m = ('An exception has occurred, use %tb to see the '
1361 'full traceback.')
1361 'full traceback.')
1362 print m
1362 print m
1363 self.InteractiveTB.show_exception_only(etype, value)
1363 self.InteractiveTB.show_exception_only(etype, value)
1364 else:
1364 else:
1365 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1365 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1366 if self.InteractiveTB.call_pdb:
1366 if self.InteractiveTB.call_pdb:
1367 # pdb mucks up readline, fix it back
1367 # pdb mucks up readline, fix it back
1368 self.set_completer()
1368 self.set_completer()
1369
1369
1370 except KeyboardInterrupt:
1370 except KeyboardInterrupt:
1371 self.write("\nKeyboardInterrupt\n")
1371 self.write("\nKeyboardInterrupt\n")
1372
1372
1373
1373
1374 def showsyntaxerror(self, filename=None):
1374 def showsyntaxerror(self, filename=None):
1375 """Display the syntax error that just occurred.
1375 """Display the syntax error that just occurred.
1376
1376
1377 This doesn't display a stack trace because there isn't one.
1377 This doesn't display a stack trace because there isn't one.
1378
1378
1379 If a filename is given, it is stuffed in the exception instead
1379 If a filename is given, it is stuffed in the exception instead
1380 of what was there before (because Python's parser always uses
1380 of what was there before (because Python's parser always uses
1381 "<string>" when reading from a string).
1381 "<string>" when reading from a string).
1382 """
1382 """
1383 etype, value, last_traceback = sys.exc_info()
1383 etype, value, last_traceback = sys.exc_info()
1384
1384
1385 # See note about these variables in showtraceback() above
1385 # See note about these variables in showtraceback() above
1386 sys.last_type = etype
1386 sys.last_type = etype
1387 sys.last_value = value
1387 sys.last_value = value
1388 sys.last_traceback = last_traceback
1388 sys.last_traceback = last_traceback
1389
1389
1390 if filename and etype is SyntaxError:
1390 if filename and etype is SyntaxError:
1391 # Work hard to stuff the correct filename in the exception
1391 # Work hard to stuff the correct filename in the exception
1392 try:
1392 try:
1393 msg, (dummy_filename, lineno, offset, line) = value
1393 msg, (dummy_filename, lineno, offset, line) = value
1394 except:
1394 except:
1395 # Not the format we expect; leave it alone
1395 # Not the format we expect; leave it alone
1396 pass
1396 pass
1397 else:
1397 else:
1398 # Stuff in the right filename
1398 # Stuff in the right filename
1399 try:
1399 try:
1400 # Assume SyntaxError is a class exception
1400 # Assume SyntaxError is a class exception
1401 value = SyntaxError(msg, (filename, lineno, offset, line))
1401 value = SyntaxError(msg, (filename, lineno, offset, line))
1402 except:
1402 except:
1403 # If that failed, assume SyntaxError is a string
1403 # If that failed, assume SyntaxError is a string
1404 value = msg, (filename, lineno, offset, line)
1404 value = msg, (filename, lineno, offset, line)
1405 self.SyntaxTB(etype,value,[])
1405 self.SyntaxTB(etype,value,[])
1406
1406
1407 def edit_syntax_error(self):
1407 def edit_syntax_error(self):
1408 """The bottom half of the syntax error handler called in the main loop.
1408 """The bottom half of the syntax error handler called in the main loop.
1409
1409
1410 Loop until syntax error is fixed or user cancels.
1410 Loop until syntax error is fixed or user cancels.
1411 """
1411 """
1412
1412
1413 while self.SyntaxTB.last_syntax_error:
1413 while self.SyntaxTB.last_syntax_error:
1414 # copy and clear last_syntax_error
1414 # copy and clear last_syntax_error
1415 err = self.SyntaxTB.clear_err_state()
1415 err = self.SyntaxTB.clear_err_state()
1416 if not self._should_recompile(err):
1416 if not self._should_recompile(err):
1417 return
1417 return
1418 try:
1418 try:
1419 # may set last_syntax_error again if a SyntaxError is raised
1419 # may set last_syntax_error again if a SyntaxError is raised
1420 self.safe_execfile(err.filename,self.user_ns)
1420 self.safe_execfile(err.filename,self.user_ns)
1421 except:
1421 except:
1422 self.showtraceback()
1422 self.showtraceback()
1423 else:
1423 else:
1424 try:
1424 try:
1425 f = file(err.filename)
1425 f = file(err.filename)
1426 try:
1426 try:
1427 # This should be inside a display_trap block and I
1427 # This should be inside a display_trap block and I
1428 # think it is.
1428 # think it is.
1429 sys.displayhook(f.read())
1429 sys.displayhook(f.read())
1430 finally:
1430 finally:
1431 f.close()
1431 f.close()
1432 except:
1432 except:
1433 self.showtraceback()
1433 self.showtraceback()
1434
1434
1435 def _should_recompile(self,e):
1435 def _should_recompile(self,e):
1436 """Utility routine for edit_syntax_error"""
1436 """Utility routine for edit_syntax_error"""
1437
1437
1438 if e.filename in ('<ipython console>','<input>','<string>',
1438 if e.filename in ('<ipython console>','<input>','<string>',
1439 '<console>','<BackgroundJob compilation>',
1439 '<console>','<BackgroundJob compilation>',
1440 None):
1440 None):
1441
1441
1442 return False
1442 return False
1443 try:
1443 try:
1444 if (self.autoedit_syntax and
1444 if (self.autoedit_syntax and
1445 not self.ask_yes_no('Return to editor to correct syntax error? '
1445 not self.ask_yes_no('Return to editor to correct syntax error? '
1446 '[Y/n] ','y')):
1446 '[Y/n] ','y')):
1447 return False
1447 return False
1448 except EOFError:
1448 except EOFError:
1449 return False
1449 return False
1450
1450
1451 def int0(x):
1451 def int0(x):
1452 try:
1452 try:
1453 return int(x)
1453 return int(x)
1454 except TypeError:
1454 except TypeError:
1455 return 0
1455 return 0
1456 # always pass integer line and offset values to editor hook
1456 # always pass integer line and offset values to editor hook
1457 try:
1457 try:
1458 self.hooks.fix_error_editor(e.filename,
1458 self.hooks.fix_error_editor(e.filename,
1459 int0(e.lineno),int0(e.offset),e.msg)
1459 int0(e.lineno),int0(e.offset),e.msg)
1460 except TryNext:
1460 except TryNext:
1461 warn('Could not open editor')
1461 warn('Could not open editor')
1462 return False
1462 return False
1463 return True
1463 return True
1464
1464
1465 #-------------------------------------------------------------------------
1465 #-------------------------------------------------------------------------
1466 # Things related to tab completion
1466 # Things related to tab completion
1467 #-------------------------------------------------------------------------
1467 #-------------------------------------------------------------------------
1468
1468
1469 def complete(self, text):
1469 def complete(self, text):
1470 """Return a sorted list of all possible completions on text.
1470 """Return a sorted list of all possible completions on text.
1471
1471
1472 Inputs:
1472 Inputs:
1473
1473
1474 - text: a string of text to be completed on.
1474 - text: a string of text to be completed on.
1475
1475
1476 This is a wrapper around the completion mechanism, similar to what
1476 This is a wrapper around the completion mechanism, similar to what
1477 readline does at the command line when the TAB key is hit. By
1477 readline does at the command line when the TAB key is hit. By
1478 exposing it as a method, it can be used by other non-readline
1478 exposing it as a method, it can be used by other non-readline
1479 environments (such as GUIs) for text completion.
1479 environments (such as GUIs) for text completion.
1480
1480
1481 Simple usage example:
1481 Simple usage example:
1482
1482
1483 In [7]: x = 'hello'
1483 In [7]: x = 'hello'
1484
1484
1485 In [8]: x
1485 In [8]: x
1486 Out[8]: 'hello'
1486 Out[8]: 'hello'
1487
1487
1488 In [9]: print x
1488 In [9]: print x
1489 hello
1489 hello
1490
1490
1491 In [10]: _ip.complete('x.l')
1491 In [10]: _ip.complete('x.l')
1492 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1492 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1493 """
1493 """
1494
1494
1495 # Inject names into __builtin__ so we can complete on the added names.
1495 # Inject names into __builtin__ so we can complete on the added names.
1496 with self.builtin_trap:
1496 with self.builtin_trap:
1497 complete = self.Completer.complete
1497 complete = self.Completer.complete
1498 state = 0
1498 state = 0
1499 # use a dict so we get unique keys, since ipyhton's multiple
1499 # use a dict so we get unique keys, since ipyhton's multiple
1500 # completers can return duplicates. When we make 2.4 a requirement,
1500 # completers can return duplicates. When we make 2.4 a requirement,
1501 # start using sets instead, which are faster.
1501 # start using sets instead, which are faster.
1502 comps = {}
1502 comps = {}
1503 while True:
1503 while True:
1504 newcomp = complete(text,state,line_buffer=text)
1504 newcomp = complete(text,state,line_buffer=text)
1505 if newcomp is None:
1505 if newcomp is None:
1506 break
1506 break
1507 comps[newcomp] = 1
1507 comps[newcomp] = 1
1508 state += 1
1508 state += 1
1509 outcomps = comps.keys()
1509 outcomps = comps.keys()
1510 outcomps.sort()
1510 outcomps.sort()
1511 #print "T:",text,"OC:",outcomps # dbg
1511 #print "T:",text,"OC:",outcomps # dbg
1512 #print "vars:",self.user_ns.keys()
1512 #print "vars:",self.user_ns.keys()
1513 return outcomps
1513 return outcomps
1514
1514
1515 def set_custom_completer(self,completer,pos=0):
1515 def set_custom_completer(self,completer,pos=0):
1516 """Adds a new custom completer function.
1516 """Adds a new custom completer function.
1517
1517
1518 The position argument (defaults to 0) is the index in the completers
1518 The position argument (defaults to 0) is the index in the completers
1519 list where you want the completer to be inserted."""
1519 list where you want the completer to be inserted."""
1520
1520
1521 newcomp = new.instancemethod(completer,self.Completer,
1521 newcomp = new.instancemethod(completer,self.Completer,
1522 self.Completer.__class__)
1522 self.Completer.__class__)
1523 self.Completer.matchers.insert(pos,newcomp)
1523 self.Completer.matchers.insert(pos,newcomp)
1524
1524
1525 def set_completer(self):
1525 def set_completer(self):
1526 """Reset readline's completer to be our own."""
1526 """Reset readline's completer to be our own."""
1527 self.readline.set_completer(self.Completer.complete)
1527 self.readline.set_completer(self.Completer.complete)
1528
1528
1529 def set_completer_frame(self, frame=None):
1529 def set_completer_frame(self, frame=None):
1530 """Set the frame of the completer."""
1530 """Set the frame of the completer."""
1531 if frame:
1531 if frame:
1532 self.Completer.namespace = frame.f_locals
1532 self.Completer.namespace = frame.f_locals
1533 self.Completer.global_namespace = frame.f_globals
1533 self.Completer.global_namespace = frame.f_globals
1534 else:
1534 else:
1535 self.Completer.namespace = self.user_ns
1535 self.Completer.namespace = self.user_ns
1536 self.Completer.global_namespace = self.user_global_ns
1536 self.Completer.global_namespace = self.user_global_ns
1537
1537
1538 #-------------------------------------------------------------------------
1538 #-------------------------------------------------------------------------
1539 # Things related to readline
1539 # Things related to readline
1540 #-------------------------------------------------------------------------
1540 #-------------------------------------------------------------------------
1541
1541
1542 def init_readline(self):
1542 def init_readline(self):
1543 """Command history completion/saving/reloading."""
1543 """Command history completion/saving/reloading."""
1544
1544
1545 if self.readline_use:
1545 if self.readline_use:
1546 import IPython.utils.rlineimpl as readline
1546 import IPython.utils.rlineimpl as readline
1547
1547
1548 self.rl_next_input = None
1548 self.rl_next_input = None
1549 self.rl_do_indent = False
1549 self.rl_do_indent = False
1550
1550
1551 if not self.readline_use or not readline.have_readline:
1551 if not self.readline_use or not readline.have_readline:
1552 self.has_readline = False
1552 self.has_readline = False
1553 self.readline = None
1553 self.readline = None
1554 # Set a number of methods that depend on readline to be no-op
1554 # Set a number of methods that depend on readline to be no-op
1555 self.savehist = no_op
1555 self.savehist = no_op
1556 self.reloadhist = no_op
1556 self.reloadhist = no_op
1557 self.set_completer = no_op
1557 self.set_completer = no_op
1558 self.set_custom_completer = no_op
1558 self.set_custom_completer = no_op
1559 self.set_completer_frame = no_op
1559 self.set_completer_frame = no_op
1560 warn('Readline services not available or not loaded.')
1560 warn('Readline services not available or not loaded.')
1561 else:
1561 else:
1562 self.has_readline = True
1562 self.has_readline = True
1563 self.readline = readline
1563 self.readline = readline
1564 sys.modules['readline'] = readline
1564 sys.modules['readline'] = readline
1565 import atexit
1565 import atexit
1566 from IPython.core.completer import IPCompleter
1566 from IPython.core.completer import IPCompleter
1567 self.Completer = IPCompleter(self,
1567 self.Completer = IPCompleter(self,
1568 self.user_ns,
1568 self.user_ns,
1569 self.user_global_ns,
1569 self.user_global_ns,
1570 self.readline_omit__names,
1570 self.readline_omit__names,
1571 self.alias_manager.alias_table)
1571 self.alias_manager.alias_table)
1572 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1572 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1573 self.strdispatchers['complete_command'] = sdisp
1573 self.strdispatchers['complete_command'] = sdisp
1574 self.Completer.custom_completers = sdisp
1574 self.Completer.custom_completers = sdisp
1575 # Platform-specific configuration
1575 # Platform-specific configuration
1576 if os.name == 'nt':
1576 if os.name == 'nt':
1577 self.readline_startup_hook = readline.set_pre_input_hook
1577 self.readline_startup_hook = readline.set_pre_input_hook
1578 else:
1578 else:
1579 self.readline_startup_hook = readline.set_startup_hook
1579 self.readline_startup_hook = readline.set_startup_hook
1580
1580
1581 # Load user's initrc file (readline config)
1581 # Load user's initrc file (readline config)
1582 # Or if libedit is used, load editrc.
1582 # Or if libedit is used, load editrc.
1583 inputrc_name = os.environ.get('INPUTRC')
1583 inputrc_name = os.environ.get('INPUTRC')
1584 if inputrc_name is None:
1584 if inputrc_name is None:
1585 home_dir = get_home_dir()
1585 home_dir = get_home_dir()
1586 if home_dir is not None:
1586 if home_dir is not None:
1587 inputrc_name = '.inputrc'
1587 inputrc_name = '.inputrc'
1588 if readline.uses_libedit:
1588 if readline.uses_libedit:
1589 inputrc_name = '.editrc'
1589 inputrc_name = '.editrc'
1590 inputrc_name = os.path.join(home_dir, inputrc_name)
1590 inputrc_name = os.path.join(home_dir, inputrc_name)
1591 if os.path.isfile(inputrc_name):
1591 if os.path.isfile(inputrc_name):
1592 try:
1592 try:
1593 readline.read_init_file(inputrc_name)
1593 readline.read_init_file(inputrc_name)
1594 except:
1594 except:
1595 warn('Problems reading readline initialization file <%s>'
1595 warn('Problems reading readline initialization file <%s>'
1596 % inputrc_name)
1596 % inputrc_name)
1597
1597
1598 # save this in sys so embedded copies can restore it properly
1598 # save this in sys so embedded copies can restore it properly
1599 sys.ipcompleter = self.Completer.complete
1599 sys.ipcompleter = self.Completer.complete
1600 self.set_completer()
1600 self.set_completer()
1601
1601
1602 # Configure readline according to user's prefs
1602 # Configure readline according to user's prefs
1603 # This is only done if GNU readline is being used. If libedit
1603 # This is only done if GNU readline is being used. If libedit
1604 # is being used (as on Leopard) the readline config is
1604 # is being used (as on Leopard) the readline config is
1605 # not run as the syntax for libedit is different.
1605 # not run as the syntax for libedit is different.
1606 if not readline.uses_libedit:
1606 if not readline.uses_libedit:
1607 for rlcommand in self.readline_parse_and_bind:
1607 for rlcommand in self.readline_parse_and_bind:
1608 #print "loading rl:",rlcommand # dbg
1608 #print "loading rl:",rlcommand # dbg
1609 readline.parse_and_bind(rlcommand)
1609 readline.parse_and_bind(rlcommand)
1610
1610
1611 # Remove some chars from the delimiters list. If we encounter
1611 # Remove some chars from the delimiters list. If we encounter
1612 # unicode chars, discard them.
1612 # unicode chars, discard them.
1613 delims = readline.get_completer_delims().encode("ascii", "ignore")
1613 delims = readline.get_completer_delims().encode("ascii", "ignore")
1614 delims = delims.translate(string._idmap,
1614 delims = delims.translate(string._idmap,
1615 self.readline_remove_delims)
1615 self.readline_remove_delims)
1616 readline.set_completer_delims(delims)
1616 readline.set_completer_delims(delims)
1617 # otherwise we end up with a monster history after a while:
1617 # otherwise we end up with a monster history after a while:
1618 readline.set_history_length(1000)
1618 readline.set_history_length(1000)
1619 try:
1619 try:
1620 #print '*** Reading readline history' # dbg
1620 #print '*** Reading readline history' # dbg
1621 readline.read_history_file(self.histfile)
1621 readline.read_history_file(self.histfile)
1622 except IOError:
1622 except IOError:
1623 pass # It doesn't exist yet.
1623 pass # It doesn't exist yet.
1624
1624
1625 atexit.register(self.atexit_operations)
1625 atexit.register(self.atexit_operations)
1626 del atexit
1626 del atexit
1627
1627
1628 # Configure auto-indent for all platforms
1628 # Configure auto-indent for all platforms
1629 self.set_autoindent(self.autoindent)
1629 self.set_autoindent(self.autoindent)
1630
1630
1631 def set_next_input(self, s):
1631 def set_next_input(self, s):
1632 """ Sets the 'default' input string for the next command line.
1632 """ Sets the 'default' input string for the next command line.
1633
1633
1634 Requires readline.
1634 Requires readline.
1635
1635
1636 Example:
1636 Example:
1637
1637
1638 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1638 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1639 [D:\ipython]|2> Hello Word_ # cursor is here
1639 [D:\ipython]|2> Hello Word_ # cursor is here
1640 """
1640 """
1641
1641
1642 self.rl_next_input = s
1642 self.rl_next_input = s
1643
1643
1644 def pre_readline(self):
1644 def pre_readline(self):
1645 """readline hook to be used at the start of each line.
1645 """readline hook to be used at the start of each line.
1646
1646
1647 Currently it handles auto-indent only."""
1647 Currently it handles auto-indent only."""
1648
1648
1649 #debugx('self.indent_current_nsp','pre_readline:')
1649 #debugx('self.indent_current_nsp','pre_readline:')
1650
1650
1651 if self.rl_do_indent:
1651 if self.rl_do_indent:
1652 self.readline.insert_text(self._indent_current_str())
1652 self.readline.insert_text(self._indent_current_str())
1653 if self.rl_next_input is not None:
1653 if self.rl_next_input is not None:
1654 self.readline.insert_text(self.rl_next_input)
1654 self.readline.insert_text(self.rl_next_input)
1655 self.rl_next_input = None
1655 self.rl_next_input = None
1656
1656
1657 def _indent_current_str(self):
1657 def _indent_current_str(self):
1658 """return the current level of indentation as a string"""
1658 """return the current level of indentation as a string"""
1659 return self.indent_current_nsp * ' '
1659 return self.indent_current_nsp * ' '
1660
1660
1661 #-------------------------------------------------------------------------
1661 #-------------------------------------------------------------------------
1662 # Things related to magics
1662 # Things related to magics
1663 #-------------------------------------------------------------------------
1663 #-------------------------------------------------------------------------
1664
1664
1665 def init_magics(self):
1665 def init_magics(self):
1666 # Set user colors (don't do it in the constructor above so that it
1666 # Set user colors (don't do it in the constructor above so that it
1667 # doesn't crash if colors option is invalid)
1667 # doesn't crash if colors option is invalid)
1668 self.magic_colors(self.colors)
1668 self.magic_colors(self.colors)
1669 # History was moved to a separate module
1669 # History was moved to a separate module
1670 from . import history
1670 from . import history
1671 history.init_ipython(self)
1671 history.init_ipython(self)
1672
1672
1673 def magic(self,arg_s):
1673 def magic(self,arg_s):
1674 """Call a magic function by name.
1674 """Call a magic function by name.
1675
1675
1676 Input: a string containing the name of the magic function to call and any
1676 Input: a string containing the name of the magic function to call and any
1677 additional arguments to be passed to the magic.
1677 additional arguments to be passed to the magic.
1678
1678
1679 magic('name -opt foo bar') is equivalent to typing at the ipython
1679 magic('name -opt foo bar') is equivalent to typing at the ipython
1680 prompt:
1680 prompt:
1681
1681
1682 In[1]: %name -opt foo bar
1682 In[1]: %name -opt foo bar
1683
1683
1684 To call a magic without arguments, simply use magic('name').
1684 To call a magic without arguments, simply use magic('name').
1685
1685
1686 This provides a proper Python function to call IPython's magics in any
1686 This provides a proper Python function to call IPython's magics in any
1687 valid Python code you can type at the interpreter, including loops and
1687 valid Python code you can type at the interpreter, including loops and
1688 compound statements.
1688 compound statements.
1689 """
1689 """
1690 args = arg_s.split(' ',1)
1690 args = arg_s.split(' ',1)
1691 magic_name = args[0]
1691 magic_name = args[0]
1692 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1692 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1693
1693
1694 try:
1694 try:
1695 magic_args = args[1]
1695 magic_args = args[1]
1696 except IndexError:
1696 except IndexError:
1697 magic_args = ''
1697 magic_args = ''
1698 fn = getattr(self,'magic_'+magic_name,None)
1698 fn = getattr(self,'magic_'+magic_name,None)
1699 if fn is None:
1699 if fn is None:
1700 error("Magic function `%s` not found." % magic_name)
1700 error("Magic function `%s` not found." % magic_name)
1701 else:
1701 else:
1702 magic_args = self.var_expand(magic_args,1)
1702 magic_args = self.var_expand(magic_args,1)
1703 with nested(self.builtin_trap,):
1703 with nested(self.builtin_trap,):
1704 result = fn(magic_args)
1704 result = fn(magic_args)
1705 return result
1705 return result
1706
1706
1707 def define_magic(self, magicname, func):
1707 def define_magic(self, magicname, func):
1708 """Expose own function as magic function for ipython
1708 """Expose own function as magic function for ipython
1709
1709
1710 def foo_impl(self,parameter_s=''):
1710 def foo_impl(self,parameter_s=''):
1711 'My very own magic!. (Use docstrings, IPython reads them).'
1711 'My very own magic!. (Use docstrings, IPython reads them).'
1712 print 'Magic function. Passed parameter is between < >:'
1712 print 'Magic function. Passed parameter is between < >:'
1713 print '<%s>' % parameter_s
1713 print '<%s>' % parameter_s
1714 print 'The self object is:',self
1714 print 'The self object is:',self
1715
1715
1716 self.define_magic('foo',foo_impl)
1716 self.define_magic('foo',foo_impl)
1717 """
1717 """
1718
1718
1719 import new
1719 import new
1720 im = new.instancemethod(func,self, self.__class__)
1720 im = new.instancemethod(func,self, self.__class__)
1721 old = getattr(self, "magic_" + magicname, None)
1721 old = getattr(self, "magic_" + magicname, None)
1722 setattr(self, "magic_" + magicname, im)
1722 setattr(self, "magic_" + magicname, im)
1723 return old
1723 return old
1724
1724
1725 #-------------------------------------------------------------------------
1725 #-------------------------------------------------------------------------
1726 # Things related to macros
1726 # Things related to macros
1727 #-------------------------------------------------------------------------
1727 #-------------------------------------------------------------------------
1728
1728
1729 def define_macro(self, name, themacro):
1729 def define_macro(self, name, themacro):
1730 """Define a new macro
1730 """Define a new macro
1731
1731
1732 Parameters
1732 Parameters
1733 ----------
1733 ----------
1734 name : str
1734 name : str
1735 The name of the macro.
1735 The name of the macro.
1736 themacro : str or Macro
1736 themacro : str or Macro
1737 The action to do upon invoking the macro. If a string, a new
1737 The action to do upon invoking the macro. If a string, a new
1738 Macro object is created by passing the string to it.
1738 Macro object is created by passing the string to it.
1739 """
1739 """
1740
1740
1741 from IPython.core import macro
1741 from IPython.core import macro
1742
1742
1743 if isinstance(themacro, basestring):
1743 if isinstance(themacro, basestring):
1744 themacro = macro.Macro(themacro)
1744 themacro = macro.Macro(themacro)
1745 if not isinstance(themacro, macro.Macro):
1745 if not isinstance(themacro, macro.Macro):
1746 raise ValueError('A macro must be a string or a Macro instance.')
1746 raise ValueError('A macro must be a string or a Macro instance.')
1747 self.user_ns[name] = themacro
1747 self.user_ns[name] = themacro
1748
1748
1749 #-------------------------------------------------------------------------
1749 #-------------------------------------------------------------------------
1750 # Things related to the running of system commands
1750 # Things related to the running of system commands
1751 #-------------------------------------------------------------------------
1751 #-------------------------------------------------------------------------
1752
1752
1753 def system(self, cmd):
1753 def system(self, cmd):
1754 """Make a system call, using IPython."""
1754 """Make a system call, using IPython."""
1755 return self.hooks.shell_hook(self.var_expand(cmd, depth=2))
1755 return self.hooks.shell_hook(self.var_expand(cmd, depth=2))
1756
1756
1757 #-------------------------------------------------------------------------
1757 #-------------------------------------------------------------------------
1758 # Things related to aliases
1758 # Things related to aliases
1759 #-------------------------------------------------------------------------
1759 #-------------------------------------------------------------------------
1760
1760
1761 def init_alias(self):
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 self.ns_table['alias'] = self.alias_manager.alias_table,
1763 self.ns_table['alias'] = self.alias_manager.alias_table,
1764
1764
1765 #-------------------------------------------------------------------------
1765 #-------------------------------------------------------------------------
1766 # Things related to extensions and plugins
1766 # Things related to extensions and plugins
1767 #-------------------------------------------------------------------------
1767 #-------------------------------------------------------------------------
1768
1768
1769 def init_extension_manager(self):
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 def init_plugin_manager(self):
1772 def init_plugin_manager(self):
1773 self.plugin_manager = PluginManager(config=self.config)
1773 self.plugin_manager = PluginManager(config=self.config)
1774
1774
1775 #-------------------------------------------------------------------------
1775 #-------------------------------------------------------------------------
1776 # Things related to the running of code
1776 # Things related to the running of code
1777 #-------------------------------------------------------------------------
1777 #-------------------------------------------------------------------------
1778
1778
1779 def ex(self, cmd):
1779 def ex(self, cmd):
1780 """Execute a normal python statement in user namespace."""
1780 """Execute a normal python statement in user namespace."""
1781 with nested(self.builtin_trap,):
1781 with nested(self.builtin_trap,):
1782 exec cmd in self.user_global_ns, self.user_ns
1782 exec cmd in self.user_global_ns, self.user_ns
1783
1783
1784 def ev(self, expr):
1784 def ev(self, expr):
1785 """Evaluate python expression expr in user namespace.
1785 """Evaluate python expression expr in user namespace.
1786
1786
1787 Returns the result of evaluation
1787 Returns the result of evaluation
1788 """
1788 """
1789 with nested(self.builtin_trap,):
1789 with nested(self.builtin_trap,):
1790 return eval(expr, self.user_global_ns, self.user_ns)
1790 return eval(expr, self.user_global_ns, self.user_ns)
1791
1791
1792 def mainloop(self, display_banner=None):
1792 def mainloop(self, display_banner=None):
1793 """Start the mainloop.
1793 """Start the mainloop.
1794
1794
1795 If an optional banner argument is given, it will override the
1795 If an optional banner argument is given, it will override the
1796 internally created default banner.
1796 internally created default banner.
1797 """
1797 """
1798
1798
1799 with nested(self.builtin_trap, self.display_trap):
1799 with nested(self.builtin_trap, self.display_trap):
1800
1800
1801 # if you run stuff with -c <cmd>, raw hist is not updated
1801 # if you run stuff with -c <cmd>, raw hist is not updated
1802 # ensure that it's in sync
1802 # ensure that it's in sync
1803 if len(self.input_hist) != len (self.input_hist_raw):
1803 if len(self.input_hist) != len (self.input_hist_raw):
1804 self.input_hist_raw = InputList(self.input_hist)
1804 self.input_hist_raw = InputList(self.input_hist)
1805
1805
1806 while 1:
1806 while 1:
1807 try:
1807 try:
1808 self.interact(display_banner=display_banner)
1808 self.interact(display_banner=display_banner)
1809 #self.interact_with_readline()
1809 #self.interact_with_readline()
1810 # XXX for testing of a readline-decoupled repl loop, call
1810 # XXX for testing of a readline-decoupled repl loop, call
1811 # interact_with_readline above
1811 # interact_with_readline above
1812 break
1812 break
1813 except KeyboardInterrupt:
1813 except KeyboardInterrupt:
1814 # this should not be necessary, but KeyboardInterrupt
1814 # this should not be necessary, but KeyboardInterrupt
1815 # handling seems rather unpredictable...
1815 # handling seems rather unpredictable...
1816 self.write("\nKeyboardInterrupt in interact()\n")
1816 self.write("\nKeyboardInterrupt in interact()\n")
1817
1817
1818 def interact_prompt(self):
1818 def interact_prompt(self):
1819 """ Print the prompt (in read-eval-print loop)
1819 """ Print the prompt (in read-eval-print loop)
1820
1820
1821 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1821 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1822 used in standard IPython flow.
1822 used in standard IPython flow.
1823 """
1823 """
1824 if self.more:
1824 if self.more:
1825 try:
1825 try:
1826 prompt = self.hooks.generate_prompt(True)
1826 prompt = self.hooks.generate_prompt(True)
1827 except:
1827 except:
1828 self.showtraceback()
1828 self.showtraceback()
1829 if self.autoindent:
1829 if self.autoindent:
1830 self.rl_do_indent = True
1830 self.rl_do_indent = True
1831
1831
1832 else:
1832 else:
1833 try:
1833 try:
1834 prompt = self.hooks.generate_prompt(False)
1834 prompt = self.hooks.generate_prompt(False)
1835 except:
1835 except:
1836 self.showtraceback()
1836 self.showtraceback()
1837 self.write(prompt)
1837 self.write(prompt)
1838
1838
1839 def interact_handle_input(self,line):
1839 def interact_handle_input(self,line):
1840 """ Handle the input line (in read-eval-print loop)
1840 """ Handle the input line (in read-eval-print loop)
1841
1841
1842 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1842 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1843 used in standard IPython flow.
1843 used in standard IPython flow.
1844 """
1844 """
1845 if line.lstrip() == line:
1845 if line.lstrip() == line:
1846 self.shadowhist.add(line.strip())
1846 self.shadowhist.add(line.strip())
1847 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1847 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1848
1848
1849 if line.strip():
1849 if line.strip():
1850 if self.more:
1850 if self.more:
1851 self.input_hist_raw[-1] += '%s\n' % line
1851 self.input_hist_raw[-1] += '%s\n' % line
1852 else:
1852 else:
1853 self.input_hist_raw.append('%s\n' % line)
1853 self.input_hist_raw.append('%s\n' % line)
1854
1854
1855
1855
1856 self.more = self.push_line(lineout)
1856 self.more = self.push_line(lineout)
1857 if (self.SyntaxTB.last_syntax_error and
1857 if (self.SyntaxTB.last_syntax_error and
1858 self.autoedit_syntax):
1858 self.autoedit_syntax):
1859 self.edit_syntax_error()
1859 self.edit_syntax_error()
1860
1860
1861 def interact_with_readline(self):
1861 def interact_with_readline(self):
1862 """ Demo of using interact_handle_input, interact_prompt
1862 """ Demo of using interact_handle_input, interact_prompt
1863
1863
1864 This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
1864 This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
1865 it should work like this.
1865 it should work like this.
1866 """
1866 """
1867 self.readline_startup_hook(self.pre_readline)
1867 self.readline_startup_hook(self.pre_readline)
1868 while not self.exit_now:
1868 while not self.exit_now:
1869 self.interact_prompt()
1869 self.interact_prompt()
1870 if self.more:
1870 if self.more:
1871 self.rl_do_indent = True
1871 self.rl_do_indent = True
1872 else:
1872 else:
1873 self.rl_do_indent = False
1873 self.rl_do_indent = False
1874 line = raw_input_original().decode(self.stdin_encoding)
1874 line = raw_input_original().decode(self.stdin_encoding)
1875 self.interact_handle_input(line)
1875 self.interact_handle_input(line)
1876
1876
1877 def interact(self, display_banner=None):
1877 def interact(self, display_banner=None):
1878 """Closely emulate the interactive Python console."""
1878 """Closely emulate the interactive Python console."""
1879
1879
1880 # batch run -> do not interact
1880 # batch run -> do not interact
1881 if self.exit_now:
1881 if self.exit_now:
1882 return
1882 return
1883
1883
1884 if display_banner is None:
1884 if display_banner is None:
1885 display_banner = self.display_banner
1885 display_banner = self.display_banner
1886 if display_banner:
1886 if display_banner:
1887 self.show_banner()
1887 self.show_banner()
1888
1888
1889 more = 0
1889 more = 0
1890
1890
1891 # Mark activity in the builtins
1891 # Mark activity in the builtins
1892 __builtin__.__dict__['__IPYTHON__active'] += 1
1892 __builtin__.__dict__['__IPYTHON__active'] += 1
1893
1893
1894 if self.has_readline:
1894 if self.has_readline:
1895 self.readline_startup_hook(self.pre_readline)
1895 self.readline_startup_hook(self.pre_readline)
1896 # exit_now is set by a call to %Exit or %Quit, through the
1896 # exit_now is set by a call to %Exit or %Quit, through the
1897 # ask_exit callback.
1897 # ask_exit callback.
1898
1898
1899 while not self.exit_now:
1899 while not self.exit_now:
1900 self.hooks.pre_prompt_hook()
1900 self.hooks.pre_prompt_hook()
1901 if more:
1901 if more:
1902 try:
1902 try:
1903 prompt = self.hooks.generate_prompt(True)
1903 prompt = self.hooks.generate_prompt(True)
1904 except:
1904 except:
1905 self.showtraceback()
1905 self.showtraceback()
1906 if self.autoindent:
1906 if self.autoindent:
1907 self.rl_do_indent = True
1907 self.rl_do_indent = True
1908
1908
1909 else:
1909 else:
1910 try:
1910 try:
1911 prompt = self.hooks.generate_prompt(False)
1911 prompt = self.hooks.generate_prompt(False)
1912 except:
1912 except:
1913 self.showtraceback()
1913 self.showtraceback()
1914 try:
1914 try:
1915 line = self.raw_input(prompt, more)
1915 line = self.raw_input(prompt, more)
1916 if self.exit_now:
1916 if self.exit_now:
1917 # quick exit on sys.std[in|out] close
1917 # quick exit on sys.std[in|out] close
1918 break
1918 break
1919 if self.autoindent:
1919 if self.autoindent:
1920 self.rl_do_indent = False
1920 self.rl_do_indent = False
1921
1921
1922 except KeyboardInterrupt:
1922 except KeyboardInterrupt:
1923 #double-guard against keyboardinterrupts during kbdint handling
1923 #double-guard against keyboardinterrupts during kbdint handling
1924 try:
1924 try:
1925 self.write('\nKeyboardInterrupt\n')
1925 self.write('\nKeyboardInterrupt\n')
1926 self.resetbuffer()
1926 self.resetbuffer()
1927 # keep cache in sync with the prompt counter:
1927 # keep cache in sync with the prompt counter:
1928 self.outputcache.prompt_count -= 1
1928 self.outputcache.prompt_count -= 1
1929
1929
1930 if self.autoindent:
1930 if self.autoindent:
1931 self.indent_current_nsp = 0
1931 self.indent_current_nsp = 0
1932 more = 0
1932 more = 0
1933 except KeyboardInterrupt:
1933 except KeyboardInterrupt:
1934 pass
1934 pass
1935 except EOFError:
1935 except EOFError:
1936 if self.autoindent:
1936 if self.autoindent:
1937 self.rl_do_indent = False
1937 self.rl_do_indent = False
1938 if self.has_readline:
1938 if self.has_readline:
1939 self.readline_startup_hook(None)
1939 self.readline_startup_hook(None)
1940 self.write('\n')
1940 self.write('\n')
1941 self.exit()
1941 self.exit()
1942 except bdb.BdbQuit:
1942 except bdb.BdbQuit:
1943 warn('The Python debugger has exited with a BdbQuit exception.\n'
1943 warn('The Python debugger has exited with a BdbQuit exception.\n'
1944 'Because of how pdb handles the stack, it is impossible\n'
1944 'Because of how pdb handles the stack, it is impossible\n'
1945 'for IPython to properly format this particular exception.\n'
1945 'for IPython to properly format this particular exception.\n'
1946 'IPython will resume normal operation.')
1946 'IPython will resume normal operation.')
1947 except:
1947 except:
1948 # exceptions here are VERY RARE, but they can be triggered
1948 # exceptions here are VERY RARE, but they can be triggered
1949 # asynchronously by signal handlers, for example.
1949 # asynchronously by signal handlers, for example.
1950 self.showtraceback()
1950 self.showtraceback()
1951 else:
1951 else:
1952 more = self.push_line(line)
1952 more = self.push_line(line)
1953 if (self.SyntaxTB.last_syntax_error and
1953 if (self.SyntaxTB.last_syntax_error and
1954 self.autoedit_syntax):
1954 self.autoedit_syntax):
1955 self.edit_syntax_error()
1955 self.edit_syntax_error()
1956
1956
1957 # We are off again...
1957 # We are off again...
1958 __builtin__.__dict__['__IPYTHON__active'] -= 1
1958 __builtin__.__dict__['__IPYTHON__active'] -= 1
1959
1959
1960 # Turn off the exit flag, so the mainloop can be restarted if desired
1960 # Turn off the exit flag, so the mainloop can be restarted if desired
1961 self.exit_now = False
1961 self.exit_now = False
1962
1962
1963 def safe_execfile(self, fname, *where, **kw):
1963 def safe_execfile(self, fname, *where, **kw):
1964 """A safe version of the builtin execfile().
1964 """A safe version of the builtin execfile().
1965
1965
1966 This version will never throw an exception, but instead print
1966 This version will never throw an exception, but instead print
1967 helpful error messages to the screen. This only works on pure
1967 helpful error messages to the screen. This only works on pure
1968 Python files with the .py extension.
1968 Python files with the .py extension.
1969
1969
1970 Parameters
1970 Parameters
1971 ----------
1971 ----------
1972 fname : string
1972 fname : string
1973 The name of the file to be executed.
1973 The name of the file to be executed.
1974 where : tuple
1974 where : tuple
1975 One or two namespaces, passed to execfile() as (globals,locals).
1975 One or two namespaces, passed to execfile() as (globals,locals).
1976 If only one is given, it is passed as both.
1976 If only one is given, it is passed as both.
1977 exit_ignore : bool (False)
1977 exit_ignore : bool (False)
1978 If True, then silence SystemExit for non-zero status (it is always
1978 If True, then silence SystemExit for non-zero status (it is always
1979 silenced for zero status, as it is so common).
1979 silenced for zero status, as it is so common).
1980 """
1980 """
1981 kw.setdefault('exit_ignore', False)
1981 kw.setdefault('exit_ignore', False)
1982
1982
1983 fname = os.path.abspath(os.path.expanduser(fname))
1983 fname = os.path.abspath(os.path.expanduser(fname))
1984
1984
1985 # Make sure we have a .py file
1985 # Make sure we have a .py file
1986 if not fname.endswith('.py'):
1986 if not fname.endswith('.py'):
1987 warn('File must end with .py to be run using execfile: <%s>' % fname)
1987 warn('File must end with .py to be run using execfile: <%s>' % fname)
1988
1988
1989 # Make sure we can open the file
1989 # Make sure we can open the file
1990 try:
1990 try:
1991 with open(fname) as thefile:
1991 with open(fname) as thefile:
1992 pass
1992 pass
1993 except:
1993 except:
1994 warn('Could not open file <%s> for safe execution.' % fname)
1994 warn('Could not open file <%s> for safe execution.' % fname)
1995 return
1995 return
1996
1996
1997 # Find things also in current directory. This is needed to mimic the
1997 # Find things also in current directory. This is needed to mimic the
1998 # behavior of running a script from the system command line, where
1998 # behavior of running a script from the system command line, where
1999 # Python inserts the script's directory into sys.path
1999 # Python inserts the script's directory into sys.path
2000 dname = os.path.dirname(fname)
2000 dname = os.path.dirname(fname)
2001
2001
2002 with prepended_to_syspath(dname):
2002 with prepended_to_syspath(dname):
2003 try:
2003 try:
2004 execfile(fname,*where)
2004 execfile(fname,*where)
2005 except SystemExit, status:
2005 except SystemExit, status:
2006 # If the call was made with 0 or None exit status (sys.exit(0)
2006 # If the call was made with 0 or None exit status (sys.exit(0)
2007 # or sys.exit() ), don't bother showing a traceback, as both of
2007 # or sys.exit() ), don't bother showing a traceback, as both of
2008 # these are considered normal by the OS:
2008 # these are considered normal by the OS:
2009 # > python -c'import sys;sys.exit(0)'; echo $?
2009 # > python -c'import sys;sys.exit(0)'; echo $?
2010 # 0
2010 # 0
2011 # > python -c'import sys;sys.exit()'; echo $?
2011 # > python -c'import sys;sys.exit()'; echo $?
2012 # 0
2012 # 0
2013 # For other exit status, we show the exception unless
2013 # For other exit status, we show the exception unless
2014 # explicitly silenced, but only in short form.
2014 # explicitly silenced, but only in short form.
2015 if status.code not in (0, None) and not kw['exit_ignore']:
2015 if status.code not in (0, None) and not kw['exit_ignore']:
2016 self.showtraceback(exception_only=True)
2016 self.showtraceback(exception_only=True)
2017 except:
2017 except:
2018 self.showtraceback()
2018 self.showtraceback()
2019
2019
2020 def safe_execfile_ipy(self, fname):
2020 def safe_execfile_ipy(self, fname):
2021 """Like safe_execfile, but for .ipy files with IPython syntax.
2021 """Like safe_execfile, but for .ipy files with IPython syntax.
2022
2022
2023 Parameters
2023 Parameters
2024 ----------
2024 ----------
2025 fname : str
2025 fname : str
2026 The name of the file to execute. The filename must have a
2026 The name of the file to execute. The filename must have a
2027 .ipy extension.
2027 .ipy extension.
2028 """
2028 """
2029 fname = os.path.abspath(os.path.expanduser(fname))
2029 fname = os.path.abspath(os.path.expanduser(fname))
2030
2030
2031 # Make sure we have a .py file
2031 # Make sure we have a .py file
2032 if not fname.endswith('.ipy'):
2032 if not fname.endswith('.ipy'):
2033 warn('File must end with .py to be run using execfile: <%s>' % fname)
2033 warn('File must end with .py to be run using execfile: <%s>' % fname)
2034
2034
2035 # Make sure we can open the file
2035 # Make sure we can open the file
2036 try:
2036 try:
2037 with open(fname) as thefile:
2037 with open(fname) as thefile:
2038 pass
2038 pass
2039 except:
2039 except:
2040 warn('Could not open file <%s> for safe execution.' % fname)
2040 warn('Could not open file <%s> for safe execution.' % fname)
2041 return
2041 return
2042
2042
2043 # Find things also in current directory. This is needed to mimic the
2043 # Find things also in current directory. This is needed to mimic the
2044 # behavior of running a script from the system command line, where
2044 # behavior of running a script from the system command line, where
2045 # Python inserts the script's directory into sys.path
2045 # Python inserts the script's directory into sys.path
2046 dname = os.path.dirname(fname)
2046 dname = os.path.dirname(fname)
2047
2047
2048 with prepended_to_syspath(dname):
2048 with prepended_to_syspath(dname):
2049 try:
2049 try:
2050 with open(fname) as thefile:
2050 with open(fname) as thefile:
2051 script = thefile.read()
2051 script = thefile.read()
2052 # self.runlines currently captures all exceptions
2052 # self.runlines currently captures all exceptions
2053 # raise in user code. It would be nice if there were
2053 # raise in user code. It would be nice if there were
2054 # versions of runlines, execfile that did raise, so
2054 # versions of runlines, execfile that did raise, so
2055 # we could catch the errors.
2055 # we could catch the errors.
2056 self.runlines(script, clean=True)
2056 self.runlines(script, clean=True)
2057 except:
2057 except:
2058 self.showtraceback()
2058 self.showtraceback()
2059 warn('Unknown failure executing file: <%s>' % fname)
2059 warn('Unknown failure executing file: <%s>' % fname)
2060
2060
2061 def _is_secondary_block_start(self, s):
2061 def _is_secondary_block_start(self, s):
2062 if not s.endswith(':'):
2062 if not s.endswith(':'):
2063 return False
2063 return False
2064 if (s.startswith('elif') or
2064 if (s.startswith('elif') or
2065 s.startswith('else') or
2065 s.startswith('else') or
2066 s.startswith('except') or
2066 s.startswith('except') or
2067 s.startswith('finally')):
2067 s.startswith('finally')):
2068 return True
2068 return True
2069
2069
2070 def cleanup_ipy_script(self, script):
2070 def cleanup_ipy_script(self, script):
2071 """Make a script safe for self.runlines()
2071 """Make a script safe for self.runlines()
2072
2072
2073 Currently, IPython is lines based, with blocks being detected by
2073 Currently, IPython is lines based, with blocks being detected by
2074 empty lines. This is a problem for block based scripts that may
2074 empty lines. This is a problem for block based scripts that may
2075 not have empty lines after blocks. This script adds those empty
2075 not have empty lines after blocks. This script adds those empty
2076 lines to make scripts safe for running in the current line based
2076 lines to make scripts safe for running in the current line based
2077 IPython.
2077 IPython.
2078 """
2078 """
2079 res = []
2079 res = []
2080 lines = script.splitlines()
2080 lines = script.splitlines()
2081 level = 0
2081 level = 0
2082
2082
2083 for l in lines:
2083 for l in lines:
2084 lstripped = l.lstrip()
2084 lstripped = l.lstrip()
2085 stripped = l.strip()
2085 stripped = l.strip()
2086 if not stripped:
2086 if not stripped:
2087 continue
2087 continue
2088 newlevel = len(l) - len(lstripped)
2088 newlevel = len(l) - len(lstripped)
2089 if level > 0 and newlevel == 0 and \
2089 if level > 0 and newlevel == 0 and \
2090 not self._is_secondary_block_start(stripped):
2090 not self._is_secondary_block_start(stripped):
2091 # add empty line
2091 # add empty line
2092 res.append('')
2092 res.append('')
2093 res.append(l)
2093 res.append(l)
2094 level = newlevel
2094 level = newlevel
2095
2095
2096 return '\n'.join(res) + '\n'
2096 return '\n'.join(res) + '\n'
2097
2097
2098 def runlines(self, lines, clean=False):
2098 def runlines(self, lines, clean=False):
2099 """Run a string of one or more lines of source.
2099 """Run a string of one or more lines of source.
2100
2100
2101 This method is capable of running a string containing multiple source
2101 This method is capable of running a string containing multiple source
2102 lines, as if they had been entered at the IPython prompt. Since it
2102 lines, as if they had been entered at the IPython prompt. Since it
2103 exposes IPython's processing machinery, the given strings can contain
2103 exposes IPython's processing machinery, the given strings can contain
2104 magic calls (%magic), special shell access (!cmd), etc.
2104 magic calls (%magic), special shell access (!cmd), etc.
2105 """
2105 """
2106
2106
2107 if isinstance(lines, (list, tuple)):
2107 if isinstance(lines, (list, tuple)):
2108 lines = '\n'.join(lines)
2108 lines = '\n'.join(lines)
2109
2109
2110 if clean:
2110 if clean:
2111 lines = self.cleanup_ipy_script(lines)
2111 lines = self.cleanup_ipy_script(lines)
2112
2112
2113 # We must start with a clean buffer, in case this is run from an
2113 # We must start with a clean buffer, in case this is run from an
2114 # interactive IPython session (via a magic, for example).
2114 # interactive IPython session (via a magic, for example).
2115 self.resetbuffer()
2115 self.resetbuffer()
2116 lines = lines.splitlines()
2116 lines = lines.splitlines()
2117 more = 0
2117 more = 0
2118
2118
2119 with nested(self.builtin_trap, self.display_trap):
2119 with nested(self.builtin_trap, self.display_trap):
2120 for line in lines:
2120 for line in lines:
2121 # skip blank lines so we don't mess up the prompt counter, but do
2121 # skip blank lines so we don't mess up the prompt counter, but do
2122 # NOT skip even a blank line if we are in a code block (more is
2122 # NOT skip even a blank line if we are in a code block (more is
2123 # true)
2123 # true)
2124
2124
2125 if line or more:
2125 if line or more:
2126 # push to raw history, so hist line numbers stay in sync
2126 # push to raw history, so hist line numbers stay in sync
2127 self.input_hist_raw.append("# " + line + "\n")
2127 self.input_hist_raw.append("# " + line + "\n")
2128 prefiltered = self.prefilter_manager.prefilter_lines(line,more)
2128 prefiltered = self.prefilter_manager.prefilter_lines(line,more)
2129 more = self.push_line(prefiltered)
2129 more = self.push_line(prefiltered)
2130 # IPython's runsource returns None if there was an error
2130 # IPython's runsource returns None if there was an error
2131 # compiling the code. This allows us to stop processing right
2131 # compiling the code. This allows us to stop processing right
2132 # away, so the user gets the error message at the right place.
2132 # away, so the user gets the error message at the right place.
2133 if more is None:
2133 if more is None:
2134 break
2134 break
2135 else:
2135 else:
2136 self.input_hist_raw.append("\n")
2136 self.input_hist_raw.append("\n")
2137 # final newline in case the input didn't have it, so that the code
2137 # final newline in case the input didn't have it, so that the code
2138 # actually does get executed
2138 # actually does get executed
2139 if more:
2139 if more:
2140 self.push_line('\n')
2140 self.push_line('\n')
2141
2141
2142 def runsource(self, source, filename='<input>', symbol='single'):
2142 def runsource(self, source, filename='<input>', symbol='single'):
2143 """Compile and run some source in the interpreter.
2143 """Compile and run some source in the interpreter.
2144
2144
2145 Arguments are as for compile_command().
2145 Arguments are as for compile_command().
2146
2146
2147 One several things can happen:
2147 One several things can happen:
2148
2148
2149 1) The input is incorrect; compile_command() raised an
2149 1) The input is incorrect; compile_command() raised an
2150 exception (SyntaxError or OverflowError). A syntax traceback
2150 exception (SyntaxError or OverflowError). A syntax traceback
2151 will be printed by calling the showsyntaxerror() method.
2151 will be printed by calling the showsyntaxerror() method.
2152
2152
2153 2) The input is incomplete, and more input is required;
2153 2) The input is incomplete, and more input is required;
2154 compile_command() returned None. Nothing happens.
2154 compile_command() returned None. Nothing happens.
2155
2155
2156 3) The input is complete; compile_command() returned a code
2156 3) The input is complete; compile_command() returned a code
2157 object. The code is executed by calling self.runcode() (which
2157 object. The code is executed by calling self.runcode() (which
2158 also handles run-time exceptions, except for SystemExit).
2158 also handles run-time exceptions, except for SystemExit).
2159
2159
2160 The return value is:
2160 The return value is:
2161
2161
2162 - True in case 2
2162 - True in case 2
2163
2163
2164 - False in the other cases, unless an exception is raised, where
2164 - False in the other cases, unless an exception is raised, where
2165 None is returned instead. This can be used by external callers to
2165 None is returned instead. This can be used by external callers to
2166 know whether to continue feeding input or not.
2166 know whether to continue feeding input or not.
2167
2167
2168 The return value can be used to decide whether to use sys.ps1 or
2168 The return value can be used to decide whether to use sys.ps1 or
2169 sys.ps2 to prompt the next line."""
2169 sys.ps2 to prompt the next line."""
2170
2170
2171 # if the source code has leading blanks, add 'if 1:\n' to it
2171 # if the source code has leading blanks, add 'if 1:\n' to it
2172 # this allows execution of indented pasted code. It is tempting
2172 # this allows execution of indented pasted code. It is tempting
2173 # to add '\n' at the end of source to run commands like ' a=1'
2173 # to add '\n' at the end of source to run commands like ' a=1'
2174 # directly, but this fails for more complicated scenarios
2174 # directly, but this fails for more complicated scenarios
2175 source=source.encode(self.stdin_encoding)
2175 source=source.encode(self.stdin_encoding)
2176 if source[:1] in [' ', '\t']:
2176 if source[:1] in [' ', '\t']:
2177 source = 'if 1:\n%s' % source
2177 source = 'if 1:\n%s' % source
2178
2178
2179 try:
2179 try:
2180 code = self.compile(source,filename,symbol)
2180 code = self.compile(source,filename,symbol)
2181 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2181 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2182 # Case 1
2182 # Case 1
2183 self.showsyntaxerror(filename)
2183 self.showsyntaxerror(filename)
2184 return None
2184 return None
2185
2185
2186 if code is None:
2186 if code is None:
2187 # Case 2
2187 # Case 2
2188 return True
2188 return True
2189
2189
2190 # Case 3
2190 # Case 3
2191 # We store the code object so that threaded shells and
2191 # We store the code object so that threaded shells and
2192 # custom exception handlers can access all this info if needed.
2192 # custom exception handlers can access all this info if needed.
2193 # The source corresponding to this can be obtained from the
2193 # The source corresponding to this can be obtained from the
2194 # buffer attribute as '\n'.join(self.buffer).
2194 # buffer attribute as '\n'.join(self.buffer).
2195 self.code_to_run = code
2195 self.code_to_run = code
2196 # now actually execute the code object
2196 # now actually execute the code object
2197 if self.runcode(code) == 0:
2197 if self.runcode(code) == 0:
2198 return False
2198 return False
2199 else:
2199 else:
2200 return None
2200 return None
2201
2201
2202 def runcode(self,code_obj):
2202 def runcode(self,code_obj):
2203 """Execute a code object.
2203 """Execute a code object.
2204
2204
2205 When an exception occurs, self.showtraceback() is called to display a
2205 When an exception occurs, self.showtraceback() is called to display a
2206 traceback.
2206 traceback.
2207
2207
2208 Return value: a flag indicating whether the code to be run completed
2208 Return value: a flag indicating whether the code to be run completed
2209 successfully:
2209 successfully:
2210
2210
2211 - 0: successful execution.
2211 - 0: successful execution.
2212 - 1: an error occurred.
2212 - 1: an error occurred.
2213 """
2213 """
2214
2214
2215 # Set our own excepthook in case the user code tries to call it
2215 # Set our own excepthook in case the user code tries to call it
2216 # directly, so that the IPython crash handler doesn't get triggered
2216 # directly, so that the IPython crash handler doesn't get triggered
2217 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2217 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2218
2218
2219 # we save the original sys.excepthook in the instance, in case config
2219 # we save the original sys.excepthook in the instance, in case config
2220 # code (such as magics) needs access to it.
2220 # code (such as magics) needs access to it.
2221 self.sys_excepthook = old_excepthook
2221 self.sys_excepthook = old_excepthook
2222 outflag = 1 # happens in more places, so it's easier as default
2222 outflag = 1 # happens in more places, so it's easier as default
2223 try:
2223 try:
2224 try:
2224 try:
2225 self.hooks.pre_runcode_hook()
2225 self.hooks.pre_runcode_hook()
2226 exec code_obj in self.user_global_ns, self.user_ns
2226 exec code_obj in self.user_global_ns, self.user_ns
2227 finally:
2227 finally:
2228 # Reset our crash handler in place
2228 # Reset our crash handler in place
2229 sys.excepthook = old_excepthook
2229 sys.excepthook = old_excepthook
2230 except SystemExit:
2230 except SystemExit:
2231 self.resetbuffer()
2231 self.resetbuffer()
2232 self.showtraceback(exception_only=True)
2232 self.showtraceback(exception_only=True)
2233 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2233 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2234 except self.custom_exceptions:
2234 except self.custom_exceptions:
2235 etype,value,tb = sys.exc_info()
2235 etype,value,tb = sys.exc_info()
2236 self.CustomTB(etype,value,tb)
2236 self.CustomTB(etype,value,tb)
2237 except:
2237 except:
2238 self.showtraceback()
2238 self.showtraceback()
2239 else:
2239 else:
2240 outflag = 0
2240 outflag = 0
2241 if softspace(sys.stdout, 0):
2241 if softspace(sys.stdout, 0):
2242 print
2242 print
2243 # Flush out code object which has been run (and source)
2243 # Flush out code object which has been run (and source)
2244 self.code_to_run = None
2244 self.code_to_run = None
2245 return outflag
2245 return outflag
2246
2246
2247 def push_line(self, line):
2247 def push_line(self, line):
2248 """Push a line to the interpreter.
2248 """Push a line to the interpreter.
2249
2249
2250 The line should not have a trailing newline; it may have
2250 The line should not have a trailing newline; it may have
2251 internal newlines. The line is appended to a buffer and the
2251 internal newlines. The line is appended to a buffer and the
2252 interpreter's runsource() method is called with the
2252 interpreter's runsource() method is called with the
2253 concatenated contents of the buffer as source. If this
2253 concatenated contents of the buffer as source. If this
2254 indicates that the command was executed or invalid, the buffer
2254 indicates that the command was executed or invalid, the buffer
2255 is reset; otherwise, the command is incomplete, and the buffer
2255 is reset; otherwise, the command is incomplete, and the buffer
2256 is left as it was after the line was appended. The return
2256 is left as it was after the line was appended. The return
2257 value is 1 if more input is required, 0 if the line was dealt
2257 value is 1 if more input is required, 0 if the line was dealt
2258 with in some way (this is the same as runsource()).
2258 with in some way (this is the same as runsource()).
2259 """
2259 """
2260
2260
2261 # autoindent management should be done here, and not in the
2261 # autoindent management should be done here, and not in the
2262 # interactive loop, since that one is only seen by keyboard input. We
2262 # interactive loop, since that one is only seen by keyboard input. We
2263 # need this done correctly even for code run via runlines (which uses
2263 # need this done correctly even for code run via runlines (which uses
2264 # push).
2264 # push).
2265
2265
2266 #print 'push line: <%s>' % line # dbg
2266 #print 'push line: <%s>' % line # dbg
2267 for subline in line.splitlines():
2267 for subline in line.splitlines():
2268 self._autoindent_update(subline)
2268 self._autoindent_update(subline)
2269 self.buffer.append(line)
2269 self.buffer.append(line)
2270 more = self.runsource('\n'.join(self.buffer), self.filename)
2270 more = self.runsource('\n'.join(self.buffer), self.filename)
2271 if not more:
2271 if not more:
2272 self.resetbuffer()
2272 self.resetbuffer()
2273 return more
2273 return more
2274
2274
2275 def _autoindent_update(self,line):
2275 def _autoindent_update(self,line):
2276 """Keep track of the indent level."""
2276 """Keep track of the indent level."""
2277
2277
2278 #debugx('line')
2278 #debugx('line')
2279 #debugx('self.indent_current_nsp')
2279 #debugx('self.indent_current_nsp')
2280 if self.autoindent:
2280 if self.autoindent:
2281 if line:
2281 if line:
2282 inisp = num_ini_spaces(line)
2282 inisp = num_ini_spaces(line)
2283 if inisp < self.indent_current_nsp:
2283 if inisp < self.indent_current_nsp:
2284 self.indent_current_nsp = inisp
2284 self.indent_current_nsp = inisp
2285
2285
2286 if line[-1] == ':':
2286 if line[-1] == ':':
2287 self.indent_current_nsp += 4
2287 self.indent_current_nsp += 4
2288 elif dedent_re.match(line):
2288 elif dedent_re.match(line):
2289 self.indent_current_nsp -= 4
2289 self.indent_current_nsp -= 4
2290 else:
2290 else:
2291 self.indent_current_nsp = 0
2291 self.indent_current_nsp = 0
2292
2292
2293 def resetbuffer(self):
2293 def resetbuffer(self):
2294 """Reset the input buffer."""
2294 """Reset the input buffer."""
2295 self.buffer[:] = []
2295 self.buffer[:] = []
2296
2296
2297 def raw_input(self,prompt='',continue_prompt=False):
2297 def raw_input(self,prompt='',continue_prompt=False):
2298 """Write a prompt and read a line.
2298 """Write a prompt and read a line.
2299
2299
2300 The returned line does not include the trailing newline.
2300 The returned line does not include the trailing newline.
2301 When the user enters the EOF key sequence, EOFError is raised.
2301 When the user enters the EOF key sequence, EOFError is raised.
2302
2302
2303 Optional inputs:
2303 Optional inputs:
2304
2304
2305 - prompt(''): a string to be printed to prompt the user.
2305 - prompt(''): a string to be printed to prompt the user.
2306
2306
2307 - continue_prompt(False): whether this line is the first one or a
2307 - continue_prompt(False): whether this line is the first one or a
2308 continuation in a sequence of inputs.
2308 continuation in a sequence of inputs.
2309 """
2309 """
2310 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2310 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2311
2311
2312 # Code run by the user may have modified the readline completer state.
2312 # Code run by the user may have modified the readline completer state.
2313 # We must ensure that our completer is back in place.
2313 # We must ensure that our completer is back in place.
2314
2314
2315 if self.has_readline:
2315 if self.has_readline:
2316 self.set_completer()
2316 self.set_completer()
2317
2317
2318 try:
2318 try:
2319 line = raw_input_original(prompt).decode(self.stdin_encoding)
2319 line = raw_input_original(prompt).decode(self.stdin_encoding)
2320 except ValueError:
2320 except ValueError:
2321 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
2321 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
2322 " or sys.stdout.close()!\nExiting IPython!")
2322 " or sys.stdout.close()!\nExiting IPython!")
2323 self.ask_exit()
2323 self.ask_exit()
2324 return ""
2324 return ""
2325
2325
2326 # Try to be reasonably smart about not re-indenting pasted input more
2326 # Try to be reasonably smart about not re-indenting pasted input more
2327 # than necessary. We do this by trimming out the auto-indent initial
2327 # than necessary. We do this by trimming out the auto-indent initial
2328 # spaces, if the user's actual input started itself with whitespace.
2328 # spaces, if the user's actual input started itself with whitespace.
2329 #debugx('self.buffer[-1]')
2329 #debugx('self.buffer[-1]')
2330
2330
2331 if self.autoindent:
2331 if self.autoindent:
2332 if num_ini_spaces(line) > self.indent_current_nsp:
2332 if num_ini_spaces(line) > self.indent_current_nsp:
2333 line = line[self.indent_current_nsp:]
2333 line = line[self.indent_current_nsp:]
2334 self.indent_current_nsp = 0
2334 self.indent_current_nsp = 0
2335
2335
2336 # store the unfiltered input before the user has any chance to modify
2336 # store the unfiltered input before the user has any chance to modify
2337 # it.
2337 # it.
2338 if line.strip():
2338 if line.strip():
2339 if continue_prompt:
2339 if continue_prompt:
2340 self.input_hist_raw[-1] += '%s\n' % line
2340 self.input_hist_raw[-1] += '%s\n' % line
2341 if self.has_readline and self.readline_use:
2341 if self.has_readline and self.readline_use:
2342 try:
2342 try:
2343 histlen = self.readline.get_current_history_length()
2343 histlen = self.readline.get_current_history_length()
2344 if histlen > 1:
2344 if histlen > 1:
2345 newhist = self.input_hist_raw[-1].rstrip()
2345 newhist = self.input_hist_raw[-1].rstrip()
2346 self.readline.remove_history_item(histlen-1)
2346 self.readline.remove_history_item(histlen-1)
2347 self.readline.replace_history_item(histlen-2,
2347 self.readline.replace_history_item(histlen-2,
2348 newhist.encode(self.stdin_encoding))
2348 newhist.encode(self.stdin_encoding))
2349 except AttributeError:
2349 except AttributeError:
2350 pass # re{move,place}_history_item are new in 2.4.
2350 pass # re{move,place}_history_item are new in 2.4.
2351 else:
2351 else:
2352 self.input_hist_raw.append('%s\n' % line)
2352 self.input_hist_raw.append('%s\n' % line)
2353 # only entries starting at first column go to shadow history
2353 # only entries starting at first column go to shadow history
2354 if line.lstrip() == line:
2354 if line.lstrip() == line:
2355 self.shadowhist.add(line.strip())
2355 self.shadowhist.add(line.strip())
2356 elif not continue_prompt:
2356 elif not continue_prompt:
2357 self.input_hist_raw.append('\n')
2357 self.input_hist_raw.append('\n')
2358 try:
2358 try:
2359 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2359 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2360 except:
2360 except:
2361 # blanket except, in case a user-defined prefilter crashes, so it
2361 # blanket except, in case a user-defined prefilter crashes, so it
2362 # can't take all of ipython with it.
2362 # can't take all of ipython with it.
2363 self.showtraceback()
2363 self.showtraceback()
2364 return ''
2364 return ''
2365 else:
2365 else:
2366 return lineout
2366 return lineout
2367
2367
2368 #-------------------------------------------------------------------------
2368 #-------------------------------------------------------------------------
2369 # Things related to the prefilter
2369 # Things related to the prefilter
2370 #-------------------------------------------------------------------------
2370 #-------------------------------------------------------------------------
2371
2371
2372 def init_prefilter(self):
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 # Ultimately this will be refactored in the new interpreter code, but
2374 # Ultimately this will be refactored in the new interpreter code, but
2375 # for now, we should expose the main prefilter method (there's legacy
2375 # for now, we should expose the main prefilter method (there's legacy
2376 # code out there that may rely on this).
2376 # code out there that may rely on this).
2377 self.prefilter = self.prefilter_manager.prefilter_lines
2377 self.prefilter = self.prefilter_manager.prefilter_lines
2378
2378
2379 #-------------------------------------------------------------------------
2379 #-------------------------------------------------------------------------
2380 # Utilities
2380 # Utilities
2381 #-------------------------------------------------------------------------
2381 #-------------------------------------------------------------------------
2382
2382
2383 def getoutput(self, cmd):
2383 def getoutput(self, cmd):
2384 return getoutput(self.var_expand(cmd,depth=2),
2384 return getoutput(self.var_expand(cmd,depth=2),
2385 header=self.system_header,
2385 header=self.system_header,
2386 verbose=self.system_verbose)
2386 verbose=self.system_verbose)
2387
2387
2388 def getoutputerror(self, cmd):
2388 def getoutputerror(self, cmd):
2389 return getoutputerror(self.var_expand(cmd,depth=2),
2389 return getoutputerror(self.var_expand(cmd,depth=2),
2390 header=self.system_header,
2390 header=self.system_header,
2391 verbose=self.system_verbose)
2391 verbose=self.system_verbose)
2392
2392
2393 def var_expand(self,cmd,depth=0):
2393 def var_expand(self,cmd,depth=0):
2394 """Expand python variables in a string.
2394 """Expand python variables in a string.
2395
2395
2396 The depth argument indicates how many frames above the caller should
2396 The depth argument indicates how many frames above the caller should
2397 be walked to look for the local namespace where to expand variables.
2397 be walked to look for the local namespace where to expand variables.
2398
2398
2399 The global namespace for expansion is always the user's interactive
2399 The global namespace for expansion is always the user's interactive
2400 namespace.
2400 namespace.
2401 """
2401 """
2402
2402
2403 return str(ItplNS(cmd,
2403 return str(ItplNS(cmd,
2404 self.user_ns, # globals
2404 self.user_ns, # globals
2405 # Skip our own frame in searching for locals:
2405 # Skip our own frame in searching for locals:
2406 sys._getframe(depth+1).f_locals # locals
2406 sys._getframe(depth+1).f_locals # locals
2407 ))
2407 ))
2408
2408
2409 def mktempfile(self,data=None):
2409 def mktempfile(self,data=None):
2410 """Make a new tempfile and return its filename.
2410 """Make a new tempfile and return its filename.
2411
2411
2412 This makes a call to tempfile.mktemp, but it registers the created
2412 This makes a call to tempfile.mktemp, but it registers the created
2413 filename internally so ipython cleans it up at exit time.
2413 filename internally so ipython cleans it up at exit time.
2414
2414
2415 Optional inputs:
2415 Optional inputs:
2416
2416
2417 - data(None): if data is given, it gets written out to the temp file
2417 - data(None): if data is given, it gets written out to the temp file
2418 immediately, and the file is closed again."""
2418 immediately, and the file is closed again."""
2419
2419
2420 filename = tempfile.mktemp('.py','ipython_edit_')
2420 filename = tempfile.mktemp('.py','ipython_edit_')
2421 self.tempfiles.append(filename)
2421 self.tempfiles.append(filename)
2422
2422
2423 if data:
2423 if data:
2424 tmp_file = open(filename,'w')
2424 tmp_file = open(filename,'w')
2425 tmp_file.write(data)
2425 tmp_file.write(data)
2426 tmp_file.close()
2426 tmp_file.close()
2427 return filename
2427 return filename
2428
2428
2429 def write(self,data):
2429 def write(self,data):
2430 """Write a string to the default output"""
2430 """Write a string to the default output"""
2431 Term.cout.write(data)
2431 Term.cout.write(data)
2432
2432
2433 def write_err(self,data):
2433 def write_err(self,data):
2434 """Write a string to the default error output"""
2434 """Write a string to the default error output"""
2435 Term.cerr.write(data)
2435 Term.cerr.write(data)
2436
2436
2437 def ask_yes_no(self,prompt,default=True):
2437 def ask_yes_no(self,prompt,default=True):
2438 if self.quiet:
2438 if self.quiet:
2439 return True
2439 return True
2440 return ask_yes_no(prompt,default)
2440 return ask_yes_no(prompt,default)
2441
2441
2442 #-------------------------------------------------------------------------
2442 #-------------------------------------------------------------------------
2443 # Things related to GUI support and pylab
2443 # Things related to GUI support and pylab
2444 #-------------------------------------------------------------------------
2444 #-------------------------------------------------------------------------
2445
2445
2446 def enable_pylab(self, gui=None):
2446 def enable_pylab(self, gui=None):
2447 """Activate pylab support at runtime.
2447 """Activate pylab support at runtime.
2448
2448
2449 This turns on support for matplotlib, preloads into the interactive
2449 This turns on support for matplotlib, preloads into the interactive
2450 namespace all of numpy and pylab, and configures IPython to correcdtly
2450 namespace all of numpy and pylab, and configures IPython to correcdtly
2451 interact with the GUI event loop. The GUI backend to be used can be
2451 interact with the GUI event loop. The GUI backend to be used can be
2452 optionally selected with the optional :param:`gui` argument.
2452 optionally selected with the optional :param:`gui` argument.
2453
2453
2454 Parameters
2454 Parameters
2455 ----------
2455 ----------
2456 gui : optional, string
2456 gui : optional, string
2457
2457
2458 If given, dictates the choice of matplotlib GUI backend to use
2458 If given, dictates the choice of matplotlib GUI backend to use
2459 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
2459 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
2460 'gtk'), otherwise we use the default chosen by matplotlib (as
2460 'gtk'), otherwise we use the default chosen by matplotlib (as
2461 dictated by the matplotlib build-time options plus the user's
2461 dictated by the matplotlib build-time options plus the user's
2462 matplotlibrc configuration file).
2462 matplotlibrc configuration file).
2463 """
2463 """
2464 # We want to prevent the loading of pylab to pollute the user's
2464 # We want to prevent the loading of pylab to pollute the user's
2465 # namespace as shown by the %who* magics, so we execute the activation
2465 # namespace as shown by the %who* magics, so we execute the activation
2466 # code in an empty namespace, and we update *both* user_ns and
2466 # code in an empty namespace, and we update *both* user_ns and
2467 # user_ns_hidden with this information.
2467 # user_ns_hidden with this information.
2468 ns = {}
2468 ns = {}
2469 gui = pylab_activate(ns, gui)
2469 gui = pylab_activate(ns, gui)
2470 self.user_ns.update(ns)
2470 self.user_ns.update(ns)
2471 self.user_ns_hidden.update(ns)
2471 self.user_ns_hidden.update(ns)
2472 # Now we must activate the gui pylab wants to use, and fix %run to take
2472 # Now we must activate the gui pylab wants to use, and fix %run to take
2473 # plot updates into account
2473 # plot updates into account
2474 enable_gui(gui)
2474 enable_gui(gui)
2475 self.magic_run = self._pylab_magic_run
2475 self.magic_run = self._pylab_magic_run
2476
2476
2477 #-------------------------------------------------------------------------
2477 #-------------------------------------------------------------------------
2478 # Things related to IPython exiting
2478 # Things related to IPython exiting
2479 #-------------------------------------------------------------------------
2479 #-------------------------------------------------------------------------
2480
2480
2481 def ask_exit(self):
2481 def ask_exit(self):
2482 """ Ask the shell to exit. Can be overiden and used as a callback. """
2482 """ Ask the shell to exit. Can be overiden and used as a callback. """
2483 self.exit_now = True
2483 self.exit_now = True
2484
2484
2485 def exit(self):
2485 def exit(self):
2486 """Handle interactive exit.
2486 """Handle interactive exit.
2487
2487
2488 This method calls the ask_exit callback."""
2488 This method calls the ask_exit callback."""
2489 if self.confirm_exit:
2489 if self.confirm_exit:
2490 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
2490 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
2491 self.ask_exit()
2491 self.ask_exit()
2492 else:
2492 else:
2493 self.ask_exit()
2493 self.ask_exit()
2494
2494
2495 def atexit_operations(self):
2495 def atexit_operations(self):
2496 """This will be executed at the time of exit.
2496 """This will be executed at the time of exit.
2497
2497
2498 Saving of persistent data should be performed here.
2498 Saving of persistent data should be performed here.
2499 """
2499 """
2500 self.savehist()
2500 self.savehist()
2501
2501
2502 # Cleanup all tempfiles left around
2502 # Cleanup all tempfiles left around
2503 for tfile in self.tempfiles:
2503 for tfile in self.tempfiles:
2504 try:
2504 try:
2505 os.unlink(tfile)
2505 os.unlink(tfile)
2506 except OSError:
2506 except OSError:
2507 pass
2507 pass
2508
2508
2509 # Clear all user namespaces to release all references cleanly.
2509 # Clear all user namespaces to release all references cleanly.
2510 self.reset()
2510 self.reset()
2511
2511
2512 # Run user hooks
2512 # Run user hooks
2513 self.hooks.shutdown_hook()
2513 self.hooks.shutdown_hook()
2514
2514
2515 def cleanup(self):
2515 def cleanup(self):
2516 self.restore_sys_module_state()
2516 self.restore_sys_module_state()
2517
2517
2518
2518
2519 class InteractiveShellABC(object):
2519 class InteractiveShellABC(object):
2520 """An abstract base class for InteractiveShell."""
2520 """An abstract base class for InteractiveShell."""
2521 __metaclass__ = abc.ABCMeta
2521 __metaclass__ = abc.ABCMeta
2522
2522
2523 InteractiveShellABC.register(InteractiveShell)
2523 InteractiveShellABC.register(InteractiveShell)
@@ -1,1016 +1,1022 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Prefiltering components.
4 Prefiltering components.
5
5
6 Prefilters transform user input before it is exec'd by Python. These
6 Prefilters transform user input before it is exec'd by Python. These
7 transforms are used to implement additional syntax such as !ls and %magic.
7 transforms are used to implement additional syntax such as !ls and %magic.
8
8
9 Authors:
9 Authors:
10
10
11 * Brian Granger
11 * Brian Granger
12 * Fernando Perez
12 * Fernando Perez
13 * Dan Milstein
13 * Dan Milstein
14 * Ville Vainio
14 * Ville Vainio
15 """
15 """
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2008-2009 The IPython Development Team
18 # Copyright (C) 2008-2009 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 import __builtin__
28 import __builtin__
29 import codeop
29 import codeop
30 import re
30 import re
31
31
32 from IPython.core.alias import AliasManager
32 from IPython.core.alias import AliasManager
33 from IPython.core.autocall import IPyAutocall
33 from IPython.core.autocall import IPyAutocall
34 from IPython.config.configurable import Configurable
34 from IPython.config.configurable import Configurable
35 from IPython.core.splitinput import split_user_input
35 from IPython.core.splitinput import split_user_input
36 from IPython.core.page import page
36 from IPython.core.page import page
37
37
38 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool, Instance
38 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool, Instance
39 from IPython.utils.io import Term
39 from IPython.utils.io import Term
40 from IPython.utils.text import make_quoted_expr
40 from IPython.utils.text import make_quoted_expr
41 from IPython.utils.autoattr import auto_attr
41 from IPython.utils.autoattr import auto_attr
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Global utilities, errors and constants
44 # Global utilities, errors and constants
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 # Warning, these cannot be changed unless various regular expressions
47 # Warning, these cannot be changed unless various regular expressions
48 # are updated in a number of places. Not great, but at least we told you.
48 # are updated in a number of places. Not great, but at least we told you.
49 ESC_SHELL = '!'
49 ESC_SHELL = '!'
50 ESC_SH_CAP = '!!'
50 ESC_SH_CAP = '!!'
51 ESC_HELP = '?'
51 ESC_HELP = '?'
52 ESC_MAGIC = '%'
52 ESC_MAGIC = '%'
53 ESC_QUOTE = ','
53 ESC_QUOTE = ','
54 ESC_QUOTE2 = ';'
54 ESC_QUOTE2 = ';'
55 ESC_PAREN = '/'
55 ESC_PAREN = '/'
56
56
57
57
58 class PrefilterError(Exception):
58 class PrefilterError(Exception):
59 pass
59 pass
60
60
61
61
62 # RegExp to identify potential function names
62 # RegExp to identify potential function names
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
64
64
65 # RegExp to exclude strings with this start from autocalling. In
65 # RegExp to exclude strings with this start from autocalling. In
66 # particular, all binary operators should be excluded, so that if foo is
66 # particular, all binary operators should be excluded, so that if foo is
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
69 # routine explicitely does so, to catch direct calls and rebindings of
69 # routine explicitely does so, to catch direct calls and rebindings of
70 # existing names.
70 # existing names.
71
71
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
73 # it affects the rest of the group in square brackets.
73 # it affects the rest of the group in square brackets.
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
75 r'|^is |^not |^in |^and |^or ')
75 r'|^is |^not |^in |^and |^or ')
76
76
77 # try to catch also methods for stuff in lists/tuples/dicts: off
77 # try to catch also methods for stuff in lists/tuples/dicts: off
78 # (experimental). For this to work, the line_split regexp would need
78 # (experimental). For this to work, the line_split regexp would need
79 # to be modified so it wouldn't break things at '['. That line is
79 # to be modified so it wouldn't break things at '['. That line is
80 # nasty enough that I shouldn't change it until I can test it _well_.
80 # nasty enough that I shouldn't change it until I can test it _well_.
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
82
82
83
83
84 # Handler Check Utilities
84 # Handler Check Utilities
85 def is_shadowed(identifier, ip):
85 def is_shadowed(identifier, ip):
86 """Is the given identifier defined in one of the namespaces which shadow
86 """Is the given identifier defined in one of the namespaces which shadow
87 the alias and magic namespaces? Note that an identifier is different
87 the alias and magic namespaces? Note that an identifier is different
88 than ifun, because it can not contain a '.' character."""
88 than ifun, because it can not contain a '.' character."""
89 # This is much safer than calling ofind, which can change state
89 # This is much safer than calling ofind, which can change state
90 return (identifier in ip.user_ns \
90 return (identifier in ip.user_ns \
91 or identifier in ip.internal_ns \
91 or identifier in ip.internal_ns \
92 or identifier in ip.ns_table['builtin'])
92 or identifier in ip.ns_table['builtin'])
93
93
94
94
95 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
96 # The LineInfo class used throughout
96 # The LineInfo class used throughout
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98
98
99
99
100 class LineInfo(object):
100 class LineInfo(object):
101 """A single line of input and associated info.
101 """A single line of input and associated info.
102
102
103 Includes the following as properties:
103 Includes the following as properties:
104
104
105 line
105 line
106 The original, raw line
106 The original, raw line
107
107
108 continue_prompt
108 continue_prompt
109 Is this line a continuation in a sequence of multiline input?
109 Is this line a continuation in a sequence of multiline input?
110
110
111 pre
111 pre
112 The initial esc character or whitespace.
112 The initial esc character or whitespace.
113
113
114 pre_char
114 pre_char
115 The escape character(s) in pre or the empty string if there isn't one.
115 The escape character(s) in pre or the empty string if there isn't one.
116 Note that '!!' is a possible value for pre_char. Otherwise it will
116 Note that '!!' is a possible value for pre_char. Otherwise it will
117 always be a single character.
117 always be a single character.
118
118
119 pre_whitespace
119 pre_whitespace
120 The leading whitespace from pre if it exists. If there is a pre_char,
120 The leading whitespace from pre if it exists. If there is a pre_char,
121 this is just ''.
121 this is just ''.
122
122
123 ifun
123 ifun
124 The 'function part', which is basically the maximal initial sequence
124 The 'function part', which is basically the maximal initial sequence
125 of valid python identifiers and the '.' character. This is what is
125 of valid python identifiers and the '.' character. This is what is
126 checked for alias and magic transformations, used for auto-calling,
126 checked for alias and magic transformations, used for auto-calling,
127 etc.
127 etc.
128
128
129 the_rest
129 the_rest
130 Everything else on the line.
130 Everything else on the line.
131 """
131 """
132 def __init__(self, line, continue_prompt):
132 def __init__(self, line, continue_prompt):
133 self.line = line
133 self.line = line
134 self.continue_prompt = continue_prompt
134 self.continue_prompt = continue_prompt
135 self.pre, self.ifun, self.the_rest = split_user_input(line)
135 self.pre, self.ifun, self.the_rest = split_user_input(line)
136
136
137 self.pre_char = self.pre.strip()
137 self.pre_char = self.pre.strip()
138 if self.pre_char:
138 if self.pre_char:
139 self.pre_whitespace = '' # No whitespace allowd before esc chars
139 self.pre_whitespace = '' # No whitespace allowd before esc chars
140 else:
140 else:
141 self.pre_whitespace = self.pre
141 self.pre_whitespace = self.pre
142
142
143 self._oinfo = None
143 self._oinfo = None
144
144
145 def ofind(self, ip):
145 def ofind(self, ip):
146 """Do a full, attribute-walking lookup of the ifun in the various
146 """Do a full, attribute-walking lookup of the ifun in the various
147 namespaces for the given IPython InteractiveShell instance.
147 namespaces for the given IPython InteractiveShell instance.
148
148
149 Return a dict with keys: found,obj,ospace,ismagic
149 Return a dict with keys: found,obj,ospace,ismagic
150
150
151 Note: can cause state changes because of calling getattr, but should
151 Note: can cause state changes because of calling getattr, but should
152 only be run if autocall is on and if the line hasn't matched any
152 only be run if autocall is on and if the line hasn't matched any
153 other, less dangerous handlers.
153 other, less dangerous handlers.
154
154
155 Does cache the results of the call, so can be called multiple times
155 Does cache the results of the call, so can be called multiple times
156 without worrying about *further* damaging state.
156 without worrying about *further* damaging state.
157 """
157 """
158 if not self._oinfo:
158 if not self._oinfo:
159 # ip.shell._ofind is actually on the Magic class!
159 # ip.shell._ofind is actually on the Magic class!
160 self._oinfo = ip.shell._ofind(self.ifun)
160 self._oinfo = ip.shell._ofind(self.ifun)
161 return self._oinfo
161 return self._oinfo
162
162
163 def __str__(self):
163 def __str__(self):
164 return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest)
164 return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest)
165
165
166
166
167 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
168 # Main Prefilter manager
168 # Main Prefilter manager
169 #-----------------------------------------------------------------------------
169 #-----------------------------------------------------------------------------
170
170
171
171
172 class PrefilterManager(Configurable):
172 class PrefilterManager(Configurable):
173 """Main prefilter component.
173 """Main prefilter component.
174
174
175 The IPython prefilter is run on all user input before it is run. The
175 The IPython prefilter is run on all user input before it is run. The
176 prefilter consumes lines of input and produces transformed lines of
176 prefilter consumes lines of input and produces transformed lines of
177 input.
177 input.
178
178
179 The iplementation consists of two phases:
179 The iplementation consists of two phases:
180
180
181 1. Transformers
181 1. Transformers
182 2. Checkers and handlers
182 2. Checkers and handlers
183
183
184 Over time, we plan on deprecating the checkers and handlers and doing
184 Over time, we plan on deprecating the checkers and handlers and doing
185 everything in the transformers.
185 everything in the transformers.
186
186
187 The transformers are instances of :class:`PrefilterTransformer` and have
187 The transformers are instances of :class:`PrefilterTransformer` and have
188 a single method :meth:`transform` that takes a line and returns a
188 a single method :meth:`transform` that takes a line and returns a
189 transformed line. The transformation can be accomplished using any
189 transformed line. The transformation can be accomplished using any
190 tool, but our current ones use regular expressions for speed. We also
190 tool, but our current ones use regular expressions for speed. We also
191 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
191 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
192
192
193 After all the transformers have been run, the line is fed to the checkers,
193 After all the transformers have been run, the line is fed to the checkers,
194 which are instances of :class:`PrefilterChecker`. The line is passed to
194 which are instances of :class:`PrefilterChecker`. The line is passed to
195 the :meth:`check` method, which either returns `None` or a
195 the :meth:`check` method, which either returns `None` or a
196 :class:`PrefilterHandler` instance. If `None` is returned, the other
196 :class:`PrefilterHandler` instance. If `None` is returned, the other
197 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
197 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
198 the line is passed to the :meth:`handle` method of the returned
198 the line is passed to the :meth:`handle` method of the returned
199 handler and no further checkers are tried.
199 handler and no further checkers are tried.
200
200
201 Both transformers and checkers have a `priority` attribute, that determines
201 Both transformers and checkers have a `priority` attribute, that determines
202 the order in which they are called. Smaller priorities are tried first.
202 the order in which they are called. Smaller priorities are tried first.
203
203
204 Both transformers and checkers also have `enabled` attribute, which is
204 Both transformers and checkers also have `enabled` attribute, which is
205 a boolean that determines if the instance is used.
205 a boolean that determines if the instance is used.
206
206
207 Users or developers can change the priority or enabled attribute of
207 Users or developers can change the priority or enabled attribute of
208 transformers or checkers, but they must call the :meth:`sort_checkers`
208 transformers or checkers, but they must call the :meth:`sort_checkers`
209 or :meth:`sort_transformers` method after changing the priority.
209 or :meth:`sort_transformers` method after changing the priority.
210 """
210 """
211
211
212 multi_line_specials = CBool(True, config=True)
212 multi_line_specials = CBool(True, config=True)
213 shell = Instance('IPython.core.iplib.InteractiveShellABC')
213 shell = Instance('IPython.core.iplib.InteractiveShellABC')
214
214
215 def __init__(self, shell, config=None):
215 def __init__(self, shell=None, config=None):
216 super(PrefilterManager, self).__init__(config=config)
216 super(PrefilterManager, self).__init__(shell=shell, config=config)
217 self.shell = shell
217 self.shell = shell
218 self.init_transformers()
218 self.init_transformers()
219 self.init_handlers()
219 self.init_handlers()
220 self.init_checkers()
220 self.init_checkers()
221
221
222 #-------------------------------------------------------------------------
222 #-------------------------------------------------------------------------
223 # API for managing transformers
223 # API for managing transformers
224 #-------------------------------------------------------------------------
224 #-------------------------------------------------------------------------
225
225
226 def init_transformers(self):
226 def init_transformers(self):
227 """Create the default transformers."""
227 """Create the default transformers."""
228 self._transformers = []
228 self._transformers = []
229 for transformer_cls in _default_transformers:
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 def sort_transformers(self):
234 def sort_transformers(self):
233 """Sort the transformers by priority.
235 """Sort the transformers by priority.
234
236
235 This must be called after the priority of a transformer is changed.
237 This must be called after the priority of a transformer is changed.
236 The :meth:`register_transformer` method calls this automatically.
238 The :meth:`register_transformer` method calls this automatically.
237 """
239 """
238 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
240 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
239
241
240 @property
242 @property
241 def transformers(self):
243 def transformers(self):
242 """Return a list of checkers, sorted by priority."""
244 """Return a list of checkers, sorted by priority."""
243 return self._transformers
245 return self._transformers
244
246
245 def register_transformer(self, transformer):
247 def register_transformer(self, transformer):
246 """Register a transformer instance."""
248 """Register a transformer instance."""
247 if transformer not in self._transformers:
249 if transformer not in self._transformers:
248 self._transformers.append(transformer)
250 self._transformers.append(transformer)
249 self.sort_transformers()
251 self.sort_transformers()
250
252
251 def unregister_transformer(self, transformer):
253 def unregister_transformer(self, transformer):
252 """Unregister a transformer instance."""
254 """Unregister a transformer instance."""
253 if transformer in self._transformers:
255 if transformer in self._transformers:
254 self._transformers.remove(transformer)
256 self._transformers.remove(transformer)
255
257
256 #-------------------------------------------------------------------------
258 #-------------------------------------------------------------------------
257 # API for managing checkers
259 # API for managing checkers
258 #-------------------------------------------------------------------------
260 #-------------------------------------------------------------------------
259
261
260 def init_checkers(self):
262 def init_checkers(self):
261 """Create the default checkers."""
263 """Create the default checkers."""
262 self._checkers = []
264 self._checkers = []
263 for checker in _default_checkers:
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 def sort_checkers(self):
270 def sort_checkers(self):
267 """Sort the checkers by priority.
271 """Sort the checkers by priority.
268
272
269 This must be called after the priority of a checker is changed.
273 This must be called after the priority of a checker is changed.
270 The :meth:`register_checker` method calls this automatically.
274 The :meth:`register_checker` method calls this automatically.
271 """
275 """
272 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
276 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
273
277
274 @property
278 @property
275 def checkers(self):
279 def checkers(self):
276 """Return a list of checkers, sorted by priority."""
280 """Return a list of checkers, sorted by priority."""
277 return self._checkers
281 return self._checkers
278
282
279 def register_checker(self, checker):
283 def register_checker(self, checker):
280 """Register a checker instance."""
284 """Register a checker instance."""
281 if checker not in self._checkers:
285 if checker not in self._checkers:
282 self._checkers.append(checker)
286 self._checkers.append(checker)
283 self.sort_checkers()
287 self.sort_checkers()
284
288
285 def unregister_checker(self, checker):
289 def unregister_checker(self, checker):
286 """Unregister a checker instance."""
290 """Unregister a checker instance."""
287 if checker in self._checkers:
291 if checker in self._checkers:
288 self._checkers.remove(checker)
292 self._checkers.remove(checker)
289
293
290 #-------------------------------------------------------------------------
294 #-------------------------------------------------------------------------
291 # API for managing checkers
295 # API for managing checkers
292 #-------------------------------------------------------------------------
296 #-------------------------------------------------------------------------
293
297
294 def init_handlers(self):
298 def init_handlers(self):
295 """Create the default handlers."""
299 """Create the default handlers."""
296 self._handlers = {}
300 self._handlers = {}
297 self._esc_handlers = {}
301 self._esc_handlers = {}
298 for handler in _default_handlers:
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 @property
307 @property
302 def handlers(self):
308 def handlers(self):
303 """Return a dict of all the handlers."""
309 """Return a dict of all the handlers."""
304 return self._handlers
310 return self._handlers
305
311
306 def register_handler(self, name, handler, esc_strings):
312 def register_handler(self, name, handler, esc_strings):
307 """Register a handler instance by name with esc_strings."""
313 """Register a handler instance by name with esc_strings."""
308 self._handlers[name] = handler
314 self._handlers[name] = handler
309 for esc_str in esc_strings:
315 for esc_str in esc_strings:
310 self._esc_handlers[esc_str] = handler
316 self._esc_handlers[esc_str] = handler
311
317
312 def unregister_handler(self, name, handler, esc_strings):
318 def unregister_handler(self, name, handler, esc_strings):
313 """Unregister a handler instance by name with esc_strings."""
319 """Unregister a handler instance by name with esc_strings."""
314 try:
320 try:
315 del self._handlers[name]
321 del self._handlers[name]
316 except KeyError:
322 except KeyError:
317 pass
323 pass
318 for esc_str in esc_strings:
324 for esc_str in esc_strings:
319 h = self._esc_handlers.get(esc_str)
325 h = self._esc_handlers.get(esc_str)
320 if h is handler:
326 if h is handler:
321 del self._esc_handlers[esc_str]
327 del self._esc_handlers[esc_str]
322
328
323 def get_handler_by_name(self, name):
329 def get_handler_by_name(self, name):
324 """Get a handler by its name."""
330 """Get a handler by its name."""
325 return self._handlers.get(name)
331 return self._handlers.get(name)
326
332
327 def get_handler_by_esc(self, esc_str):
333 def get_handler_by_esc(self, esc_str):
328 """Get a handler by its escape string."""
334 """Get a handler by its escape string."""
329 return self._esc_handlers.get(esc_str)
335 return self._esc_handlers.get(esc_str)
330
336
331 #-------------------------------------------------------------------------
337 #-------------------------------------------------------------------------
332 # Main prefiltering API
338 # Main prefiltering API
333 #-------------------------------------------------------------------------
339 #-------------------------------------------------------------------------
334
340
335 def prefilter_line_info(self, line_info):
341 def prefilter_line_info(self, line_info):
336 """Prefilter a line that has been converted to a LineInfo object.
342 """Prefilter a line that has been converted to a LineInfo object.
337
343
338 This implements the checker/handler part of the prefilter pipe.
344 This implements the checker/handler part of the prefilter pipe.
339 """
345 """
340 # print "prefilter_line_info: ", line_info
346 # print "prefilter_line_info: ", line_info
341 handler = self.find_handler(line_info)
347 handler = self.find_handler(line_info)
342 return handler.handle(line_info)
348 return handler.handle(line_info)
343
349
344 def find_handler(self, line_info):
350 def find_handler(self, line_info):
345 """Find a handler for the line_info by trying checkers."""
351 """Find a handler for the line_info by trying checkers."""
346 for checker in self.checkers:
352 for checker in self.checkers:
347 if checker.enabled:
353 if checker.enabled:
348 handler = checker.check(line_info)
354 handler = checker.check(line_info)
349 if handler:
355 if handler:
350 return handler
356 return handler
351 return self.get_handler_by_name('normal')
357 return self.get_handler_by_name('normal')
352
358
353 def transform_line(self, line, continue_prompt):
359 def transform_line(self, line, continue_prompt):
354 """Calls the enabled transformers in order of increasing priority."""
360 """Calls the enabled transformers in order of increasing priority."""
355 for transformer in self.transformers:
361 for transformer in self.transformers:
356 if transformer.enabled:
362 if transformer.enabled:
357 line = transformer.transform(line, continue_prompt)
363 line = transformer.transform(line, continue_prompt)
358 return line
364 return line
359
365
360 def prefilter_line(self, line, continue_prompt=False):
366 def prefilter_line(self, line, continue_prompt=False):
361 """Prefilter a single input line as text.
367 """Prefilter a single input line as text.
362
368
363 This method prefilters a single line of text by calling the
369 This method prefilters a single line of text by calling the
364 transformers and then the checkers/handlers.
370 transformers and then the checkers/handlers.
365 """
371 """
366
372
367 # print "prefilter_line: ", line, continue_prompt
373 # print "prefilter_line: ", line, continue_prompt
368 # All handlers *must* return a value, even if it's blank ('').
374 # All handlers *must* return a value, even if it's blank ('').
369
375
370 # Lines are NOT logged here. Handlers should process the line as
376 # Lines are NOT logged here. Handlers should process the line as
371 # needed, update the cache AND log it (so that the input cache array
377 # needed, update the cache AND log it (so that the input cache array
372 # stays synced).
378 # stays synced).
373
379
374 # save the line away in case we crash, so the post-mortem handler can
380 # save the line away in case we crash, so the post-mortem handler can
375 # record it
381 # record it
376 self.shell._last_input_line = line
382 self.shell._last_input_line = line
377
383
378 if not line:
384 if not line:
379 # Return immediately on purely empty lines, so that if the user
385 # Return immediately on purely empty lines, so that if the user
380 # previously typed some whitespace that started a continuation
386 # previously typed some whitespace that started a continuation
381 # prompt, he can break out of that loop with just an empty line.
387 # prompt, he can break out of that loop with just an empty line.
382 # This is how the default python prompt works.
388 # This is how the default python prompt works.
383
389
384 # Only return if the accumulated input buffer was just whitespace!
390 # Only return if the accumulated input buffer was just whitespace!
385 if ''.join(self.shell.buffer).isspace():
391 if ''.join(self.shell.buffer).isspace():
386 self.shell.buffer[:] = []
392 self.shell.buffer[:] = []
387 return ''
393 return ''
388
394
389 # At this point, we invoke our transformers.
395 # At this point, we invoke our transformers.
390 if not continue_prompt or (continue_prompt and self.multi_line_specials):
396 if not continue_prompt or (continue_prompt and self.multi_line_specials):
391 line = self.transform_line(line, continue_prompt)
397 line = self.transform_line(line, continue_prompt)
392
398
393 # Now we compute line_info for the checkers and handlers
399 # Now we compute line_info for the checkers and handlers
394 line_info = LineInfo(line, continue_prompt)
400 line_info = LineInfo(line, continue_prompt)
395
401
396 # the input history needs to track even empty lines
402 # the input history needs to track even empty lines
397 stripped = line.strip()
403 stripped = line.strip()
398
404
399 normal_handler = self.get_handler_by_name('normal')
405 normal_handler = self.get_handler_by_name('normal')
400 if not stripped:
406 if not stripped:
401 if not continue_prompt:
407 if not continue_prompt:
402 self.shell.outputcache.prompt_count -= 1
408 self.shell.outputcache.prompt_count -= 1
403
409
404 return normal_handler.handle(line_info)
410 return normal_handler.handle(line_info)
405
411
406 # special handlers are only allowed for single line statements
412 # special handlers are only allowed for single line statements
407 if continue_prompt and not self.multi_line_specials:
413 if continue_prompt and not self.multi_line_specials:
408 return normal_handler.handle(line_info)
414 return normal_handler.handle(line_info)
409
415
410 prefiltered = self.prefilter_line_info(line_info)
416 prefiltered = self.prefilter_line_info(line_info)
411 # print "prefiltered line: %r" % prefiltered
417 # print "prefiltered line: %r" % prefiltered
412 return prefiltered
418 return prefiltered
413
419
414 def prefilter_lines(self, lines, continue_prompt=False):
420 def prefilter_lines(self, lines, continue_prompt=False):
415 """Prefilter multiple input lines of text.
421 """Prefilter multiple input lines of text.
416
422
417 This is the main entry point for prefiltering multiple lines of
423 This is the main entry point for prefiltering multiple lines of
418 input. This simply calls :meth:`prefilter_line` for each line of
424 input. This simply calls :meth:`prefilter_line` for each line of
419 input.
425 input.
420
426
421 This covers cases where there are multiple lines in the user entry,
427 This covers cases where there are multiple lines in the user entry,
422 which is the case when the user goes back to a multiline history
428 which is the case when the user goes back to a multiline history
423 entry and presses enter.
429 entry and presses enter.
424 """
430 """
425 llines = lines.rstrip('\n').split('\n')
431 llines = lines.rstrip('\n').split('\n')
426 # We can get multiple lines in one shot, where multiline input 'blends'
432 # We can get multiple lines in one shot, where multiline input 'blends'
427 # into one line, in cases like recalling from the readline history
433 # into one line, in cases like recalling from the readline history
428 # buffer. We need to make sure that in such cases, we correctly
434 # buffer. We need to make sure that in such cases, we correctly
429 # communicate downstream which line is first and which are continuation
435 # communicate downstream which line is first and which are continuation
430 # ones.
436 # ones.
431 if len(llines) > 1:
437 if len(llines) > 1:
432 out = '\n'.join([self.prefilter_line(line, lnum>0)
438 out = '\n'.join([self.prefilter_line(line, lnum>0)
433 for lnum, line in enumerate(llines) ])
439 for lnum, line in enumerate(llines) ])
434 else:
440 else:
435 out = self.prefilter_line(llines[0], continue_prompt)
441 out = self.prefilter_line(llines[0], continue_prompt)
436
442
437 return out
443 return out
438
444
439 #-----------------------------------------------------------------------------
445 #-----------------------------------------------------------------------------
440 # Prefilter transformers
446 # Prefilter transformers
441 #-----------------------------------------------------------------------------
447 #-----------------------------------------------------------------------------
442
448
443
449
444 class PrefilterTransformer(Configurable):
450 class PrefilterTransformer(Configurable):
445 """Transform a line of user input."""
451 """Transform a line of user input."""
446
452
447 priority = Int(100, config=True)
453 priority = Int(100, config=True)
448 # Transformers don't currently use shell or prefilter_manager, but as we
454 # Transformers don't currently use shell or prefilter_manager, but as we
449 # move away from checkers and handlers, they will need them.
455 # move away from checkers and handlers, they will need them.
450 shell = Instance('IPython.core.iplib.InteractiveShellABC')
456 shell = Instance('IPython.core.iplib.InteractiveShellABC')
451 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
457 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
452 enabled = Bool(True, config=True)
458 enabled = Bool(True, config=True)
453
459
454 def __init__(self, shell, prefilter_manager, config=None):
460 def __init__(self, shell=None, prefilter_manager=None, config=None):
455 super(PrefilterTransformer, self).__init__(config=config)
461 super(PrefilterTransformer, self).__init__(
456 self.shell = shell
462 shell=shell, prefilter_manager=prefilter_manager, config=config
457 self.prefilter_manager = prefilter_manager
463 )
458 self.prefilter_manager.register_transformer(self)
464 self.prefilter_manager.register_transformer(self)
459
465
460 def transform(self, line, continue_prompt):
466 def transform(self, line, continue_prompt):
461 """Transform a line, returning the new one."""
467 """Transform a line, returning the new one."""
462 return None
468 return None
463
469
464 def __repr__(self):
470 def __repr__(self):
465 return "<%s(priority=%r, enabled=%r)>" % (
471 return "<%s(priority=%r, enabled=%r)>" % (
466 self.__class__.__name__, self.priority, self.enabled)
472 self.__class__.__name__, self.priority, self.enabled)
467
473
468
474
469 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
475 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
470 r'\s*=\s*!(?P<cmd>.*)')
476 r'\s*=\s*!(?P<cmd>.*)')
471
477
472
478
473 class AssignSystemTransformer(PrefilterTransformer):
479 class AssignSystemTransformer(PrefilterTransformer):
474 """Handle the `files = !ls` syntax."""
480 """Handle the `files = !ls` syntax."""
475
481
476 priority = Int(100, config=True)
482 priority = Int(100, config=True)
477
483
478 def transform(self, line, continue_prompt):
484 def transform(self, line, continue_prompt):
479 m = _assign_system_re.match(line)
485 m = _assign_system_re.match(line)
480 if m is not None:
486 if m is not None:
481 cmd = m.group('cmd')
487 cmd = m.group('cmd')
482 lhs = m.group('lhs')
488 lhs = m.group('lhs')
483 expr = make_quoted_expr("sc -l =%s" % cmd)
489 expr = make_quoted_expr("sc -l =%s" % cmd)
484 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
490 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
485 return new_line
491 return new_line
486 return line
492 return line
487
493
488
494
489 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
495 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
490 r'\s*=\s*%(?P<cmd>.*)')
496 r'\s*=\s*%(?P<cmd>.*)')
491
497
492 class AssignMagicTransformer(PrefilterTransformer):
498 class AssignMagicTransformer(PrefilterTransformer):
493 """Handle the `a = %who` syntax."""
499 """Handle the `a = %who` syntax."""
494
500
495 priority = Int(200, config=True)
501 priority = Int(200, config=True)
496
502
497 def transform(self, line, continue_prompt):
503 def transform(self, line, continue_prompt):
498 m = _assign_magic_re.match(line)
504 m = _assign_magic_re.match(line)
499 if m is not None:
505 if m is not None:
500 cmd = m.group('cmd')
506 cmd = m.group('cmd')
501 lhs = m.group('lhs')
507 lhs = m.group('lhs')
502 expr = make_quoted_expr(cmd)
508 expr = make_quoted_expr(cmd)
503 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
509 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
504 return new_line
510 return new_line
505 return line
511 return line
506
512
507
513
508 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
514 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
509
515
510 class PyPromptTransformer(PrefilterTransformer):
516 class PyPromptTransformer(PrefilterTransformer):
511 """Handle inputs that start with '>>> ' syntax."""
517 """Handle inputs that start with '>>> ' syntax."""
512
518
513 priority = Int(50, config=True)
519 priority = Int(50, config=True)
514
520
515 def transform(self, line, continue_prompt):
521 def transform(self, line, continue_prompt):
516
522
517 if not line or line.isspace() or line.strip() == '...':
523 if not line or line.isspace() or line.strip() == '...':
518 # This allows us to recognize multiple input prompts separated by
524 # This allows us to recognize multiple input prompts separated by
519 # blank lines and pasted in a single chunk, very common when
525 # blank lines and pasted in a single chunk, very common when
520 # pasting doctests or long tutorial passages.
526 # pasting doctests or long tutorial passages.
521 return ''
527 return ''
522 m = _classic_prompt_re.match(line)
528 m = _classic_prompt_re.match(line)
523 if m:
529 if m:
524 return line[len(m.group(0)):]
530 return line[len(m.group(0)):]
525 else:
531 else:
526 return line
532 return line
527
533
528
534
529 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
535 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
530
536
531 class IPyPromptTransformer(PrefilterTransformer):
537 class IPyPromptTransformer(PrefilterTransformer):
532 """Handle inputs that start classic IPython prompt syntax."""
538 """Handle inputs that start classic IPython prompt syntax."""
533
539
534 priority = Int(50, config=True)
540 priority = Int(50, config=True)
535
541
536 def transform(self, line, continue_prompt):
542 def transform(self, line, continue_prompt):
537
543
538 if not line or line.isspace() or line.strip() == '...':
544 if not line or line.isspace() or line.strip() == '...':
539 # This allows us to recognize multiple input prompts separated by
545 # This allows us to recognize multiple input prompts separated by
540 # blank lines and pasted in a single chunk, very common when
546 # blank lines and pasted in a single chunk, very common when
541 # pasting doctests or long tutorial passages.
547 # pasting doctests or long tutorial passages.
542 return ''
548 return ''
543 m = _ipy_prompt_re.match(line)
549 m = _ipy_prompt_re.match(line)
544 if m:
550 if m:
545 return line[len(m.group(0)):]
551 return line[len(m.group(0)):]
546 else:
552 else:
547 return line
553 return line
548
554
549 #-----------------------------------------------------------------------------
555 #-----------------------------------------------------------------------------
550 # Prefilter checkers
556 # Prefilter checkers
551 #-----------------------------------------------------------------------------
557 #-----------------------------------------------------------------------------
552
558
553
559
554 class PrefilterChecker(Configurable):
560 class PrefilterChecker(Configurable):
555 """Inspect an input line and return a handler for that line."""
561 """Inspect an input line and return a handler for that line."""
556
562
557 priority = Int(100, config=True)
563 priority = Int(100, config=True)
558 shell = Instance('IPython.core.iplib.InteractiveShellABC')
564 shell = Instance('IPython.core.iplib.InteractiveShellABC')
559 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
565 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
560 enabled = Bool(True, config=True)
566 enabled = Bool(True, config=True)
561
567
562 def __init__(self, shell, prefilter_manager, config=None):
568 def __init__(self, shell=None, prefilter_manager=None, config=None):
563 super(PrefilterChecker, self).__init__(config=config)
569 super(PrefilterChecker, self).__init__(
564 self.shell = shell
570 shell=shell, prefilter_manager=prefilter_manager, config=config
565 self.prefilter_manager = prefilter_manager
571 )
566 self.prefilter_manager.register_checker(self)
572 self.prefilter_manager.register_checker(self)
567
573
568 def check(self, line_info):
574 def check(self, line_info):
569 """Inspect line_info and return a handler instance or None."""
575 """Inspect line_info and return a handler instance or None."""
570 return None
576 return None
571
577
572 def __repr__(self):
578 def __repr__(self):
573 return "<%s(priority=%r, enabled=%r)>" % (
579 return "<%s(priority=%r, enabled=%r)>" % (
574 self.__class__.__name__, self.priority, self.enabled)
580 self.__class__.__name__, self.priority, self.enabled)
575
581
576
582
577 class EmacsChecker(PrefilterChecker):
583 class EmacsChecker(PrefilterChecker):
578
584
579 priority = Int(100, config=True)
585 priority = Int(100, config=True)
580 enabled = Bool(False, config=True)
586 enabled = Bool(False, config=True)
581
587
582 def check(self, line_info):
588 def check(self, line_info):
583 "Emacs ipython-mode tags certain input lines."
589 "Emacs ipython-mode tags certain input lines."
584 if line_info.line.endswith('# PYTHON-MODE'):
590 if line_info.line.endswith('# PYTHON-MODE'):
585 return self.prefilter_manager.get_handler_by_name('emacs')
591 return self.prefilter_manager.get_handler_by_name('emacs')
586 else:
592 else:
587 return None
593 return None
588
594
589
595
590 class ShellEscapeChecker(PrefilterChecker):
596 class ShellEscapeChecker(PrefilterChecker):
591
597
592 priority = Int(200, config=True)
598 priority = Int(200, config=True)
593
599
594 def check(self, line_info):
600 def check(self, line_info):
595 if line_info.line.lstrip().startswith(ESC_SHELL):
601 if line_info.line.lstrip().startswith(ESC_SHELL):
596 return self.prefilter_manager.get_handler_by_name('shell')
602 return self.prefilter_manager.get_handler_by_name('shell')
597
603
598
604
599 class IPyAutocallChecker(PrefilterChecker):
605 class IPyAutocallChecker(PrefilterChecker):
600
606
601 priority = Int(300, config=True)
607 priority = Int(300, config=True)
602
608
603 def check(self, line_info):
609 def check(self, line_info):
604 "Instances of IPyAutocall in user_ns get autocalled immediately"
610 "Instances of IPyAutocall in user_ns get autocalled immediately"
605 obj = self.shell.user_ns.get(line_info.ifun, None)
611 obj = self.shell.user_ns.get(line_info.ifun, None)
606 if isinstance(obj, IPyAutocall):
612 if isinstance(obj, IPyAutocall):
607 obj.set_ip(self.shell)
613 obj.set_ip(self.shell)
608 return self.prefilter_manager.get_handler_by_name('auto')
614 return self.prefilter_manager.get_handler_by_name('auto')
609 else:
615 else:
610 return None
616 return None
611
617
612
618
613 class MultiLineMagicChecker(PrefilterChecker):
619 class MultiLineMagicChecker(PrefilterChecker):
614
620
615 priority = Int(400, config=True)
621 priority = Int(400, config=True)
616
622
617 def check(self, line_info):
623 def check(self, line_info):
618 "Allow ! and !! in multi-line statements if multi_line_specials is on"
624 "Allow ! and !! in multi-line statements if multi_line_specials is on"
619 # Note that this one of the only places we check the first character of
625 # Note that this one of the only places we check the first character of
620 # ifun and *not* the pre_char. Also note that the below test matches
626 # ifun and *not* the pre_char. Also note that the below test matches
621 # both ! and !!.
627 # both ! and !!.
622 if line_info.continue_prompt \
628 if line_info.continue_prompt \
623 and self.prefilter_manager.multi_line_specials:
629 and self.prefilter_manager.multi_line_specials:
624 if line_info.ifun.startswith(ESC_MAGIC):
630 if line_info.ifun.startswith(ESC_MAGIC):
625 return self.prefilter_manager.get_handler_by_name('magic')
631 return self.prefilter_manager.get_handler_by_name('magic')
626 else:
632 else:
627 return None
633 return None
628
634
629
635
630 class EscCharsChecker(PrefilterChecker):
636 class EscCharsChecker(PrefilterChecker):
631
637
632 priority = Int(500, config=True)
638 priority = Int(500, config=True)
633
639
634 def check(self, line_info):
640 def check(self, line_info):
635 """Check for escape character and return either a handler to handle it,
641 """Check for escape character and return either a handler to handle it,
636 or None if there is no escape char."""
642 or None if there is no escape char."""
637 if line_info.line[-1] == ESC_HELP \
643 if line_info.line[-1] == ESC_HELP \
638 and line_info.pre_char != ESC_SHELL \
644 and line_info.pre_char != ESC_SHELL \
639 and line_info.pre_char != ESC_SH_CAP:
645 and line_info.pre_char != ESC_SH_CAP:
640 # the ? can be at the end, but *not* for either kind of shell escape,
646 # the ? can be at the end, but *not* for either kind of shell escape,
641 # because a ? can be a vaild final char in a shell cmd
647 # because a ? can be a vaild final char in a shell cmd
642 return self.prefilter_manager.get_handler_by_name('help')
648 return self.prefilter_manager.get_handler_by_name('help')
643 else:
649 else:
644 # This returns None like it should if no handler exists
650 # This returns None like it should if no handler exists
645 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
651 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
646
652
647
653
648 class AssignmentChecker(PrefilterChecker):
654 class AssignmentChecker(PrefilterChecker):
649
655
650 priority = Int(600, config=True)
656 priority = Int(600, config=True)
651
657
652 def check(self, line_info):
658 def check(self, line_info):
653 """Check to see if user is assigning to a var for the first time, in
659 """Check to see if user is assigning to a var for the first time, in
654 which case we want to avoid any sort of automagic / autocall games.
660 which case we want to avoid any sort of automagic / autocall games.
655
661
656 This allows users to assign to either alias or magic names true python
662 This allows users to assign to either alias or magic names true python
657 variables (the magic/alias systems always take second seat to true
663 variables (the magic/alias systems always take second seat to true
658 python code). E.g. ls='hi', or ls,that=1,2"""
664 python code). E.g. ls='hi', or ls,that=1,2"""
659 if line_info.the_rest:
665 if line_info.the_rest:
660 if line_info.the_rest[0] in '=,':
666 if line_info.the_rest[0] in '=,':
661 return self.prefilter_manager.get_handler_by_name('normal')
667 return self.prefilter_manager.get_handler_by_name('normal')
662 else:
668 else:
663 return None
669 return None
664
670
665
671
666 class AutoMagicChecker(PrefilterChecker):
672 class AutoMagicChecker(PrefilterChecker):
667
673
668 priority = Int(700, config=True)
674 priority = Int(700, config=True)
669
675
670 def check(self, line_info):
676 def check(self, line_info):
671 """If the ifun is magic, and automagic is on, run it. Note: normal,
677 """If the ifun is magic, and automagic is on, run it. Note: normal,
672 non-auto magic would already have been triggered via '%' in
678 non-auto magic would already have been triggered via '%' in
673 check_esc_chars. This just checks for automagic. Also, before
679 check_esc_chars. This just checks for automagic. Also, before
674 triggering the magic handler, make sure that there is nothing in the
680 triggering the magic handler, make sure that there is nothing in the
675 user namespace which could shadow it."""
681 user namespace which could shadow it."""
676 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
682 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
677 return None
683 return None
678
684
679 # We have a likely magic method. Make sure we should actually call it.
685 # We have a likely magic method. Make sure we should actually call it.
680 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
686 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
681 return None
687 return None
682
688
683 head = line_info.ifun.split('.',1)[0]
689 head = line_info.ifun.split('.',1)[0]
684 if is_shadowed(head, self.shell):
690 if is_shadowed(head, self.shell):
685 return None
691 return None
686
692
687 return self.prefilter_manager.get_handler_by_name('magic')
693 return self.prefilter_manager.get_handler_by_name('magic')
688
694
689
695
690 class AliasChecker(PrefilterChecker):
696 class AliasChecker(PrefilterChecker):
691
697
692 priority = Int(800, config=True)
698 priority = Int(800, config=True)
693
699
694 def check(self, line_info):
700 def check(self, line_info):
695 "Check if the initital identifier on the line is an alias."
701 "Check if the initital identifier on the line is an alias."
696 # Note: aliases can not contain '.'
702 # Note: aliases can not contain '.'
697 head = line_info.ifun.split('.',1)[0]
703 head = line_info.ifun.split('.',1)[0]
698 if line_info.ifun not in self.shell.alias_manager \
704 if line_info.ifun not in self.shell.alias_manager \
699 or head not in self.shell.alias_manager \
705 or head not in self.shell.alias_manager \
700 or is_shadowed(head, self.shell):
706 or is_shadowed(head, self.shell):
701 return None
707 return None
702
708
703 return self.prefilter_manager.get_handler_by_name('alias')
709 return self.prefilter_manager.get_handler_by_name('alias')
704
710
705
711
706 class PythonOpsChecker(PrefilterChecker):
712 class PythonOpsChecker(PrefilterChecker):
707
713
708 priority = Int(900, config=True)
714 priority = Int(900, config=True)
709
715
710 def check(self, line_info):
716 def check(self, line_info):
711 """If the 'rest' of the line begins with a function call or pretty much
717 """If the 'rest' of the line begins with a function call or pretty much
712 any python operator, we should simply execute the line (regardless of
718 any python operator, we should simply execute the line (regardless of
713 whether or not there's a possible autocall expansion). This avoids
719 whether or not there's a possible autocall expansion). This avoids
714 spurious (and very confusing) geattr() accesses."""
720 spurious (and very confusing) geattr() accesses."""
715 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
721 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
716 return self.prefilter_manager.get_handler_by_name('normal')
722 return self.prefilter_manager.get_handler_by_name('normal')
717 else:
723 else:
718 return None
724 return None
719
725
720
726
721 class AutocallChecker(PrefilterChecker):
727 class AutocallChecker(PrefilterChecker):
722
728
723 priority = Int(1000, config=True)
729 priority = Int(1000, config=True)
724
730
725 def check(self, line_info):
731 def check(self, line_info):
726 "Check if the initial word/function is callable and autocall is on."
732 "Check if the initial word/function is callable and autocall is on."
727 if not self.shell.autocall:
733 if not self.shell.autocall:
728 return None
734 return None
729
735
730 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
736 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
731 if not oinfo['found']:
737 if not oinfo['found']:
732 return None
738 return None
733
739
734 if callable(oinfo['obj']) \
740 if callable(oinfo['obj']) \
735 and (not re_exclude_auto.match(line_info.the_rest)) \
741 and (not re_exclude_auto.match(line_info.the_rest)) \
736 and re_fun_name.match(line_info.ifun):
742 and re_fun_name.match(line_info.ifun):
737 return self.prefilter_manager.get_handler_by_name('auto')
743 return self.prefilter_manager.get_handler_by_name('auto')
738 else:
744 else:
739 return None
745 return None
740
746
741
747
742 #-----------------------------------------------------------------------------
748 #-----------------------------------------------------------------------------
743 # Prefilter handlers
749 # Prefilter handlers
744 #-----------------------------------------------------------------------------
750 #-----------------------------------------------------------------------------
745
751
746
752
747 class PrefilterHandler(Configurable):
753 class PrefilterHandler(Configurable):
748
754
749 handler_name = Str('normal')
755 handler_name = Str('normal')
750 esc_strings = List([])
756 esc_strings = List([])
751 shell = Instance('IPython.core.iplib.InteractiveShellABC')
757 shell = Instance('IPython.core.iplib.InteractiveShellABC')
752 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
758 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
753
759
754 def __init__(self, shell, prefilter_manager, config=None):
760 def __init__(self, shell=None, prefilter_manager=None, config=None):
755 super(PrefilterHandler, self).__init__(config=config)
761 super(PrefilterHandler, self).__init__(
756 self.shell = shell
762 shell=shell, prefilter_manager=prefilter_manager, config=config
757 self.prefilter_manager = prefilter_manager
763 )
758 self.prefilter_manager.register_handler(
764 self.prefilter_manager.register_handler(
759 self.handler_name,
765 self.handler_name,
760 self,
766 self,
761 self.esc_strings
767 self.esc_strings
762 )
768 )
763
769
764 def handle(self, line_info):
770 def handle(self, line_info):
765 # print "normal: ", line_info
771 # print "normal: ", line_info
766 """Handle normal input lines. Use as a template for handlers."""
772 """Handle normal input lines. Use as a template for handlers."""
767
773
768 # With autoindent on, we need some way to exit the input loop, and I
774 # With autoindent on, we need some way to exit the input loop, and I
769 # don't want to force the user to have to backspace all the way to
775 # don't want to force the user to have to backspace all the way to
770 # clear the line. The rule will be in this case, that either two
776 # clear the line. The rule will be in this case, that either two
771 # lines of pure whitespace in a row, or a line of pure whitespace but
777 # lines of pure whitespace in a row, or a line of pure whitespace but
772 # of a size different to the indent level, will exit the input loop.
778 # of a size different to the indent level, will exit the input loop.
773 line = line_info.line
779 line = line_info.line
774 continue_prompt = line_info.continue_prompt
780 continue_prompt = line_info.continue_prompt
775
781
776 if (continue_prompt and
782 if (continue_prompt and
777 self.shell.autoindent and
783 self.shell.autoindent and
778 line.isspace() and
784 line.isspace() and
779
785
780 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2
786 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2
781 or
787 or
782 not self.shell.buffer
788 not self.shell.buffer
783 or
789 or
784 (self.shell.buffer[-1]).isspace()
790 (self.shell.buffer[-1]).isspace()
785 )
791 )
786 ):
792 ):
787 line = ''
793 line = ''
788
794
789 self.shell.log(line, line, continue_prompt)
795 self.shell.log(line, line, continue_prompt)
790 return line
796 return line
791
797
792 def __str__(self):
798 def __str__(self):
793 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
799 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
794
800
795
801
796 class AliasHandler(PrefilterHandler):
802 class AliasHandler(PrefilterHandler):
797
803
798 handler_name = Str('alias')
804 handler_name = Str('alias')
799
805
800 def handle(self, line_info):
806 def handle(self, line_info):
801 """Handle alias input lines. """
807 """Handle alias input lines. """
802 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
808 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
803 # pre is needed, because it carries the leading whitespace. Otherwise
809 # pre is needed, because it carries the leading whitespace. Otherwise
804 # aliases won't work in indented sections.
810 # aliases won't work in indented sections.
805 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
811 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
806 make_quoted_expr(transformed))
812 make_quoted_expr(transformed))
807
813
808 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
814 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
809 return line_out
815 return line_out
810
816
811
817
812 class ShellEscapeHandler(PrefilterHandler):
818 class ShellEscapeHandler(PrefilterHandler):
813
819
814 handler_name = Str('shell')
820 handler_name = Str('shell')
815 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
821 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
816
822
817 def handle(self, line_info):
823 def handle(self, line_info):
818 """Execute the line in a shell, empty return value"""
824 """Execute the line in a shell, empty return value"""
819 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
825 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
820
826
821 line = line_info.line
827 line = line_info.line
822 if line.lstrip().startswith(ESC_SH_CAP):
828 if line.lstrip().startswith(ESC_SH_CAP):
823 # rewrite LineInfo's line, ifun and the_rest to properly hold the
829 # rewrite LineInfo's line, ifun and the_rest to properly hold the
824 # call to %sx and the actual command to be executed, so
830 # call to %sx and the actual command to be executed, so
825 # handle_magic can work correctly. Note that this works even if
831 # handle_magic can work correctly. Note that this works even if
826 # the line is indented, so it handles multi_line_specials
832 # the line is indented, so it handles multi_line_specials
827 # properly.
833 # properly.
828 new_rest = line.lstrip()[2:]
834 new_rest = line.lstrip()[2:]
829 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
835 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
830 line_info.ifun = 'sx'
836 line_info.ifun = 'sx'
831 line_info.the_rest = new_rest
837 line_info.the_rest = new_rest
832 return magic_handler.handle(line_info)
838 return magic_handler.handle(line_info)
833 else:
839 else:
834 cmd = line.lstrip().lstrip(ESC_SHELL)
840 cmd = line.lstrip().lstrip(ESC_SHELL)
835 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
841 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
836 make_quoted_expr(cmd))
842 make_quoted_expr(cmd))
837 # update cache/log and return
843 # update cache/log and return
838 self.shell.log(line, line_out, line_info.continue_prompt)
844 self.shell.log(line, line_out, line_info.continue_prompt)
839 return line_out
845 return line_out
840
846
841
847
842 class MagicHandler(PrefilterHandler):
848 class MagicHandler(PrefilterHandler):
843
849
844 handler_name = Str('magic')
850 handler_name = Str('magic')
845 esc_strings = List([ESC_MAGIC])
851 esc_strings = List([ESC_MAGIC])
846
852
847 def handle(self, line_info):
853 def handle(self, line_info):
848 """Execute magic functions."""
854 """Execute magic functions."""
849 ifun = line_info.ifun
855 ifun = line_info.ifun
850 the_rest = line_info.the_rest
856 the_rest = line_info.the_rest
851 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
857 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
852 make_quoted_expr(ifun + " " + the_rest))
858 make_quoted_expr(ifun + " " + the_rest))
853 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
859 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
854 return cmd
860 return cmd
855
861
856
862
857 class AutoHandler(PrefilterHandler):
863 class AutoHandler(PrefilterHandler):
858
864
859 handler_name = Str('auto')
865 handler_name = Str('auto')
860 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
866 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
861
867
862 def handle(self, line_info):
868 def handle(self, line_info):
863 """Handle lines which can be auto-executed, quoting if requested."""
869 """Handle lines which can be auto-executed, quoting if requested."""
864 line = line_info.line
870 line = line_info.line
865 ifun = line_info.ifun
871 ifun = line_info.ifun
866 the_rest = line_info.the_rest
872 the_rest = line_info.the_rest
867 pre = line_info.pre
873 pre = line_info.pre
868 continue_prompt = line_info.continue_prompt
874 continue_prompt = line_info.continue_prompt
869 obj = line_info.ofind(self)['obj']
875 obj = line_info.ofind(self)['obj']
870 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
876 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
871
877
872 # This should only be active for single-line input!
878 # This should only be active for single-line input!
873 if continue_prompt:
879 if continue_prompt:
874 self.shell.log(line,line,continue_prompt)
880 self.shell.log(line,line,continue_prompt)
875 return line
881 return line
876
882
877 force_auto = isinstance(obj, IPyAutocall)
883 force_auto = isinstance(obj, IPyAutocall)
878 auto_rewrite = True
884 auto_rewrite = True
879
885
880 if pre == ESC_QUOTE:
886 if pre == ESC_QUOTE:
881 # Auto-quote splitting on whitespace
887 # Auto-quote splitting on whitespace
882 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
888 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
883 elif pre == ESC_QUOTE2:
889 elif pre == ESC_QUOTE2:
884 # Auto-quote whole string
890 # Auto-quote whole string
885 newcmd = '%s("%s")' % (ifun,the_rest)
891 newcmd = '%s("%s")' % (ifun,the_rest)
886 elif pre == ESC_PAREN:
892 elif pre == ESC_PAREN:
887 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
893 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
888 else:
894 else:
889 # Auto-paren.
895 # Auto-paren.
890 # We only apply it to argument-less calls if the autocall
896 # We only apply it to argument-less calls if the autocall
891 # parameter is set to 2. We only need to check that autocall is <
897 # parameter is set to 2. We only need to check that autocall is <
892 # 2, since this function isn't called unless it's at least 1.
898 # 2, since this function isn't called unless it's at least 1.
893 if not the_rest and (self.shell.autocall < 2) and not force_auto:
899 if not the_rest and (self.shell.autocall < 2) and not force_auto:
894 newcmd = '%s %s' % (ifun,the_rest)
900 newcmd = '%s %s' % (ifun,the_rest)
895 auto_rewrite = False
901 auto_rewrite = False
896 else:
902 else:
897 if not force_auto and the_rest.startswith('['):
903 if not force_auto and the_rest.startswith('['):
898 if hasattr(obj,'__getitem__'):
904 if hasattr(obj,'__getitem__'):
899 # Don't autocall in this case: item access for an object
905 # Don't autocall in this case: item access for an object
900 # which is BOTH callable and implements __getitem__.
906 # which is BOTH callable and implements __getitem__.
901 newcmd = '%s %s' % (ifun,the_rest)
907 newcmd = '%s %s' % (ifun,the_rest)
902 auto_rewrite = False
908 auto_rewrite = False
903 else:
909 else:
904 # if the object doesn't support [] access, go ahead and
910 # if the object doesn't support [] access, go ahead and
905 # autocall
911 # autocall
906 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
912 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
907 elif the_rest.endswith(';'):
913 elif the_rest.endswith(';'):
908 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
914 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
909 else:
915 else:
910 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
916 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
911
917
912 if auto_rewrite:
918 if auto_rewrite:
913 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
919 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
914
920
915 try:
921 try:
916 # plain ascii works better w/ pyreadline, on some machines, so
922 # plain ascii works better w/ pyreadline, on some machines, so
917 # we use it and only print uncolored rewrite if we have unicode
923 # we use it and only print uncolored rewrite if we have unicode
918 rw = str(rw)
924 rw = str(rw)
919 print >>Term.cout, rw
925 print >>Term.cout, rw
920 except UnicodeEncodeError:
926 except UnicodeEncodeError:
921 print "-------------->" + newcmd
927 print "-------------->" + newcmd
922
928
923 # log what is now valid Python, not the actual user input (without the
929 # log what is now valid Python, not the actual user input (without the
924 # final newline)
930 # final newline)
925 self.shell.log(line,newcmd,continue_prompt)
931 self.shell.log(line,newcmd,continue_prompt)
926 return newcmd
932 return newcmd
927
933
928
934
929 class HelpHandler(PrefilterHandler):
935 class HelpHandler(PrefilterHandler):
930
936
931 handler_name = Str('help')
937 handler_name = Str('help')
932 esc_strings = List([ESC_HELP])
938 esc_strings = List([ESC_HELP])
933
939
934 def handle(self, line_info):
940 def handle(self, line_info):
935 """Try to get some help for the object.
941 """Try to get some help for the object.
936
942
937 obj? or ?obj -> basic information.
943 obj? or ?obj -> basic information.
938 obj?? or ??obj -> more details.
944 obj?? or ??obj -> more details.
939 """
945 """
940 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
946 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
941 line = line_info.line
947 line = line_info.line
942 # We need to make sure that we don't process lines which would be
948 # We need to make sure that we don't process lines which would be
943 # otherwise valid python, such as "x=1 # what?"
949 # otherwise valid python, such as "x=1 # what?"
944 try:
950 try:
945 codeop.compile_command(line)
951 codeop.compile_command(line)
946 except SyntaxError:
952 except SyntaxError:
947 # We should only handle as help stuff which is NOT valid syntax
953 # We should only handle as help stuff which is NOT valid syntax
948 if line[0]==ESC_HELP:
954 if line[0]==ESC_HELP:
949 line = line[1:]
955 line = line[1:]
950 elif line[-1]==ESC_HELP:
956 elif line[-1]==ESC_HELP:
951 line = line[:-1]
957 line = line[:-1]
952 self.shell.log(line, '#?'+line, line_info.continue_prompt)
958 self.shell.log(line, '#?'+line, line_info.continue_prompt)
953 if line:
959 if line:
954 #print 'line:<%r>' % line # dbg
960 #print 'line:<%r>' % line # dbg
955 self.shell.magic_pinfo(line)
961 self.shell.magic_pinfo(line)
956 else:
962 else:
957 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
963 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
958 return '' # Empty string is needed here!
964 return '' # Empty string is needed here!
959 except:
965 except:
960 raise
966 raise
961 # Pass any other exceptions through to the normal handler
967 # Pass any other exceptions through to the normal handler
962 return normal_handler.handle(line_info)
968 return normal_handler.handle(line_info)
963 else:
969 else:
964 # If the code compiles ok, we should handle it normally
970 # If the code compiles ok, we should handle it normally
965 return normal_handler.handle(line_info)
971 return normal_handler.handle(line_info)
966
972
967
973
968 class EmacsHandler(PrefilterHandler):
974 class EmacsHandler(PrefilterHandler):
969
975
970 handler_name = Str('emacs')
976 handler_name = Str('emacs')
971 esc_strings = List([])
977 esc_strings = List([])
972
978
973 def handle(self, line_info):
979 def handle(self, line_info):
974 """Handle input lines marked by python-mode."""
980 """Handle input lines marked by python-mode."""
975
981
976 # Currently, nothing is done. Later more functionality can be added
982 # Currently, nothing is done. Later more functionality can be added
977 # here if needed.
983 # here if needed.
978
984
979 # The input cache shouldn't be updated
985 # The input cache shouldn't be updated
980 return line_info.line
986 return line_info.line
981
987
982
988
983 #-----------------------------------------------------------------------------
989 #-----------------------------------------------------------------------------
984 # Defaults
990 # Defaults
985 #-----------------------------------------------------------------------------
991 #-----------------------------------------------------------------------------
986
992
987
993
988 _default_transformers = [
994 _default_transformers = [
989 AssignSystemTransformer,
995 AssignSystemTransformer,
990 AssignMagicTransformer,
996 AssignMagicTransformer,
991 PyPromptTransformer,
997 PyPromptTransformer,
992 IPyPromptTransformer,
998 IPyPromptTransformer,
993 ]
999 ]
994
1000
995 _default_checkers = [
1001 _default_checkers = [
996 EmacsChecker,
1002 EmacsChecker,
997 ShellEscapeChecker,
1003 ShellEscapeChecker,
998 IPyAutocallChecker,
1004 IPyAutocallChecker,
999 MultiLineMagicChecker,
1005 MultiLineMagicChecker,
1000 EscCharsChecker,
1006 EscCharsChecker,
1001 AssignmentChecker,
1007 AssignmentChecker,
1002 AutoMagicChecker,
1008 AutoMagicChecker,
1003 AliasChecker,
1009 AliasChecker,
1004 PythonOpsChecker,
1010 PythonOpsChecker,
1005 AutocallChecker
1011 AutocallChecker
1006 ]
1012 ]
1007
1013
1008 _default_handlers = [
1014 _default_handlers = [
1009 PrefilterHandler,
1015 PrefilterHandler,
1010 AliasHandler,
1016 AliasHandler,
1011 ShellEscapeHandler,
1017 ShellEscapeHandler,
1012 MagicHandler,
1018 MagicHandler,
1013 AutoHandler,
1019 AutoHandler,
1014 HelpHandler,
1020 HelpHandler,
1015 EmacsHandler
1021 EmacsHandler
1016 ]
1022 ]
@@ -1,202 +1,201 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 """Magic command interface for interactive parallel work."""
4 """Magic command interface for interactive parallel work."""
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import new
17 import new
18
18
19 from IPython.core.plugin import Plugin
19 from IPython.core.plugin import Plugin
20 from IPython.utils.traitlets import Bool, Any, Instance
20 from IPython.utils.traitlets import Bool, Any, Instance
21 from IPython.utils.autoattr import auto_attr
21 from IPython.utils.autoattr import auto_attr
22 from IPython.testing import decorators as testdec
22 from IPython.testing import decorators as testdec
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Definitions of magic functions for use with IPython
25 # Definitions of magic functions for use with IPython
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28
28
29 NO_ACTIVE_MULTIENGINE_CLIENT = """
29 NO_ACTIVE_MULTIENGINE_CLIENT = """
30 Use activate() on a MultiEngineClient object to activate it for magics.
30 Use activate() on a MultiEngineClient object to activate it for magics.
31 """
31 """
32
32
33
33
34 class ParalleMagic(Plugin):
34 class ParalleMagic(Plugin):
35 """A component to manage the %result, %px and %autopx magics."""
35 """A component to manage the %result, %px and %autopx magics."""
36
36
37 active_multiengine_client = Any()
37 active_multiengine_client = Any()
38 verbose = Bool(False, config=True)
38 verbose = Bool(False, config=True)
39 shell = Instance('IPython.core.iplib.InteractiveShellABC')
39 shell = Instance('IPython.core.iplib.InteractiveShellABC')
40
40
41 def __init__(self, shell, config=None):
41 def __init__(self, shell=None, config=None):
42 super(ParalleMagic, self).__init__(config=config)
42 super(ParalleMagic, self).__init__(shell=shell, config=config)
43 self.shell = shell
44 self._define_magics()
43 self._define_magics()
45 # A flag showing if autopx is activated or not
44 # A flag showing if autopx is activated or not
46 self.autopx = False
45 self.autopx = False
47
46
48 def _define_magics(self):
47 def _define_magics(self):
49 """Define the magic functions."""
48 """Define the magic functions."""
50 self.shell.define_magic('result', self.magic_result)
49 self.shell.define_magic('result', self.magic_result)
51 self.shell.define_magic('px', self.magic_px)
50 self.shell.define_magic('px', self.magic_px)
52 self.shell.define_magic('autopx', self.magic_autopx)
51 self.shell.define_magic('autopx', self.magic_autopx)
53
52
54 @testdec.skip_doctest
53 @testdec.skip_doctest
55 def magic_result(self, ipself, parameter_s=''):
54 def magic_result(self, ipself, parameter_s=''):
56 """Print the result of command i on all engines..
55 """Print the result of command i on all engines..
57
56
58 To use this a :class:`MultiEngineClient` instance must be created
57 To use this a :class:`MultiEngineClient` instance must be created
59 and then activated by calling its :meth:`activate` method.
58 and then activated by calling its :meth:`activate` method.
60
59
61 Then you can do the following::
60 Then you can do the following::
62
61
63 In [23]: %result
62 In [23]: %result
64 Out[23]:
63 Out[23]:
65 <Results List>
64 <Results List>
66 [0] In [6]: a = 10
65 [0] In [6]: a = 10
67 [1] In [6]: a = 10
66 [1] In [6]: a = 10
68
67
69 In [22]: %result 6
68 In [22]: %result 6
70 Out[22]:
69 Out[22]:
71 <Results List>
70 <Results List>
72 [0] In [6]: a = 10
71 [0] In [6]: a = 10
73 [1] In [6]: a = 10
72 [1] In [6]: a = 10
74 """
73 """
75 if self.active_multiengine_client is None:
74 if self.active_multiengine_client is None:
76 print NO_ACTIVE_MULTIENGINE_CLIENT
75 print NO_ACTIVE_MULTIENGINE_CLIENT
77 return
76 return
78
77
79 try:
78 try:
80 index = int(parameter_s)
79 index = int(parameter_s)
81 except:
80 except:
82 index = None
81 index = None
83 result = self.active_multiengine_client.get_result(index)
82 result = self.active_multiengine_client.get_result(index)
84 return result
83 return result
85
84
86 @testdec.skip_doctest
85 @testdec.skip_doctest
87 def magic_px(self, ipself, parameter_s=''):
86 def magic_px(self, ipself, parameter_s=''):
88 """Executes the given python command in parallel.
87 """Executes the given python command in parallel.
89
88
90 To use this a :class:`MultiEngineClient` instance must be created
89 To use this a :class:`MultiEngineClient` instance must be created
91 and then activated by calling its :meth:`activate` method.
90 and then activated by calling its :meth:`activate` method.
92
91
93 Then you can do the following::
92 Then you can do the following::
94
93
95 In [24]: %px a = 5
94 In [24]: %px a = 5
96 Parallel execution on engines: all
95 Parallel execution on engines: all
97 Out[24]:
96 Out[24]:
98 <Results List>
97 <Results List>
99 [0] In [7]: a = 5
98 [0] In [7]: a = 5
100 [1] In [7]: a = 5
99 [1] In [7]: a = 5
101 """
100 """
102
101
103 if self.active_multiengine_client is None:
102 if self.active_multiengine_client is None:
104 print NO_ACTIVE_MULTIENGINE_CLIENT
103 print NO_ACTIVE_MULTIENGINE_CLIENT
105 return
104 return
106 print "Parallel execution on engines: %s" % self.active_multiengine_client.targets
105 print "Parallel execution on engines: %s" % self.active_multiengine_client.targets
107 result = self.active_multiengine_client.execute(parameter_s)
106 result = self.active_multiengine_client.execute(parameter_s)
108 return result
107 return result
109
108
110 @testdec.skip_doctest
109 @testdec.skip_doctest
111 def magic_autopx(self, ipself, parameter_s=''):
110 def magic_autopx(self, ipself, parameter_s=''):
112 """Toggles auto parallel mode.
111 """Toggles auto parallel mode.
113
112
114 To use this a :class:`MultiEngineClient` instance must be created
113 To use this a :class:`MultiEngineClient` instance must be created
115 and then activated by calling its :meth:`activate` method. Once this
114 and then activated by calling its :meth:`activate` method. Once this
116 is called, all commands typed at the command line are send to
115 is called, all commands typed at the command line are send to
117 the engines to be executed in parallel. To control which engine
116 the engines to be executed in parallel. To control which engine
118 are used, set the ``targets`` attributed of the multiengine client
117 are used, set the ``targets`` attributed of the multiengine client
119 before entering ``%autopx`` mode.
118 before entering ``%autopx`` mode.
120
119
121 Then you can do the following::
120 Then you can do the following::
122
121
123 In [25]: %autopx
122 In [25]: %autopx
124 %autopx to enabled
123 %autopx to enabled
125
124
126 In [26]: a = 10
125 In [26]: a = 10
127 <Results List>
126 <Results List>
128 [0] In [8]: a = 10
127 [0] In [8]: a = 10
129 [1] In [8]: a = 10
128 [1] In [8]: a = 10
130
129
131
130
132 In [27]: %autopx
131 In [27]: %autopx
133 %autopx disabled
132 %autopx disabled
134 """
133 """
135 if self.autopx:
134 if self.autopx:
136 self._disable_autopx()
135 self._disable_autopx()
137 else:
136 else:
138 self._enable_autopx()
137 self._enable_autopx()
139
138
140 def _enable_autopx(self):
139 def _enable_autopx(self):
141 """Enable %autopx mode by saving the original runsource and installing
140 """Enable %autopx mode by saving the original runsource and installing
142 pxrunsource.
141 pxrunsource.
143 """
142 """
144 if self.active_multiengine_client is None:
143 if self.active_multiengine_client is None:
145 print NO_ACTIVE_MULTIENGINE_CLIENT
144 print NO_ACTIVE_MULTIENGINE_CLIENT
146 return
145 return
147
146
148 self._original_runsource = self.shell.runsource
147 self._original_runsource = self.shell.runsource
149 self.shell.runsource = new.instancemethod(
148 self.shell.runsource = new.instancemethod(
150 self.pxrunsource, self.shell, self.shell.__class__
149 self.pxrunsource, self.shell, self.shell.__class__
151 )
150 )
152 self.autopx = True
151 self.autopx = True
153 print "%autopx enabled"
152 print "%autopx enabled"
154
153
155 def _disable_autopx(self):
154 def _disable_autopx(self):
156 """Disable %autopx by restoring the original InteractiveShell.runsource."""
155 """Disable %autopx by restoring the original InteractiveShell.runsource."""
157 if self.autopx:
156 if self.autopx:
158 self.shell.runsource = self._original_runsource
157 self.shell.runsource = self._original_runsource
159 self.autopx = False
158 self.autopx = False
160 print "%autopx disabled"
159 print "%autopx disabled"
161
160
162 def pxrunsource(self, ipself, source, filename="<input>", symbol="single"):
161 def pxrunsource(self, ipself, source, filename="<input>", symbol="single"):
163 """A parallel replacement for InteractiveShell.runsource."""
162 """A parallel replacement for InteractiveShell.runsource."""
164
163
165 try:
164 try:
166 code = ipself.compile(source, filename, symbol)
165 code = ipself.compile(source, filename, symbol)
167 except (OverflowError, SyntaxError, ValueError):
166 except (OverflowError, SyntaxError, ValueError):
168 # Case 1
167 # Case 1
169 ipself.showsyntaxerror(filename)
168 ipself.showsyntaxerror(filename)
170 return None
169 return None
171
170
172 if code is None:
171 if code is None:
173 # Case 2
172 # Case 2
174 return True
173 return True
175
174
176 # Case 3
175 # Case 3
177 # Because autopx is enabled, we now call executeAll or disable autopx if
176 # Because autopx is enabled, we now call executeAll or disable autopx if
178 # %autopx or autopx has been called
177 # %autopx or autopx has been called
179 if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
178 if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
180 self._disable_autopx()
179 self._disable_autopx()
181 return False
180 return False
182 else:
181 else:
183 try:
182 try:
184 result = self.active_multiengine_client.execute(source)
183 result = self.active_multiengine_client.execute(source)
185 except:
184 except:
186 ipself.showtraceback()
185 ipself.showtraceback()
187 else:
186 else:
188 print result.__repr__()
187 print result.__repr__()
189 return False
188 return False
190
189
191
190
192 _loaded = False
191 _loaded = False
193
192
194
193
195 def load_ipython_extension(ip):
194 def load_ipython_extension(ip):
196 """Load the extension in IPython."""
195 """Load the extension in IPython."""
197 global _loaded
196 global _loaded
198 if not _loaded:
197 if not _loaded:
199 plugin = ParalleMagic(ip, config=ip.config)
198 plugin = ParalleMagic(shell=ip, config=ip.config)
200 ip.plugin_manager.register_plugin('parallel_magic', plugin)
199 ip.plugin_manager.register_plugin('parallel_magic', plugin)
201 _loaded = True
200 _loaded = True
202
201
@@ -1,158 +1,157 b''
1 """Use pretty.py for configurable pretty-printing.
1 """Use pretty.py for configurable pretty-printing.
2
2
3 To enable this extension in your configuration
3 To enable this extension in your configuration
4 file, add the following to :file:`ipython_config.py`::
4 file, add the following to :file:`ipython_config.py`::
5
5
6 c.Global.extensions = ['IPython.extensions.pretty']
6 c.Global.extensions = ['IPython.extensions.pretty']
7 def dict_pprinter(obj, p, cycle):
7 def dict_pprinter(obj, p, cycle):
8 return p.text("<dict>")
8 return p.text("<dict>")
9 c.PrettyResultDisplay.verbose = True
9 c.PrettyResultDisplay.verbose = True
10 c.PrettyResultDisplay.defaults_for_type = [
10 c.PrettyResultDisplay.defaults_for_type = [
11 (dict, dict_pprinter)
11 (dict, dict_pprinter)
12 ]
12 ]
13 c.PrettyResultDisplay.defaults_for_type_by_name = [
13 c.PrettyResultDisplay.defaults_for_type_by_name = [
14 ('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')
14 ('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')
15 ]
15 ]
16
16
17 This extension can also be loaded by using the ``%load_ext`` magic::
17 This extension can also be loaded by using the ``%load_ext`` magic::
18
18
19 %load_ext IPython.extensions.pretty
19 %load_ext IPython.extensions.pretty
20
20
21 If this extension is enabled, you can always add additional pretty printers
21 If this extension is enabled, you can always add additional pretty printers
22 by doing::
22 by doing::
23
23
24 ip = get_ipython()
24 ip = get_ipython()
25 prd = ip.get_component('pretty_result_display')
25 prd = ip.get_component('pretty_result_display')
26 import numpy
26 import numpy
27 from IPython.extensions.pretty import dtype_pprinter
27 from IPython.extensions.pretty import dtype_pprinter
28 prd.for_type(numpy.dtype, dtype_pprinter)
28 prd.for_type(numpy.dtype, dtype_pprinter)
29
29
30 # If you don't want to have numpy imported until it needs to be:
30 # If you don't want to have numpy imported until it needs to be:
31 prd.for_type_by_name('numpy', 'dtype', dtype_pprinter)
31 prd.for_type_by_name('numpy', 'dtype', dtype_pprinter)
32 """
32 """
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Imports
35 # Imports
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 from IPython.core.error import TryNext
38 from IPython.core.error import TryNext
39 from IPython.external import pretty
39 from IPython.external import pretty
40 from IPython.core.plugin import Plugin
40 from IPython.core.plugin import Plugin
41 from IPython.utils.traitlets import Bool, List, Instance
41 from IPython.utils.traitlets import Bool, List, Instance
42 from IPython.utils.io import Term
42 from IPython.utils.io import Term
43 from IPython.utils.autoattr import auto_attr
43 from IPython.utils.autoattr import auto_attr
44 from IPython.utils.importstring import import_item
44 from IPython.utils.importstring import import_item
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Code
47 # Code
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 _loaded = False
51 _loaded = False
52
52
53
53
54 class PrettyResultDisplay(Plugin):
54 class PrettyResultDisplay(Plugin):
55 """A component for pretty printing on steroids."""
55 """A component for pretty printing on steroids."""
56
56
57 verbose = Bool(False, config=True)
57 verbose = Bool(False, config=True)
58 shell = Instance('IPython.core.iplib.InteractiveShellABC')
58 shell = Instance('IPython.core.iplib.InteractiveShellABC')
59
59
60 # A list of (type, func_name), like
60 # A list of (type, func_name), like
61 # [(dict, 'my_dict_printer')]
61 # [(dict, 'my_dict_printer')]
62 # The final argument can also be a callable
62 # The final argument can also be a callable
63 defaults_for_type = List(default_value=[], config=True)
63 defaults_for_type = List(default_value=[], config=True)
64
64
65 # A list of (module_name, type_name, func_name), like
65 # A list of (module_name, type_name, func_name), like
66 # [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')]
66 # [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')]
67 # The final argument can also be a callable
67 # The final argument can also be a callable
68 defaults_for_type_by_name = List(default_value=[], config=True)
68 defaults_for_type_by_name = List(default_value=[], config=True)
69
69
70 def __init__(self, shell, config=None):
70 def __init__(self, shell=None, config=None):
71 super(PrettyResultDisplay, self).__init__(config=config)
71 super(PrettyResultDisplay, self).__init__(shell=shell, config=config)
72 self.shell = shell
73 self._setup_defaults()
72 self._setup_defaults()
74
73
75 def _setup_defaults(self):
74 def _setup_defaults(self):
76 """Initialize the default pretty printers."""
75 """Initialize the default pretty printers."""
77 for typ, func_name in self.defaults_for_type:
76 for typ, func_name in self.defaults_for_type:
78 func = self._resolve_func_name(func_name)
77 func = self._resolve_func_name(func_name)
79 self.for_type(typ, func)
78 self.for_type(typ, func)
80 for type_module, type_name, func_name in self.defaults_for_type_by_name:
79 for type_module, type_name, func_name in self.defaults_for_type_by_name:
81 func = self._resolve_func_name(func_name)
80 func = self._resolve_func_name(func_name)
82 self.for_type_by_name(type_module, type_name, func)
81 self.for_type_by_name(type_module, type_name, func)
83
82
84 def _resolve_func_name(self, func_name):
83 def _resolve_func_name(self, func_name):
85 if callable(func_name):
84 if callable(func_name):
86 return func_name
85 return func_name
87 elif isinstance(func_name, basestring):
86 elif isinstance(func_name, basestring):
88 return import_item(func_name)
87 return import_item(func_name)
89 else:
88 else:
90 raise TypeError('func_name must be a str or callable, got: %r' % func_name)
89 raise TypeError('func_name must be a str or callable, got: %r' % func_name)
91
90
92 def __call__(self, otherself, arg):
91 def __call__(self, otherself, arg):
93 """Uber-pretty-printing display hook.
92 """Uber-pretty-printing display hook.
94
93
95 Called for displaying the result to the user.
94 Called for displaying the result to the user.
96 """
95 """
97
96
98 if self.shell.pprint:
97 if self.shell.pprint:
99 out = pretty.pretty(arg, verbose=self.verbose)
98 out = pretty.pretty(arg, verbose=self.verbose)
100 if '\n' in out:
99 if '\n' in out:
101 # So that multi-line strings line up with the left column of
100 # So that multi-line strings line up with the left column of
102 # the screen, instead of having the output prompt mess up
101 # the screen, instead of having the output prompt mess up
103 # their first line.
102 # their first line.
104 Term.cout.write('\n')
103 Term.cout.write('\n')
105 print >>Term.cout, out
104 print >>Term.cout, out
106 else:
105 else:
107 raise TryNext
106 raise TryNext
108
107
109 def for_type(self, typ, func):
108 def for_type(self, typ, func):
110 """Add a pretty printer for a type."""
109 """Add a pretty printer for a type."""
111 return pretty.for_type(typ, func)
110 return pretty.for_type(typ, func)
112
111
113 def for_type_by_name(self, type_module, type_name, func):
112 def for_type_by_name(self, type_module, type_name, func):
114 """Add a pretty printer for a type by its name and module name."""
113 """Add a pretty printer for a type by its name and module name."""
115 return pretty.for_type_by_name(type_module, type_name, func)
114 return pretty.for_type_by_name(type_module, type_name, func)
116
115
117
116
118 #-----------------------------------------------------------------------------
117 #-----------------------------------------------------------------------------
119 # Initialization code for the extension
118 # Initialization code for the extension
120 #-----------------------------------------------------------------------------
119 #-----------------------------------------------------------------------------
121
120
122
121
123 def load_ipython_extension(ip):
122 def load_ipython_extension(ip):
124 """Load the extension in IPython as a hook."""
123 """Load the extension in IPython as a hook."""
125 global _loaded
124 global _loaded
126 if not _loaded:
125 if not _loaded:
127 plugin = PrettyResultDisplay(ip, config=ip.config)
126 plugin = PrettyResultDisplay(shell=ip, config=ip.config)
128 ip.set_hook('result_display', plugin, priority=99)
127 ip.set_hook('result_display', plugin, priority=99)
129 _loaded = True
128 _loaded = True
130 ip.plugin_manager.register_plugin('pretty_result_display', plugin)
129 ip.plugin_manager.register_plugin('pretty_result_display', plugin)
131
130
132 def unload_ipython_extension(ip):
131 def unload_ipython_extension(ip):
133 """Unload the extension."""
132 """Unload the extension."""
134 # The hook system does not have a way to remove a hook so this is a pass
133 # The hook system does not have a way to remove a hook so this is a pass
135 pass
134 pass
136
135
137
136
138 #-----------------------------------------------------------------------------
137 #-----------------------------------------------------------------------------
139 # Example pretty printers
138 # Example pretty printers
140 #-----------------------------------------------------------------------------
139 #-----------------------------------------------------------------------------
141
140
142
141
143 def dtype_pprinter(obj, p, cycle):
142 def dtype_pprinter(obj, p, cycle):
144 """ A pretty-printer for numpy dtype objects.
143 """ A pretty-printer for numpy dtype objects.
145 """
144 """
146 if cycle:
145 if cycle:
147 return p.text('dtype(...)')
146 return p.text('dtype(...)')
148 if hasattr(obj, 'fields'):
147 if hasattr(obj, 'fields'):
149 if obj.fields is None:
148 if obj.fields is None:
150 p.text(repr(obj))
149 p.text(repr(obj))
151 else:
150 else:
152 p.begin_group(7, 'dtype([')
151 p.begin_group(7, 'dtype([')
153 for i, field in enumerate(obj.descr):
152 for i, field in enumerate(obj.descr):
154 if i > 0:
153 if i > 0:
155 p.text(',')
154 p.text(',')
156 p.breakable()
155 p.breakable()
157 p.pretty(field)
156 p.pretty(field)
158 p.end_group(7, '])')
157 p.end_group(7, '])')
@@ -1,100 +1,100 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Simple tests for :mod:`IPython.extensions.pretty`.
4 Simple tests for :mod:`IPython.extensions.pretty`.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from unittest import TestCase
18 from unittest import TestCase
19
19
20 from IPython.config.configurable import Configurable
20 from IPython.config.configurable import Configurable
21 from IPython.core.iplib import InteractiveShellABC
21 from IPython.core.iplib import InteractiveShellABC
22 from IPython.extensions import pretty as pretty_ext
22 from IPython.extensions import pretty as pretty_ext
23 from IPython.external import pretty
23 from IPython.external import pretty
24 from IPython.testing import decorators as dec
24 from IPython.testing import decorators as dec
25 from IPython.testing import tools as tt
25 from IPython.testing import tools as tt
26 from IPython.utils.traitlets import Bool
26 from IPython.utils.traitlets import Bool
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Tests
29 # Tests
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 class InteractiveShellStub(Configurable):
32 class InteractiveShellStub(Configurable):
33 pprint = Bool(True)
33 pprint = Bool(True)
34
34
35 InteractiveShellABC.register(InteractiveShellStub)
35 InteractiveShellABC.register(InteractiveShellStub)
36
36
37 class A(object):
37 class A(object):
38 pass
38 pass
39
39
40 def a_pprinter(o, p, c):
40 def a_pprinter(o, p, c):
41 return p.text("<A>")
41 return p.text("<A>")
42
42
43 class TestPrettyResultDisplay(TestCase):
43 class TestPrettyResultDisplay(TestCase):
44
44
45 def setUp(self):
45 def setUp(self):
46 self.ip = InteractiveShellStub()
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 def test_for_type(self):
49 def test_for_type(self):
50 self.prd.for_type(A, a_pprinter)
50 self.prd.for_type(A, a_pprinter)
51 a = A()
51 a = A()
52 result = pretty.pretty(a)
52 result = pretty.pretty(a)
53 self.assertEquals(result, "<A>")
53 self.assertEquals(result, "<A>")
54
54
55 ipy_src = """
55 ipy_src = """
56 class A(object):
56 class A(object):
57 def __repr__(self):
57 def __repr__(self):
58 return 'A()'
58 return 'A()'
59
59
60 class B(object):
60 class B(object):
61 def __repr__(self):
61 def __repr__(self):
62 return 'B()'
62 return 'B()'
63
63
64 a = A()
64 a = A()
65 b = B()
65 b = B()
66
66
67 def a_pretty_printer(obj, p, cycle):
67 def a_pretty_printer(obj, p, cycle):
68 p.text('<A>')
68 p.text('<A>')
69
69
70 def b_pretty_printer(obj, p, cycle):
70 def b_pretty_printer(obj, p, cycle):
71 p.text('<B>')
71 p.text('<B>')
72
72
73
73
74 a
74 a
75 b
75 b
76
76
77 ip = get_ipython()
77 ip = get_ipython()
78 ip.extension_manager.load_extension('pretty')
78 ip.extension_manager.load_extension('pretty')
79 prd = ip.plugin_manager.get_plugin('pretty_result_display')
79 prd = ip.plugin_manager.get_plugin('pretty_result_display')
80 prd.for_type(A, a_pretty_printer)
80 prd.for_type(A, a_pretty_printer)
81 prd.for_type_by_name(B.__module__, B.__name__, b_pretty_printer)
81 prd.for_type_by_name(B.__module__, B.__name__, b_pretty_printer)
82
82
83 a
83 a
84 b
84 b
85 """
85 """
86 ipy_out = """
86 ipy_out = """
87 A()
87 A()
88 B()
88 B()
89 <A>
89 <A>
90 <B>
90 <B>
91 """
91 """
92
92
93 class TestPrettyInteractively(tt.TempFileMixin):
93 class TestPrettyInteractively(tt.TempFileMixin):
94
94
95 # XXX Unfortunately, ipexec_validate fails under win32. If someone helps
95 # XXX Unfortunately, ipexec_validate fails under win32. If someone helps
96 # us write a win32-compatible version, we can reactivate this test.
96 # us write a win32-compatible version, we can reactivate this test.
97 @dec.skip_win32
97 @dec.skip_win32
98 def test_printers(self):
98 def test_printers(self):
99 self.mktmp(ipy_src, '.ipy')
99 self.mktmp(ipy_src, '.ipy')
100 tt.ipexec_validate(self.fname, ipy_out)
100 tt.ipexec_validate(self.fname, ipy_out)
@@ -1,539 +1,538 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython cluster directory
4 The IPython cluster directory
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import with_statement
18 from __future__ import with_statement
19
19
20 import os
20 import os
21 import shutil
21 import shutil
22 import sys
22 import sys
23 import warnings
23 import warnings
24
24
25 from twisted.python import log
25 from twisted.python import log
26
26
27 from IPython.config.loader import PyFileConfigLoader
27 from IPython.config.loader import PyFileConfigLoader
28 from IPython.core.application import Application, BaseAppConfigLoader
28 from IPython.core.application import Application, BaseAppConfigLoader
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.core.crashhandler import CrashHandler
30 from IPython.core.crashhandler import CrashHandler
31 from IPython.core import release
31 from IPython.core import release
32 from IPython.utils.path import (
32 from IPython.utils.path import (
33 get_ipython_package_dir,
33 get_ipython_package_dir,
34 expand_path
34 expand_path
35 )
35 )
36 from IPython.utils.traitlets import Unicode
36 from IPython.utils.traitlets import Unicode
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Warnings control
39 # Warnings control
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Twisted generates annoying warnings with Python 2.6, as will do other code
41 # Twisted generates annoying warnings with Python 2.6, as will do other code
42 # that imports 'sets' as of today
42 # that imports 'sets' as of today
43 warnings.filterwarnings('ignore', 'the sets module is deprecated',
43 warnings.filterwarnings('ignore', 'the sets module is deprecated',
44 DeprecationWarning )
44 DeprecationWarning )
45
45
46 # This one also comes from Twisted
46 # This one also comes from Twisted
47 warnings.filterwarnings('ignore', 'the sha module is deprecated',
47 warnings.filterwarnings('ignore', 'the sha module is deprecated',
48 DeprecationWarning)
48 DeprecationWarning)
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Module errors
51 # Module errors
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 class ClusterDirError(Exception):
54 class ClusterDirError(Exception):
55 pass
55 pass
56
56
57
57
58 class PIDFileError(Exception):
58 class PIDFileError(Exception):
59 pass
59 pass
60
60
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # Class for managing cluster directories
63 # Class for managing cluster directories
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65
65
66 class ClusterDir(Configurable):
66 class ClusterDir(Configurable):
67 """An object to manage the cluster directory and its resources.
67 """An object to manage the cluster directory and its resources.
68
68
69 The cluster directory is used by :command:`ipcontroller`,
69 The cluster directory is used by :command:`ipcontroller`,
70 :command:`ipcontroller` and :command:`ipcontroller` to manage the
70 :command:`ipcontroller` and :command:`ipcontroller` to manage the
71 configuration, logging and security of these applications.
71 configuration, logging and security of these applications.
72
72
73 This object knows how to find, create and manage these directories. This
73 This object knows how to find, create and manage these directories. This
74 should be used by any code that want's to handle cluster directories.
74 should be used by any code that want's to handle cluster directories.
75 """
75 """
76
76
77 security_dir_name = Unicode('security')
77 security_dir_name = Unicode('security')
78 log_dir_name = Unicode('log')
78 log_dir_name = Unicode('log')
79 pid_dir_name = Unicode('pid')
79 pid_dir_name = Unicode('pid')
80 security_dir = Unicode(u'')
80 security_dir = Unicode(u'')
81 log_dir = Unicode(u'')
81 log_dir = Unicode(u'')
82 pid_dir = Unicode(u'')
82 pid_dir = Unicode(u'')
83 location = Unicode(u'')
83 location = Unicode(u'')
84
84
85 def __init__(self, location):
85 def __init__(self, location=u''):
86 super(ClusterDir, self).__init__(None)
86 super(ClusterDir, self).__init__(location=location)
87 self.location = location
88
87
89 def _location_changed(self, name, old, new):
88 def _location_changed(self, name, old, new):
90 if not os.path.isdir(new):
89 if not os.path.isdir(new):
91 os.makedirs(new)
90 os.makedirs(new)
92 self.security_dir = os.path.join(new, self.security_dir_name)
91 self.security_dir = os.path.join(new, self.security_dir_name)
93 self.log_dir = os.path.join(new, self.log_dir_name)
92 self.log_dir = os.path.join(new, self.log_dir_name)
94 self.pid_dir = os.path.join(new, self.pid_dir_name)
93 self.pid_dir = os.path.join(new, self.pid_dir_name)
95 self.check_dirs()
94 self.check_dirs()
96
95
97 def _log_dir_changed(self, name, old, new):
96 def _log_dir_changed(self, name, old, new):
98 self.check_log_dir()
97 self.check_log_dir()
99
98
100 def check_log_dir(self):
99 def check_log_dir(self):
101 if not os.path.isdir(self.log_dir):
100 if not os.path.isdir(self.log_dir):
102 os.mkdir(self.log_dir)
101 os.mkdir(self.log_dir)
103
102
104 def _security_dir_changed(self, name, old, new):
103 def _security_dir_changed(self, name, old, new):
105 self.check_security_dir()
104 self.check_security_dir()
106
105
107 def check_security_dir(self):
106 def check_security_dir(self):
108 if not os.path.isdir(self.security_dir):
107 if not os.path.isdir(self.security_dir):
109 os.mkdir(self.security_dir, 0700)
108 os.mkdir(self.security_dir, 0700)
110 os.chmod(self.security_dir, 0700)
109 os.chmod(self.security_dir, 0700)
111
110
112 def _pid_dir_changed(self, name, old, new):
111 def _pid_dir_changed(self, name, old, new):
113 self.check_pid_dir()
112 self.check_pid_dir()
114
113
115 def check_pid_dir(self):
114 def check_pid_dir(self):
116 if not os.path.isdir(self.pid_dir):
115 if not os.path.isdir(self.pid_dir):
117 os.mkdir(self.pid_dir, 0700)
116 os.mkdir(self.pid_dir, 0700)
118 os.chmod(self.pid_dir, 0700)
117 os.chmod(self.pid_dir, 0700)
119
118
120 def check_dirs(self):
119 def check_dirs(self):
121 self.check_security_dir()
120 self.check_security_dir()
122 self.check_log_dir()
121 self.check_log_dir()
123 self.check_pid_dir()
122 self.check_pid_dir()
124
123
125 def load_config_file(self, filename):
124 def load_config_file(self, filename):
126 """Load a config file from the top level of the cluster dir.
125 """Load a config file from the top level of the cluster dir.
127
126
128 Parameters
127 Parameters
129 ----------
128 ----------
130 filename : unicode or str
129 filename : unicode or str
131 The filename only of the config file that must be located in
130 The filename only of the config file that must be located in
132 the top-level of the cluster directory.
131 the top-level of the cluster directory.
133 """
132 """
134 loader = PyFileConfigLoader(filename, self.location)
133 loader = PyFileConfigLoader(filename, self.location)
135 return loader.load_config()
134 return loader.load_config()
136
135
137 def copy_config_file(self, config_file, path=None, overwrite=False):
136 def copy_config_file(self, config_file, path=None, overwrite=False):
138 """Copy a default config file into the active cluster directory.
137 """Copy a default config file into the active cluster directory.
139
138
140 Default configuration files are kept in :mod:`IPython.config.default`.
139 Default configuration files are kept in :mod:`IPython.config.default`.
141 This function moves these from that location to the working cluster
140 This function moves these from that location to the working cluster
142 directory.
141 directory.
143 """
142 """
144 if path is None:
143 if path is None:
145 import IPython.config.default
144 import IPython.config.default
146 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
145 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
147 path = os.path.sep.join(path)
146 path = os.path.sep.join(path)
148 src = os.path.join(path, config_file)
147 src = os.path.join(path, config_file)
149 dst = os.path.join(self.location, config_file)
148 dst = os.path.join(self.location, config_file)
150 if not os.path.isfile(dst) or overwrite:
149 if not os.path.isfile(dst) or overwrite:
151 shutil.copy(src, dst)
150 shutil.copy(src, dst)
152
151
153 def copy_all_config_files(self, path=None, overwrite=False):
152 def copy_all_config_files(self, path=None, overwrite=False):
154 """Copy all config files into the active cluster directory."""
153 """Copy all config files into the active cluster directory."""
155 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
154 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
156 u'ipcluster_config.py']:
155 u'ipcluster_config.py']:
157 self.copy_config_file(f, path=path, overwrite=overwrite)
156 self.copy_config_file(f, path=path, overwrite=overwrite)
158
157
159 @classmethod
158 @classmethod
160 def create_cluster_dir(csl, cluster_dir):
159 def create_cluster_dir(csl, cluster_dir):
161 """Create a new cluster directory given a full path.
160 """Create a new cluster directory given a full path.
162
161
163 Parameters
162 Parameters
164 ----------
163 ----------
165 cluster_dir : str
164 cluster_dir : str
166 The full path to the cluster directory. If it does exist, it will
165 The full path to the cluster directory. If it does exist, it will
167 be used. If not, it will be created.
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 @classmethod
170 @classmethod
172 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
171 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
173 """Create a cluster dir by profile name and path.
172 """Create a cluster dir by profile name and path.
174
173
175 Parameters
174 Parameters
176 ----------
175 ----------
177 path : str
176 path : str
178 The path (directory) to put the cluster directory in.
177 The path (directory) to put the cluster directory in.
179 profile : str
178 profile : str
180 The name of the profile. The name of the cluster directory will
179 The name of the profile. The name of the cluster directory will
181 be "cluster_<profile>".
180 be "cluster_<profile>".
182 """
181 """
183 if not os.path.isdir(path):
182 if not os.path.isdir(path):
184 raise ClusterDirError('Directory not found: %s' % path)
183 raise ClusterDirError('Directory not found: %s' % path)
185 cluster_dir = os.path.join(path, u'cluster_' + profile)
184 cluster_dir = os.path.join(path, u'cluster_' + profile)
186 return ClusterDir(cluster_dir)
185 return ClusterDir(location=cluster_dir)
187
186
188 @classmethod
187 @classmethod
189 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
188 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
190 """Find an existing cluster dir by profile name, return its ClusterDir.
189 """Find an existing cluster dir by profile name, return its ClusterDir.
191
190
192 This searches through a sequence of paths for a cluster dir. If it
191 This searches through a sequence of paths for a cluster dir. If it
193 is not found, a :class:`ClusterDirError` exception will be raised.
192 is not found, a :class:`ClusterDirError` exception will be raised.
194
193
195 The search path algorithm is:
194 The search path algorithm is:
196 1. ``os.getcwd()``
195 1. ``os.getcwd()``
197 2. ``ipython_dir``
196 2. ``ipython_dir``
198 3. The directories found in the ":" separated
197 3. The directories found in the ":" separated
199 :env:`IPCLUSTER_DIR_PATH` environment variable.
198 :env:`IPCLUSTER_DIR_PATH` environment variable.
200
199
201 Parameters
200 Parameters
202 ----------
201 ----------
203 ipython_dir : unicode or str
202 ipython_dir : unicode or str
204 The IPython directory to use.
203 The IPython directory to use.
205 profile : unicode or str
204 profile : unicode or str
206 The name of the profile. The name of the cluster directory
205 The name of the profile. The name of the cluster directory
207 will be "cluster_<profile>".
206 will be "cluster_<profile>".
208 """
207 """
209 dirname = u'cluster_' + profile
208 dirname = u'cluster_' + profile
210 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
209 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
211 if cluster_dir_paths:
210 if cluster_dir_paths:
212 cluster_dir_paths = cluster_dir_paths.split(':')
211 cluster_dir_paths = cluster_dir_paths.split(':')
213 else:
212 else:
214 cluster_dir_paths = []
213 cluster_dir_paths = []
215 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
214 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
216 for p in paths:
215 for p in paths:
217 cluster_dir = os.path.join(p, dirname)
216 cluster_dir = os.path.join(p, dirname)
218 if os.path.isdir(cluster_dir):
217 if os.path.isdir(cluster_dir):
219 return ClusterDir(cluster_dir)
218 return ClusterDir(location=cluster_dir)
220 else:
219 else:
221 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
220 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
222
221
223 @classmethod
222 @classmethod
224 def find_cluster_dir(cls, cluster_dir):
223 def find_cluster_dir(cls, cluster_dir):
225 """Find/create a cluster dir and return its ClusterDir.
224 """Find/create a cluster dir and return its ClusterDir.
226
225
227 This will create the cluster directory if it doesn't exist.
226 This will create the cluster directory if it doesn't exist.
228
227
229 Parameters
228 Parameters
230 ----------
229 ----------
231 cluster_dir : unicode or str
230 cluster_dir : unicode or str
232 The path of the cluster directory. This is expanded using
231 The path of the cluster directory. This is expanded using
233 :func:`IPython.utils.genutils.expand_path`.
232 :func:`IPython.utils.genutils.expand_path`.
234 """
233 """
235 cluster_dir = expand_path(cluster_dir)
234 cluster_dir = expand_path(cluster_dir)
236 if not os.path.isdir(cluster_dir):
235 if not os.path.isdir(cluster_dir):
237 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
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 # Command line options
241 # Command line options
243 #-----------------------------------------------------------------------------
242 #-----------------------------------------------------------------------------
244
243
245 class ClusterDirConfigLoader(BaseAppConfigLoader):
244 class ClusterDirConfigLoader(BaseAppConfigLoader):
246
245
247 def _add_cluster_profile(self, parser):
246 def _add_cluster_profile(self, parser):
248 paa = parser.add_argument
247 paa = parser.add_argument
249 paa('-p', '--profile',
248 paa('-p', '--profile',
250 dest='Global.profile',type=unicode,
249 dest='Global.profile',type=unicode,
251 help=
250 help=
252 """The string name of the profile to be used. This determines the name
251 """The string name of the profile to be used. This determines the name
253 of the cluster dir as: cluster_<profile>. The default profile is named
252 of the cluster dir as: cluster_<profile>. The default profile is named
254 'default'. The cluster directory is resolve this way if the
253 'default'. The cluster directory is resolve this way if the
255 --cluster-dir option is not used.""",
254 --cluster-dir option is not used.""",
256 metavar='Global.profile')
255 metavar='Global.profile')
257
256
258 def _add_cluster_dir(self, parser):
257 def _add_cluster_dir(self, parser):
259 paa = parser.add_argument
258 paa = parser.add_argument
260 paa('--cluster-dir',
259 paa('--cluster-dir',
261 dest='Global.cluster_dir',type=unicode,
260 dest='Global.cluster_dir',type=unicode,
262 help="""Set the cluster dir. This overrides the logic used by the
261 help="""Set the cluster dir. This overrides the logic used by the
263 --profile option.""",
262 --profile option.""",
264 metavar='Global.cluster_dir')
263 metavar='Global.cluster_dir')
265
264
266 def _add_work_dir(self, parser):
265 def _add_work_dir(self, parser):
267 paa = parser.add_argument
266 paa = parser.add_argument
268 paa('--work-dir',
267 paa('--work-dir',
269 dest='Global.work_dir',type=unicode,
268 dest='Global.work_dir',type=unicode,
270 help='Set the working dir for the process.',
269 help='Set the working dir for the process.',
271 metavar='Global.work_dir')
270 metavar='Global.work_dir')
272
271
273 def _add_clean_logs(self, parser):
272 def _add_clean_logs(self, parser):
274 paa = parser.add_argument
273 paa = parser.add_argument
275 paa('--clean-logs',
274 paa('--clean-logs',
276 dest='Global.clean_logs', action='store_true',
275 dest='Global.clean_logs', action='store_true',
277 help='Delete old log flies before starting.')
276 help='Delete old log flies before starting.')
278
277
279 def _add_no_clean_logs(self, parser):
278 def _add_no_clean_logs(self, parser):
280 paa = parser.add_argument
279 paa = parser.add_argument
281 paa('--no-clean-logs',
280 paa('--no-clean-logs',
282 dest='Global.clean_logs', action='store_false',
281 dest='Global.clean_logs', action='store_false',
283 help="Don't Delete old log flies before starting.")
282 help="Don't Delete old log flies before starting.")
284
283
285 def _add_arguments(self):
284 def _add_arguments(self):
286 super(ClusterDirConfigLoader, self)._add_arguments()
285 super(ClusterDirConfigLoader, self)._add_arguments()
287 self._add_cluster_profile(self.parser)
286 self._add_cluster_profile(self.parser)
288 self._add_cluster_dir(self.parser)
287 self._add_cluster_dir(self.parser)
289 self._add_work_dir(self.parser)
288 self._add_work_dir(self.parser)
290 self._add_clean_logs(self.parser)
289 self._add_clean_logs(self.parser)
291 self._add_no_clean_logs(self.parser)
290 self._add_no_clean_logs(self.parser)
292
291
293
292
294 #-----------------------------------------------------------------------------
293 #-----------------------------------------------------------------------------
295 # Crash handler for this application
294 # Crash handler for this application
296 #-----------------------------------------------------------------------------
295 #-----------------------------------------------------------------------------
297
296
298
297
299 _message_template = """\
298 _message_template = """\
300 Oops, $self.app_name crashed. We do our best to make it stable, but...
299 Oops, $self.app_name crashed. We do our best to make it stable, but...
301
300
302 A crash report was automatically generated with the following information:
301 A crash report was automatically generated with the following information:
303 - A verbatim copy of the crash traceback.
302 - A verbatim copy of the crash traceback.
304 - Data on your current $self.app_name configuration.
303 - Data on your current $self.app_name configuration.
305
304
306 It was left in the file named:
305 It was left in the file named:
307 \t'$self.crash_report_fname'
306 \t'$self.crash_report_fname'
308 If you can email this file to the developers, the information in it will help
307 If you can email this file to the developers, the information in it will help
309 them in understanding and correcting the problem.
308 them in understanding and correcting the problem.
310
309
311 You can mail it to: $self.contact_name at $self.contact_email
310 You can mail it to: $self.contact_name at $self.contact_email
312 with the subject '$self.app_name Crash Report'.
311 with the subject '$self.app_name Crash Report'.
313
312
314 If you want to do it now, the following command will work (under Unix):
313 If you want to do it now, the following command will work (under Unix):
315 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
314 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
316
315
317 To ensure accurate tracking of this issue, please file a report about it at:
316 To ensure accurate tracking of this issue, please file a report about it at:
318 $self.bug_tracker
317 $self.bug_tracker
319 """
318 """
320
319
321 class ClusterDirCrashHandler(CrashHandler):
320 class ClusterDirCrashHandler(CrashHandler):
322 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
321 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
323
322
324 message_template = _message_template
323 message_template = _message_template
325
324
326 def __init__(self, app):
325 def __init__(self, app):
327 contact_name = release.authors['Brian'][0]
326 contact_name = release.authors['Brian'][0]
328 contact_email = release.authors['Brian'][1]
327 contact_email = release.authors['Brian'][1]
329 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
328 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
330 super(ClusterDirCrashHandler,self).__init__(
329 super(ClusterDirCrashHandler,self).__init__(
331 app, contact_name, contact_email, bug_tracker
330 app, contact_name, contact_email, bug_tracker
332 )
331 )
333
332
334
333
335 #-----------------------------------------------------------------------------
334 #-----------------------------------------------------------------------------
336 # Main application
335 # Main application
337 #-----------------------------------------------------------------------------
336 #-----------------------------------------------------------------------------
338
337
339 class ApplicationWithClusterDir(Application):
338 class ApplicationWithClusterDir(Application):
340 """An application that puts everything into a cluster directory.
339 """An application that puts everything into a cluster directory.
341
340
342 Instead of looking for things in the ipython_dir, this type of application
341 Instead of looking for things in the ipython_dir, this type of application
343 will use its own private directory called the "cluster directory"
342 will use its own private directory called the "cluster directory"
344 for things like config files, log files, etc.
343 for things like config files, log files, etc.
345
344
346 The cluster directory is resolved as follows:
345 The cluster directory is resolved as follows:
347
346
348 * If the ``--cluster-dir`` option is given, it is used.
347 * If the ``--cluster-dir`` option is given, it is used.
349 * If ``--cluster-dir`` is not given, the application directory is
348 * If ``--cluster-dir`` is not given, the application directory is
350 resolve using the profile name as ``cluster_<profile>``. The search
349 resolve using the profile name as ``cluster_<profile>``. The search
351 path for this directory is then i) cwd if it is found there
350 path for this directory is then i) cwd if it is found there
352 and ii) in ipython_dir otherwise.
351 and ii) in ipython_dir otherwise.
353
352
354 The config file for the application is to be put in the cluster
353 The config file for the application is to be put in the cluster
355 dir and named the value of the ``config_file_name`` class attribute.
354 dir and named the value of the ``config_file_name`` class attribute.
356 """
355 """
357
356
358 command_line_loader = ClusterDirConfigLoader
357 command_line_loader = ClusterDirConfigLoader
359 crash_handler_class = ClusterDirCrashHandler
358 crash_handler_class = ClusterDirCrashHandler
360 auto_create_cluster_dir = True
359 auto_create_cluster_dir = True
361
360
362 def create_default_config(self):
361 def create_default_config(self):
363 super(ApplicationWithClusterDir, self).create_default_config()
362 super(ApplicationWithClusterDir, self).create_default_config()
364 self.default_config.Global.profile = u'default'
363 self.default_config.Global.profile = u'default'
365 self.default_config.Global.cluster_dir = u''
364 self.default_config.Global.cluster_dir = u''
366 self.default_config.Global.work_dir = os.getcwd()
365 self.default_config.Global.work_dir = os.getcwd()
367 self.default_config.Global.log_to_file = False
366 self.default_config.Global.log_to_file = False
368 self.default_config.Global.clean_logs = False
367 self.default_config.Global.clean_logs = False
369
368
370 def find_resources(self):
369 def find_resources(self):
371 """This resolves the cluster directory.
370 """This resolves the cluster directory.
372
371
373 This tries to find the cluster directory and if successful, it will
372 This tries to find the cluster directory and if successful, it will
374 have done:
373 have done:
375 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
374 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
376 the application.
375 the application.
377 * Sets ``self.cluster_dir`` attribute of the application and config
376 * Sets ``self.cluster_dir`` attribute of the application and config
378 objects.
377 objects.
379
378
380 The algorithm used for this is as follows:
379 The algorithm used for this is as follows:
381 1. Try ``Global.cluster_dir``.
380 1. Try ``Global.cluster_dir``.
382 2. Try using ``Global.profile``.
381 2. Try using ``Global.profile``.
383 3. If both of these fail and ``self.auto_create_cluster_dir`` is
382 3. If both of these fail and ``self.auto_create_cluster_dir`` is
384 ``True``, then create the new cluster dir in the IPython directory.
383 ``True``, then create the new cluster dir in the IPython directory.
385 4. If all fails, then raise :class:`ClusterDirError`.
384 4. If all fails, then raise :class:`ClusterDirError`.
386 """
385 """
387
386
388 try:
387 try:
389 cluster_dir = self.command_line_config.Global.cluster_dir
388 cluster_dir = self.command_line_config.Global.cluster_dir
390 except AttributeError:
389 except AttributeError:
391 cluster_dir = self.default_config.Global.cluster_dir
390 cluster_dir = self.default_config.Global.cluster_dir
392 cluster_dir = expand_path(cluster_dir)
391 cluster_dir = expand_path(cluster_dir)
393 try:
392 try:
394 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
393 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
395 except ClusterDirError:
394 except ClusterDirError:
396 pass
395 pass
397 else:
396 else:
398 self.log.info('Using existing cluster dir: %s' % \
397 self.log.info('Using existing cluster dir: %s' % \
399 self.cluster_dir_obj.location
398 self.cluster_dir_obj.location
400 )
399 )
401 self.finish_cluster_dir()
400 self.finish_cluster_dir()
402 return
401 return
403
402
404 try:
403 try:
405 self.profile = self.command_line_config.Global.profile
404 self.profile = self.command_line_config.Global.profile
406 except AttributeError:
405 except AttributeError:
407 self.profile = self.default_config.Global.profile
406 self.profile = self.default_config.Global.profile
408 try:
407 try:
409 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
408 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
410 self.ipython_dir, self.profile)
409 self.ipython_dir, self.profile)
411 except ClusterDirError:
410 except ClusterDirError:
412 pass
411 pass
413 else:
412 else:
414 self.log.info('Using existing cluster dir: %s' % \
413 self.log.info('Using existing cluster dir: %s' % \
415 self.cluster_dir_obj.location
414 self.cluster_dir_obj.location
416 )
415 )
417 self.finish_cluster_dir()
416 self.finish_cluster_dir()
418 return
417 return
419
418
420 if self.auto_create_cluster_dir:
419 if self.auto_create_cluster_dir:
421 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
420 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
422 self.ipython_dir, self.profile
421 self.ipython_dir, self.profile
423 )
422 )
424 self.log.info('Creating new cluster dir: %s' % \
423 self.log.info('Creating new cluster dir: %s' % \
425 self.cluster_dir_obj.location
424 self.cluster_dir_obj.location
426 )
425 )
427 self.finish_cluster_dir()
426 self.finish_cluster_dir()
428 else:
427 else:
429 raise ClusterDirError('Could not find a valid cluster directory.')
428 raise ClusterDirError('Could not find a valid cluster directory.')
430
429
431 def finish_cluster_dir(self):
430 def finish_cluster_dir(self):
432 # Set the cluster directory
431 # Set the cluster directory
433 self.cluster_dir = self.cluster_dir_obj.location
432 self.cluster_dir = self.cluster_dir_obj.location
434
433
435 # These have to be set because they could be different from the one
434 # These have to be set because they could be different from the one
436 # that we just computed. Because command line has the highest
435 # that we just computed. Because command line has the highest
437 # priority, this will always end up in the master_config.
436 # priority, this will always end up in the master_config.
438 self.default_config.Global.cluster_dir = self.cluster_dir
437 self.default_config.Global.cluster_dir = self.cluster_dir
439 self.command_line_config.Global.cluster_dir = self.cluster_dir
438 self.command_line_config.Global.cluster_dir = self.cluster_dir
440
439
441 def find_config_file_name(self):
440 def find_config_file_name(self):
442 """Find the config file name for this application."""
441 """Find the config file name for this application."""
443 # For this type of Application it should be set as a class attribute.
442 # For this type of Application it should be set as a class attribute.
444 if not hasattr(self, 'default_config_file_name'):
443 if not hasattr(self, 'default_config_file_name'):
445 self.log.critical("No config filename found")
444 self.log.critical("No config filename found")
446 else:
445 else:
447 self.config_file_name = self.default_config_file_name
446 self.config_file_name = self.default_config_file_name
448
447
449 def find_config_file_paths(self):
448 def find_config_file_paths(self):
450 # Set the search path to to the cluster directory. We should NOT
449 # Set the search path to to the cluster directory. We should NOT
451 # include IPython.config.default here as the default config files
450 # include IPython.config.default here as the default config files
452 # are ALWAYS automatically moved to the cluster directory.
451 # are ALWAYS automatically moved to the cluster directory.
453 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
452 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
454 self.config_file_paths = (self.cluster_dir,)
453 self.config_file_paths = (self.cluster_dir,)
455
454
456 def pre_construct(self):
455 def pre_construct(self):
457 # The log and security dirs were set earlier, but here we put them
456 # The log and security dirs were set earlier, but here we put them
458 # into the config and log them.
457 # into the config and log them.
459 config = self.master_config
458 config = self.master_config
460 sdir = self.cluster_dir_obj.security_dir
459 sdir = self.cluster_dir_obj.security_dir
461 self.security_dir = config.Global.security_dir = sdir
460 self.security_dir = config.Global.security_dir = sdir
462 ldir = self.cluster_dir_obj.log_dir
461 ldir = self.cluster_dir_obj.log_dir
463 self.log_dir = config.Global.log_dir = ldir
462 self.log_dir = config.Global.log_dir = ldir
464 pdir = self.cluster_dir_obj.pid_dir
463 pdir = self.cluster_dir_obj.pid_dir
465 self.pid_dir = config.Global.pid_dir = pdir
464 self.pid_dir = config.Global.pid_dir = pdir
466 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
465 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
467 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
466 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
468 # Change to the working directory. We do this just before construct
467 # Change to the working directory. We do this just before construct
469 # is called so all the components there have the right working dir.
468 # is called so all the components there have the right working dir.
470 self.to_work_dir()
469 self.to_work_dir()
471
470
472 def to_work_dir(self):
471 def to_work_dir(self):
473 wd = self.master_config.Global.work_dir
472 wd = self.master_config.Global.work_dir
474 if unicode(wd) != unicode(os.getcwd()):
473 if unicode(wd) != unicode(os.getcwd()):
475 os.chdir(wd)
474 os.chdir(wd)
476 self.log.info("Changing to working dir: %s" % wd)
475 self.log.info("Changing to working dir: %s" % wd)
477
476
478 def start_logging(self):
477 def start_logging(self):
479 # Remove old log files
478 # Remove old log files
480 if self.master_config.Global.clean_logs:
479 if self.master_config.Global.clean_logs:
481 log_dir = self.master_config.Global.log_dir
480 log_dir = self.master_config.Global.log_dir
482 for f in os.listdir(log_dir):
481 for f in os.listdir(log_dir):
483 if f.startswith(self.name + u'-') and f.endswith('.log'):
482 if f.startswith(self.name + u'-') and f.endswith('.log'):
484 os.remove(os.path.join(log_dir, f))
483 os.remove(os.path.join(log_dir, f))
485 # Start logging to the new log file
484 # Start logging to the new log file
486 if self.master_config.Global.log_to_file:
485 if self.master_config.Global.log_to_file:
487 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
486 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
488 logfile = os.path.join(self.log_dir, log_filename)
487 logfile = os.path.join(self.log_dir, log_filename)
489 open_log_file = open(logfile, 'w')
488 open_log_file = open(logfile, 'w')
490 else:
489 else:
491 open_log_file = sys.stdout
490 open_log_file = sys.stdout
492 log.startLogging(open_log_file)
491 log.startLogging(open_log_file)
493
492
494 def write_pid_file(self, overwrite=False):
493 def write_pid_file(self, overwrite=False):
495 """Create a .pid file in the pid_dir with my pid.
494 """Create a .pid file in the pid_dir with my pid.
496
495
497 This must be called after pre_construct, which sets `self.pid_dir`.
496 This must be called after pre_construct, which sets `self.pid_dir`.
498 This raises :exc:`PIDFileError` if the pid file exists already.
497 This raises :exc:`PIDFileError` if the pid file exists already.
499 """
498 """
500 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
499 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
501 if os.path.isfile(pid_file):
500 if os.path.isfile(pid_file):
502 pid = self.get_pid_from_file()
501 pid = self.get_pid_from_file()
503 if not overwrite:
502 if not overwrite:
504 raise PIDFileError(
503 raise PIDFileError(
505 'The pid file [%s] already exists. \nThis could mean that this '
504 'The pid file [%s] already exists. \nThis could mean that this '
506 'server is already running with [pid=%s].' % (pid_file, pid)
505 'server is already running with [pid=%s].' % (pid_file, pid)
507 )
506 )
508 with open(pid_file, 'w') as f:
507 with open(pid_file, 'w') as f:
509 self.log.info("Creating pid file: %s" % pid_file)
508 self.log.info("Creating pid file: %s" % pid_file)
510 f.write(repr(os.getpid())+'\n')
509 f.write(repr(os.getpid())+'\n')
511
510
512 def remove_pid_file(self):
511 def remove_pid_file(self):
513 """Remove the pid file.
512 """Remove the pid file.
514
513
515 This should be called at shutdown by registering a callback with
514 This should be called at shutdown by registering a callback with
516 :func:`reactor.addSystemEventTrigger`. This needs to return
515 :func:`reactor.addSystemEventTrigger`. This needs to return
517 ``None``.
516 ``None``.
518 """
517 """
519 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
518 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
520 if os.path.isfile(pid_file):
519 if os.path.isfile(pid_file):
521 try:
520 try:
522 self.log.info("Removing pid file: %s" % pid_file)
521 self.log.info("Removing pid file: %s" % pid_file)
523 os.remove(pid_file)
522 os.remove(pid_file)
524 except:
523 except:
525 self.log.warn("Error removing the pid file: %s" % pid_file)
524 self.log.warn("Error removing the pid file: %s" % pid_file)
526
525
527 def get_pid_from_file(self):
526 def get_pid_from_file(self):
528 """Get the pid from the pid file.
527 """Get the pid from the pid file.
529
528
530 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
529 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
531 """
530 """
532 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
531 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
533 if os.path.isfile(pid_file):
532 if os.path.isfile(pid_file):
534 with open(pid_file, 'r') as f:
533 with open(pid_file, 'r') as f:
535 pid = int(f.read().strip())
534 pid = int(f.read().strip())
536 return pid
535 return pid
537 else:
536 else:
538 raise PIDFileError('pid file not found: %s' % pid_file)
537 raise PIDFileError('pid file not found: %s' % pid_file)
539
538
@@ -1,79 +1,79 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A class for creating a Twisted service that is configured using IPython's
4 A class for creating a Twisted service that is configured using IPython's
5 configuration system.
5 configuration system.
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2009 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import zope.interface as zi
19 import zope.interface as zi
20
20
21 from IPython.config.configurable import Configurable
21 from IPython.config.configurable import Configurable
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Code
24 # Code
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27
27
28 class IConfiguredObjectFactory(zi.Interface):
28 class IConfiguredObjectFactory(zi.Interface):
29 """I am a component that creates a configured object.
29 """I am a component that creates a configured object.
30
30
31 This class is useful if you want to configure a class that is not a
31 This class is useful if you want to configure a class that is not a
32 subclass of :class:`IPython.config.configurable.Configurable`.
32 subclass of :class:`IPython.config.configurable.Configurable`.
33 """
33 """
34
34
35 def __init__(config):
35 def __init__(config):
36 """Get ready to configure the object using config."""
36 """Get ready to configure the object using config."""
37
37
38 def create():
38 def create():
39 """Return an instance of the configured object."""
39 """Return an instance of the configured object."""
40
40
41
41
42 class ConfiguredObjectFactory(Configurable):
42 class ConfiguredObjectFactory(Configurable):
43
43
44 zi.implements(IConfiguredObjectFactory)
44 zi.implements(IConfiguredObjectFactory)
45
45
46 def __init__(self, config):
46 def __init__(self, config=None):
47 super(ConfiguredObjectFactory, self).__init__(config=config)
47 super(ConfiguredObjectFactory, self).__init__(config=config)
48
48
49 def create(self):
49 def create(self):
50 raise NotImplementedError('create must be implemented in a subclass')
50 raise NotImplementedError('create must be implemented in a subclass')
51
51
52
52
53 class IAdaptedConfiguredObjectFactory(zi.Interface):
53 class IAdaptedConfiguredObjectFactory(zi.Interface):
54 """I am a component that adapts and configures an object.
54 """I am a component that adapts and configures an object.
55
55
56 This class is useful if you have the adapt an instance and configure it.
56 This class is useful if you have the adapt an instance and configure it.
57 """
57 """
58
58
59 def __init__(config, adaptee=None):
59 def __init__(config=None, adaptee=None):
60 """Get ready to adapt adaptee and then configure it using config."""
60 """Get ready to adapt adaptee and then configure it using config."""
61
61
62 def create():
62 def create():
63 """Return an instance of the adapted and configured object."""
63 """Return an instance of the adapted and configured object."""
64
64
65
65
66 class AdaptedConfiguredObjectFactory(Configurable):
66 class AdaptedConfiguredObjectFactory(Configurable):
67
67
68 # zi.implements(IAdaptedConfiguredObjectFactory)
68 # zi.implements(IAdaptedConfiguredObjectFactory)
69
69
70 def __init__(self, config, adaptee):
70 def __init__(self, config=None, adaptee=None):
71 # print
71 # print
72 # print "config pre:", config
72 # print "config pre:", config
73 super(AdaptedConfiguredObjectFactory, self).__init__(config=config)
73 super(AdaptedConfiguredObjectFactory, self).__init__(config=config)
74 # print
74 # print
75 # print "config post:", config
75 # print "config post:", config
76 self.adaptee = adaptee
76 self.adaptee = adaptee
77
77
78 def create(self):
78 def create(self):
79 raise NotImplementedError('create must be implemented in a subclass')
79 raise NotImplementedError('create must be implemented in a subclass')
@@ -1,835 +1,834 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Facilities for launching IPython processes asynchronously.
4 Facilities for launching IPython processes asynchronously.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21
21
22 from IPython.config.configurable import Configurable
22 from IPython.config.configurable import Configurable
23 from IPython.external import Itpl
23 from IPython.external import Itpl
24 from IPython.utils.traitlets import Str, Int, List, Unicode
24 from IPython.utils.traitlets import Str, Int, List, Unicode
25 from IPython.utils.path import get_ipython_module_path
25 from IPython.utils.path import get_ipython_module_path
26 from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError
26 from IPython.utils.process import find_cmd, pycmd2argv, FindCmdError
27 from IPython.kernel.twistedutil import (
27 from IPython.kernel.twistedutil import (
28 gatherBoth,
28 gatherBoth,
29 make_deferred,
29 make_deferred,
30 sleep_deferred
30 sleep_deferred
31 )
31 )
32 from IPython.kernel.winhpcjob import (
32 from IPython.kernel.winhpcjob import (
33 IPControllerTask, IPEngineTask,
33 IPControllerTask, IPEngineTask,
34 IPControllerJob, IPEngineSetJob
34 IPControllerJob, IPEngineSetJob
35 )
35 )
36
36
37 from twisted.internet import reactor, defer
37 from twisted.internet import reactor, defer
38 from twisted.internet.defer import inlineCallbacks
38 from twisted.internet.defer import inlineCallbacks
39 from twisted.internet.protocol import ProcessProtocol
39 from twisted.internet.protocol import ProcessProtocol
40 from twisted.internet.utils import getProcessOutput
40 from twisted.internet.utils import getProcessOutput
41 from twisted.internet.error import ProcessDone, ProcessTerminated
41 from twisted.internet.error import ProcessDone, ProcessTerminated
42 from twisted.python import log
42 from twisted.python import log
43 from twisted.python.failure import Failure
43 from twisted.python.failure import Failure
44
44
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Paths to the kernel apps
47 # Paths to the kernel apps
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 ipcluster_cmd_argv = pycmd2argv(get_ipython_module_path(
51 ipcluster_cmd_argv = pycmd2argv(get_ipython_module_path(
52 'IPython.kernel.ipclusterapp'
52 'IPython.kernel.ipclusterapp'
53 ))
53 ))
54
54
55 ipengine_cmd_argv = pycmd2argv(get_ipython_module_path(
55 ipengine_cmd_argv = pycmd2argv(get_ipython_module_path(
56 'IPython.kernel.ipengineapp'
56 'IPython.kernel.ipengineapp'
57 ))
57 ))
58
58
59 ipcontroller_cmd_argv = pycmd2argv(get_ipython_module_path(
59 ipcontroller_cmd_argv = pycmd2argv(get_ipython_module_path(
60 'IPython.kernel.ipcontrollerapp'
60 'IPython.kernel.ipcontrollerapp'
61 ))
61 ))
62
62
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 # Base launchers and errors
64 # Base launchers and errors
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67
67
68 class LauncherError(Exception):
68 class LauncherError(Exception):
69 pass
69 pass
70
70
71
71
72 class ProcessStateError(LauncherError):
72 class ProcessStateError(LauncherError):
73 pass
73 pass
74
74
75
75
76 class UnknownStatus(LauncherError):
76 class UnknownStatus(LauncherError):
77 pass
77 pass
78
78
79
79
80 class BaseLauncher(Configurable):
80 class BaseLauncher(Configurable):
81 """An asbtraction for starting, stopping and signaling a process."""
81 """An asbtraction for starting, stopping and signaling a process."""
82
82
83 # In all of the launchers, the work_dir is where child processes will be
83 # In all of the launchers, the work_dir is where child processes will be
84 # run. This will usually be the cluster_dir, but may not be. any work_dir
84 # run. This will usually be the cluster_dir, but may not be. any work_dir
85 # passed into the __init__ method will override the config value.
85 # passed into the __init__ method will override the config value.
86 # This should not be used to set the work_dir for the actual engine
86 # This should not be used to set the work_dir for the actual engine
87 # and controller. Instead, use their own config files or the
87 # and controller. Instead, use their own config files or the
88 # controller_args, engine_args attributes of the launchers to add
88 # controller_args, engine_args attributes of the launchers to add
89 # the --work-dir option.
89 # the --work-dir option.
90 work_dir = Unicode(u'')
90 work_dir = Unicode(u'')
91
91
92 def __init__(self, work_dir, config=None):
92 def __init__(self, work_dir=u'', config=None):
93 super(BaseLauncher, self).__init__(config)
93 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config)
94 self.work_dir = work_dir
95 self.state = 'before' # can be before, running, after
94 self.state = 'before' # can be before, running, after
96 self.stop_deferreds = []
95 self.stop_deferreds = []
97 self.start_data = None
96 self.start_data = None
98 self.stop_data = None
97 self.stop_data = None
99
98
100 @property
99 @property
101 def args(self):
100 def args(self):
102 """A list of cmd and args that will be used to start the process.
101 """A list of cmd and args that will be used to start the process.
103
102
104 This is what is passed to :func:`spawnProcess` and the first element
103 This is what is passed to :func:`spawnProcess` and the first element
105 will be the process name.
104 will be the process name.
106 """
105 """
107 return self.find_args()
106 return self.find_args()
108
107
109 def find_args(self):
108 def find_args(self):
110 """The ``.args`` property calls this to find the args list.
109 """The ``.args`` property calls this to find the args list.
111
110
112 Subcommand should implement this to construct the cmd and args.
111 Subcommand should implement this to construct the cmd and args.
113 """
112 """
114 raise NotImplementedError('find_args must be implemented in a subclass')
113 raise NotImplementedError('find_args must be implemented in a subclass')
115
114
116 @property
115 @property
117 def arg_str(self):
116 def arg_str(self):
118 """The string form of the program arguments."""
117 """The string form of the program arguments."""
119 return ' '.join(self.args)
118 return ' '.join(self.args)
120
119
121 @property
120 @property
122 def running(self):
121 def running(self):
123 """Am I running."""
122 """Am I running."""
124 if self.state == 'running':
123 if self.state == 'running':
125 return True
124 return True
126 else:
125 else:
127 return False
126 return False
128
127
129 def start(self):
128 def start(self):
130 """Start the process.
129 """Start the process.
131
130
132 This must return a deferred that fires with information about the
131 This must return a deferred that fires with information about the
133 process starting (like a pid, job id, etc.).
132 process starting (like a pid, job id, etc.).
134 """
133 """
135 return defer.fail(
134 return defer.fail(
136 Failure(NotImplementedError(
135 Failure(NotImplementedError(
137 'start must be implemented in a subclass')
136 'start must be implemented in a subclass')
138 )
137 )
139 )
138 )
140
139
141 def stop(self):
140 def stop(self):
142 """Stop the process and notify observers of stopping.
141 """Stop the process and notify observers of stopping.
143
142
144 This must return a deferred that fires with information about the
143 This must return a deferred that fires with information about the
145 processing stopping, like errors that occur while the process is
144 processing stopping, like errors that occur while the process is
146 attempting to be shut down. This deferred won't fire when the process
145 attempting to be shut down. This deferred won't fire when the process
147 actually stops. To observe the actual process stopping, see
146 actually stops. To observe the actual process stopping, see
148 :func:`observe_stop`.
147 :func:`observe_stop`.
149 """
148 """
150 return defer.fail(
149 return defer.fail(
151 Failure(NotImplementedError(
150 Failure(NotImplementedError(
152 'stop must be implemented in a subclass')
151 'stop must be implemented in a subclass')
153 )
152 )
154 )
153 )
155
154
156 def observe_stop(self):
155 def observe_stop(self):
157 """Get a deferred that will fire when the process stops.
156 """Get a deferred that will fire when the process stops.
158
157
159 The deferred will fire with data that contains information about
158 The deferred will fire with data that contains information about
160 the exit status of the process.
159 the exit status of the process.
161 """
160 """
162 if self.state=='after':
161 if self.state=='after':
163 return defer.succeed(self.stop_data)
162 return defer.succeed(self.stop_data)
164 else:
163 else:
165 d = defer.Deferred()
164 d = defer.Deferred()
166 self.stop_deferreds.append(d)
165 self.stop_deferreds.append(d)
167 return d
166 return d
168
167
169 def notify_start(self, data):
168 def notify_start(self, data):
170 """Call this to trigger startup actions.
169 """Call this to trigger startup actions.
171
170
172 This logs the process startup and sets the state to 'running'. It is
171 This logs the process startup and sets the state to 'running'. It is
173 a pass-through so it can be used as a callback.
172 a pass-through so it can be used as a callback.
174 """
173 """
175
174
176 log.msg('Process %r started: %r' % (self.args[0], data))
175 log.msg('Process %r started: %r' % (self.args[0], data))
177 self.start_data = data
176 self.start_data = data
178 self.state = 'running'
177 self.state = 'running'
179 return data
178 return data
180
179
181 def notify_stop(self, data):
180 def notify_stop(self, data):
182 """Call this to trigger process stop actions.
181 """Call this to trigger process stop actions.
183
182
184 This logs the process stopping and sets the state to 'after'. Call
183 This logs the process stopping and sets the state to 'after'. Call
185 this to trigger all the deferreds from :func:`observe_stop`."""
184 this to trigger all the deferreds from :func:`observe_stop`."""
186
185
187 log.msg('Process %r stopped: %r' % (self.args[0], data))
186 log.msg('Process %r stopped: %r' % (self.args[0], data))
188 self.stop_data = data
187 self.stop_data = data
189 self.state = 'after'
188 self.state = 'after'
190 for i in range(len(self.stop_deferreds)):
189 for i in range(len(self.stop_deferreds)):
191 d = self.stop_deferreds.pop()
190 d = self.stop_deferreds.pop()
192 d.callback(data)
191 d.callback(data)
193 return data
192 return data
194
193
195 def signal(self, sig):
194 def signal(self, sig):
196 """Signal the process.
195 """Signal the process.
197
196
198 Return a semi-meaningless deferred after signaling the process.
197 Return a semi-meaningless deferred after signaling the process.
199
198
200 Parameters
199 Parameters
201 ----------
200 ----------
202 sig : str or int
201 sig : str or int
203 'KILL', 'INT', etc., or any signal number
202 'KILL', 'INT', etc., or any signal number
204 """
203 """
205 return defer.fail(
204 return defer.fail(
206 Failure(NotImplementedError(
205 Failure(NotImplementedError(
207 'signal must be implemented in a subclass')
206 'signal must be implemented in a subclass')
208 )
207 )
209 )
208 )
210
209
211
210
212 #-----------------------------------------------------------------------------
211 #-----------------------------------------------------------------------------
213 # Local process launchers
212 # Local process launchers
214 #-----------------------------------------------------------------------------
213 #-----------------------------------------------------------------------------
215
214
216
215
217 class LocalProcessLauncherProtocol(ProcessProtocol):
216 class LocalProcessLauncherProtocol(ProcessProtocol):
218 """A ProcessProtocol to go with the LocalProcessLauncher."""
217 """A ProcessProtocol to go with the LocalProcessLauncher."""
219
218
220 def __init__(self, process_launcher):
219 def __init__(self, process_launcher):
221 self.process_launcher = process_launcher
220 self.process_launcher = process_launcher
222 self.pid = None
221 self.pid = None
223
222
224 def connectionMade(self):
223 def connectionMade(self):
225 self.pid = self.transport.pid
224 self.pid = self.transport.pid
226 self.process_launcher.notify_start(self.transport.pid)
225 self.process_launcher.notify_start(self.transport.pid)
227
226
228 def processEnded(self, status):
227 def processEnded(self, status):
229 value = status.value
228 value = status.value
230 if isinstance(value, ProcessDone):
229 if isinstance(value, ProcessDone):
231 self.process_launcher.notify_stop(
230 self.process_launcher.notify_stop(
232 {'exit_code':0,
231 {'exit_code':0,
233 'signal':None,
232 'signal':None,
234 'status':None,
233 'status':None,
235 'pid':self.pid
234 'pid':self.pid
236 }
235 }
237 )
236 )
238 elif isinstance(value, ProcessTerminated):
237 elif isinstance(value, ProcessTerminated):
239 self.process_launcher.notify_stop(
238 self.process_launcher.notify_stop(
240 {'exit_code':value.exitCode,
239 {'exit_code':value.exitCode,
241 'signal':value.signal,
240 'signal':value.signal,
242 'status':value.status,
241 'status':value.status,
243 'pid':self.pid
242 'pid':self.pid
244 }
243 }
245 )
244 )
246 else:
245 else:
247 raise UnknownStatus("Unknown exit status, this is probably a "
246 raise UnknownStatus("Unknown exit status, this is probably a "
248 "bug in Twisted")
247 "bug in Twisted")
249
248
250 def outReceived(self, data):
249 def outReceived(self, data):
251 log.msg(data)
250 log.msg(data)
252
251
253 def errReceived(self, data):
252 def errReceived(self, data):
254 log.err(data)
253 log.err(data)
255
254
256
255
257 class LocalProcessLauncher(BaseLauncher):
256 class LocalProcessLauncher(BaseLauncher):
258 """Start and stop an external process in an asynchronous manner.
257 """Start and stop an external process in an asynchronous manner.
259
258
260 This will launch the external process with a working directory of
259 This will launch the external process with a working directory of
261 ``self.work_dir``.
260 ``self.work_dir``.
262 """
261 """
263
262
264 # This is used to to construct self.args, which is passed to
263 # This is used to to construct self.args, which is passed to
265 # spawnProcess.
264 # spawnProcess.
266 cmd_and_args = List([])
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 super(LocalProcessLauncher, self).__init__(
268 super(LocalProcessLauncher, self).__init__(
270 work_dir, config
269 work_dir=work_dir, config=config
271 )
270 )
272 self.process_protocol = None
271 self.process_protocol = None
273 self.start_deferred = None
272 self.start_deferred = None
274
273
275 def find_args(self):
274 def find_args(self):
276 return self.cmd_and_args
275 return self.cmd_and_args
277
276
278 def start(self):
277 def start(self):
279 if self.state == 'before':
278 if self.state == 'before':
280 self.process_protocol = LocalProcessLauncherProtocol(self)
279 self.process_protocol = LocalProcessLauncherProtocol(self)
281 self.start_deferred = defer.Deferred()
280 self.start_deferred = defer.Deferred()
282 self.process_transport = reactor.spawnProcess(
281 self.process_transport = reactor.spawnProcess(
283 self.process_protocol,
282 self.process_protocol,
284 str(self.args[0]), # twisted expects these to be str, not unicode
283 str(self.args[0]), # twisted expects these to be str, not unicode
285 [str(a) for a in self.args], # str expected, not unicode
284 [str(a) for a in self.args], # str expected, not unicode
286 env=os.environ,
285 env=os.environ,
287 path=self.work_dir # start in the work_dir
286 path=self.work_dir # start in the work_dir
288 )
287 )
289 return self.start_deferred
288 return self.start_deferred
290 else:
289 else:
291 s = 'The process was already started and has state: %r' % self.state
290 s = 'The process was already started and has state: %r' % self.state
292 return defer.fail(ProcessStateError(s))
291 return defer.fail(ProcessStateError(s))
293
292
294 def notify_start(self, data):
293 def notify_start(self, data):
295 super(LocalProcessLauncher, self).notify_start(data)
294 super(LocalProcessLauncher, self).notify_start(data)
296 self.start_deferred.callback(data)
295 self.start_deferred.callback(data)
297
296
298 def stop(self):
297 def stop(self):
299 return self.interrupt_then_kill()
298 return self.interrupt_then_kill()
300
299
301 @make_deferred
300 @make_deferred
302 def signal(self, sig):
301 def signal(self, sig):
303 if self.state == 'running':
302 if self.state == 'running':
304 self.process_transport.signalProcess(sig)
303 self.process_transport.signalProcess(sig)
305
304
306 @inlineCallbacks
305 @inlineCallbacks
307 def interrupt_then_kill(self, delay=2.0):
306 def interrupt_then_kill(self, delay=2.0):
308 """Send INT, wait a delay and then send KILL."""
307 """Send INT, wait a delay and then send KILL."""
309 yield self.signal('INT')
308 yield self.signal('INT')
310 yield sleep_deferred(delay)
309 yield sleep_deferred(delay)
311 yield self.signal('KILL')
310 yield self.signal('KILL')
312
311
313
312
314 class LocalControllerLauncher(LocalProcessLauncher):
313 class LocalControllerLauncher(LocalProcessLauncher):
315 """Launch a controller as a regular external process."""
314 """Launch a controller as a regular external process."""
316
315
317 controller_cmd = List(ipcontroller_cmd_argv, config=True)
316 controller_cmd = List(ipcontroller_cmd_argv, config=True)
318 # Command line arguments to ipcontroller.
317 # Command line arguments to ipcontroller.
319 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
318 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
320
319
321 def find_args(self):
320 def find_args(self):
322 return self.controller_cmd + self.controller_args
321 return self.controller_cmd + self.controller_args
323
322
324 def start(self, cluster_dir):
323 def start(self, cluster_dir):
325 """Start the controller by cluster_dir."""
324 """Start the controller by cluster_dir."""
326 self.controller_args.extend(['--cluster-dir', cluster_dir])
325 self.controller_args.extend(['--cluster-dir', cluster_dir])
327 self.cluster_dir = unicode(cluster_dir)
326 self.cluster_dir = unicode(cluster_dir)
328 log.msg("Starting LocalControllerLauncher: %r" % self.args)
327 log.msg("Starting LocalControllerLauncher: %r" % self.args)
329 return super(LocalControllerLauncher, self).start()
328 return super(LocalControllerLauncher, self).start()
330
329
331
330
332 class LocalEngineLauncher(LocalProcessLauncher):
331 class LocalEngineLauncher(LocalProcessLauncher):
333 """Launch a single engine as a regular externall process."""
332 """Launch a single engine as a regular externall process."""
334
333
335 engine_cmd = List(ipengine_cmd_argv, config=True)
334 engine_cmd = List(ipengine_cmd_argv, config=True)
336 # Command line arguments for ipengine.
335 # Command line arguments for ipengine.
337 engine_args = List(
336 engine_args = List(
338 ['--log-to-file','--log-level', '40'], config=True
337 ['--log-to-file','--log-level', '40'], config=True
339 )
338 )
340
339
341 def find_args(self):
340 def find_args(self):
342 return self.engine_cmd + self.engine_args
341 return self.engine_cmd + self.engine_args
343
342
344 def start(self, cluster_dir):
343 def start(self, cluster_dir):
345 """Start the engine by cluster_dir."""
344 """Start the engine by cluster_dir."""
346 self.engine_args.extend(['--cluster-dir', cluster_dir])
345 self.engine_args.extend(['--cluster-dir', cluster_dir])
347 self.cluster_dir = unicode(cluster_dir)
346 self.cluster_dir = unicode(cluster_dir)
348 return super(LocalEngineLauncher, self).start()
347 return super(LocalEngineLauncher, self).start()
349
348
350
349
351 class LocalEngineSetLauncher(BaseLauncher):
350 class LocalEngineSetLauncher(BaseLauncher):
352 """Launch a set of engines as regular external processes."""
351 """Launch a set of engines as regular external processes."""
353
352
354 # Command line arguments for ipengine.
353 # Command line arguments for ipengine.
355 engine_args = List(
354 engine_args = List(
356 ['--log-to-file','--log-level', '40'], config=True
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 super(LocalEngineSetLauncher, self).__init__(
359 super(LocalEngineSetLauncher, self).__init__(
361 work_dir, config
360 work_dir=work_dir, config=config
362 )
361 )
363 self.launchers = []
362 self.launchers = []
364
363
365 def start(self, n, cluster_dir):
364 def start(self, n, cluster_dir):
366 """Start n engines by profile or cluster_dir."""
365 """Start n engines by profile or cluster_dir."""
367 self.cluster_dir = unicode(cluster_dir)
366 self.cluster_dir = unicode(cluster_dir)
368 dlist = []
367 dlist = []
369 for i in range(n):
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 # Copy the engine args over to each engine launcher.
370 # Copy the engine args over to each engine launcher.
372 import copy
371 import copy
373 el.engine_args = copy.deepcopy(self.engine_args)
372 el.engine_args = copy.deepcopy(self.engine_args)
374 d = el.start(cluster_dir)
373 d = el.start(cluster_dir)
375 if i==0:
374 if i==0:
376 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
375 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
377 self.launchers.append(el)
376 self.launchers.append(el)
378 dlist.append(d)
377 dlist.append(d)
379 # The consumeErrors here could be dangerous
378 # The consumeErrors here could be dangerous
380 dfinal = gatherBoth(dlist, consumeErrors=True)
379 dfinal = gatherBoth(dlist, consumeErrors=True)
381 dfinal.addCallback(self.notify_start)
380 dfinal.addCallback(self.notify_start)
382 return dfinal
381 return dfinal
383
382
384 def find_args(self):
383 def find_args(self):
385 return ['engine set']
384 return ['engine set']
386
385
387 def signal(self, sig):
386 def signal(self, sig):
388 dlist = []
387 dlist = []
389 for el in self.launchers:
388 for el in self.launchers:
390 d = el.signal(sig)
389 d = el.signal(sig)
391 dlist.append(d)
390 dlist.append(d)
392 dfinal = gatherBoth(dlist, consumeErrors=True)
391 dfinal = gatherBoth(dlist, consumeErrors=True)
393 return dfinal
392 return dfinal
394
393
395 def interrupt_then_kill(self, delay=1.0):
394 def interrupt_then_kill(self, delay=1.0):
396 dlist = []
395 dlist = []
397 for el in self.launchers:
396 for el in self.launchers:
398 d = el.interrupt_then_kill(delay)
397 d = el.interrupt_then_kill(delay)
399 dlist.append(d)
398 dlist.append(d)
400 dfinal = gatherBoth(dlist, consumeErrors=True)
399 dfinal = gatherBoth(dlist, consumeErrors=True)
401 return dfinal
400 return dfinal
402
401
403 def stop(self):
402 def stop(self):
404 return self.interrupt_then_kill()
403 return self.interrupt_then_kill()
405
404
406 def observe_stop(self):
405 def observe_stop(self):
407 dlist = [el.observe_stop() for el in self.launchers]
406 dlist = [el.observe_stop() for el in self.launchers]
408 dfinal = gatherBoth(dlist, consumeErrors=False)
407 dfinal = gatherBoth(dlist, consumeErrors=False)
409 dfinal.addCallback(self.notify_stop)
408 dfinal.addCallback(self.notify_stop)
410 return dfinal
409 return dfinal
411
410
412
411
413 #-----------------------------------------------------------------------------
412 #-----------------------------------------------------------------------------
414 # MPIExec launchers
413 # MPIExec launchers
415 #-----------------------------------------------------------------------------
414 #-----------------------------------------------------------------------------
416
415
417
416
418 class MPIExecLauncher(LocalProcessLauncher):
417 class MPIExecLauncher(LocalProcessLauncher):
419 """Launch an external process using mpiexec."""
418 """Launch an external process using mpiexec."""
420
419
421 # The mpiexec command to use in starting the process.
420 # The mpiexec command to use in starting the process.
422 mpi_cmd = List(['mpiexec'], config=True)
421 mpi_cmd = List(['mpiexec'], config=True)
423 # The command line arguments to pass to mpiexec.
422 # The command line arguments to pass to mpiexec.
424 mpi_args = List([], config=True)
423 mpi_args = List([], config=True)
425 # The program to start using mpiexec.
424 # The program to start using mpiexec.
426 program = List(['date'], config=True)
425 program = List(['date'], config=True)
427 # The command line argument to the program.
426 # The command line argument to the program.
428 program_args = List([], config=True)
427 program_args = List([], config=True)
429 # The number of instances of the program to start.
428 # The number of instances of the program to start.
430 n = Int(1, config=True)
429 n = Int(1, config=True)
431
430
432 def find_args(self):
431 def find_args(self):
433 """Build self.args using all the fields."""
432 """Build self.args using all the fields."""
434 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
433 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
435 self.program + self.program_args
434 self.program + self.program_args
436
435
437 def start(self, n):
436 def start(self, n):
438 """Start n instances of the program using mpiexec."""
437 """Start n instances of the program using mpiexec."""
439 self.n = n
438 self.n = n
440 return super(MPIExecLauncher, self).start()
439 return super(MPIExecLauncher, self).start()
441
440
442
441
443 class MPIExecControllerLauncher(MPIExecLauncher):
442 class MPIExecControllerLauncher(MPIExecLauncher):
444 """Launch a controller using mpiexec."""
443 """Launch a controller using mpiexec."""
445
444
446 controller_cmd = List(ipcontroller_cmd_argv, config=True)
445 controller_cmd = List(ipcontroller_cmd_argv, config=True)
447 # Command line arguments to ipcontroller.
446 # Command line arguments to ipcontroller.
448 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
447 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
449 n = Int(1, config=False)
448 n = Int(1, config=False)
450
449
451 def start(self, cluster_dir):
450 def start(self, cluster_dir):
452 """Start the controller by cluster_dir."""
451 """Start the controller by cluster_dir."""
453 self.controller_args.extend(['--cluster-dir', cluster_dir])
452 self.controller_args.extend(['--cluster-dir', cluster_dir])
454 self.cluster_dir = unicode(cluster_dir)
453 self.cluster_dir = unicode(cluster_dir)
455 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
454 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
456 return super(MPIExecControllerLauncher, self).start(1)
455 return super(MPIExecControllerLauncher, self).start(1)
457
456
458 def find_args(self):
457 def find_args(self):
459 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
458 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
460 self.controller_cmd + self.controller_args
459 self.controller_cmd + self.controller_args
461
460
462
461
463 class MPIExecEngineSetLauncher(MPIExecLauncher):
462 class MPIExecEngineSetLauncher(MPIExecLauncher):
464
463
465 engine_cmd = List(ipengine_cmd_argv, config=True)
464 engine_cmd = List(ipengine_cmd_argv, config=True)
466 # Command line arguments for ipengine.
465 # Command line arguments for ipengine.
467 engine_args = List(
466 engine_args = List(
468 ['--log-to-file','--log-level', '40'], config=True
467 ['--log-to-file','--log-level', '40'], config=True
469 )
468 )
470 n = Int(1, config=True)
469 n = Int(1, config=True)
471
470
472 def start(self, n, cluster_dir):
471 def start(self, n, cluster_dir):
473 """Start n engines by profile or cluster_dir."""
472 """Start n engines by profile or cluster_dir."""
474 self.engine_args.extend(['--cluster-dir', cluster_dir])
473 self.engine_args.extend(['--cluster-dir', cluster_dir])
475 self.cluster_dir = unicode(cluster_dir)
474 self.cluster_dir = unicode(cluster_dir)
476 self.n = n
475 self.n = n
477 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
476 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
478 return super(MPIExecEngineSetLauncher, self).start(n)
477 return super(MPIExecEngineSetLauncher, self).start(n)
479
478
480 def find_args(self):
479 def find_args(self):
481 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
480 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
482 self.engine_cmd + self.engine_args
481 self.engine_cmd + self.engine_args
483
482
484
483
485 #-----------------------------------------------------------------------------
484 #-----------------------------------------------------------------------------
486 # SSH launchers
485 # SSH launchers
487 #-----------------------------------------------------------------------------
486 #-----------------------------------------------------------------------------
488
487
489 # TODO: Get SSH Launcher working again.
488 # TODO: Get SSH Launcher working again.
490
489
491 class SSHLauncher(BaseLauncher):
490 class SSHLauncher(BaseLauncher):
492 """A minimal launcher for ssh.
491 """A minimal launcher for ssh.
493
492
494 To be useful this will probably have to be extended to use the ``sshx``
493 To be useful this will probably have to be extended to use the ``sshx``
495 idea for environment variables. There could be other things this needs
494 idea for environment variables. There could be other things this needs
496 as well.
495 as well.
497 """
496 """
498
497
499 ssh_cmd = List(['ssh'], config=True)
498 ssh_cmd = List(['ssh'], config=True)
500 ssh_args = List([], config=True)
499 ssh_args = List([], config=True)
501 program = List(['date'], config=True)
500 program = List(['date'], config=True)
502 program_args = List([], config=True)
501 program_args = List([], config=True)
503 hostname = Str('', config=True)
502 hostname = Str('', config=True)
504 user = Str('', config=True)
503 user = Str('', config=True)
505 location = Str('')
504 location = Str('')
506
505
507 def _hostname_changed(self, name, old, new):
506 def _hostname_changed(self, name, old, new):
508 self.location = '%s@%s' % (self.user, new)
507 self.location = '%s@%s' % (self.user, new)
509
508
510 def _user_changed(self, name, old, new):
509 def _user_changed(self, name, old, new):
511 self.location = '%s@%s' % (new, self.hostname)
510 self.location = '%s@%s' % (new, self.hostname)
512
511
513 def find_args(self):
512 def find_args(self):
514 return self.ssh_cmd + self.ssh_args + [self.location] + \
513 return self.ssh_cmd + self.ssh_args + [self.location] + \
515 self.program + self.program_args
514 self.program + self.program_args
516
515
517 def start(self, n, hostname=None, user=None):
516 def start(self, n, hostname=None, user=None):
518 if hostname is not None:
517 if hostname is not None:
519 self.hostname = hostname
518 self.hostname = hostname
520 if user is not None:
519 if user is not None:
521 self.user = user
520 self.user = user
522 return super(SSHLauncher, self).start()
521 return super(SSHLauncher, self).start()
523
522
524
523
525 class SSHControllerLauncher(SSHLauncher):
524 class SSHControllerLauncher(SSHLauncher):
526 pass
525 pass
527
526
528
527
529 class SSHEngineSetLauncher(BaseLauncher):
528 class SSHEngineSetLauncher(BaseLauncher):
530 pass
529 pass
531
530
532
531
533 #-----------------------------------------------------------------------------
532 #-----------------------------------------------------------------------------
534 # Windows HPC Server 2008 scheduler launchers
533 # Windows HPC Server 2008 scheduler launchers
535 #-----------------------------------------------------------------------------
534 #-----------------------------------------------------------------------------
536
535
537
536
538 # This is only used on Windows.
537 # This is only used on Windows.
539 def find_job_cmd():
538 def find_job_cmd():
540 if os.name=='nt':
539 if os.name=='nt':
541 try:
540 try:
542 return find_cmd('job')
541 return find_cmd('job')
543 except FindCmdError:
542 except FindCmdError:
544 return 'job'
543 return 'job'
545 else:
544 else:
546 return 'job'
545 return 'job'
547
546
548
547
549 class WindowsHPCLauncher(BaseLauncher):
548 class WindowsHPCLauncher(BaseLauncher):
550
549
551 # A regular expression used to get the job id from the output of the
550 # A regular expression used to get the job id from the output of the
552 # submit_command.
551 # submit_command.
553 job_id_regexp = Str(r'\d+', config=True)
552 job_id_regexp = Str(r'\d+', config=True)
554 # The filename of the instantiated job script.
553 # The filename of the instantiated job script.
555 job_file_name = Unicode(u'ipython_job.xml', config=True)
554 job_file_name = Unicode(u'ipython_job.xml', config=True)
556 # The full path to the instantiated job script. This gets made dynamically
555 # The full path to the instantiated job script. This gets made dynamically
557 # by combining the work_dir with the job_file_name.
556 # by combining the work_dir with the job_file_name.
558 job_file = Unicode(u'')
557 job_file = Unicode(u'')
559 # The hostname of the scheduler to submit the job to
558 # The hostname of the scheduler to submit the job to
560 scheduler = Str('', config=True)
559 scheduler = Str('', config=True)
561 job_cmd = Str(find_job_cmd(), config=True)
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 super(WindowsHPCLauncher, self).__init__(
563 super(WindowsHPCLauncher, self).__init__(
565 work_dir, config
564 work_dir=work_dir, config=config
566 )
565 )
567
566
568 @property
567 @property
569 def job_file(self):
568 def job_file(self):
570 return os.path.join(self.work_dir, self.job_file_name)
569 return os.path.join(self.work_dir, self.job_file_name)
571
570
572 def write_job_file(self, n):
571 def write_job_file(self, n):
573 raise NotImplementedError("Implement write_job_file in a subclass.")
572 raise NotImplementedError("Implement write_job_file in a subclass.")
574
573
575 def find_args(self):
574 def find_args(self):
576 return ['job.exe']
575 return ['job.exe']
577
576
578 def parse_job_id(self, output):
577 def parse_job_id(self, output):
579 """Take the output of the submit command and return the job id."""
578 """Take the output of the submit command and return the job id."""
580 m = re.search(self.job_id_regexp, output)
579 m = re.search(self.job_id_regexp, output)
581 if m is not None:
580 if m is not None:
582 job_id = m.group()
581 job_id = m.group()
583 else:
582 else:
584 raise LauncherError("Job id couldn't be determined: %s" % output)
583 raise LauncherError("Job id couldn't be determined: %s" % output)
585 self.job_id = job_id
584 self.job_id = job_id
586 log.msg('Job started with job id: %r' % job_id)
585 log.msg('Job started with job id: %r' % job_id)
587 return job_id
586 return job_id
588
587
589 @inlineCallbacks
588 @inlineCallbacks
590 def start(self, n):
589 def start(self, n):
591 """Start n copies of the process using the Win HPC job scheduler."""
590 """Start n copies of the process using the Win HPC job scheduler."""
592 self.write_job_file(n)
591 self.write_job_file(n)
593 args = [
592 args = [
594 'submit',
593 'submit',
595 '/jobfile:%s' % self.job_file,
594 '/jobfile:%s' % self.job_file,
596 '/scheduler:%s' % self.scheduler
595 '/scheduler:%s' % self.scheduler
597 ]
596 ]
598 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
597 log.msg("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
599 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
598 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
600 output = yield getProcessOutput(str(self.job_cmd),
599 output = yield getProcessOutput(str(self.job_cmd),
601 [str(a) for a in args],
600 [str(a) for a in args],
602 env=dict((str(k),str(v)) for k,v in os.environ.items()),
601 env=dict((str(k),str(v)) for k,v in os.environ.items()),
603 path=self.work_dir
602 path=self.work_dir
604 )
603 )
605 job_id = self.parse_job_id(output)
604 job_id = self.parse_job_id(output)
606 self.notify_start(job_id)
605 self.notify_start(job_id)
607 defer.returnValue(job_id)
606 defer.returnValue(job_id)
608
607
609 @inlineCallbacks
608 @inlineCallbacks
610 def stop(self):
609 def stop(self):
611 args = [
610 args = [
612 'cancel',
611 'cancel',
613 self.job_id,
612 self.job_id,
614 '/scheduler:%s' % self.scheduler
613 '/scheduler:%s' % self.scheduler
615 ]
614 ]
616 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
615 log.msg("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
617 try:
616 try:
618 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
617 # Twisted will raise DeprecationWarnings if we try to pass unicode to this
619 output = yield getProcessOutput(str(self.job_cmd),
618 output = yield getProcessOutput(str(self.job_cmd),
620 [str(a) for a in args],
619 [str(a) for a in args],
621 env=dict((str(k),str(v)) for k,v in os.environ.items()),
620 env=dict((str(k),str(v)) for k,v in os.environ.items()),
622 path=self.work_dir
621 path=self.work_dir
623 )
622 )
624 except:
623 except:
625 output = 'The job already appears to be stoppped: %r' % self.job_id
624 output = 'The job already appears to be stoppped: %r' % self.job_id
626 self.notify_stop(output) # Pass the output of the kill cmd
625 self.notify_stop(output) # Pass the output of the kill cmd
627 defer.returnValue(output)
626 defer.returnValue(output)
628
627
629
628
630 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
629 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
631
630
632 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
631 job_file_name = Unicode(u'ipcontroller_job.xml', config=True)
633 extra_args = List([], config=False)
632 extra_args = List([], config=False)
634
633
635 def write_job_file(self, n):
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 # The tasks work directory is *not* the actual work directory of
638 # The tasks work directory is *not* the actual work directory of
640 # the controller. It is used as the base path for the stdout/stderr
639 # the controller. It is used as the base path for the stdout/stderr
641 # files that the scheduler redirects to.
640 # files that the scheduler redirects to.
642 t.work_directory = self.cluster_dir
641 t.work_directory = self.cluster_dir
643 # Add the --cluster-dir and from self.start().
642 # Add the --cluster-dir and from self.start().
644 t.controller_args.extend(self.extra_args)
643 t.controller_args.extend(self.extra_args)
645 job.add_task(t)
644 job.add_task(t)
646
645
647 log.msg("Writing job description file: %s" % self.job_file)
646 log.msg("Writing job description file: %s" % self.job_file)
648 job.write(self.job_file)
647 job.write(self.job_file)
649
648
650 @property
649 @property
651 def job_file(self):
650 def job_file(self):
652 return os.path.join(self.cluster_dir, self.job_file_name)
651 return os.path.join(self.cluster_dir, self.job_file_name)
653
652
654 def start(self, cluster_dir):
653 def start(self, cluster_dir):
655 """Start the controller by cluster_dir."""
654 """Start the controller by cluster_dir."""
656 self.extra_args = ['--cluster-dir', cluster_dir]
655 self.extra_args = ['--cluster-dir', cluster_dir]
657 self.cluster_dir = unicode(cluster_dir)
656 self.cluster_dir = unicode(cluster_dir)
658 return super(WindowsHPCControllerLauncher, self).start(1)
657 return super(WindowsHPCControllerLauncher, self).start(1)
659
658
660
659
661 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
660 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
662
661
663 job_file_name = Unicode(u'ipengineset_job.xml', config=True)
662 job_file_name = Unicode(u'ipengineset_job.xml', config=True)
664 extra_args = List([], config=False)
663 extra_args = List([], config=False)
665
664
666 def write_job_file(self, n):
665 def write_job_file(self, n):
667 job = IPEngineSetJob(self)
666 job = IPEngineSetJob(config=self.config)
668
667
669 for i in range(n):
668 for i in range(n):
670 t = IPEngineTask(self)
669 t = IPEngineTask(config=self.config)
671 # The tasks work directory is *not* the actual work directory of
670 # The tasks work directory is *not* the actual work directory of
672 # the engine. It is used as the base path for the stdout/stderr
671 # the engine. It is used as the base path for the stdout/stderr
673 # files that the scheduler redirects to.
672 # files that the scheduler redirects to.
674 t.work_directory = self.cluster_dir
673 t.work_directory = self.cluster_dir
675 # Add the --cluster-dir and from self.start().
674 # Add the --cluster-dir and from self.start().
676 t.engine_args.extend(self.extra_args)
675 t.engine_args.extend(self.extra_args)
677 job.add_task(t)
676 job.add_task(t)
678
677
679 log.msg("Writing job description file: %s" % self.job_file)
678 log.msg("Writing job description file: %s" % self.job_file)
680 job.write(self.job_file)
679 job.write(self.job_file)
681
680
682 @property
681 @property
683 def job_file(self):
682 def job_file(self):
684 return os.path.join(self.cluster_dir, self.job_file_name)
683 return os.path.join(self.cluster_dir, self.job_file_name)
685
684
686 def start(self, n, cluster_dir):
685 def start(self, n, cluster_dir):
687 """Start the controller by cluster_dir."""
686 """Start the controller by cluster_dir."""
688 self.extra_args = ['--cluster-dir', cluster_dir]
687 self.extra_args = ['--cluster-dir', cluster_dir]
689 self.cluster_dir = unicode(cluster_dir)
688 self.cluster_dir = unicode(cluster_dir)
690 return super(WindowsHPCEngineSetLauncher, self).start(n)
689 return super(WindowsHPCEngineSetLauncher, self).start(n)
691
690
692
691
693 #-----------------------------------------------------------------------------
692 #-----------------------------------------------------------------------------
694 # Batch (PBS) system launchers
693 # Batch (PBS) system launchers
695 #-----------------------------------------------------------------------------
694 #-----------------------------------------------------------------------------
696
695
697 # TODO: Get PBS launcher working again.
696 # TODO: Get PBS launcher working again.
698
697
699 class BatchSystemLauncher(BaseLauncher):
698 class BatchSystemLauncher(BaseLauncher):
700 """Launch an external process using a batch system.
699 """Launch an external process using a batch system.
701
700
702 This class is designed to work with UNIX batch systems like PBS, LSF,
701 This class is designed to work with UNIX batch systems like PBS, LSF,
703 GridEngine, etc. The overall model is that there are different commands
702 GridEngine, etc. The overall model is that there are different commands
704 like qsub, qdel, etc. that handle the starting and stopping of the process.
703 like qsub, qdel, etc. that handle the starting and stopping of the process.
705
704
706 This class also has the notion of a batch script. The ``batch_template``
705 This class also has the notion of a batch script. The ``batch_template``
707 attribute can be set to a string that is a template for the batch script.
706 attribute can be set to a string that is a template for the batch script.
708 This template is instantiated using Itpl. Thus the template can use
707 This template is instantiated using Itpl. Thus the template can use
709 ${n} fot the number of instances. Subclasses can add additional variables
708 ${n} fot the number of instances. Subclasses can add additional variables
710 to the template dict.
709 to the template dict.
711 """
710 """
712
711
713 # Subclasses must fill these in. See PBSEngineSet
712 # Subclasses must fill these in. See PBSEngineSet
714 # The name of the command line program used to submit jobs.
713 # The name of the command line program used to submit jobs.
715 submit_command = Str('', config=True)
714 submit_command = Str('', config=True)
716 # The name of the command line program used to delete jobs.
715 # The name of the command line program used to delete jobs.
717 delete_command = Str('', config=True)
716 delete_command = Str('', config=True)
718 # A regular expression used to get the job id from the output of the
717 # A regular expression used to get the job id from the output of the
719 # submit_command.
718 # submit_command.
720 job_id_regexp = Str('', config=True)
719 job_id_regexp = Str('', config=True)
721 # The string that is the batch script template itself.
720 # The string that is the batch script template itself.
722 batch_template = Str('', config=True)
721 batch_template = Str('', config=True)
723 # The filename of the instantiated batch script.
722 # The filename of the instantiated batch script.
724 batch_file_name = Unicode(u'batch_script', config=True)
723 batch_file_name = Unicode(u'batch_script', config=True)
725 # The full path to the instantiated batch script.
724 # The full path to the instantiated batch script.
726 batch_file = Unicode(u'')
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 super(BatchSystemLauncher, self).__init__(
728 super(BatchSystemLauncher, self).__init__(
730 work_dir, config
729 work_dir=work_dir, config=config
731 )
730 )
732 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
731 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
733 self.context = {}
732 self.context = {}
734
733
735 def parse_job_id(self, output):
734 def parse_job_id(self, output):
736 """Take the output of the submit command and return the job id."""
735 """Take the output of the submit command and return the job id."""
737 m = re.match(self.job_id_regexp, output)
736 m = re.match(self.job_id_regexp, output)
738 if m is not None:
737 if m is not None:
739 job_id = m.group()
738 job_id = m.group()
740 else:
739 else:
741 raise LauncherError("Job id couldn't be determined: %s" % output)
740 raise LauncherError("Job id couldn't be determined: %s" % output)
742 self.job_id = job_id
741 self.job_id = job_id
743 log.msg('Job started with job id: %r' % job_id)
742 log.msg('Job started with job id: %r' % job_id)
744 return job_id
743 return job_id
745
744
746 def write_batch_script(self, n):
745 def write_batch_script(self, n):
747 """Instantiate and write the batch script to the work_dir."""
746 """Instantiate and write the batch script to the work_dir."""
748 self.context['n'] = n
747 self.context['n'] = n
749 script_as_string = Itpl.itplns(self.batch_template, self.context)
748 script_as_string = Itpl.itplns(self.batch_template, self.context)
750 log.msg('Writing instantiated batch script: %s' % self.batch_file)
749 log.msg('Writing instantiated batch script: %s' % self.batch_file)
751 f = open(self.batch_file, 'w')
750 f = open(self.batch_file, 'w')
752 f.write(script_as_string)
751 f.write(script_as_string)
753 f.close()
752 f.close()
754
753
755 @inlineCallbacks
754 @inlineCallbacks
756 def start(self, n):
755 def start(self, n):
757 """Start n copies of the process using a batch system."""
756 """Start n copies of the process using a batch system."""
758 self.write_batch_script(n)
757 self.write_batch_script(n)
759 output = yield getProcessOutput(self.submit_command,
758 output = yield getProcessOutput(self.submit_command,
760 [self.batch_file], env=os.environ)
759 [self.batch_file], env=os.environ)
761 job_id = self.parse_job_id(output)
760 job_id = self.parse_job_id(output)
762 self.notify_start(job_id)
761 self.notify_start(job_id)
763 defer.returnValue(job_id)
762 defer.returnValue(job_id)
764
763
765 @inlineCallbacks
764 @inlineCallbacks
766 def stop(self):
765 def stop(self):
767 output = yield getProcessOutput(self.delete_command,
766 output = yield getProcessOutput(self.delete_command,
768 [self.job_id], env=os.environ
767 [self.job_id], env=os.environ
769 )
768 )
770 self.notify_stop(output) # Pass the output of the kill cmd
769 self.notify_stop(output) # Pass the output of the kill cmd
771 defer.returnValue(output)
770 defer.returnValue(output)
772
771
773
772
774 class PBSLauncher(BatchSystemLauncher):
773 class PBSLauncher(BatchSystemLauncher):
775 """A BatchSystemLauncher subclass for PBS."""
774 """A BatchSystemLauncher subclass for PBS."""
776
775
777 submit_command = Str('qsub', config=True)
776 submit_command = Str('qsub', config=True)
778 delete_command = Str('qdel', config=True)
777 delete_command = Str('qdel', config=True)
779 job_id_regexp = Str(r'\d+', config=True)
778 job_id_regexp = Str(r'\d+', config=True)
780 batch_template = Str('', config=True)
779 batch_template = Str('', config=True)
781 batch_file_name = Unicode(u'pbs_batch_script', config=True)
780 batch_file_name = Unicode(u'pbs_batch_script', config=True)
782 batch_file = Unicode(u'')
781 batch_file = Unicode(u'')
783
782
784
783
785 class PBSControllerLauncher(PBSLauncher):
784 class PBSControllerLauncher(PBSLauncher):
786 """Launch a controller using PBS."""
785 """Launch a controller using PBS."""
787
786
788 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
787 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
789
788
790 def start(self, cluster_dir):
789 def start(self, cluster_dir):
791 """Start the controller by profile or cluster_dir."""
790 """Start the controller by profile or cluster_dir."""
792 # Here we save profile and cluster_dir in the context so they
791 # Here we save profile and cluster_dir in the context so they
793 # can be used in the batch script template as ${profile} and
792 # can be used in the batch script template as ${profile} and
794 # ${cluster_dir}
793 # ${cluster_dir}
795 self.context['cluster_dir'] = cluster_dir
794 self.context['cluster_dir'] = cluster_dir
796 self.cluster_dir = unicode(cluster_dir)
795 self.cluster_dir = unicode(cluster_dir)
797 log.msg("Starting PBSControllerLauncher: %r" % self.args)
796 log.msg("Starting PBSControllerLauncher: %r" % self.args)
798 return super(PBSControllerLauncher, self).start(1)
797 return super(PBSControllerLauncher, self).start(1)
799
798
800
799
801 class PBSEngineSetLauncher(PBSLauncher):
800 class PBSEngineSetLauncher(PBSLauncher):
802
801
803 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
802 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
804
803
805 def start(self, n, cluster_dir):
804 def start(self, n, cluster_dir):
806 """Start n engines by profile or cluster_dir."""
805 """Start n engines by profile or cluster_dir."""
807 self.program_args.extend(['--cluster-dir', cluster_dir])
806 self.program_args.extend(['--cluster-dir', cluster_dir])
808 self.cluster_dir = unicode(cluster_dir)
807 self.cluster_dir = unicode(cluster_dir)
809 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
808 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
810 return super(PBSEngineSetLauncher, self).start(n)
809 return super(PBSEngineSetLauncher, self).start(n)
811
810
812
811
813 #-----------------------------------------------------------------------------
812 #-----------------------------------------------------------------------------
814 # A launcher for ipcluster itself!
813 # A launcher for ipcluster itself!
815 #-----------------------------------------------------------------------------
814 #-----------------------------------------------------------------------------
816
815
817
816
818 class IPClusterLauncher(LocalProcessLauncher):
817 class IPClusterLauncher(LocalProcessLauncher):
819 """Launch the ipcluster program in an external process."""
818 """Launch the ipcluster program in an external process."""
820
819
821 ipcluster_cmd = List(ipcluster_cmd_argv, config=True)
820 ipcluster_cmd = List(ipcluster_cmd_argv, config=True)
822 # Command line arguments to pass to ipcluster.
821 # Command line arguments to pass to ipcluster.
823 ipcluster_args = List(
822 ipcluster_args = List(
824 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
823 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
825 ipcluster_subcommand = Str('start')
824 ipcluster_subcommand = Str('start')
826 ipcluster_n = Int(2)
825 ipcluster_n = Int(2)
827
826
828 def find_args(self):
827 def find_args(self):
829 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
828 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
830 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
829 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
831
830
832 def start(self):
831 def start(self):
833 log.msg("Starting ipcluster: %r" % self.args)
832 log.msg("Starting ipcluster: %r" % self.args)
834 return super(IPClusterLauncher, self).start()
833 return super(IPClusterLauncher, self).start()
835
834
@@ -1,316 +1,316 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Job and task components for writing .xml files that the Windows HPC Server
4 Job and task components for writing .xml files that the Windows HPC Server
5 2008 can use to start jobs.
5 2008 can use to start jobs.
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2009 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from __future__ import with_statement
19 from __future__ import with_statement
20
20
21 import os
21 import os
22 import re
22 import re
23 import uuid
23 import uuid
24
24
25 from xml.etree import ElementTree as ET
25 from xml.etree import ElementTree as ET
26
26
27 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
28 from IPython.utils.traitlets import (
28 from IPython.utils.traitlets import (
29 Str, Int, List, Instance,
29 Str, Int, List, Instance,
30 Enum, Bool, CStr
30 Enum, Bool, CStr
31 )
31 )
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Job and Task classes
34 # Job and Task classes
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37
37
38 def as_str(value):
38 def as_str(value):
39 if isinstance(value, str):
39 if isinstance(value, str):
40 return value
40 return value
41 elif isinstance(value, bool):
41 elif isinstance(value, bool):
42 if value:
42 if value:
43 return 'true'
43 return 'true'
44 else:
44 else:
45 return 'false'
45 return 'false'
46 elif isinstance(value, (int, float)):
46 elif isinstance(value, (int, float)):
47 return repr(value)
47 return repr(value)
48 else:
48 else:
49 return value
49 return value
50
50
51
51
52 def indent(elem, level=0):
52 def indent(elem, level=0):
53 i = "\n" + level*" "
53 i = "\n" + level*" "
54 if len(elem):
54 if len(elem):
55 if not elem.text or not elem.text.strip():
55 if not elem.text or not elem.text.strip():
56 elem.text = i + " "
56 elem.text = i + " "
57 if not elem.tail or not elem.tail.strip():
57 if not elem.tail or not elem.tail.strip():
58 elem.tail = i
58 elem.tail = i
59 for elem in elem:
59 for elem in elem:
60 indent(elem, level+1)
60 indent(elem, level+1)
61 if not elem.tail or not elem.tail.strip():
61 if not elem.tail or not elem.tail.strip():
62 elem.tail = i
62 elem.tail = i
63 else:
63 else:
64 if level and (not elem.tail or not elem.tail.strip()):
64 if level and (not elem.tail or not elem.tail.strip()):
65 elem.tail = i
65 elem.tail = i
66
66
67
67
68 def find_username():
68 def find_username():
69 domain = os.environ.get('USERDOMAIN')
69 domain = os.environ.get('USERDOMAIN')
70 username = os.environ.get('USERNAME','')
70 username = os.environ.get('USERNAME','')
71 if domain is None:
71 if domain is None:
72 return username
72 return username
73 else:
73 else:
74 return '%s\\%s' % (domain, username)
74 return '%s\\%s' % (domain, username)
75
75
76
76
77 class WinHPCJob(Configurable):
77 class WinHPCJob(Configurable):
78
78
79 job_id = Str('')
79 job_id = Str('')
80 job_name = Str('MyJob', config=True)
80 job_name = Str('MyJob', config=True)
81 min_cores = Int(1, config=True)
81 min_cores = Int(1, config=True)
82 max_cores = Int(1, config=True)
82 max_cores = Int(1, config=True)
83 min_sockets = Int(1, config=True)
83 min_sockets = Int(1, config=True)
84 max_sockets = Int(1, config=True)
84 max_sockets = Int(1, config=True)
85 min_nodes = Int(1, config=True)
85 min_nodes = Int(1, config=True)
86 max_nodes = Int(1, config=True)
86 max_nodes = Int(1, config=True)
87 unit_type = Str("Core", config=True)
87 unit_type = Str("Core", config=True)
88 auto_calculate_min = Bool(True, config=True)
88 auto_calculate_min = Bool(True, config=True)
89 auto_calculate_max = Bool(True, config=True)
89 auto_calculate_max = Bool(True, config=True)
90 run_until_canceled = Bool(False, config=True)
90 run_until_canceled = Bool(False, config=True)
91 is_exclusive = Bool(False, config=True)
91 is_exclusive = Bool(False, config=True)
92 username = Str(find_username(), config=True)
92 username = Str(find_username(), config=True)
93 job_type = Str('Batch', config=True)
93 job_type = Str('Batch', config=True)
94 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
94 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
95 default_value='Highest', config=True)
95 default_value='Highest', config=True)
96 requested_nodes = Str('', config=True)
96 requested_nodes = Str('', config=True)
97 project = Str('IPython', config=True)
97 project = Str('IPython', config=True)
98 xmlns = Str('http://schemas.microsoft.com/HPCS2008/scheduler/')
98 xmlns = Str('http://schemas.microsoft.com/HPCS2008/scheduler/')
99 version = Str("2.000")
99 version = Str("2.000")
100 tasks = List([])
100 tasks = List([])
101
101
102 @property
102 @property
103 def owner(self):
103 def owner(self):
104 return self.username
104 return self.username
105
105
106 def _write_attr(self, root, attr, key):
106 def _write_attr(self, root, attr, key):
107 s = as_str(getattr(self, attr, ''))
107 s = as_str(getattr(self, attr, ''))
108 if s:
108 if s:
109 root.set(key, s)
109 root.set(key, s)
110
110
111 def as_element(self):
111 def as_element(self):
112 # We have to add _A_ type things to get the right order than
112 # We have to add _A_ type things to get the right order than
113 # the MSFT XML parser expects.
113 # the MSFT XML parser expects.
114 root = ET.Element('Job')
114 root = ET.Element('Job')
115 self._write_attr(root, 'version', '_A_Version')
115 self._write_attr(root, 'version', '_A_Version')
116 self._write_attr(root, 'job_name', '_B_Name')
116 self._write_attr(root, 'job_name', '_B_Name')
117 self._write_attr(root, 'unit_type', '_C_UnitType')
117 self._write_attr(root, 'unit_type', '_C_UnitType')
118 self._write_attr(root, 'min_cores', '_D_MinCores')
118 self._write_attr(root, 'min_cores', '_D_MinCores')
119 self._write_attr(root, 'max_cores', '_E_MaxCores')
119 self._write_attr(root, 'max_cores', '_E_MaxCores')
120 self._write_attr(root, 'min_sockets', '_F_MinSockets')
120 self._write_attr(root, 'min_sockets', '_F_MinSockets')
121 self._write_attr(root, 'max_sockets', '_G_MaxSockets')
121 self._write_attr(root, 'max_sockets', '_G_MaxSockets')
122 self._write_attr(root, 'min_nodes', '_H_MinNodes')
122 self._write_attr(root, 'min_nodes', '_H_MinNodes')
123 self._write_attr(root, 'max_nodes', '_I_MaxNodes')
123 self._write_attr(root, 'max_nodes', '_I_MaxNodes')
124 self._write_attr(root, 'run_until_canceled', '_J_RunUntilCanceled')
124 self._write_attr(root, 'run_until_canceled', '_J_RunUntilCanceled')
125 self._write_attr(root, 'is_exclusive', '_K_IsExclusive')
125 self._write_attr(root, 'is_exclusive', '_K_IsExclusive')
126 self._write_attr(root, 'username', '_L_UserName')
126 self._write_attr(root, 'username', '_L_UserName')
127 self._write_attr(root, 'job_type', '_M_JobType')
127 self._write_attr(root, 'job_type', '_M_JobType')
128 self._write_attr(root, 'priority', '_N_Priority')
128 self._write_attr(root, 'priority', '_N_Priority')
129 self._write_attr(root, 'requested_nodes', '_O_RequestedNodes')
129 self._write_attr(root, 'requested_nodes', '_O_RequestedNodes')
130 self._write_attr(root, 'auto_calculate_max', '_P_AutoCalculateMax')
130 self._write_attr(root, 'auto_calculate_max', '_P_AutoCalculateMax')
131 self._write_attr(root, 'auto_calculate_min', '_Q_AutoCalculateMin')
131 self._write_attr(root, 'auto_calculate_min', '_Q_AutoCalculateMin')
132 self._write_attr(root, 'project', '_R_Project')
132 self._write_attr(root, 'project', '_R_Project')
133 self._write_attr(root, 'owner', '_S_Owner')
133 self._write_attr(root, 'owner', '_S_Owner')
134 self._write_attr(root, 'xmlns', '_T_xmlns')
134 self._write_attr(root, 'xmlns', '_T_xmlns')
135 dependencies = ET.SubElement(root, "Dependencies")
135 dependencies = ET.SubElement(root, "Dependencies")
136 etasks = ET.SubElement(root, "Tasks")
136 etasks = ET.SubElement(root, "Tasks")
137 for t in self.tasks:
137 for t in self.tasks:
138 etasks.append(t.as_element())
138 etasks.append(t.as_element())
139 return root
139 return root
140
140
141 def tostring(self):
141 def tostring(self):
142 """Return the string representation of the job description XML."""
142 """Return the string representation of the job description XML."""
143 root = self.as_element()
143 root = self.as_element()
144 indent(root)
144 indent(root)
145 txt = ET.tostring(root, encoding="utf-8")
145 txt = ET.tostring(root, encoding="utf-8")
146 # Now remove the tokens used to order the attributes.
146 # Now remove the tokens used to order the attributes.
147 txt = re.sub(r'_[A-Z]_','',txt)
147 txt = re.sub(r'_[A-Z]_','',txt)
148 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
148 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
149 return txt
149 return txt
150
150
151 def write(self, filename):
151 def write(self, filename):
152 """Write the XML job description to a file."""
152 """Write the XML job description to a file."""
153 txt = self.tostring()
153 txt = self.tostring()
154 with open(filename, 'w') as f:
154 with open(filename, 'w') as f:
155 f.write(txt)
155 f.write(txt)
156
156
157 def add_task(self, task):
157 def add_task(self, task):
158 """Add a task to the job.
158 """Add a task to the job.
159
159
160 Parameters
160 Parameters
161 ----------
161 ----------
162 task : :class:`WinHPCTask`
162 task : :class:`WinHPCTask`
163 The task object to add.
163 The task object to add.
164 """
164 """
165 self.tasks.append(task)
165 self.tasks.append(task)
166
166
167
167
168 class WinHPCTask(Configurable):
168 class WinHPCTask(Configurable):
169
169
170 task_id = Str('')
170 task_id = Str('')
171 task_name = Str('')
171 task_name = Str('')
172 version = Str("2.000")
172 version = Str("2.000")
173 min_cores = Int(1, config=True)
173 min_cores = Int(1, config=True)
174 max_cores = Int(1, config=True)
174 max_cores = Int(1, config=True)
175 min_sockets = Int(1, config=True)
175 min_sockets = Int(1, config=True)
176 max_sockets = Int(1, config=True)
176 max_sockets = Int(1, config=True)
177 min_nodes = Int(1, config=True)
177 min_nodes = Int(1, config=True)
178 max_nodes = Int(1, config=True)
178 max_nodes = Int(1, config=True)
179 unit_type = Str("Core", config=True)
179 unit_type = Str("Core", config=True)
180 command_line = CStr('', config=True)
180 command_line = CStr('', config=True)
181 work_directory = CStr('', config=True)
181 work_directory = CStr('', config=True)
182 is_rerunnaable = Bool(True, config=True)
182 is_rerunnaable = Bool(True, config=True)
183 std_out_file_path = CStr('', config=True)
183 std_out_file_path = CStr('', config=True)
184 std_err_file_path = CStr('', config=True)
184 std_err_file_path = CStr('', config=True)
185 is_parametric = Bool(False, config=True)
185 is_parametric = Bool(False, config=True)
186 environment_variables = Instance(dict, args=(), config=True)
186 environment_variables = Instance(dict, args=(), config=True)
187
187
188 def _write_attr(self, root, attr, key):
188 def _write_attr(self, root, attr, key):
189 s = as_str(getattr(self, attr, ''))
189 s = as_str(getattr(self, attr, ''))
190 if s:
190 if s:
191 root.set(key, s)
191 root.set(key, s)
192
192
193 def as_element(self):
193 def as_element(self):
194 root = ET.Element('Task')
194 root = ET.Element('Task')
195 self._write_attr(root, 'version', '_A_Version')
195 self._write_attr(root, 'version', '_A_Version')
196 self._write_attr(root, 'task_name', '_B_Name')
196 self._write_attr(root, 'task_name', '_B_Name')
197 self._write_attr(root, 'min_cores', '_C_MinCores')
197 self._write_attr(root, 'min_cores', '_C_MinCores')
198 self._write_attr(root, 'max_cores', '_D_MaxCores')
198 self._write_attr(root, 'max_cores', '_D_MaxCores')
199 self._write_attr(root, 'min_sockets', '_E_MinSockets')
199 self._write_attr(root, 'min_sockets', '_E_MinSockets')
200 self._write_attr(root, 'max_sockets', '_F_MaxSockets')
200 self._write_attr(root, 'max_sockets', '_F_MaxSockets')
201 self._write_attr(root, 'min_nodes', '_G_MinNodes')
201 self._write_attr(root, 'min_nodes', '_G_MinNodes')
202 self._write_attr(root, 'max_nodes', '_H_MaxNodes')
202 self._write_attr(root, 'max_nodes', '_H_MaxNodes')
203 self._write_attr(root, 'command_line', '_I_CommandLine')
203 self._write_attr(root, 'command_line', '_I_CommandLine')
204 self._write_attr(root, 'work_directory', '_J_WorkDirectory')
204 self._write_attr(root, 'work_directory', '_J_WorkDirectory')
205 self._write_attr(root, 'is_rerunnaable', '_K_IsRerunnable')
205 self._write_attr(root, 'is_rerunnaable', '_K_IsRerunnable')
206 self._write_attr(root, 'std_out_file_path', '_L_StdOutFilePath')
206 self._write_attr(root, 'std_out_file_path', '_L_StdOutFilePath')
207 self._write_attr(root, 'std_err_file_path', '_M_StdErrFilePath')
207 self._write_attr(root, 'std_err_file_path', '_M_StdErrFilePath')
208 self._write_attr(root, 'is_parametric', '_N_IsParametric')
208 self._write_attr(root, 'is_parametric', '_N_IsParametric')
209 self._write_attr(root, 'unit_type', '_O_UnitType')
209 self._write_attr(root, 'unit_type', '_O_UnitType')
210 root.append(self.get_env_vars())
210 root.append(self.get_env_vars())
211 return root
211 return root
212
212
213 def get_env_vars(self):
213 def get_env_vars(self):
214 env_vars = ET.Element('EnvironmentVariables')
214 env_vars = ET.Element('EnvironmentVariables')
215 for k, v in self.environment_variables.items():
215 for k, v in self.environment_variables.items():
216 variable = ET.SubElement(env_vars, "Variable")
216 variable = ET.SubElement(env_vars, "Variable")
217 name = ET.SubElement(variable, "Name")
217 name = ET.SubElement(variable, "Name")
218 name.text = k
218 name.text = k
219 value = ET.SubElement(variable, "Value")
219 value = ET.SubElement(variable, "Value")
220 value.text = v
220 value.text = v
221 return env_vars
221 return env_vars
222
222
223
223
224
224
225 # By declaring these, we can configure the controller and engine separately!
225 # By declaring these, we can configure the controller and engine separately!
226
226
227 class IPControllerJob(WinHPCJob):
227 class IPControllerJob(WinHPCJob):
228 job_name = Str('IPController', config=False)
228 job_name = Str('IPController', config=False)
229 is_exclusive = Bool(False, config=True)
229 is_exclusive = Bool(False, config=True)
230 username = Str(find_username(), config=True)
230 username = Str(find_username(), config=True)
231 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
231 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
232 default_value='Highest', config=True)
232 default_value='Highest', config=True)
233 requested_nodes = Str('', config=True)
233 requested_nodes = Str('', config=True)
234 project = Str('IPython', config=True)
234 project = Str('IPython', config=True)
235
235
236
236
237 class IPEngineSetJob(WinHPCJob):
237 class IPEngineSetJob(WinHPCJob):
238 job_name = Str('IPEngineSet', config=False)
238 job_name = Str('IPEngineSet', config=False)
239 is_exclusive = Bool(False, config=True)
239 is_exclusive = Bool(False, config=True)
240 username = Str(find_username(), config=True)
240 username = Str(find_username(), config=True)
241 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
241 priority = Enum(('Lowest','BelowNormal','Normal','AboveNormal','Highest'),
242 default_value='Highest', config=True)
242 default_value='Highest', config=True)
243 requested_nodes = Str('', config=True)
243 requested_nodes = Str('', config=True)
244 project = Str('IPython', config=True)
244 project = Str('IPython', config=True)
245
245
246
246
247 class IPControllerTask(WinHPCTask):
247 class IPControllerTask(WinHPCTask):
248
248
249 task_name = Str('IPController', config=True)
249 task_name = Str('IPController', config=True)
250 controller_cmd = List(['ipcontroller.exe'], config=True)
250 controller_cmd = List(['ipcontroller.exe'], config=True)
251 controller_args = List(['--log-to-file', '--log-level', '40'], config=True)
251 controller_args = List(['--log-to-file', '--log-level', '40'], config=True)
252 # I don't want these to be configurable
252 # I don't want these to be configurable
253 std_out_file_path = CStr('', config=False)
253 std_out_file_path = CStr('', config=False)
254 std_err_file_path = CStr('', config=False)
254 std_err_file_path = CStr('', config=False)
255 min_cores = Int(1, config=False)
255 min_cores = Int(1, config=False)
256 max_cores = Int(1, config=False)
256 max_cores = Int(1, config=False)
257 min_sockets = Int(1, config=False)
257 min_sockets = Int(1, config=False)
258 max_sockets = Int(1, config=False)
258 max_sockets = Int(1, config=False)
259 min_nodes = Int(1, config=False)
259 min_nodes = Int(1, config=False)
260 max_nodes = Int(1, config=False)
260 max_nodes = Int(1, config=False)
261 unit_type = Str("Core", config=False)
261 unit_type = Str("Core", config=False)
262 work_directory = CStr('', config=False)
262 work_directory = CStr('', config=False)
263
263
264 def __init__(self, config=None):
264 def __init__(self, config=None):
265 super(IPControllerTask, self).__init__(config)
265 super(IPControllerTask, self).__init__(config=config)
266 the_uuid = uuid.uuid1()
266 the_uuid = uuid.uuid1()
267 self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid)
267 self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid)
268 self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid)
268 self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid)
269
269
270 @property
270 @property
271 def command_line(self):
271 def command_line(self):
272 return ' '.join(self.controller_cmd + self.controller_args)
272 return ' '.join(self.controller_cmd + self.controller_args)
273
273
274
274
275 class IPEngineTask(WinHPCTask):
275 class IPEngineTask(WinHPCTask):
276
276
277 task_name = Str('IPEngine', config=True)
277 task_name = Str('IPEngine', config=True)
278 engine_cmd = List(['ipengine.exe'], config=True)
278 engine_cmd = List(['ipengine.exe'], config=True)
279 engine_args = List(['--log-to-file', '--log-level', '40'], config=True)
279 engine_args = List(['--log-to-file', '--log-level', '40'], config=True)
280 # I don't want these to be configurable
280 # I don't want these to be configurable
281 std_out_file_path = CStr('', config=False)
281 std_out_file_path = CStr('', config=False)
282 std_err_file_path = CStr('', config=False)
282 std_err_file_path = CStr('', config=False)
283 min_cores = Int(1, config=False)
283 min_cores = Int(1, config=False)
284 max_cores = Int(1, config=False)
284 max_cores = Int(1, config=False)
285 min_sockets = Int(1, config=False)
285 min_sockets = Int(1, config=False)
286 max_sockets = Int(1, config=False)
286 max_sockets = Int(1, config=False)
287 min_nodes = Int(1, config=False)
287 min_nodes = Int(1, config=False)
288 max_nodes = Int(1, config=False)
288 max_nodes = Int(1, config=False)
289 unit_type = Str("Core", config=False)
289 unit_type = Str("Core", config=False)
290 work_directory = CStr('', config=False)
290 work_directory = CStr('', config=False)
291
291
292 def __init__(self, config=None):
292 def __init__(self, config=None):
293 super(IPEngineTask,self).__init__(config)
293 super(IPEngineTask,self).__init__(config=config)
294 the_uuid = uuid.uuid1()
294 the_uuid = uuid.uuid1()
295 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
295 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
296 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
296 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
297
297
298 @property
298 @property
299 def command_line(self):
299 def command_line(self):
300 return ' '.join(self.engine_cmd + self.engine_args)
300 return ' '.join(self.engine_cmd + self.engine_args)
301
301
302
302
303 # j = WinHPCJob(None)
303 # j = WinHPCJob(None)
304 # j.job_name = 'IPCluster'
304 # j.job_name = 'IPCluster'
305 # j.username = 'GNET\\bgranger'
305 # j.username = 'GNET\\bgranger'
306 # j.requested_nodes = 'GREEN'
306 # j.requested_nodes = 'GREEN'
307 #
307 #
308 # t = WinHPCTask(None)
308 # t = WinHPCTask(None)
309 # t.task_name = 'Controller'
309 # t.task_name = 'Controller'
310 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
310 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
311 # t.work_directory = r"\\blue\domainusers$\bgranger\.ipython\cluster_default"
311 # t.work_directory = r"\\blue\domainusers$\bgranger\.ipython\cluster_default"
312 # t.std_out_file_path = 'controller-out.txt'
312 # t.std_out_file_path = 'controller-out.txt'
313 # t.std_err_file_path = 'controller-err.txt'
313 # t.std_err_file_path = 'controller-err.txt'
314 # t.environment_variables['PYTHONPATH'] = r"\\blue\domainusers$\bgranger\Python\Python25\Lib\site-packages"
314 # t.environment_variables['PYTHONPATH'] = r"\\blue\domainusers$\bgranger\Python\Python25\Lib\site-packages"
315 # j.add_task(t)
315 # j.add_task(t)
316
316
@@ -1,686 +1,693 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Tests for IPython.utils.traitlets.
4 Tests for IPython.utils.traitlets.
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Enthought, Inc. Some of the code in this file comes from enthought.traits
9 * Enthought, Inc. Some of the code in this file comes from enthought.traits
10 and is licensed under the BSD license. Also, many of the ideas also come
10 and is licensed under the BSD license. Also, many of the ideas also come
11 from enthought.traits even though our implementation is very different.
11 from enthought.traits even though our implementation is very different.
12 """
12 """
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2008-2009 The IPython Development Team
15 # Copyright (C) 2008-2009 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 from unittest import TestCase
25 from unittest import TestCase
26
26
27 from IPython.utils.traitlets import (
27 from IPython.utils.traitlets import (
28 HasTraits, MetaHasTraits, TraitType, Any,
28 HasTraits, MetaHasTraits, TraitType, Any,
29 Int, Long, Float, Complex, Str, Unicode, TraitError,
29 Int, Long, Float, Complex, Str, Unicode, TraitError,
30 Undefined, Type, This, Instance
30 Undefined, Type, This, Instance
31 )
31 )
32
32
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Helper classes for testing
35 # Helper classes for testing
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38
38
39 class HasTraitsStub(HasTraits):
39 class HasTraitsStub(HasTraits):
40
40
41 def _notify_trait(self, name, old, new):
41 def _notify_trait(self, name, old, new):
42 self._notify_name = name
42 self._notify_name = name
43 self._notify_old = old
43 self._notify_old = old
44 self._notify_new = new
44 self._notify_new = new
45
45
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Test classes
48 # Test classes
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51
51
52 class TestTraitType(TestCase):
52 class TestTraitType(TestCase):
53
53
54 def test_get_undefined(self):
54 def test_get_undefined(self):
55 class A(HasTraits):
55 class A(HasTraits):
56 a = TraitType
56 a = TraitType
57 a = A()
57 a = A()
58 self.assertEquals(a.a, Undefined)
58 self.assertEquals(a.a, Undefined)
59
59
60 def test_set(self):
60 def test_set(self):
61 class A(HasTraitsStub):
61 class A(HasTraitsStub):
62 a = TraitType
62 a = TraitType
63
63
64 a = A()
64 a = A()
65 a.a = 10
65 a.a = 10
66 self.assertEquals(a.a, 10)
66 self.assertEquals(a.a, 10)
67 self.assertEquals(a._notify_name, 'a')
67 self.assertEquals(a._notify_name, 'a')
68 self.assertEquals(a._notify_old, Undefined)
68 self.assertEquals(a._notify_old, Undefined)
69 self.assertEquals(a._notify_new, 10)
69 self.assertEquals(a._notify_new, 10)
70
70
71 def test_validate(self):
71 def test_validate(self):
72 class MyTT(TraitType):
72 class MyTT(TraitType):
73 def validate(self, inst, value):
73 def validate(self, inst, value):
74 return -1
74 return -1
75 class A(HasTraitsStub):
75 class A(HasTraitsStub):
76 tt = MyTT
76 tt = MyTT
77
77
78 a = A()
78 a = A()
79 a.tt = 10
79 a.tt = 10
80 self.assertEquals(a.tt, -1)
80 self.assertEquals(a.tt, -1)
81
81
82 def test_default_validate(self):
82 def test_default_validate(self):
83 class MyIntTT(TraitType):
83 class MyIntTT(TraitType):
84 def validate(self, obj, value):
84 def validate(self, obj, value):
85 if isinstance(value, int):
85 if isinstance(value, int):
86 return value
86 return value
87 self.error(obj, value)
87 self.error(obj, value)
88 class A(HasTraits):
88 class A(HasTraits):
89 tt = MyIntTT(10)
89 tt = MyIntTT(10)
90 a = A()
90 a = A()
91 self.assertEquals(a.tt, 10)
91 self.assertEquals(a.tt, 10)
92
92
93 # Defaults are validated when the HasTraits is instantiated
93 # Defaults are validated when the HasTraits is instantiated
94 class B(HasTraits):
94 class B(HasTraits):
95 tt = MyIntTT('bad default')
95 tt = MyIntTT('bad default')
96 self.assertRaises(TraitError, B)
96 self.assertRaises(TraitError, B)
97
97
98 def test_is_valid_for(self):
98 def test_is_valid_for(self):
99 class MyTT(TraitType):
99 class MyTT(TraitType):
100 def is_valid_for(self, value):
100 def is_valid_for(self, value):
101 return True
101 return True
102 class A(HasTraits):
102 class A(HasTraits):
103 tt = MyTT
103 tt = MyTT
104
104
105 a = A()
105 a = A()
106 a.tt = 10
106 a.tt = 10
107 self.assertEquals(a.tt, 10)
107 self.assertEquals(a.tt, 10)
108
108
109 def test_value_for(self):
109 def test_value_for(self):
110 class MyTT(TraitType):
110 class MyTT(TraitType):
111 def value_for(self, value):
111 def value_for(self, value):
112 return 20
112 return 20
113 class A(HasTraits):
113 class A(HasTraits):
114 tt = MyTT
114 tt = MyTT
115
115
116 a = A()
116 a = A()
117 a.tt = 10
117 a.tt = 10
118 self.assertEquals(a.tt, 20)
118 self.assertEquals(a.tt, 20)
119
119
120 def test_info(self):
120 def test_info(self):
121 class A(HasTraits):
121 class A(HasTraits):
122 tt = TraitType
122 tt = TraitType
123 a = A()
123 a = A()
124 self.assertEquals(A.tt.info(), 'any value')
124 self.assertEquals(A.tt.info(), 'any value')
125
125
126 def test_error(self):
126 def test_error(self):
127 class A(HasTraits):
127 class A(HasTraits):
128 tt = TraitType
128 tt = TraitType
129 a = A()
129 a = A()
130 self.assertRaises(TraitError, A.tt.error, a, 10)
130 self.assertRaises(TraitError, A.tt.error, a, 10)
131
131
132
132
133 class TestHasTraitsMeta(TestCase):
133 class TestHasTraitsMeta(TestCase):
134
134
135 def test_metaclass(self):
135 def test_metaclass(self):
136 self.assertEquals(type(HasTraits), MetaHasTraits)
136 self.assertEquals(type(HasTraits), MetaHasTraits)
137
137
138 class A(HasTraits):
138 class A(HasTraits):
139 a = Int
139 a = Int
140
140
141 a = A()
141 a = A()
142 self.assertEquals(type(a.__class__), MetaHasTraits)
142 self.assertEquals(type(a.__class__), MetaHasTraits)
143 self.assertEquals(a.a,0)
143 self.assertEquals(a.a,0)
144 a.a = 10
144 a.a = 10
145 self.assertEquals(a.a,10)
145 self.assertEquals(a.a,10)
146
146
147 class B(HasTraits):
147 class B(HasTraits):
148 b = Int()
148 b = Int()
149
149
150 b = B()
150 b = B()
151 self.assertEquals(b.b,0)
151 self.assertEquals(b.b,0)
152 b.b = 10
152 b.b = 10
153 self.assertEquals(b.b,10)
153 self.assertEquals(b.b,10)
154
154
155 class C(HasTraits):
155 class C(HasTraits):
156 c = Int(30)
156 c = Int(30)
157
157
158 c = C()
158 c = C()
159 self.assertEquals(c.c,30)
159 self.assertEquals(c.c,30)
160 c.c = 10
160 c.c = 10
161 self.assertEquals(c.c,10)
161 self.assertEquals(c.c,10)
162
162
163 def test_this_class(self):
163 def test_this_class(self):
164 class A(HasTraits):
164 class A(HasTraits):
165 t = This()
165 t = This()
166 tt = This()
166 tt = This()
167 class B(A):
167 class B(A):
168 tt = This()
168 tt = This()
169 ttt = This()
169 ttt = This()
170 self.assertEquals(A.t.this_class, A)
170 self.assertEquals(A.t.this_class, A)
171 self.assertEquals(B.t.this_class, A)
171 self.assertEquals(B.t.this_class, A)
172 self.assertEquals(B.tt.this_class, B)
172 self.assertEquals(B.tt.this_class, B)
173 self.assertEquals(B.ttt.this_class, B)
173 self.assertEquals(B.ttt.this_class, B)
174
174
175 class TestHasTraitsNotify(TestCase):
175 class TestHasTraitsNotify(TestCase):
176
176
177 def setUp(self):
177 def setUp(self):
178 self._notify1 = []
178 self._notify1 = []
179 self._notify2 = []
179 self._notify2 = []
180
180
181 def notify1(self, name, old, new):
181 def notify1(self, name, old, new):
182 self._notify1.append((name, old, new))
182 self._notify1.append((name, old, new))
183
183
184 def notify2(self, name, old, new):
184 def notify2(self, name, old, new):
185 self._notify2.append((name, old, new))
185 self._notify2.append((name, old, new))
186
186
187 def test_notify_all(self):
187 def test_notify_all(self):
188
188
189 class A(HasTraits):
189 class A(HasTraits):
190 a = Int
190 a = Int
191 b = Float
191 b = Float
192
192
193 a = A()
193 a = A()
194 a.on_trait_change(self.notify1)
194 a.on_trait_change(self.notify1)
195 a.a = 0
195 a.a = 0
196 self.assertEquals(len(self._notify1),0)
196 self.assertEquals(len(self._notify1),0)
197 a.b = 0.0
197 a.b = 0.0
198 self.assertEquals(len(self._notify1),0)
198 self.assertEquals(len(self._notify1),0)
199 a.a = 10
199 a.a = 10
200 self.assert_(('a',0,10) in self._notify1)
200 self.assert_(('a',0,10) in self._notify1)
201 a.b = 10.0
201 a.b = 10.0
202 self.assert_(('b',0.0,10.0) in self._notify1)
202 self.assert_(('b',0.0,10.0) in self._notify1)
203 self.assertRaises(TraitError,setattr,a,'a','bad string')
203 self.assertRaises(TraitError,setattr,a,'a','bad string')
204 self.assertRaises(TraitError,setattr,a,'b','bad string')
204 self.assertRaises(TraitError,setattr,a,'b','bad string')
205 self._notify1 = []
205 self._notify1 = []
206 a.on_trait_change(self.notify1,remove=True)
206 a.on_trait_change(self.notify1,remove=True)
207 a.a = 20
207 a.a = 20
208 a.b = 20.0
208 a.b = 20.0
209 self.assertEquals(len(self._notify1),0)
209 self.assertEquals(len(self._notify1),0)
210
210
211 def test_notify_one(self):
211 def test_notify_one(self):
212
212
213 class A(HasTraits):
213 class A(HasTraits):
214 a = Int
214 a = Int
215 b = Float
215 b = Float
216
216
217 a = A()
217 a = A()
218 a.on_trait_change(self.notify1, 'a')
218 a.on_trait_change(self.notify1, 'a')
219 a.a = 0
219 a.a = 0
220 self.assertEquals(len(self._notify1),0)
220 self.assertEquals(len(self._notify1),0)
221 a.a = 10
221 a.a = 10
222 self.assert_(('a',0,10) in self._notify1)
222 self.assert_(('a',0,10) in self._notify1)
223 self.assertRaises(TraitError,setattr,a,'a','bad string')
223 self.assertRaises(TraitError,setattr,a,'a','bad string')
224
224
225 def test_subclass(self):
225 def test_subclass(self):
226
226
227 class A(HasTraits):
227 class A(HasTraits):
228 a = Int
228 a = Int
229
229
230 class B(A):
230 class B(A):
231 b = Float
231 b = Float
232
232
233 b = B()
233 b = B()
234 self.assertEquals(b.a,0)
234 self.assertEquals(b.a,0)
235 self.assertEquals(b.b,0.0)
235 self.assertEquals(b.b,0.0)
236 b.a = 100
236 b.a = 100
237 b.b = 100.0
237 b.b = 100.0
238 self.assertEquals(b.a,100)
238 self.assertEquals(b.a,100)
239 self.assertEquals(b.b,100.0)
239 self.assertEquals(b.b,100.0)
240
240
241 def test_notify_subclass(self):
241 def test_notify_subclass(self):
242
242
243 class A(HasTraits):
243 class A(HasTraits):
244 a = Int
244 a = Int
245
245
246 class B(A):
246 class B(A):
247 b = Float
247 b = Float
248
248
249 b = B()
249 b = B()
250 b.on_trait_change(self.notify1, 'a')
250 b.on_trait_change(self.notify1, 'a')
251 b.on_trait_change(self.notify2, 'b')
251 b.on_trait_change(self.notify2, 'b')
252 b.a = 0
252 b.a = 0
253 b.b = 0.0
253 b.b = 0.0
254 self.assertEquals(len(self._notify1),0)
254 self.assertEquals(len(self._notify1),0)
255 self.assertEquals(len(self._notify2),0)
255 self.assertEquals(len(self._notify2),0)
256 b.a = 10
256 b.a = 10
257 b.b = 10.0
257 b.b = 10.0
258 self.assert_(('a',0,10) in self._notify1)
258 self.assert_(('a',0,10) in self._notify1)
259 self.assert_(('b',0.0,10.0) in self._notify2)
259 self.assert_(('b',0.0,10.0) in self._notify2)
260
260
261 def test_static_notify(self):
261 def test_static_notify(self):
262
262
263 class A(HasTraits):
263 class A(HasTraits):
264 a = Int
264 a = Int
265 _notify1 = []
265 _notify1 = []
266 def _a_changed(self, name, old, new):
266 def _a_changed(self, name, old, new):
267 self._notify1.append((name, old, new))
267 self._notify1.append((name, old, new))
268
268
269 a = A()
269 a = A()
270 a.a = 0
270 a.a = 0
271 # This is broken!!!
271 # This is broken!!!
272 self.assertEquals(len(a._notify1),0)
272 self.assertEquals(len(a._notify1),0)
273 a.a = 10
273 a.a = 10
274 self.assert_(('a',0,10) in a._notify1)
274 self.assert_(('a',0,10) in a._notify1)
275
275
276 class B(A):
276 class B(A):
277 b = Float
277 b = Float
278 _notify2 = []
278 _notify2 = []
279 def _b_changed(self, name, old, new):
279 def _b_changed(self, name, old, new):
280 self._notify2.append((name, old, new))
280 self._notify2.append((name, old, new))
281
281
282 b = B()
282 b = B()
283 b.a = 10
283 b.a = 10
284 b.b = 10.0
284 b.b = 10.0
285 self.assert_(('a',0,10) in b._notify1)
285 self.assert_(('a',0,10) in b._notify1)
286 self.assert_(('b',0.0,10.0) in b._notify2)
286 self.assert_(('b',0.0,10.0) in b._notify2)
287
287
288 def test_notify_args(self):
288 def test_notify_args(self):
289
289
290 def callback0():
290 def callback0():
291 self.cb = ()
291 self.cb = ()
292 def callback1(name):
292 def callback1(name):
293 self.cb = (name,)
293 self.cb = (name,)
294 def callback2(name, new):
294 def callback2(name, new):
295 self.cb = (name, new)
295 self.cb = (name, new)
296 def callback3(name, old, new):
296 def callback3(name, old, new):
297 self.cb = (name, old, new)
297 self.cb = (name, old, new)
298
298
299 class A(HasTraits):
299 class A(HasTraits):
300 a = Int
300 a = Int
301
301
302 a = A()
302 a = A()
303 a.on_trait_change(callback0, 'a')
303 a.on_trait_change(callback0, 'a')
304 a.a = 10
304 a.a = 10
305 self.assertEquals(self.cb,())
305 self.assertEquals(self.cb,())
306 a.on_trait_change(callback0, 'a', remove=True)
306 a.on_trait_change(callback0, 'a', remove=True)
307
307
308 a.on_trait_change(callback1, 'a')
308 a.on_trait_change(callback1, 'a')
309 a.a = 100
309 a.a = 100
310 self.assertEquals(self.cb,('a',))
310 self.assertEquals(self.cb,('a',))
311 a.on_trait_change(callback1, 'a', remove=True)
311 a.on_trait_change(callback1, 'a', remove=True)
312
312
313 a.on_trait_change(callback2, 'a')
313 a.on_trait_change(callback2, 'a')
314 a.a = 1000
314 a.a = 1000
315 self.assertEquals(self.cb,('a',1000))
315 self.assertEquals(self.cb,('a',1000))
316 a.on_trait_change(callback2, 'a', remove=True)
316 a.on_trait_change(callback2, 'a', remove=True)
317
317
318 a.on_trait_change(callback3, 'a')
318 a.on_trait_change(callback3, 'a')
319 a.a = 10000
319 a.a = 10000
320 self.assertEquals(self.cb,('a',1000,10000))
320 self.assertEquals(self.cb,('a',1000,10000))
321 a.on_trait_change(callback3, 'a', remove=True)
321 a.on_trait_change(callback3, 'a', remove=True)
322
322
323 self.assertEquals(len(a._trait_notifiers['a']),0)
323 self.assertEquals(len(a._trait_notifiers['a']),0)
324
324
325
325
326 class TestHasTraits(TestCase):
326 class TestHasTraits(TestCase):
327
327
328 def test_trait_names(self):
328 def test_trait_names(self):
329 class A(HasTraits):
329 class A(HasTraits):
330 i = Int
330 i = Int
331 f = Float
331 f = Float
332 a = A()
332 a = A()
333 self.assertEquals(a.trait_names(),['i','f'])
333 self.assertEquals(a.trait_names(),['i','f'])
334
334
335 def test_trait_metadata(self):
335 def test_trait_metadata(self):
336 class A(HasTraits):
336 class A(HasTraits):
337 i = Int(config_key='MY_VALUE')
337 i = Int(config_key='MY_VALUE')
338 a = A()
338 a = A()
339 self.assertEquals(a.trait_metadata('i','config_key'), 'MY_VALUE')
339 self.assertEquals(a.trait_metadata('i','config_key'), 'MY_VALUE')
340
340
341 def test_traits(self):
341 def test_traits(self):
342 class A(HasTraits):
342 class A(HasTraits):
343 i = Int
343 i = Int
344 f = Float
344 f = Float
345 a = A()
345 a = A()
346 self.assertEquals(a.traits(), dict(i=A.i, f=A.f))
346 self.assertEquals(a.traits(), dict(i=A.i, f=A.f))
347
347
348 def test_traits_metadata(self):
348 def test_traits_metadata(self):
349 class A(HasTraits):
349 class A(HasTraits):
350 i = Int(config_key='VALUE1', other_thing='VALUE2')
350 i = Int(config_key='VALUE1', other_thing='VALUE2')
351 f = Float(config_key='VALUE3', other_thing='VALUE2')
351 f = Float(config_key='VALUE3', other_thing='VALUE2')
352 j = Int(0)
352 j = Int(0)
353 a = A()
353 a = A()
354 self.assertEquals(a.traits(), dict(i=A.i, f=A.f, j=A.j))
354 self.assertEquals(a.traits(), dict(i=A.i, f=A.f, j=A.j))
355 traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
355 traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
356 self.assertEquals(traits, dict(i=A.i))
356 self.assertEquals(traits, dict(i=A.i))
357
357
358 # This passes, but it shouldn't because I am replicating a bug in
358 # This passes, but it shouldn't because I am replicating a bug in
359 # traits.
359 # traits.
360 traits = a.traits(config_key=lambda v: True)
360 traits = a.traits(config_key=lambda v: True)
361 self.assertEquals(traits, dict(i=A.i, f=A.f, j=A.j))
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 # Tests for specific trait types
372 # Tests for specific trait types
366 #-----------------------------------------------------------------------------
373 #-----------------------------------------------------------------------------
367
374
368
375
369 class TestType(TestCase):
376 class TestType(TestCase):
370
377
371 def test_default(self):
378 def test_default(self):
372
379
373 class B(object): pass
380 class B(object): pass
374 class A(HasTraits):
381 class A(HasTraits):
375 klass = Type
382 klass = Type
376
383
377 a = A()
384 a = A()
378 self.assertEquals(a.klass, None)
385 self.assertEquals(a.klass, None)
379
386
380 a.klass = B
387 a.klass = B
381 self.assertEquals(a.klass, B)
388 self.assertEquals(a.klass, B)
382 self.assertRaises(TraitError, setattr, a, 'klass', 10)
389 self.assertRaises(TraitError, setattr, a, 'klass', 10)
383
390
384 def test_value(self):
391 def test_value(self):
385
392
386 class B(object): pass
393 class B(object): pass
387 class C(object): pass
394 class C(object): pass
388 class A(HasTraits):
395 class A(HasTraits):
389 klass = Type(B)
396 klass = Type(B)
390
397
391 a = A()
398 a = A()
392 self.assertEquals(a.klass, B)
399 self.assertEquals(a.klass, B)
393 self.assertRaises(TraitError, setattr, a, 'klass', C)
400 self.assertRaises(TraitError, setattr, a, 'klass', C)
394 self.assertRaises(TraitError, setattr, a, 'klass', object)
401 self.assertRaises(TraitError, setattr, a, 'klass', object)
395 a.klass = B
402 a.klass = B
396
403
397 def test_allow_none(self):
404 def test_allow_none(self):
398
405
399 class B(object): pass
406 class B(object): pass
400 class C(B): pass
407 class C(B): pass
401 class A(HasTraits):
408 class A(HasTraits):
402 klass = Type(B, allow_none=False)
409 klass = Type(B, allow_none=False)
403
410
404 a = A()
411 a = A()
405 self.assertEquals(a.klass, B)
412 self.assertEquals(a.klass, B)
406 self.assertRaises(TraitError, setattr, a, 'klass', None)
413 self.assertRaises(TraitError, setattr, a, 'klass', None)
407 a.klass = C
414 a.klass = C
408 self.assertEquals(a.klass, C)
415 self.assertEquals(a.klass, C)
409
416
410 def test_validate_klass(self):
417 def test_validate_klass(self):
411
418
412 class A(HasTraits):
419 class A(HasTraits):
413 klass = Type('no strings allowed')
420 klass = Type('no strings allowed')
414
421
415 self.assertRaises(ImportError, A)
422 self.assertRaises(ImportError, A)
416
423
417 class A(HasTraits):
424 class A(HasTraits):
418 klass = Type('rub.adub.Duck')
425 klass = Type('rub.adub.Duck')
419
426
420 self.assertRaises(ImportError, A)
427 self.assertRaises(ImportError, A)
421
428
422 def test_validate_default(self):
429 def test_validate_default(self):
423
430
424 class B(object): pass
431 class B(object): pass
425 class A(HasTraits):
432 class A(HasTraits):
426 klass = Type('bad default', B)
433 klass = Type('bad default', B)
427
434
428 self.assertRaises(ImportError, A)
435 self.assertRaises(ImportError, A)
429
436
430 class C(HasTraits):
437 class C(HasTraits):
431 klass = Type(None, B, allow_none=False)
438 klass = Type(None, B, allow_none=False)
432
439
433 self.assertRaises(TraitError, C)
440 self.assertRaises(TraitError, C)
434
441
435 def test_str_klass(self):
442 def test_str_klass(self):
436
443
437 class A(HasTraits):
444 class A(HasTraits):
438 klass = Type('IPython.utils.ipstruct.Struct')
445 klass = Type('IPython.utils.ipstruct.Struct')
439
446
440 from IPython.utils.ipstruct import Struct
447 from IPython.utils.ipstruct import Struct
441 a = A()
448 a = A()
442 a.klass = Struct
449 a.klass = Struct
443 self.assertEquals(a.klass, Struct)
450 self.assertEquals(a.klass, Struct)
444
451
445 self.assertRaises(TraitError, setattr, a, 'klass', 10)
452 self.assertRaises(TraitError, setattr, a, 'klass', 10)
446
453
447 class TestInstance(TestCase):
454 class TestInstance(TestCase):
448
455
449 def test_basic(self):
456 def test_basic(self):
450 class Foo(object): pass
457 class Foo(object): pass
451 class Bar(Foo): pass
458 class Bar(Foo): pass
452 class Bah(object): pass
459 class Bah(object): pass
453
460
454 class A(HasTraits):
461 class A(HasTraits):
455 inst = Instance(Foo)
462 inst = Instance(Foo)
456
463
457 a = A()
464 a = A()
458 self.assert_(a.inst is None)
465 self.assert_(a.inst is None)
459 a.inst = Foo()
466 a.inst = Foo()
460 self.assert_(isinstance(a.inst, Foo))
467 self.assert_(isinstance(a.inst, Foo))
461 a.inst = Bar()
468 a.inst = Bar()
462 self.assert_(isinstance(a.inst, Foo))
469 self.assert_(isinstance(a.inst, Foo))
463 self.assertRaises(TraitError, setattr, a, 'inst', Foo)
470 self.assertRaises(TraitError, setattr, a, 'inst', Foo)
464 self.assertRaises(TraitError, setattr, a, 'inst', Bar)
471 self.assertRaises(TraitError, setattr, a, 'inst', Bar)
465 self.assertRaises(TraitError, setattr, a, 'inst', Bah())
472 self.assertRaises(TraitError, setattr, a, 'inst', Bah())
466
473
467 def test_unique_default_value(self):
474 def test_unique_default_value(self):
468 class Foo(object): pass
475 class Foo(object): pass
469 class A(HasTraits):
476 class A(HasTraits):
470 inst = Instance(Foo,(),{})
477 inst = Instance(Foo,(),{})
471
478
472 a = A()
479 a = A()
473 b = A()
480 b = A()
474 self.assert_(a.inst is not b.inst)
481 self.assert_(a.inst is not b.inst)
475
482
476 def test_args_kw(self):
483 def test_args_kw(self):
477 class Foo(object):
484 class Foo(object):
478 def __init__(self, c): self.c = c
485 def __init__(self, c): self.c = c
479 class Bar(object): pass
486 class Bar(object): pass
480 class Bah(object):
487 class Bah(object):
481 def __init__(self, c, d):
488 def __init__(self, c, d):
482 self.c = c; self.d = d
489 self.c = c; self.d = d
483
490
484 class A(HasTraits):
491 class A(HasTraits):
485 inst = Instance(Foo, (10,))
492 inst = Instance(Foo, (10,))
486 a = A()
493 a = A()
487 self.assertEquals(a.inst.c, 10)
494 self.assertEquals(a.inst.c, 10)
488
495
489 class B(HasTraits):
496 class B(HasTraits):
490 inst = Instance(Bah, args=(10,), kw=dict(d=20))
497 inst = Instance(Bah, args=(10,), kw=dict(d=20))
491 b = B()
498 b = B()
492 self.assertEquals(b.inst.c, 10)
499 self.assertEquals(b.inst.c, 10)
493 self.assertEquals(b.inst.d, 20)
500 self.assertEquals(b.inst.d, 20)
494
501
495 class C(HasTraits):
502 class C(HasTraits):
496 inst = Instance(Foo)
503 inst = Instance(Foo)
497 c = C()
504 c = C()
498 self.assert_(c.inst is None)
505 self.assert_(c.inst is None)
499
506
500 def test_bad_default(self):
507 def test_bad_default(self):
501 class Foo(object): pass
508 class Foo(object): pass
502
509
503 class A(HasTraits):
510 class A(HasTraits):
504 inst = Instance(Foo, allow_none=False)
511 inst = Instance(Foo, allow_none=False)
505
512
506 self.assertRaises(TraitError, A)
513 self.assertRaises(TraitError, A)
507
514
508 def test_instance(self):
515 def test_instance(self):
509 class Foo(object): pass
516 class Foo(object): pass
510
517
511 def inner():
518 def inner():
512 class A(HasTraits):
519 class A(HasTraits):
513 inst = Instance(Foo())
520 inst = Instance(Foo())
514
521
515 self.assertRaises(TraitError, inner)
522 self.assertRaises(TraitError, inner)
516
523
517
524
518 class TestThis(TestCase):
525 class TestThis(TestCase):
519
526
520 def test_this_class(self):
527 def test_this_class(self):
521 class Foo(HasTraits):
528 class Foo(HasTraits):
522 this = This
529 this = This
523
530
524 f = Foo()
531 f = Foo()
525 self.assertEquals(f.this, None)
532 self.assertEquals(f.this, None)
526 g = Foo()
533 g = Foo()
527 f.this = g
534 f.this = g
528 self.assertEquals(f.this, g)
535 self.assertEquals(f.this, g)
529 self.assertRaises(TraitError, setattr, f, 'this', 10)
536 self.assertRaises(TraitError, setattr, f, 'this', 10)
530
537
531 def test_this_inst(self):
538 def test_this_inst(self):
532 class Foo(HasTraits):
539 class Foo(HasTraits):
533 this = This()
540 this = This()
534
541
535 f = Foo()
542 f = Foo()
536 f.this = Foo()
543 f.this = Foo()
537 self.assert_(isinstance(f.this, Foo))
544 self.assert_(isinstance(f.this, Foo))
538
545
539 def test_subclass(self):
546 def test_subclass(self):
540 class Foo(HasTraits):
547 class Foo(HasTraits):
541 t = This()
548 t = This()
542 class Bar(Foo):
549 class Bar(Foo):
543 pass
550 pass
544 f = Foo()
551 f = Foo()
545 b = Bar()
552 b = Bar()
546 f.t = b
553 f.t = b
547 b.t = f
554 b.t = f
548 self.assertEquals(f.t, b)
555 self.assertEquals(f.t, b)
549 self.assertEquals(b.t, f)
556 self.assertEquals(b.t, f)
550
557
551 def test_subclass_override(self):
558 def test_subclass_override(self):
552 class Foo(HasTraits):
559 class Foo(HasTraits):
553 t = This()
560 t = This()
554 class Bar(Foo):
561 class Bar(Foo):
555 t = This()
562 t = This()
556 f = Foo()
563 f = Foo()
557 b = Bar()
564 b = Bar()
558 f.t = b
565 f.t = b
559 self.assertEquals(f.t, b)
566 self.assertEquals(f.t, b)
560 self.assertRaises(TraitError, setattr, b, 't', f)
567 self.assertRaises(TraitError, setattr, b, 't', f)
561
568
562 class TraitTestBase(TestCase):
569 class TraitTestBase(TestCase):
563 """A best testing class for basic trait types."""
570 """A best testing class for basic trait types."""
564
571
565 def assign(self, value):
572 def assign(self, value):
566 self.obj.value = value
573 self.obj.value = value
567
574
568 def coerce(self, value):
575 def coerce(self, value):
569 return value
576 return value
570
577
571 def test_good_values(self):
578 def test_good_values(self):
572 if hasattr(self, '_good_values'):
579 if hasattr(self, '_good_values'):
573 for value in self._good_values:
580 for value in self._good_values:
574 self.assign(value)
581 self.assign(value)
575 self.assertEquals(self.obj.value, self.coerce(value))
582 self.assertEquals(self.obj.value, self.coerce(value))
576
583
577 def test_bad_values(self):
584 def test_bad_values(self):
578 if hasattr(self, '_bad_values'):
585 if hasattr(self, '_bad_values'):
579 for value in self._bad_values:
586 for value in self._bad_values:
580 self.assertRaises(TraitError, self.assign, value)
587 self.assertRaises(TraitError, self.assign, value)
581
588
582 def test_default_value(self):
589 def test_default_value(self):
583 if hasattr(self, '_default_value'):
590 if hasattr(self, '_default_value'):
584 self.assertEquals(self._default_value, self.obj.value)
591 self.assertEquals(self._default_value, self.obj.value)
585
592
586
593
587 class AnyTrait(HasTraits):
594 class AnyTrait(HasTraits):
588
595
589 value = Any
596 value = Any
590
597
591 class AnyTraitTest(TraitTestBase):
598 class AnyTraitTest(TraitTestBase):
592
599
593 obj = AnyTrait()
600 obj = AnyTrait()
594
601
595 _default_value = None
602 _default_value = None
596 _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
603 _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
597 _bad_values = []
604 _bad_values = []
598
605
599
606
600 class IntTrait(HasTraits):
607 class IntTrait(HasTraits):
601
608
602 value = Int(99)
609 value = Int(99)
603
610
604 class TestInt(TraitTestBase):
611 class TestInt(TraitTestBase):
605
612
606 obj = IntTrait()
613 obj = IntTrait()
607 _default_value = 99
614 _default_value = 99
608 _good_values = [10, -10]
615 _good_values = [10, -10]
609 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j, 10L,
616 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j, 10L,
610 -10L, 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
617 -10L, 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
611 u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
618 u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
612
619
613
620
614 class LongTrait(HasTraits):
621 class LongTrait(HasTraits):
615
622
616 value = Long(99L)
623 value = Long(99L)
617
624
618 class TestLong(TraitTestBase):
625 class TestLong(TraitTestBase):
619
626
620 obj = LongTrait()
627 obj = LongTrait()
621
628
622 _default_value = 99L
629 _default_value = 99L
623 _good_values = [10, -10, 10L, -10L]
630 _good_values = [10, -10, 10L, -10L]
624 _bad_values = ['ten', u'ten', [10], [10l], {'ten': 10},(10,),(10L,),
631 _bad_values = ['ten', u'ten', [10], [10l], {'ten': 10},(10,),(10L,),
625 None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
632 None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
626 '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
633 '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
627 u'-10.1']
634 u'-10.1']
628
635
629
636
630 class FloatTrait(HasTraits):
637 class FloatTrait(HasTraits):
631
638
632 value = Float(99.0)
639 value = Float(99.0)
633
640
634 class TestFloat(TraitTestBase):
641 class TestFloat(TraitTestBase):
635
642
636 obj = FloatTrait()
643 obj = FloatTrait()
637
644
638 _default_value = 99.0
645 _default_value = 99.0
639 _good_values = [10, -10, 10.1, -10.1]
646 _good_values = [10, -10, 10.1, -10.1]
640 _bad_values = [10L, -10L, 'ten', u'ten', [10], {'ten': 10},(10,), None,
647 _bad_values = [10L, -10L, 'ten', u'ten', [10], {'ten': 10},(10,), None,
641 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
648 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
642 u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
649 u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
643
650
644
651
645 class ComplexTrait(HasTraits):
652 class ComplexTrait(HasTraits):
646
653
647 value = Complex(99.0-99.0j)
654 value = Complex(99.0-99.0j)
648
655
649 class TestComplex(TraitTestBase):
656 class TestComplex(TraitTestBase):
650
657
651 obj = ComplexTrait()
658 obj = ComplexTrait()
652
659
653 _default_value = 99.0-99.0j
660 _default_value = 99.0-99.0j
654 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
661 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
655 10.1j, 10.1+10.1j, 10.1-10.1j]
662 10.1j, 10.1+10.1j, 10.1-10.1j]
656 _bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
663 _bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
657
664
658
665
659 class StringTrait(HasTraits):
666 class StringTrait(HasTraits):
660
667
661 value = Str('string')
668 value = Str('string')
662
669
663 class TestString(TraitTestBase):
670 class TestString(TraitTestBase):
664
671
665 obj = StringTrait()
672 obj = StringTrait()
666
673
667 _default_value = 'string'
674 _default_value = 'string'
668 _good_values = ['10', '-10', '10L',
675 _good_values = ['10', '-10', '10L',
669 '-10L', '10.1', '-10.1', 'string']
676 '-10L', '10.1', '-10.1', 'string']
670 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j, [10],
677 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j, [10],
671 ['ten'],{'ten': 10},(10,), None, u'string']
678 ['ten'],{'ten': 10},(10,), None, u'string']
672
679
673
680
674 class UnicodeTrait(HasTraits):
681 class UnicodeTrait(HasTraits):
675
682
676 value = Unicode(u'unicode')
683 value = Unicode(u'unicode')
677
684
678 class TestUnicode(TraitTestBase):
685 class TestUnicode(TraitTestBase):
679
686
680 obj = UnicodeTrait()
687 obj = UnicodeTrait()
681
688
682 _default_value = u'unicode'
689 _default_value = u'unicode'
683 _good_values = ['10', '-10', '10L', '-10L', '10.1',
690 _good_values = ['10', '-10', '10L', '-10L', '10.1',
684 '-10.1', '', u'', 'string', u'string', ]
691 '-10.1', '', u'', 'string', u'string', ]
685 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
692 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
686 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
693 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
@@ -1,1048 +1,1048 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A lightweight Traits like module.
4 A lightweight Traits like module.
5
5
6 This is designed to provide a lightweight, simple, pure Python version of
6 This is designed to provide a lightweight, simple, pure Python version of
7 many of the capabilities of enthought.traits. This includes:
7 many of the capabilities of enthought.traits. This includes:
8
8
9 * Validation
9 * Validation
10 * Type specification with defaults
10 * Type specification with defaults
11 * Static and dynamic notification
11 * Static and dynamic notification
12 * Basic predefined types
12 * Basic predefined types
13 * An API that is similar to enthought.traits
13 * An API that is similar to enthought.traits
14
14
15 We don't support:
15 We don't support:
16
16
17 * Delegation
17 * Delegation
18 * Automatic GUI generation
18 * Automatic GUI generation
19 * A full set of trait types. Most importantly, we don't provide container
19 * A full set of trait types. Most importantly, we don't provide container
20 traits (list, dict, tuple) that can trigger notifications if their
20 traits (list, dict, tuple) that can trigger notifications if their
21 contents change.
21 contents change.
22 * API compatibility with enthought.traits
22 * API compatibility with enthought.traits
23
23
24 There are also some important difference in our design:
24 There are also some important difference in our design:
25
25
26 * enthought.traits does not validate default values. We do.
26 * enthought.traits does not validate default values. We do.
27
27
28 We choose to create this module because we need these capabilities, but
28 We choose to create this module because we need these capabilities, but
29 we need them to be pure Python so they work in all Python implementations,
29 we need them to be pure Python so they work in all Python implementations,
30 including Jython and IronPython.
30 including Jython and IronPython.
31
31
32 Authors:
32 Authors:
33
33
34 * Brian Granger
34 * Brian Granger
35 * Enthought, Inc. Some of the code in this file comes from enthought.traits
35 * Enthought, Inc. Some of the code in this file comes from enthought.traits
36 and is licensed under the BSD license. Also, many of the ideas also come
36 and is licensed under the BSD license. Also, many of the ideas also come
37 from enthought.traits even though our implementation is very different.
37 from enthought.traits even though our implementation is very different.
38 """
38 """
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Copyright (C) 2008-2009 The IPython Development Team
41 # Copyright (C) 2008-2009 The IPython Development Team
42 #
42 #
43 # Distributed under the terms of the BSD License. The full license is in
43 # Distributed under the terms of the BSD License. The full license is in
44 # the file COPYING, distributed as part of this software.
44 # the file COPYING, distributed as part of this software.
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Imports
48 # Imports
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51
51
52 import inspect
52 import inspect
53 import sys
53 import sys
54 import types
54 import types
55 from types import (
55 from types import (
56 InstanceType, ClassType, FunctionType,
56 InstanceType, ClassType, FunctionType,
57 ListType, TupleType
57 ListType, TupleType
58 )
58 )
59
59
60 def import_item(name):
60 def import_item(name):
61 """Import and return bar given the string foo.bar."""
61 """Import and return bar given the string foo.bar."""
62 package = '.'.join(name.split('.')[0:-1])
62 package = '.'.join(name.split('.')[0:-1])
63 obj = name.split('.')[-1]
63 obj = name.split('.')[-1]
64 execString = 'from %s import %s' % (package, obj)
64 execString = 'from %s import %s' % (package, obj)
65 try:
65 try:
66 exec execString
66 exec execString
67 except SyntaxError:
67 except SyntaxError:
68 raise ImportError("Invalid class specification: %s" % name)
68 raise ImportError("Invalid class specification: %s" % name)
69 exec 'temp = %s' % obj
69 exec 'temp = %s' % obj
70 return temp
70 return temp
71
71
72
72
73 ClassTypes = (ClassType, type)
73 ClassTypes = (ClassType, type)
74
74
75 SequenceTypes = (ListType, TupleType)
75 SequenceTypes = (ListType, TupleType)
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Basic classes
78 # Basic classes
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81
81
82 class NoDefaultSpecified ( object ): pass
82 class NoDefaultSpecified ( object ): pass
83 NoDefaultSpecified = NoDefaultSpecified()
83 NoDefaultSpecified = NoDefaultSpecified()
84
84
85
85
86 class Undefined ( object ): pass
86 class Undefined ( object ): pass
87 Undefined = Undefined()
87 Undefined = Undefined()
88
88
89 class TraitError(Exception):
89 class TraitError(Exception):
90 pass
90 pass
91
91
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93 # Utilities
93 # Utilities
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95
95
96
96
97 def class_of ( object ):
97 def class_of ( object ):
98 """ Returns a string containing the class name of an object with the
98 """ Returns a string containing the class name of an object with the
99 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
99 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
100 'a PlotValue').
100 'a PlotValue').
101 """
101 """
102 if isinstance( object, basestring ):
102 if isinstance( object, basestring ):
103 return add_article( object )
103 return add_article( object )
104
104
105 return add_article( object.__class__.__name__ )
105 return add_article( object.__class__.__name__ )
106
106
107
107
108 def add_article ( name ):
108 def add_article ( name ):
109 """ Returns a string containing the correct indefinite article ('a' or 'an')
109 """ Returns a string containing the correct indefinite article ('a' or 'an')
110 prefixed to the specified string.
110 prefixed to the specified string.
111 """
111 """
112 if name[:1].lower() in 'aeiou':
112 if name[:1].lower() in 'aeiou':
113 return 'an ' + name
113 return 'an ' + name
114
114
115 return 'a ' + name
115 return 'a ' + name
116
116
117
117
118 def repr_type(obj):
118 def repr_type(obj):
119 """ Return a string representation of a value and its type for readable
119 """ Return a string representation of a value and its type for readable
120 error messages.
120 error messages.
121 """
121 """
122 the_type = type(obj)
122 the_type = type(obj)
123 if the_type is InstanceType:
123 if the_type is InstanceType:
124 # Old-style class.
124 # Old-style class.
125 the_type = obj.__class__
125 the_type = obj.__class__
126 msg = '%r %r' % (obj, the_type)
126 msg = '%r %r' % (obj, the_type)
127 return msg
127 return msg
128
128
129
129
130 def parse_notifier_name(name):
130 def parse_notifier_name(name):
131 """Convert the name argument to a list of names.
131 """Convert the name argument to a list of names.
132
132
133 Examples
133 Examples
134 --------
134 --------
135
135
136 >>> parse_notifier_name('a')
136 >>> parse_notifier_name('a')
137 ['a']
137 ['a']
138 >>> parse_notifier_name(['a','b'])
138 >>> parse_notifier_name(['a','b'])
139 ['a', 'b']
139 ['a', 'b']
140 >>> parse_notifier_name(None)
140 >>> parse_notifier_name(None)
141 ['anytrait']
141 ['anytrait']
142 """
142 """
143 if isinstance(name, str):
143 if isinstance(name, str):
144 return [name]
144 return [name]
145 elif name is None:
145 elif name is None:
146 return ['anytrait']
146 return ['anytrait']
147 elif isinstance(name, (list, tuple)):
147 elif isinstance(name, (list, tuple)):
148 for n in name:
148 for n in name:
149 assert isinstance(n, str), "names must be strings"
149 assert isinstance(n, str), "names must be strings"
150 return name
150 return name
151
151
152
152
153 class _SimpleTest:
153 class _SimpleTest:
154 def __init__ ( self, value ): self.value = value
154 def __init__ ( self, value ): self.value = value
155 def __call__ ( self, test ):
155 def __call__ ( self, test ):
156 return test == self.value
156 return test == self.value
157 def __repr__(self):
157 def __repr__(self):
158 return "<SimpleTest(%r)" % self.value
158 return "<SimpleTest(%r)" % self.value
159 def __str__(self):
159 def __str__(self):
160 return self.__repr__()
160 return self.__repr__()
161
161
162
162
163 def getmembers(object, predicate=None):
163 def getmembers(object, predicate=None):
164 """A safe version of inspect.getmembers that handles missing attributes.
164 """A safe version of inspect.getmembers that handles missing attributes.
165
165
166 This is useful when there are descriptor based attributes that for
166 This is useful when there are descriptor based attributes that for
167 some reason raise AttributeError even though they exist. This happens
167 some reason raise AttributeError even though they exist. This happens
168 in zope.inteface with the __provides__ attribute.
168 in zope.inteface with the __provides__ attribute.
169 """
169 """
170 results = []
170 results = []
171 for key in dir(object):
171 for key in dir(object):
172 try:
172 try:
173 value = getattr(object, key)
173 value = getattr(object, key)
174 except AttributeError:
174 except AttributeError:
175 pass
175 pass
176 else:
176 else:
177 if not predicate or predicate(value):
177 if not predicate or predicate(value):
178 results.append((key, value))
178 results.append((key, value))
179 results.sort()
179 results.sort()
180 return results
180 return results
181
181
182
182
183 #-----------------------------------------------------------------------------
183 #-----------------------------------------------------------------------------
184 # Base TraitType for all traits
184 # Base TraitType for all traits
185 #-----------------------------------------------------------------------------
185 #-----------------------------------------------------------------------------
186
186
187
187
188 class TraitType(object):
188 class TraitType(object):
189 """A base class for all trait descriptors.
189 """A base class for all trait descriptors.
190
190
191 Notes
191 Notes
192 -----
192 -----
193 Our implementation of traits is based on Python's descriptor
193 Our implementation of traits is based on Python's descriptor
194 prototol. This class is the base class for all such descriptors. The
194 prototol. This class is the base class for all such descriptors. The
195 only magic we use is a custom metaclass for the main :class:`HasTraits`
195 only magic we use is a custom metaclass for the main :class:`HasTraits`
196 class that does the following:
196 class that does the following:
197
197
198 1. Sets the :attr:`name` attribute of every :class:`TraitType`
198 1. Sets the :attr:`name` attribute of every :class:`TraitType`
199 instance in the class dict to the name of the attribute.
199 instance in the class dict to the name of the attribute.
200 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
200 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
201 instance in the class dict to the *class* that declared the trait.
201 instance in the class dict to the *class* that declared the trait.
202 This is used by the :class:`This` trait to allow subclasses to
202 This is used by the :class:`This` trait to allow subclasses to
203 accept superclasses for :class:`This` values.
203 accept superclasses for :class:`This` values.
204 """
204 """
205
205
206
206
207 metadata = {}
207 metadata = {}
208 default_value = Undefined
208 default_value = Undefined
209 info_text = 'any value'
209 info_text = 'any value'
210
210
211 def __init__(self, default_value=NoDefaultSpecified, **metadata):
211 def __init__(self, default_value=NoDefaultSpecified, **metadata):
212 """Create a TraitType.
212 """Create a TraitType.
213 """
213 """
214 if default_value is not NoDefaultSpecified:
214 if default_value is not NoDefaultSpecified:
215 self.default_value = default_value
215 self.default_value = default_value
216
216
217 if len(metadata) > 0:
217 if len(metadata) > 0:
218 if len(self.metadata) > 0:
218 if len(self.metadata) > 0:
219 self._metadata = self.metadata.copy()
219 self._metadata = self.metadata.copy()
220 self._metadata.update(metadata)
220 self._metadata.update(metadata)
221 else:
221 else:
222 self._metadata = metadata
222 self._metadata = metadata
223 else:
223 else:
224 self._metadata = self.metadata
224 self._metadata = self.metadata
225
225
226 self.init()
226 self.init()
227
227
228 def init(self):
228 def init(self):
229 pass
229 pass
230
230
231 def get_default_value(self):
231 def get_default_value(self):
232 """Create a new instance of the default value."""
232 """Create a new instance of the default value."""
233 dv = self.default_value
233 dv = self.default_value
234 return dv
234 return dv
235
235
236 def instance_init(self, obj):
236 def instance_init(self, obj):
237 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
237 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
238
238
239 Some stages of initialization must be delayed until the parent
239 Some stages of initialization must be delayed until the parent
240 :class:`HasTraits` instance has been created. This method is
240 :class:`HasTraits` instance has been created. This method is
241 called in :meth:`HasTraits.__new__` after the instance has been
241 called in :meth:`HasTraits.__new__` after the instance has been
242 created.
242 created.
243
243
244 This method trigger the creation and validation of default values
244 This method trigger the creation and validation of default values
245 and also things like the resolution of str given class names in
245 and also things like the resolution of str given class names in
246 :class:`Type` and :class`Instance`.
246 :class:`Type` and :class`Instance`.
247
247
248 Parameters
248 Parameters
249 ----------
249 ----------
250 obj : :class:`HasTraits` instance
250 obj : :class:`HasTraits` instance
251 The parent :class:`HasTraits` instance that has just been
251 The parent :class:`HasTraits` instance that has just been
252 created.
252 created.
253 """
253 """
254 self.set_default_value(obj)
254 self.set_default_value(obj)
255
255
256 def set_default_value(self, obj):
256 def set_default_value(self, obj):
257 """Set the default value on a per instance basis.
257 """Set the default value on a per instance basis.
258
258
259 This method is called by :meth:`instance_init` to create and
259 This method is called by :meth:`instance_init` to create and
260 validate the default value. The creation and validation of
260 validate the default value. The creation and validation of
261 default values must be delayed until the parent :class:`HasTraits`
261 default values must be delayed until the parent :class:`HasTraits`
262 class has been instantiated.
262 class has been instantiated.
263 """
263 """
264 dv = self.get_default_value()
264 dv = self.get_default_value()
265 newdv = self._validate(obj, dv)
265 newdv = self._validate(obj, dv)
266 obj._trait_values[self.name] = newdv
266 obj._trait_values[self.name] = newdv
267
267
268 def __get__(self, obj, cls=None):
268 def __get__(self, obj, cls=None):
269 """Get the value of the trait by self.name for the instance.
269 """Get the value of the trait by self.name for the instance.
270
270
271 Default values are instantiated when :meth:`HasTraits.__new__`
271 Default values are instantiated when :meth:`HasTraits.__new__`
272 is called. Thus by the time this method gets called either the
272 is called. Thus by the time this method gets called either the
273 default value or a user defined value (they called :meth:`__set__`)
273 default value or a user defined value (they called :meth:`__set__`)
274 is in the :class:`HasTraits` instance.
274 is in the :class:`HasTraits` instance.
275 """
275 """
276 if obj is None:
276 if obj is None:
277 return self
277 return self
278 else:
278 else:
279 try:
279 try:
280 value = obj._trait_values[self.name]
280 value = obj._trait_values[self.name]
281 except:
281 except:
282 # HasTraits should call set_default_value to populate
282 # HasTraits should call set_default_value to populate
283 # this. So this should never be reached.
283 # this. So this should never be reached.
284 raise TraitError('Unexpected error in TraitType: '
284 raise TraitError('Unexpected error in TraitType: '
285 'default value not set properly')
285 'default value not set properly')
286 else:
286 else:
287 return value
287 return value
288
288
289 def __set__(self, obj, value):
289 def __set__(self, obj, value):
290 new_value = self._validate(obj, value)
290 new_value = self._validate(obj, value)
291 old_value = self.__get__(obj)
291 old_value = self.__get__(obj)
292 if old_value != new_value:
292 if old_value != new_value:
293 obj._trait_values[self.name] = new_value
293 obj._trait_values[self.name] = new_value
294 obj._notify_trait(self.name, old_value, new_value)
294 obj._notify_trait(self.name, old_value, new_value)
295
295
296 def _validate(self, obj, value):
296 def _validate(self, obj, value):
297 if hasattr(self, 'validate'):
297 if hasattr(self, 'validate'):
298 return self.validate(obj, value)
298 return self.validate(obj, value)
299 elif hasattr(self, 'is_valid_for'):
299 elif hasattr(self, 'is_valid_for'):
300 valid = self.is_valid_for(value)
300 valid = self.is_valid_for(value)
301 if valid:
301 if valid:
302 return value
302 return value
303 else:
303 else:
304 raise TraitError('invalid value for type: %r' % value)
304 raise TraitError('invalid value for type: %r' % value)
305 elif hasattr(self, 'value_for'):
305 elif hasattr(self, 'value_for'):
306 return self.value_for(value)
306 return self.value_for(value)
307 else:
307 else:
308 return value
308 return value
309
309
310 def info(self):
310 def info(self):
311 return self.info_text
311 return self.info_text
312
312
313 def error(self, obj, value):
313 def error(self, obj, value):
314 if obj is not None:
314 if obj is not None:
315 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
315 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
316 % (self.name, class_of(obj),
316 % (self.name, class_of(obj),
317 self.info(), repr_type(value))
317 self.info(), repr_type(value))
318 else:
318 else:
319 e = "The '%s' trait must be %s, but a value of %r was specified." \
319 e = "The '%s' trait must be %s, but a value of %r was specified." \
320 % (self.name, self.info(), repr_type(value))
320 % (self.name, self.info(), repr_type(value))
321 raise TraitError(e)
321 raise TraitError(e)
322
322
323 def get_metadata(self, key):
323 def get_metadata(self, key):
324 return getattr(self, '_metadata', {}).get(key, None)
324 return getattr(self, '_metadata', {}).get(key, None)
325
325
326 def set_metadata(self, key, value):
326 def set_metadata(self, key, value):
327 getattr(self, '_metadata', {})[key] = value
327 getattr(self, '_metadata', {})[key] = value
328
328
329
329
330 #-----------------------------------------------------------------------------
330 #-----------------------------------------------------------------------------
331 # The HasTraits implementation
331 # The HasTraits implementation
332 #-----------------------------------------------------------------------------
332 #-----------------------------------------------------------------------------
333
333
334
334
335 class MetaHasTraits(type):
335 class MetaHasTraits(type):
336 """A metaclass for HasTraits.
336 """A metaclass for HasTraits.
337
337
338 This metaclass makes sure that any TraitType class attributes are
338 This metaclass makes sure that any TraitType class attributes are
339 instantiated and sets their name attribute.
339 instantiated and sets their name attribute.
340 """
340 """
341
341
342 def __new__(mcls, name, bases, classdict):
342 def __new__(mcls, name, bases, classdict):
343 """Create the HasTraits class.
343 """Create the HasTraits class.
344
344
345 This instantiates all TraitTypes in the class dict and sets their
345 This instantiates all TraitTypes in the class dict and sets their
346 :attr:`name` attribute.
346 :attr:`name` attribute.
347 """
347 """
348 # print "MetaHasTraitlets (mcls, name): ", mcls, name
348 # print "MetaHasTraitlets (mcls, name): ", mcls, name
349 # print "MetaHasTraitlets (bases): ", bases
349 # print "MetaHasTraitlets (bases): ", bases
350 # print "MetaHasTraitlets (classdict): ", classdict
350 # print "MetaHasTraitlets (classdict): ", classdict
351 for k,v in classdict.iteritems():
351 for k,v in classdict.iteritems():
352 if isinstance(v, TraitType):
352 if isinstance(v, TraitType):
353 v.name = k
353 v.name = k
354 elif inspect.isclass(v):
354 elif inspect.isclass(v):
355 if issubclass(v, TraitType):
355 if issubclass(v, TraitType):
356 vinst = v()
356 vinst = v()
357 vinst.name = k
357 vinst.name = k
358 classdict[k] = vinst
358 classdict[k] = vinst
359 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
359 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
360
360
361 def __init__(cls, name, bases, classdict):
361 def __init__(cls, name, bases, classdict):
362 """Finish initializing the HasTraits class.
362 """Finish initializing the HasTraits class.
363
363
364 This sets the :attr:`this_class` attribute of each TraitType in the
364 This sets the :attr:`this_class` attribute of each TraitType in the
365 class dict to the newly created class ``cls``.
365 class dict to the newly created class ``cls``.
366 """
366 """
367 for k, v in classdict.iteritems():
367 for k, v in classdict.iteritems():
368 if isinstance(v, TraitType):
368 if isinstance(v, TraitType):
369 v.this_class = cls
369 v.this_class = cls
370 super(MetaHasTraits, cls).__init__(name, bases, classdict)
370 super(MetaHasTraits, cls).__init__(name, bases, classdict)
371
371
372 class HasTraits(object):
372 class HasTraits(object):
373
373
374 __metaclass__ = MetaHasTraits
374 __metaclass__ = MetaHasTraits
375
375
376 def __new__(cls, **kw):
376 def __new__(cls, **kw):
377 # This is needed because in Python 2.6 object.__new__ only accepts
377 # This is needed because in Python 2.6 object.__new__ only accepts
378 # the cls argument.
378 # the cls argument.
379 new_meth = super(HasTraits, cls).__new__
379 new_meth = super(HasTraits, cls).__new__
380 if new_meth is object.__new__:
380 if new_meth is object.__new__:
381 inst = new_meth(cls)
381 inst = new_meth(cls)
382 else:
382 else:
383 inst = new_meth(cls, **kw)
383 inst = new_meth(cls, **kw)
384 inst._trait_values = {}
384 inst._trait_values = {}
385 inst._trait_notifiers = {}
385 inst._trait_notifiers = {}
386 # Here we tell all the TraitType instances to set their default
386 # Here we tell all the TraitType instances to set their default
387 # values on the instance.
387 # values on the instance.
388 for key in dir(cls):
388 for key in dir(cls):
389 # Some descriptors raise AttributeError like zope.interface's
389 # Some descriptors raise AttributeError like zope.interface's
390 # __provides__ attributes even though they exist. This causes
390 # __provides__ attributes even though they exist. This causes
391 # AttributeErrors even though they are listed in dir(cls).
391 # AttributeErrors even though they are listed in dir(cls).
392 try:
392 try:
393 value = getattr(cls, key)
393 value = getattr(cls, key)
394 except AttributeError:
394 except AttributeError:
395 pass
395 pass
396 else:
396 else:
397 if isinstance(value, TraitType):
397 if isinstance(value, TraitType):
398 value.instance_init(inst)
398 value.instance_init(inst)
399
399
400 return inst
400 return inst
401
401
402 def __init__(self, *kw):
402 def __init__(self, **kw):
403 # Allow trait values to be set using keywork arguments.
403 # Allow trait values to be set using keyword arguments.
404 for key, value in kw.iteritems():
404 for key, value in kw.iteritems():
405 setattr(self, key, value)
405 setattr(self, key, value)
406
406
407 def _notify_trait(self, name, old_value, new_value):
407 def _notify_trait(self, name, old_value, new_value):
408
408
409 # First dynamic ones
409 # First dynamic ones
410 callables = self._trait_notifiers.get(name,[])
410 callables = self._trait_notifiers.get(name,[])
411 more_callables = self._trait_notifiers.get('anytrait',[])
411 more_callables = self._trait_notifiers.get('anytrait',[])
412 callables.extend(more_callables)
412 callables.extend(more_callables)
413
413
414 # Now static ones
414 # Now static ones
415 try:
415 try:
416 cb = getattr(self, '_%s_changed' % name)
416 cb = getattr(self, '_%s_changed' % name)
417 except:
417 except:
418 pass
418 pass
419 else:
419 else:
420 callables.append(cb)
420 callables.append(cb)
421
421
422 # Call them all now
422 # Call them all now
423 for c in callables:
423 for c in callables:
424 # Traits catches and logs errors here. I allow them to raise
424 # Traits catches and logs errors here. I allow them to raise
425 if callable(c):
425 if callable(c):
426 argspec = inspect.getargspec(c)
426 argspec = inspect.getargspec(c)
427 nargs = len(argspec[0])
427 nargs = len(argspec[0])
428 # Bound methods have an additional 'self' argument
428 # Bound methods have an additional 'self' argument
429 # I don't know how to treat unbound methods, but they
429 # I don't know how to treat unbound methods, but they
430 # can't really be used for callbacks.
430 # can't really be used for callbacks.
431 if isinstance(c, types.MethodType):
431 if isinstance(c, types.MethodType):
432 offset = -1
432 offset = -1
433 else:
433 else:
434 offset = 0
434 offset = 0
435 if nargs + offset == 0:
435 if nargs + offset == 0:
436 c()
436 c()
437 elif nargs + offset == 1:
437 elif nargs + offset == 1:
438 c(name)
438 c(name)
439 elif nargs + offset == 2:
439 elif nargs + offset == 2:
440 c(name, new_value)
440 c(name, new_value)
441 elif nargs + offset == 3:
441 elif nargs + offset == 3:
442 c(name, old_value, new_value)
442 c(name, old_value, new_value)
443 else:
443 else:
444 raise TraitError('a trait changed callback '
444 raise TraitError('a trait changed callback '
445 'must have 0-3 arguments.')
445 'must have 0-3 arguments.')
446 else:
446 else:
447 raise TraitError('a trait changed callback '
447 raise TraitError('a trait changed callback '
448 'must be callable.')
448 'must be callable.')
449
449
450
450
451 def _add_notifiers(self, handler, name):
451 def _add_notifiers(self, handler, name):
452 if not self._trait_notifiers.has_key(name):
452 if not self._trait_notifiers.has_key(name):
453 nlist = []
453 nlist = []
454 self._trait_notifiers[name] = nlist
454 self._trait_notifiers[name] = nlist
455 else:
455 else:
456 nlist = self._trait_notifiers[name]
456 nlist = self._trait_notifiers[name]
457 if handler not in nlist:
457 if handler not in nlist:
458 nlist.append(handler)
458 nlist.append(handler)
459
459
460 def _remove_notifiers(self, handler, name):
460 def _remove_notifiers(self, handler, name):
461 if self._trait_notifiers.has_key(name):
461 if self._trait_notifiers.has_key(name):
462 nlist = self._trait_notifiers[name]
462 nlist = self._trait_notifiers[name]
463 try:
463 try:
464 index = nlist.index(handler)
464 index = nlist.index(handler)
465 except ValueError:
465 except ValueError:
466 pass
466 pass
467 else:
467 else:
468 del nlist[index]
468 del nlist[index]
469
469
470 def on_trait_change(self, handler, name=None, remove=False):
470 def on_trait_change(self, handler, name=None, remove=False):
471 """Setup a handler to be called when a trait changes.
471 """Setup a handler to be called when a trait changes.
472
472
473 This is used to setup dynamic notifications of trait changes.
473 This is used to setup dynamic notifications of trait changes.
474
474
475 Static handlers can be created by creating methods on a HasTraits
475 Static handlers can be created by creating methods on a HasTraits
476 subclass with the naming convention '_[traitname]_changed'. Thus,
476 subclass with the naming convention '_[traitname]_changed'. Thus,
477 to create static handler for the trait 'a', create the method
477 to create static handler for the trait 'a', create the method
478 _a_changed(self, name, old, new) (fewer arguments can be used, see
478 _a_changed(self, name, old, new) (fewer arguments can be used, see
479 below).
479 below).
480
480
481 Parameters
481 Parameters
482 ----------
482 ----------
483 handler : callable
483 handler : callable
484 A callable that is called when a trait changes. Its
484 A callable that is called when a trait changes. Its
485 signature can be handler(), handler(name), handler(name, new)
485 signature can be handler(), handler(name), handler(name, new)
486 or handler(name, old, new).
486 or handler(name, old, new).
487 name : list, str, None
487 name : list, str, None
488 If None, the handler will apply to all traits. If a list
488 If None, the handler will apply to all traits. If a list
489 of str, handler will apply to all names in the list. If a
489 of str, handler will apply to all names in the list. If a
490 str, the handler will apply just to that name.
490 str, the handler will apply just to that name.
491 remove : bool
491 remove : bool
492 If False (the default), then install the handler. If True
492 If False (the default), then install the handler. If True
493 then unintall it.
493 then unintall it.
494 """
494 """
495 if remove:
495 if remove:
496 names = parse_notifier_name(name)
496 names = parse_notifier_name(name)
497 for n in names:
497 for n in names:
498 self._remove_notifiers(handler, n)
498 self._remove_notifiers(handler, n)
499 else:
499 else:
500 names = parse_notifier_name(name)
500 names = parse_notifier_name(name)
501 for n in names:
501 for n in names:
502 self._add_notifiers(handler, n)
502 self._add_notifiers(handler, n)
503
503
504 def trait_names(self, **metadata):
504 def trait_names(self, **metadata):
505 """Get a list of all the names of this classes traits."""
505 """Get a list of all the names of this classes traits."""
506 return self.traits(**metadata).keys()
506 return self.traits(**metadata).keys()
507
507
508 def traits(self, **metadata):
508 def traits(self, **metadata):
509 """Get a list of all the traits of this class.
509 """Get a list of all the traits of this class.
510
510
511 The TraitTypes returned don't know anything about the values
511 The TraitTypes returned don't know anything about the values
512 that the various HasTrait's instances are holding.
512 that the various HasTrait's instances are holding.
513
513
514 This follows the same algorithm as traits does and does not allow
514 This follows the same algorithm as traits does and does not allow
515 for any simple way of specifying merely that a metadata name
515 for any simple way of specifying merely that a metadata name
516 exists, but has any value. This is because get_metadata returns
516 exists, but has any value. This is because get_metadata returns
517 None if a metadata key doesn't exist.
517 None if a metadata key doesn't exist.
518 """
518 """
519 traits = dict([memb for memb in getmembers(self.__class__) if \
519 traits = dict([memb for memb in getmembers(self.__class__) if \
520 isinstance(memb[1], TraitType)])
520 isinstance(memb[1], TraitType)])
521
521
522 if len(metadata) == 0:
522 if len(metadata) == 0:
523 return traits
523 return traits
524
524
525 for meta_name, meta_eval in metadata.items():
525 for meta_name, meta_eval in metadata.items():
526 if type(meta_eval) is not FunctionType:
526 if type(meta_eval) is not FunctionType:
527 metadata[meta_name] = _SimpleTest(meta_eval)
527 metadata[meta_name] = _SimpleTest(meta_eval)
528
528
529 result = {}
529 result = {}
530 for name, trait in traits.items():
530 for name, trait in traits.items():
531 for meta_name, meta_eval in metadata.items():
531 for meta_name, meta_eval in metadata.items():
532 if not meta_eval(trait.get_metadata(meta_name)):
532 if not meta_eval(trait.get_metadata(meta_name)):
533 break
533 break
534 else:
534 else:
535 result[name] = trait
535 result[name] = trait
536
536
537 return result
537 return result
538
538
539 def trait_metadata(self, traitname, key):
539 def trait_metadata(self, traitname, key):
540 """Get metadata values for trait by key."""
540 """Get metadata values for trait by key."""
541 try:
541 try:
542 trait = getattr(self.__class__, traitname)
542 trait = getattr(self.__class__, traitname)
543 except AttributeError:
543 except AttributeError:
544 raise TraitError("Class %s does not have a trait named %s" %
544 raise TraitError("Class %s does not have a trait named %s" %
545 (self.__class__.__name__, traitname))
545 (self.__class__.__name__, traitname))
546 else:
546 else:
547 return trait.get_metadata(key)
547 return trait.get_metadata(key)
548
548
549 #-----------------------------------------------------------------------------
549 #-----------------------------------------------------------------------------
550 # Actual TraitTypes implementations/subclasses
550 # Actual TraitTypes implementations/subclasses
551 #-----------------------------------------------------------------------------
551 #-----------------------------------------------------------------------------
552
552
553 #-----------------------------------------------------------------------------
553 #-----------------------------------------------------------------------------
554 # TraitTypes subclasses for handling classes and instances of classes
554 # TraitTypes subclasses for handling classes and instances of classes
555 #-----------------------------------------------------------------------------
555 #-----------------------------------------------------------------------------
556
556
557
557
558 class ClassBasedTraitType(TraitType):
558 class ClassBasedTraitType(TraitType):
559 """A trait with error reporting for Type, Instance and This."""
559 """A trait with error reporting for Type, Instance and This."""
560
560
561 def error(self, obj, value):
561 def error(self, obj, value):
562 kind = type(value)
562 kind = type(value)
563 if kind is InstanceType:
563 if kind is InstanceType:
564 msg = 'class %s' % value.__class__.__name__
564 msg = 'class %s' % value.__class__.__name__
565 else:
565 else:
566 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
566 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
567
567
568 super(ClassBasedTraitType, self).error(obj, msg)
568 super(ClassBasedTraitType, self).error(obj, msg)
569
569
570
570
571 class Type(ClassBasedTraitType):
571 class Type(ClassBasedTraitType):
572 """A trait whose value must be a subclass of a specified class."""
572 """A trait whose value must be a subclass of a specified class."""
573
573
574 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
574 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
575 """Construct a Type trait
575 """Construct a Type trait
576
576
577 A Type trait specifies that its values must be subclasses of
577 A Type trait specifies that its values must be subclasses of
578 a particular class.
578 a particular class.
579
579
580 If only ``default_value`` is given, it is used for the ``klass`` as
580 If only ``default_value`` is given, it is used for the ``klass`` as
581 well.
581 well.
582
582
583 Parameters
583 Parameters
584 ----------
584 ----------
585 default_value : class, str or None
585 default_value : class, str or None
586 The default value must be a subclass of klass. If an str,
586 The default value must be a subclass of klass. If an str,
587 the str must be a fully specified class name, like 'foo.bar.Bah'.
587 the str must be a fully specified class name, like 'foo.bar.Bah'.
588 The string is resolved into real class, when the parent
588 The string is resolved into real class, when the parent
589 :class:`HasTraits` class is instantiated.
589 :class:`HasTraits` class is instantiated.
590 klass : class, str, None
590 klass : class, str, None
591 Values of this trait must be a subclass of klass. The klass
591 Values of this trait must be a subclass of klass. The klass
592 may be specified in a string like: 'foo.bar.MyClass'.
592 may be specified in a string like: 'foo.bar.MyClass'.
593 The string is resolved into real class, when the parent
593 The string is resolved into real class, when the parent
594 :class:`HasTraits` class is instantiated.
594 :class:`HasTraits` class is instantiated.
595 allow_none : boolean
595 allow_none : boolean
596 Indicates whether None is allowed as an assignable value. Even if
596 Indicates whether None is allowed as an assignable value. Even if
597 ``False``, the default value may be ``None``.
597 ``False``, the default value may be ``None``.
598 """
598 """
599 if default_value is None:
599 if default_value is None:
600 if klass is None:
600 if klass is None:
601 klass = object
601 klass = object
602 elif klass is None:
602 elif klass is None:
603 klass = default_value
603 klass = default_value
604
604
605 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
605 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
606 raise TraitError("A Type trait must specify a class.")
606 raise TraitError("A Type trait must specify a class.")
607
607
608 self.klass = klass
608 self.klass = klass
609 self._allow_none = allow_none
609 self._allow_none = allow_none
610
610
611 super(Type, self).__init__(default_value, **metadata)
611 super(Type, self).__init__(default_value, **metadata)
612
612
613 def validate(self, obj, value):
613 def validate(self, obj, value):
614 """Validates that the value is a valid object instance."""
614 """Validates that the value is a valid object instance."""
615 try:
615 try:
616 if issubclass(value, self.klass):
616 if issubclass(value, self.klass):
617 return value
617 return value
618 except:
618 except:
619 if (value is None) and (self._allow_none):
619 if (value is None) and (self._allow_none):
620 return value
620 return value
621
621
622 self.error(obj, value)
622 self.error(obj, value)
623
623
624 def info(self):
624 def info(self):
625 """ Returns a description of the trait."""
625 """ Returns a description of the trait."""
626 if isinstance(self.klass, basestring):
626 if isinstance(self.klass, basestring):
627 klass = self.klass
627 klass = self.klass
628 else:
628 else:
629 klass = self.klass.__name__
629 klass = self.klass.__name__
630 result = 'a subclass of ' + klass
630 result = 'a subclass of ' + klass
631 if self._allow_none:
631 if self._allow_none:
632 return result + ' or None'
632 return result + ' or None'
633 return result
633 return result
634
634
635 def instance_init(self, obj):
635 def instance_init(self, obj):
636 self._resolve_classes()
636 self._resolve_classes()
637 super(Type, self).instance_init(obj)
637 super(Type, self).instance_init(obj)
638
638
639 def _resolve_classes(self):
639 def _resolve_classes(self):
640 if isinstance(self.klass, basestring):
640 if isinstance(self.klass, basestring):
641 self.klass = import_item(self.klass)
641 self.klass = import_item(self.klass)
642 if isinstance(self.default_value, basestring):
642 if isinstance(self.default_value, basestring):
643 self.default_value = import_item(self.default_value)
643 self.default_value = import_item(self.default_value)
644
644
645 def get_default_value(self):
645 def get_default_value(self):
646 return self.default_value
646 return self.default_value
647
647
648
648
649 class DefaultValueGenerator(object):
649 class DefaultValueGenerator(object):
650 """A class for generating new default value instances."""
650 """A class for generating new default value instances."""
651
651
652 def __init__(self, *args, **kw):
652 def __init__(self, *args, **kw):
653 self.args = args
653 self.args = args
654 self.kw = kw
654 self.kw = kw
655
655
656 def generate(self, klass):
656 def generate(self, klass):
657 return klass(*self.args, **self.kw)
657 return klass(*self.args, **self.kw)
658
658
659
659
660 class Instance(ClassBasedTraitType):
660 class Instance(ClassBasedTraitType):
661 """A trait whose value must be an instance of a specified class.
661 """A trait whose value must be an instance of a specified class.
662
662
663 The value can also be an instance of a subclass of the specified class.
663 The value can also be an instance of a subclass of the specified class.
664 """
664 """
665
665
666 def __init__(self, klass=None, args=None, kw=None,
666 def __init__(self, klass=None, args=None, kw=None,
667 allow_none=True, **metadata ):
667 allow_none=True, **metadata ):
668 """Construct an Instance trait.
668 """Construct an Instance trait.
669
669
670 This trait allows values that are instances of a particular
670 This trait allows values that are instances of a particular
671 class or its sublclasses. Our implementation is quite different
671 class or its sublclasses. Our implementation is quite different
672 from that of enthough.traits as we don't allow instances to be used
672 from that of enthough.traits as we don't allow instances to be used
673 for klass and we handle the ``args`` and ``kw`` arguments differently.
673 for klass and we handle the ``args`` and ``kw`` arguments differently.
674
674
675 Parameters
675 Parameters
676 ----------
676 ----------
677 klass : class, str
677 klass : class, str
678 The class that forms the basis for the trait. Class names
678 The class that forms the basis for the trait. Class names
679 can also be specified as strings, like 'foo.bar.Bar'.
679 can also be specified as strings, like 'foo.bar.Bar'.
680 args : tuple
680 args : tuple
681 Positional arguments for generating the default value.
681 Positional arguments for generating the default value.
682 kw : dict
682 kw : dict
683 Keyword arguments for generating the default value.
683 Keyword arguments for generating the default value.
684 allow_none : bool
684 allow_none : bool
685 Indicates whether None is allowed as a value.
685 Indicates whether None is allowed as a value.
686
686
687 Default Value
687 Default Value
688 -------------
688 -------------
689 If both ``args`` and ``kw`` are None, then the default value is None.
689 If both ``args`` and ``kw`` are None, then the default value is None.
690 If ``args`` is a tuple and ``kw`` is a dict, then the default is
690 If ``args`` is a tuple and ``kw`` is a dict, then the default is
691 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
691 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
692 not (but not both), None is replace by ``()`` or ``{}``.
692 not (but not both), None is replace by ``()`` or ``{}``.
693 """
693 """
694
694
695 self._allow_none = allow_none
695 self._allow_none = allow_none
696
696
697 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
697 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
698 raise TraitError('The klass argument must be a class'
698 raise TraitError('The klass argument must be a class'
699 ' you gave: %r' % klass)
699 ' you gave: %r' % klass)
700 self.klass = klass
700 self.klass = klass
701
701
702 # self.klass is a class, so handle default_value
702 # self.klass is a class, so handle default_value
703 if args is None and kw is None:
703 if args is None and kw is None:
704 default_value = None
704 default_value = None
705 else:
705 else:
706 if args is None:
706 if args is None:
707 # kw is not None
707 # kw is not None
708 args = ()
708 args = ()
709 elif kw is None:
709 elif kw is None:
710 # args is not None
710 # args is not None
711 kw = {}
711 kw = {}
712
712
713 if not isinstance(kw, dict):
713 if not isinstance(kw, dict):
714 raise TraitError("The 'kw' argument must be a dict or None.")
714 raise TraitError("The 'kw' argument must be a dict or None.")
715 if not isinstance(args, tuple):
715 if not isinstance(args, tuple):
716 raise TraitError("The 'args' argument must be a tuple or None.")
716 raise TraitError("The 'args' argument must be a tuple or None.")
717
717
718 default_value = DefaultValueGenerator(*args, **kw)
718 default_value = DefaultValueGenerator(*args, **kw)
719
719
720 super(Instance, self).__init__(default_value, **metadata)
720 super(Instance, self).__init__(default_value, **metadata)
721
721
722 def validate(self, obj, value):
722 def validate(self, obj, value):
723 if value is None:
723 if value is None:
724 if self._allow_none:
724 if self._allow_none:
725 return value
725 return value
726 self.error(obj, value)
726 self.error(obj, value)
727
727
728 if isinstance(value, self.klass):
728 if isinstance(value, self.klass):
729 return value
729 return value
730 else:
730 else:
731 self.error(obj, value)
731 self.error(obj, value)
732
732
733 def info(self):
733 def info(self):
734 if isinstance(self.klass, basestring):
734 if isinstance(self.klass, basestring):
735 klass = self.klass
735 klass = self.klass
736 else:
736 else:
737 klass = self.klass.__name__
737 klass = self.klass.__name__
738 result = class_of(klass)
738 result = class_of(klass)
739 if self._allow_none:
739 if self._allow_none:
740 return result + ' or None'
740 return result + ' or None'
741
741
742 return result
742 return result
743
743
744 def instance_init(self, obj):
744 def instance_init(self, obj):
745 self._resolve_classes()
745 self._resolve_classes()
746 super(Instance, self).instance_init(obj)
746 super(Instance, self).instance_init(obj)
747
747
748 def _resolve_classes(self):
748 def _resolve_classes(self):
749 if isinstance(self.klass, basestring):
749 if isinstance(self.klass, basestring):
750 self.klass = import_item(self.klass)
750 self.klass = import_item(self.klass)
751
751
752 def get_default_value(self):
752 def get_default_value(self):
753 """Instantiate a default value instance.
753 """Instantiate a default value instance.
754
754
755 This is called when the containing HasTraits classes'
755 This is called when the containing HasTraits classes'
756 :meth:`__new__` method is called to ensure that a unique instance
756 :meth:`__new__` method is called to ensure that a unique instance
757 is created for each HasTraits instance.
757 is created for each HasTraits instance.
758 """
758 """
759 dv = self.default_value
759 dv = self.default_value
760 if isinstance(dv, DefaultValueGenerator):
760 if isinstance(dv, DefaultValueGenerator):
761 return dv.generate(self.klass)
761 return dv.generate(self.klass)
762 else:
762 else:
763 return dv
763 return dv
764
764
765
765
766 class This(ClassBasedTraitType):
766 class This(ClassBasedTraitType):
767 """A trait for instances of the class containing this trait.
767 """A trait for instances of the class containing this trait.
768
768
769 Because how how and when class bodies are executed, the ``This``
769 Because how how and when class bodies are executed, the ``This``
770 trait can only have a default value of None. This, and because we
770 trait can only have a default value of None. This, and because we
771 always validate default values, ``allow_none`` is *always* true.
771 always validate default values, ``allow_none`` is *always* true.
772 """
772 """
773
773
774 info_text = 'an instance of the same type as the receiver or None'
774 info_text = 'an instance of the same type as the receiver or None'
775
775
776 def __init__(self, **metadata):
776 def __init__(self, **metadata):
777 super(This, self).__init__(None, **metadata)
777 super(This, self).__init__(None, **metadata)
778
778
779 def validate(self, obj, value):
779 def validate(self, obj, value):
780 # What if value is a superclass of obj.__class__? This is
780 # What if value is a superclass of obj.__class__? This is
781 # complicated if it was the superclass that defined the This
781 # complicated if it was the superclass that defined the This
782 # trait.
782 # trait.
783 if isinstance(value, self.this_class) or (value is None):
783 if isinstance(value, self.this_class) or (value is None):
784 return value
784 return value
785 else:
785 else:
786 self.error(obj, value)
786 self.error(obj, value)
787
787
788
788
789 #-----------------------------------------------------------------------------
789 #-----------------------------------------------------------------------------
790 # Basic TraitTypes implementations/subclasses
790 # Basic TraitTypes implementations/subclasses
791 #-----------------------------------------------------------------------------
791 #-----------------------------------------------------------------------------
792
792
793
793
794 class Any(TraitType):
794 class Any(TraitType):
795 default_value = None
795 default_value = None
796 info_text = 'any value'
796 info_text = 'any value'
797
797
798
798
799 class Int(TraitType):
799 class Int(TraitType):
800 """A integer trait."""
800 """A integer trait."""
801
801
802 evaluate = int
802 evaluate = int
803 default_value = 0
803 default_value = 0
804 info_text = 'an integer'
804 info_text = 'an integer'
805
805
806 def validate(self, obj, value):
806 def validate(self, obj, value):
807 if isinstance(value, int):
807 if isinstance(value, int):
808 return value
808 return value
809 self.error(obj, value)
809 self.error(obj, value)
810
810
811 class CInt(Int):
811 class CInt(Int):
812 """A casting version of the int trait."""
812 """A casting version of the int trait."""
813
813
814 def validate(self, obj, value):
814 def validate(self, obj, value):
815 try:
815 try:
816 return int(value)
816 return int(value)
817 except:
817 except:
818 self.error(obj, value)
818 self.error(obj, value)
819
819
820
820
821 class Long(TraitType):
821 class Long(TraitType):
822 """A long integer trait."""
822 """A long integer trait."""
823
823
824 evaluate = long
824 evaluate = long
825 default_value = 0L
825 default_value = 0L
826 info_text = 'a long'
826 info_text = 'a long'
827
827
828 def validate(self, obj, value):
828 def validate(self, obj, value):
829 if isinstance(value, long):
829 if isinstance(value, long):
830 return value
830 return value
831 if isinstance(value, int):
831 if isinstance(value, int):
832 return long(value)
832 return long(value)
833 self.error(obj, value)
833 self.error(obj, value)
834
834
835
835
836 class CLong(Long):
836 class CLong(Long):
837 """A casting version of the long integer trait."""
837 """A casting version of the long integer trait."""
838
838
839 def validate(self, obj, value):
839 def validate(self, obj, value):
840 try:
840 try:
841 return long(value)
841 return long(value)
842 except:
842 except:
843 self.error(obj, value)
843 self.error(obj, value)
844
844
845
845
846 class Float(TraitType):
846 class Float(TraitType):
847 """A float trait."""
847 """A float trait."""
848
848
849 evaluate = float
849 evaluate = float
850 default_value = 0.0
850 default_value = 0.0
851 info_text = 'a float'
851 info_text = 'a float'
852
852
853 def validate(self, obj, value):
853 def validate(self, obj, value):
854 if isinstance(value, float):
854 if isinstance(value, float):
855 return value
855 return value
856 if isinstance(value, int):
856 if isinstance(value, int):
857 return float(value)
857 return float(value)
858 self.error(obj, value)
858 self.error(obj, value)
859
859
860
860
861 class CFloat(Float):
861 class CFloat(Float):
862 """A casting version of the float trait."""
862 """A casting version of the float trait."""
863
863
864 def validate(self, obj, value):
864 def validate(self, obj, value):
865 try:
865 try:
866 return float(value)
866 return float(value)
867 except:
867 except:
868 self.error(obj, value)
868 self.error(obj, value)
869
869
870 class Complex(TraitType):
870 class Complex(TraitType):
871 """A trait for complex numbers."""
871 """A trait for complex numbers."""
872
872
873 evaluate = complex
873 evaluate = complex
874 default_value = 0.0 + 0.0j
874 default_value = 0.0 + 0.0j
875 info_text = 'a complex number'
875 info_text = 'a complex number'
876
876
877 def validate(self, obj, value):
877 def validate(self, obj, value):
878 if isinstance(value, complex):
878 if isinstance(value, complex):
879 return value
879 return value
880 if isinstance(value, (float, int)):
880 if isinstance(value, (float, int)):
881 return complex(value)
881 return complex(value)
882 self.error(obj, value)
882 self.error(obj, value)
883
883
884
884
885 class CComplex(Complex):
885 class CComplex(Complex):
886 """A casting version of the complex number trait."""
886 """A casting version of the complex number trait."""
887
887
888 def validate (self, obj, value):
888 def validate (self, obj, value):
889 try:
889 try:
890 return complex(value)
890 return complex(value)
891 except:
891 except:
892 self.error(obj, value)
892 self.error(obj, value)
893
893
894
894
895 class Str(TraitType):
895 class Str(TraitType):
896 """A trait for strings."""
896 """A trait for strings."""
897
897
898 evaluate = lambda x: x
898 evaluate = lambda x: x
899 default_value = ''
899 default_value = ''
900 info_text = 'a string'
900 info_text = 'a string'
901
901
902 def validate(self, obj, value):
902 def validate(self, obj, value):
903 if isinstance(value, str):
903 if isinstance(value, str):
904 return value
904 return value
905 self.error(obj, value)
905 self.error(obj, value)
906
906
907
907
908 class CStr(Str):
908 class CStr(Str):
909 """A casting version of the string trait."""
909 """A casting version of the string trait."""
910
910
911 def validate(self, obj, value):
911 def validate(self, obj, value):
912 try:
912 try:
913 return str(value)
913 return str(value)
914 except:
914 except:
915 try:
915 try:
916 return unicode(value)
916 return unicode(value)
917 except:
917 except:
918 self.error(obj, value)
918 self.error(obj, value)
919
919
920
920
921 class Unicode(TraitType):
921 class Unicode(TraitType):
922 """A trait for unicode strings."""
922 """A trait for unicode strings."""
923
923
924 evaluate = unicode
924 evaluate = unicode
925 default_value = u''
925 default_value = u''
926 info_text = 'a unicode string'
926 info_text = 'a unicode string'
927
927
928 def validate(self, obj, value):
928 def validate(self, obj, value):
929 if isinstance(value, unicode):
929 if isinstance(value, unicode):
930 return value
930 return value
931 if isinstance(value, str):
931 if isinstance(value, str):
932 return unicode(value)
932 return unicode(value)
933 self.error(obj, value)
933 self.error(obj, value)
934
934
935
935
936 class CUnicode(Unicode):
936 class CUnicode(Unicode):
937 """A casting version of the unicode trait."""
937 """A casting version of the unicode trait."""
938
938
939 def validate(self, obj, value):
939 def validate(self, obj, value):
940 try:
940 try:
941 return unicode(value)
941 return unicode(value)
942 except:
942 except:
943 self.error(obj, value)
943 self.error(obj, value)
944
944
945
945
946 class Bool(TraitType):
946 class Bool(TraitType):
947 """A boolean (True, False) trait."""
947 """A boolean (True, False) trait."""
948 evaluate = bool
948 evaluate = bool
949 default_value = False
949 default_value = False
950 info_text = 'a boolean'
950 info_text = 'a boolean'
951
951
952 def validate(self, obj, value):
952 def validate(self, obj, value):
953 if isinstance(value, bool):
953 if isinstance(value, bool):
954 return value
954 return value
955 self.error(obj, value)
955 self.error(obj, value)
956
956
957
957
958 class CBool(Bool):
958 class CBool(Bool):
959 """A casting version of the boolean trait."""
959 """A casting version of the boolean trait."""
960
960
961 def validate(self, obj, value):
961 def validate(self, obj, value):
962 try:
962 try:
963 return bool(value)
963 return bool(value)
964 except:
964 except:
965 self.error(obj, value)
965 self.error(obj, value)
966
966
967
967
968 class Enum(TraitType):
968 class Enum(TraitType):
969 """An enum that whose value must be in a given sequence."""
969 """An enum that whose value must be in a given sequence."""
970
970
971 def __init__(self, values, default_value=None, allow_none=True, **metadata):
971 def __init__(self, values, default_value=None, allow_none=True, **metadata):
972 self.values = values
972 self.values = values
973 self._allow_none = allow_none
973 self._allow_none = allow_none
974 super(Enum, self).__init__(default_value, **metadata)
974 super(Enum, self).__init__(default_value, **metadata)
975
975
976 def validate(self, obj, value):
976 def validate(self, obj, value):
977 if value is None:
977 if value is None:
978 if self._allow_none:
978 if self._allow_none:
979 return value
979 return value
980
980
981 if value in self.values:
981 if value in self.values:
982 return value
982 return value
983 self.error(obj, value)
983 self.error(obj, value)
984
984
985 def info(self):
985 def info(self):
986 """ Returns a description of the trait."""
986 """ Returns a description of the trait."""
987 result = 'any of ' + repr(self.values)
987 result = 'any of ' + repr(self.values)
988 if self._allow_none:
988 if self._allow_none:
989 return result + ' or None'
989 return result + ' or None'
990 return result
990 return result
991
991
992 class CaselessStrEnum(Enum):
992 class CaselessStrEnum(Enum):
993 """An enum of strings that are caseless in validate."""
993 """An enum of strings that are caseless in validate."""
994
994
995 def validate(self, obj, value):
995 def validate(self, obj, value):
996 if value is None:
996 if value is None:
997 if self._allow_none:
997 if self._allow_none:
998 return value
998 return value
999
999
1000 if not isinstance(value, str):
1000 if not isinstance(value, str):
1001 self.error(obj, value)
1001 self.error(obj, value)
1002
1002
1003 for v in self.values:
1003 for v in self.values:
1004 if v.lower() == value.lower():
1004 if v.lower() == value.lower():
1005 return v
1005 return v
1006 self.error(obj, value)
1006 self.error(obj, value)
1007
1007
1008
1008
1009 class List(Instance):
1009 class List(Instance):
1010 """An instance of a Python list."""
1010 """An instance of a Python list."""
1011
1011
1012 def __init__(self, default_value=None, allow_none=True, **metadata):
1012 def __init__(self, default_value=None, allow_none=True, **metadata):
1013 """Create a list trait type from a list or tuple.
1013 """Create a list trait type from a list or tuple.
1014
1014
1015 The default value is created by doing ``list(default_value)``,
1015 The default value is created by doing ``list(default_value)``,
1016 which creates a copy of the ``default_value``.
1016 which creates a copy of the ``default_value``.
1017 """
1017 """
1018 if default_value is None:
1018 if default_value is None:
1019 args = ((),)
1019 args = ((),)
1020 elif isinstance(default_value, SequenceTypes):
1020 elif isinstance(default_value, SequenceTypes):
1021 args = (default_value,)
1021 args = (default_value,)
1022 else:
1022 else:
1023 raise TypeError('default value of List was %s' % default_value)
1023 raise TypeError('default value of List was %s' % default_value)
1024
1024
1025 super(List,self).__init__(klass=list, args=args,
1025 super(List,self).__init__(klass=list, args=args,
1026 allow_none=allow_none, **metadata)
1026 allow_none=allow_none, **metadata)
1027
1027
1028
1028
1029 class Dict(Instance):
1029 class Dict(Instance):
1030 """An instance of a Python dict."""
1030 """An instance of a Python dict."""
1031
1031
1032 def __init__(self, default_value=None, allow_none=True, **metadata):
1032 def __init__(self, default_value=None, allow_none=True, **metadata):
1033 """Create a dict trait type from a dict.
1033 """Create a dict trait type from a dict.
1034
1034
1035 The default value is created by doing ``dict(default_value)``,
1035 The default value is created by doing ``dict(default_value)``,
1036 which creates a copy of the ``default_value``.
1036 which creates a copy of the ``default_value``.
1037 """
1037 """
1038 if default_value is None:
1038 if default_value is None:
1039 args = ((),)
1039 args = ((),)
1040 elif isinstance(default_value, dict):
1040 elif isinstance(default_value, dict):
1041 args = (default_value,)
1041 args = (default_value,)
1042 elif isinstance(default_value, SequenceTypes):
1042 elif isinstance(default_value, SequenceTypes):
1043 args = (default_value,)
1043 args = (default_value,)
1044 else:
1044 else:
1045 raise TypeError('default value of Dict was %s' % default_value)
1045 raise TypeError('default value of Dict was %s' % default_value)
1046
1046
1047 super(Dict,self).__init__(klass=dict, args=args,
1047 super(Dict,self).__init__(klass=dict, args=args,
1048 allow_none=allow_none, **metadata)
1048 allow_none=allow_none, **metadata)
General Comments 0
You need to be logged in to leave comments. Login now