##// END OF EJS Templates
Merge branch 'configurable' into trunk
Brian Granger -
r2750:bb29f349 merge
parent child Browse files
Show More
@@ -0,0 +1,139 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 A base class for objects that are configurable.
5
6 Authors:
7
8 * Brian Granger
9 * Fernando Perez
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2010 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22
23 from copy import deepcopy
24 import datetime
25 from weakref import WeakValueDictionary
26
27 from IPython.utils.importstring import import_item
28 from loader import Config
29 from IPython.utils.traitlets import HasTraits, Instance
30
31
32 #-----------------------------------------------------------------------------
33 # Helper classes for Configurables
34 #-----------------------------------------------------------------------------
35
36
37 class ConfigurableError(Exception):
38 pass
39
40
41 #-----------------------------------------------------------------------------
42 # Configurable implementation
43 #-----------------------------------------------------------------------------
44
45
46 class Configurable(HasTraits):
47
48 config = Instance(Config,(),{})
49 created = None
50
51 def __init__(self, **kwargs):
52 """Create a conigurable given a config config.
53
54 Parameters
55 ----------
56 config : Config
57 If this is empty, default values are used. If config is a
58 :class:`Config` instance, it will be used to configure the
59 instance.
60
61 Notes
62 -----
63 Subclasses of Configurable must call the :meth:`__init__` method of
64 :class:`Configurable` *before* doing anything else and using
65 :func:`super`::
66
67 class MyConfigurable(Configurable):
68 def __init__(self, config=None):
69 super(MyConfigurable, self).__init__(config)
70 # Then any other code you need to finish initialization.
71
72 This ensures that instances will be configured properly.
73 """
74 config = kwargs.pop('config', None)
75 if config is not None:
76 # We used to deepcopy, but for now we are trying to just save
77 # by reference. This *could* have side effects as all components
78 # will share config. In fact, I did find such a side effect in
79 # _config_changed below. If a config attribute value was a mutable type
80 # all instances of a component were getting the same copy, effectively
81 # making that a class attribute.
82 # self.config = deepcopy(config)
83 self.config = config
84 # This should go second so individual keyword arguments override
85 # the values in config.
86 super(Configurable, self).__init__(**kwargs)
87 self.created = datetime.datetime.now()
88
89 #-------------------------------------------------------------------------
90 # Static trait notifiations
91 #-------------------------------------------------------------------------
92
93 def _config_changed(self, name, old, new):
94 """Update all the class traits having ``config=True`` as metadata.
95
96 For any class trait with a ``config`` metadata attribute that is
97 ``True``, we update the trait with the value of the corresponding
98 config entry.
99 """
100 # Get all traits with a config metadata entry that is True
101 traits = self.traits(config=True)
102
103 # We auto-load config section for this class as well as any parent
104 # classes that are Configurable subclasses. This starts with Configurable
105 # and works down the mro loading the config for each section.
106 section_names = [cls.__name__ for cls in \
107 reversed(self.__class__.__mro__) if
108 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
109
110 for sname in section_names:
111 # Don't do a blind getattr as that would cause the config to
112 # dynamically create the section with name self.__class__.__name__.
113 if new._has_section(sname):
114 my_config = new[sname]
115 for k, v in traits.items():
116 # Don't allow traitlets with config=True to start with
117 # uppercase. Otherwise, they are confused with Config
118 # subsections. But, developers shouldn't have uppercase
119 # attributes anyways! (PEP 6)
120 if k[0].upper()==k[0] and not k.startswith('_'):
121 raise ConfigurableError('Configurable traitlets with '
122 'config=True must start with a lowercase so they are '
123 'not confused with Config subsections: %s.%s' % \
124 (self.__class__.__name__, k))
125 try:
126 # Here we grab the value from the config
127 # If k has the naming convention of a config
128 # section, it will be auto created.
129 config_value = my_config[k]
130 except KeyError:
131 pass
132 else:
133 # print "Setting %s.%s from %s.%s=%r" % \
134 # (self.__class__.__name__,k,sname,k,config_value)
135 # We have to do a deepcopy here if we don't deepcopy the entire
136 # config object. If we don't, a mutable config_value will be
137 # shared by all instances, effectively making it a class attribute.
138 setattr(self, k, deepcopy(config_value))
139
@@ -0,0 +1,124 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 Tests for IPython.config.configurable
5
6 Authors:
7
8 * Brian Granger
9 * Fernando Perez (design help)
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2010 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22
23 from unittest import TestCase
24
25 from IPython.config.configurable import Configurable, ConfigurableError
26 from IPython.utils.traitlets import (
27 TraitError, Int, Float, Str
28 )
29 from IPython.config.loader import Config
30
31
32 #-----------------------------------------------------------------------------
33 # Test cases
34 #-----------------------------------------------------------------------------
35
36
37 class 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
53 class TestConfigurableConfig(TestCase):
54
55 def test_default(self):
56 c1 = Configurable()
57 c2 = Configurable(config=c1.config)
58 c3 = Configurable(config=c2.config)
59 self.assertEquals(c1.config, c2.config)
60 self.assertEquals(c2.config, c3.config)
61
62 def test_custom(self):
63 config = Config()
64 config.foo = 'foo'
65 config.bar = 'bar'
66 c1 = Configurable(config=config)
67 c2 = Configurable(config=c1.config)
68 c3 = Configurable(config=c2.config)
69 self.assertEquals(c1.config, config)
70 self.assertEquals(c2.config, config)
71 self.assertEquals(c3.config, config)
72 # Test that copies are not made
73 self.assert_(c1.config is config)
74 self.assert_(c2.config is config)
75 self.assert_(c3.config is config)
76 self.assert_(c1.config is c2.config)
77 self.assert_(c2.config is c3.config)
78
79 def test_inheritance(self):
80 config = Config()
81 config.MyConfigurable.a = 2
82 config.MyConfigurable.b = 2.0
83 c1 = MyConfigurable(config=config)
84 c2 = MyConfigurable(config=c1.config)
85 self.assertEquals(c1.a, config.MyConfigurable.a)
86 self.assertEquals(c1.b, config.MyConfigurable.b)
87 self.assertEquals(c2.a, config.MyConfigurable.a)
88 self.assertEquals(c2.b, config.MyConfigurable.b)
89
90 def test_parent(self):
91 config = Config()
92 config.Foo.a = 10
93 config.Foo.b = "wow"
94 config.Bar.b = 'later'
95 config.Bar.c = 100.0
96 f = Foo(config=config)
97 b = Bar(config=f.config)
98 self.assertEquals(f.a, 10)
99 self.assertEquals(f.b, 'wow')
100 self.assertEquals(b.b, 'gotit')
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)
@@ -0,0 +1,125 b''
1 # encoding: utf-8
2 """A class for managing IPython extensions.
3
4 Authors:
5
6 * Brian Granger
7 """
8
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
17 # Imports
18 #-----------------------------------------------------------------------------
19
20 import os
21 import sys
22
23 from IPython.config.configurable import Configurable
24 from IPython.utils.traitlets import Instance
25
26 #-----------------------------------------------------------------------------
27 # Main class
28 #-----------------------------------------------------------------------------
29
30 class ExtensionManager(Configurable):
31 """A class to manage IPython extensions.
32
33 An IPython extension is an importable Python module that has
34 a function with the signature::
35
36 def load_ipython_extension(ipython):
37 # Do things with ipython
38
39 This function is called after your extension is imported and the
40 currently active :class:`InteractiveShell` instance is passed as
41 the only argument. You can do anything you want with IPython at
42 that point, including defining new magic and aliases, adding new
43 components, etc.
44
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
47 author to add code to manage that.
48
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,
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
53 is added to ``sys.path`` automatically.
54 """
55
56 shell = Instance('IPython.core.iplib.InteractiveShellABC')
57
58 def __init__(self, shell=None, config=None):
59 super(ExtensionManager, self).__init__(shell=shell, config=config)
60 self.shell.on_trait_change(
61 self._on_ipython_dir_changed, 'ipython_dir'
62 )
63
64 def __del__(self):
65 self.shell.on_trait_change(
66 self._on_ipython_dir_changed, 'ipython_dir', remove=True
67 )
68
69 @property
70 def ipython_extension_dir(self):
71 return os.path.join(self.shell.ipython_dir, u'extensions')
72
73 def _on_ipython_dir_changed(self):
74 if not os.path.isdir(self.ipython_extension_dir):
75 os.makedirs(self.ipython_extension_dir, mode = 0777)
76
77 def load_extension(self, module_str):
78 """Load an IPython extension by its module name.
79
80 If :func:`load_ipython_extension` returns anything, this function
81 will return that object.
82 """
83 from IPython.utils.syspathcontext import prepended_to_syspath
84
85 if module_str not in sys.modules:
86 with prepended_to_syspath(self.ipython_extension_dir):
87 __import__(module_str)
88 mod = sys.modules[module_str]
89 return self._call_load_ipython_extension(mod)
90
91 def unload_extension(self, module_str):
92 """Unload an IPython extension by its module name.
93
94 This function looks up the extension's name in ``sys.modules`` and
95 simply calls ``mod.unload_ipython_extension(self)``.
96 """
97 if module_str in sys.modules:
98 mod = sys.modules[module_str]
99 self._call_unload_ipython_extension(mod)
100
101 def reload_extension(self, module_str):
102 """Reload an IPython extension by calling reload.
103
104 If the module has not been loaded before,
105 :meth:`InteractiveShell.load_extension` is called. Otherwise
106 :func:`reload` is called and then the :func:`load_ipython_extension`
107 function of the module, if it exists is called.
108 """
109 from IPython.utils.syspathcontext import prepended_to_syspath
110
111 with prepended_to_syspath(self.ipython_extension_dir):
112 if module_str in sys.modules:
113 mod = sys.modules[module_str]
114 reload(mod)
115 self._call_load_ipython_extension(mod)
116 else:
117 self.load_extension(module_str)
118
119 def _call_load_ipython_extension(self, mod):
120 if hasattr(mod, 'load_ipython_extension'):
121 return mod.load_ipython_extension(self.shell)
122
123 def _call_unload_ipython_extension(self, mod):
124 if hasattr(mod, 'unload_ipython_extension'):
125 return mod.unload_ipython_extension(self.shell)
@@ -0,0 +1,51 b''
1 # encoding: utf-8
2 """IPython plugins.
3
4 Authors:
5
6 * Brian Granger
7 """
8
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
17 # Imports
18 #-----------------------------------------------------------------------------
19
20 from IPython.config.configurable import Configurable
21 from IPython.utils.traitlets import Dict
22
23 #-----------------------------------------------------------------------------
24 # Main class
25 #-----------------------------------------------------------------------------
26
27 class PluginManager(Configurable):
28 """A manager for IPython plugins."""
29
30 plugins = Dict({})
31
32 def __init__(self, config=None):
33 super(PluginManager, self).__init__(config=config)
34
35 def register_plugin(self, name, plugin):
36 if not isinstance(plugin, Plugin):
37 raise TypeError('Expected Plugin, got: %r' % plugin)
38 if self.plugins.has_key(name):
39 raise KeyError('Plugin with name already exists: %r' % name)
40 self.plugins[name] = plugin
41
42 def unregister_plugin(self, name):
43 del self.plugins[name]
44
45 def get_plugin(self, name, default=None):
46 return self.plugins.get(name, default)
47
48
49 class Plugin(Configurable):
50 """Base class for IPython plugins."""
51 pass
@@ -0,0 +1,46 b''
1 """Tests for plugin.py"""
2
3 #-----------------------------------------------------------------------------
4 # Imports
5 #-----------------------------------------------------------------------------
6
7 from unittest import TestCase
8
9 from IPython.core.plugin import Plugin, PluginManager
10
11 #-----------------------------------------------------------------------------
12 # Tests
13 #-----------------------------------------------------------------------------
14
15 class FooPlugin(Plugin):
16 pass
17
18
19 class BarPlugin(Plugin):
20 pass
21
22
23 class BadPlugin(object):
24 pass
25
26
27 class PluginTest(TestCase):
28
29 def setUp(self):
30 self.manager = PluginManager()
31
32 def test_register_get(self):
33 self.assertEquals(None, self.manager.get_plugin('foo'))
34 foo = FooPlugin()
35 self.manager.register_plugin('foo', foo)
36 self.assertEquals(foo, self.manager.get_plugin('foo'))
37 bar = BarPlugin()
38 self.assertRaises(KeyError, self.manager.register_plugin, 'foo', bar)
39 bad = BadPlugin()
40 self.assertRaises(TypeError, self.manager.register_plugin, 'bad')
41
42 def test_unregister(self):
43 foo = FooPlugin()
44 self.manager.register_plugin('foo', foo)
45 self.manager.unregister_plugin('foo')
46 self.assertEquals(None, self.manager.get_plugin('foo'))
@@ -0,0 +1,61 b''
1 .. _extensions_overview:
2
3 ==================
4 IPython extensions
5 ==================
6
7 Configuration files are just the first level of customization that IPython
8 supports. The next level is that of extensions. An IPython extension is an
9 importable Python module that has a a few special function. By defining these
10 functions, users can customize IPython by accessing the actual runtime objects
11 of IPython. Here is a sample extension::
12
13 # myextension.py
14
15 def load_ipython_extension(ipython):
16 # The ``ipython`` argument is the currently active
17 # :class:`InteractiveShell` instance that can be used in any way.
18 # This allows you do to things like register new magics, plugins or
19 # aliases.
20
21 def unload_ipython_extension(ipython):
22 # If you want your extension to be unloadable, put that logic here.
23
24 This :func:`load_ipython_extension` function is called after your extension is
25 imported and the currently active :class:`InteractiveShell` instance is passed
26 as the only argument. You can do anything you want with IPython at that point.
27
28 The :func:`load_ipython_extension` will be called again is you load or reload
29 the extension again. It is up to the extension author to add code to manage
30 that.
31
32 You can put your extension modules anywhere you want, as long as they can be
33 imported by Python's standard import mechanism. However, to make it easy to
34 write extensions, you can also put your extensions in
35 ``os.path.join(self.ipython_dir, 'extensions')``. This directory is added to
36 ``sys.path`` automatically.
37
38 Using extensions
39 ================
40
41 There are two ways you can tell IPython to use your extension:
42
43 1. Listing it in a configuration file.
44 2. Using the ``%load_ext`` magic function.
45
46 To load an extension called :file:`myextension.py` add the following logic
47 to your configuration file::
48
49 c.Global.extensions = [
50 'myextension'
51 ]
52
53 To load that same extension at runtime, use the ``%load_ext`` magic::
54
55 .. sourcecode:: ipython
56
57 In [1]: %load_ext myextension
58
59 To summarize, in conjunction with configuration files and profiles, IPython
60 extensions give you complete and flexible control over your IPython
61 setup.
@@ -0,0 +1,23 b''
1 .. _plugins_overview:
2
3 ===============
4 IPython plugins
5 ===============
6
7 IPython has a plugin mechanism that allows users to create new and custom
8 runtime components for IPython. Plugins are different from extensions:
9
10 * Extensions are used to load plugins.
11 * Extensions are a more advanced configuration system that gives you access
12 to the running IPython instance.
13 * Plugins add entirely new capabilities to IPython.
14 * Plugins are traited and configurable.
15
16 At this point, our plugin system is brand new and the documentation is
17 minimal. If you are interested in creating a new plugin, see the following
18 files:
19
20 * :file:`IPython/extensions/parallemagic.py`
21 * :file:`IPython/extensions/pretty.`
22
23 As well as our documentation on the configuration system and extensions.
@@ -24,8 +24,8 b' import sys'
24 24 # Setup everything
25 25 #-----------------------------------------------------------------------------
26 26
27 if sys.version[0:3] < '2.5':
28 raise ImportError('Python Version 2.5 or above is required for IPython.')
27 if sys.version[0:3] < '2.6':
28 raise ImportError('Python Version 2.6 or above is required for IPython.')
29 29
30 30
31 31 # Make it easy to import extensions - they are always directly on pythonpath.
@@ -1,10 +1,11 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 IPython's alias component
4 System command aliases.
5 5
6 6 Authors:
7 7
8 * Fernando Perez
8 9 * Brian Granger
9 10 """
10 11
@@ -25,10 +26,10 b' import os'
25 26 import re
26 27 import sys
27 28
28 from IPython.core.component import Component
29 from IPython.config.configurable import Configurable
29 30 from IPython.core.splitinput import split_user_input
30 31
31 from IPython.utils.traitlets import List
32 from IPython.utils.traitlets import List, Instance
32 33 from IPython.utils.autoattr import auto_attr
33 34 from IPython.utils.warn import warn, error
34 35
@@ -99,23 +100,18 b' class InvalidAliasError(AliasError):'
99 100 #-----------------------------------------------------------------------------
100 101
101 102
102 class AliasManager(Component):
103 class AliasManager(Configurable):
103 104
104 105 default_aliases = List(default_aliases(), config=True)
105 106 user_aliases = List(default_value=[], config=True)
107 shell = Instance('IPython.core.iplib.InteractiveShellABC')
106 108
107 def __init__(self, parent, config=None):
108 super(AliasManager, self).__init__(parent, config=config)
109 def __init__(self, shell=None, config=None):
110 super(AliasManager, self).__init__(shell=shell, config=config)
109 111 self.alias_table = {}
110 112 self.exclude_aliases()
111 113 self.init_aliases()
112 114
113 @auto_attr
114 def shell(self):
115 return Component.get_instances(
116 root=self.root,
117 klass='IPython.core.iplib.InteractiveShell')[0]
118
119 115 def __contains__(self, name):
120 116 if name in self.alias_table:
121 117 return True
@@ -6,7 +6,7 b' All top-level applications should use the classes in this module for'
6 6 handling configuration and creating componenets.
7 7
8 8 The job of an :class:`Application` is to create the master configuration
9 object and then create the components, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10 10
11 11 Authors:
12 12
@@ -76,7 +76,7 b' class BaseAppConfigLoader(ArgParseConfigLoader):'
76 76
77 77
78 78 class Application(object):
79 """Load a config, construct components and set them running.
79 """Load a config, construct configurables and set them running.
80 80
81 81 The configuration of an application can be done via three different Config
82 82 objects, which are loaded and ultimately merged into a single one used
@@ -113,7 +113,7 b' class Application(object):'
113 113 file_config = None
114 114 #: Read from the system's command line flags.
115 115 command_line_config = None
116 #: The final config that will be passed to the component.
116 #: The final config that will be passed to the main object.
117 117 master_config = None
118 118 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
119 119 argv = None
@@ -223,10 +223,10 b' class Application(object):'
223 223 """Create defaults that can't be set elsewhere.
224 224
225 225 For the most part, we try to set default in the class attributes
226 of Components. But, defaults the top-level Application (which is
227 not a HasTraits or Component) are not set in this way. Instead
226 of Configurables. But, defaults the top-level Application (which is
227 not a HasTraits or Configurables) are not set in this way. Instead
228 228 we set them here. The Global section is for variables like this that
229 don't belong to a particular component.
229 don't belong to a particular configurable.
230 230 """
231 231 c = Config()
232 232 c.Global.ipython_dir = get_ipython_dir()
@@ -418,8 +418,8 b' class Application(object):'
418 418 pass
419 419
420 420 def construct(self):
421 """Construct the main components that make up this app."""
422 self.log.debug("Constructing components for application")
421 """Construct the main objects that make up this app."""
422 self.log.debug("Constructing main objects for application")
423 423
424 424 def post_construct(self):
425 425 """Do actions after construct, but before starting the app."""
@@ -21,10 +21,10 b' Authors:'
21 21
22 22 import __builtin__
23 23
24 from IPython.core.component import Component
24 from IPython.config.configurable import Configurable
25 25 from IPython.core.quitter import Quitter
26 26
27 from IPython.utils.autoattr import auto_attr
27 from IPython.utils.traitlets import Instance
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Classes and functions
@@ -35,20 +35,17 b' class __BuiltinUndefined(object): pass'
35 35 BuiltinUndefined = __BuiltinUndefined()
36 36
37 37
38 class BuiltinTrap(Component):
38 class BuiltinTrap(Configurable):
39 39
40 def __init__(self, parent):
41 super(BuiltinTrap, self).__init__(parent, None, None)
40 shell = Instance('IPython.core.iplib.InteractiveShellABC')
41
42 def __init__(self, shell=None):
43 super(BuiltinTrap, self).__init__(shell=shell, config=None)
42 44 self._orig_builtins = {}
43 45 # We define this to track if a single BuiltinTrap is nested.
44 46 # Only turn off the trap when the outermost call to __exit__ is made.
45 47 self._nested_level = 0
46
47 @auto_attr
48 def shell(self):
49 return Component.get_instances(
50 root=self.root,
51 klass='IPython.core.iplib.InteractiveShell')[0]
48 self.shell = shell
52 49
53 50 def __enter__(self):
54 51 if self._nested_level == 0:
@@ -22,34 +22,30 b' Authors:'
22 22
23 23 import sys
24 24
25 from IPython.core.component import Component
25 from IPython.config.configurable import Configurable
26 from IPython.utils.traitlets import Any
26 27
27 28 #-----------------------------------------------------------------------------
28 29 # Classes and functions
29 30 #-----------------------------------------------------------------------------
30 31
31 32
32 class DisplayTrap(Component):
33 class DisplayTrap(Configurable):
33 34 """Object to manage sys.displayhook.
34 35
35 36 This came from IPython.core.kernel.display_hook, but is simplified
36 37 (no callbacks or formatters) until more of the core is refactored.
37 38 """
38 39
39 def __init__(self, parent, hook):
40 super(DisplayTrap, self).__init__(parent, None, None)
41 self.hook = hook
40 hook = Any
41
42 def __init__(self, hook=None):
43 super(DisplayTrap, self).__init__(hook=hook, config=None)
42 44 self.old_hook = None
43 45 # We define this to track if a single BuiltinTrap is nested.
44 46 # Only turn off the trap when the outermost call to __exit__ is made.
45 47 self._nested_level = 0
46 48
47 # @auto_attr
48 # def shell(self):
49 # return Component.get_instances(
50 # root=self.root,
51 # klass='IPython.core.iplib.InteractiveShell')[0]
52
53 49 def __enter__(self):
54 50 if self._nested_level == 0:
55 51 self.set()
@@ -24,13 +24,7 b' has been made into a component, this module will be sent to deathrow.'
24 24
25 25
26 26 def get():
27 """Get the most recently created InteractiveShell instance."""
27 """Get the global InteractiveShell instance."""
28 28 from IPython.core.iplib import InteractiveShell
29 insts = InteractiveShell.get_instances()
30 if len(insts)==0:
31 return None
32 most_recent = insts[0]
33 for inst in insts[1:]:
34 if inst.created > most_recent.created:
35 most_recent = inst
36 return most_recent
29 return InteractiveShell.instance()
30
@@ -475,8 +475,8 b' class IPythonApp(Application):'
475 475 # But that might be the place for them
476 476 sys.path.insert(0, '')
477 477
478 # Create an InteractiveShell instance
479 self.shell = InteractiveShell(None, self.master_config)
478 # Create an InteractiveShell instance.
479 self.shell = InteractiveShell.instance(config=self.master_config)
480 480
481 481 def post_construct(self):
482 482 """Do actions after construct, but before starting the app."""
@@ -543,7 +543,7 b' class IPythonApp(Application):'
543 543 def _load_extensions(self):
544 544 """Load all IPython extensions in Global.extensions.
545 545
546 This uses the :meth:`InteractiveShell.load_extensions` to load all
546 This uses the :meth:`ExtensionManager.load_extensions` to load all
547 547 the extensions listed in ``self.master_config.Global.extensions``.
548 548 """
549 549 try:
@@ -553,7 +553,7 b' class IPythonApp(Application):'
553 553 for ext in extensions:
554 554 try:
555 555 self.log.info("Loading IPython extension: %s" % ext)
556 self.shell.load_extension(ext)
556 self.shell.extension_manager.load_extension(ext)
557 557 except:
558 558 self.log.warn("Error in loading extension: %s" % ext)
559 559 self.shell.showtraceback()
@@ -1,12 +1,10 b''
1 1 # -*- coding: utf-8 -*-
2 """
3 Main IPython Component
4 """
2 """Main IPython class."""
5 3
6 4 #-----------------------------------------------------------------------------
7 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
8 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
9 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2010 The IPython Development Team
10 8 #
11 9 # Distributed under the terms of the BSD License. The full license is in
12 10 # the file COPYING, distributed as part of this software.
@@ -20,6 +18,7 b' from __future__ import with_statement'
20 18 from __future__ import absolute_import
21 19
22 20 import __builtin__
21 import abc
23 22 import bdb
24 23 import codeop
25 24 import exceptions
@@ -38,12 +37,14 b' from IPython.core import shadowns'
38 37 from IPython.core import ultratb
39 38 from IPython.core.alias import AliasManager
40 39 from IPython.core.builtin_trap import BuiltinTrap
41 from IPython.core.component import Component
40 from IPython.config.configurable import Configurable
42 41 from IPython.core.display_trap import DisplayTrap
43 42 from IPython.core.error import TryNext, UsageError
43 from IPython.core.extensions import ExtensionManager
44 44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
45 45 from IPython.core.logger import Logger
46 46 from IPython.core.magic import Magic
47 from IPython.core.plugin import PluginManager
47 48 from IPython.core.prefilter import PrefilterManager
48 49 from IPython.core.prompts import CachedOutput
49 50 from IPython.core.usage import interactive_usage, default_banner
@@ -69,7 +70,7 b' from IPython.utils.syspathcontext import prepended_to_syspath'
69 70 from IPython.utils.terminal import toggle_set_term_title, set_term_title
70 71 from IPython.utils.warn import warn, error, fatal
71 72 from IPython.utils.traitlets import (
72 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode
73 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode, Instance
73 74 )
74 75
75 76 # from IPython.utils import growl
@@ -196,7 +197,7 b' class SeparateStr(Str):'
196 197 #-----------------------------------------------------------------------------
197 198
198 199
199 class InteractiveShell(Component, Magic):
200 class InteractiveShell(Configurable, Magic):
200 201 """An enhanced, interactive shell for Python."""
201 202
202 203 autocall = Enum((0,1,2), default_value=1, config=True)
@@ -281,14 +282,22 b' class InteractiveShell(Component, Magic):'
281 282 # Subclasses with thread support should override this as needed.
282 283 isthreaded = False
283 284
284 def __init__(self, parent=None, config=None, ipython_dir=None, usage=None,
285 # Subcomponents of InteractiveShell
286 alias_manager = Instance('IPython.core.alias.AliasManager')
287 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
288 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
289 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
290 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
291 plugin_manager = Instance('IPython.core.plugin.PluginManager')
292
293 def __init__(self, config=None, ipython_dir=None, usage=None,
285 294 user_ns=None, user_global_ns=None,
286 295 banner1=None, banner2=None, display_banner=None,
287 296 custom_exceptions=((),None)):
288 297
289 298 # This is where traits with a config_key argument are updated
290 299 # from the values on config.
291 super(InteractiveShell, self).__init__(parent, config=config)
300 super(InteractiveShell, self).__init__(config=config)
292 301
293 302 # These are relatively independent and stateless
294 303 self.init_ipython_dir(ipython_dir)
@@ -334,8 +343,21 b' class InteractiveShell(Component, Magic):'
334 343 self.init_reload_doctest()
335 344 self.init_magics()
336 345 self.init_pdb()
346 self.init_extension_manager()
347 self.init_plugin_manager()
337 348 self.hooks.late_startup_hook()
338 349
350 @classmethod
351 def instance(cls, *args, **kwargs):
352 """Returns a global InteractiveShell instance."""
353 if not hasattr(cls, "_instance"):
354 cls._instance = cls(*args, **kwargs)
355 return cls._instance
356
357 @classmethod
358 def initialized(cls):
359 return hasattr(cls, "_instance")
360
339 361 def get_ipython(self):
340 362 """Return the currently running IPython instance."""
341 363 return self
@@ -353,12 +375,6 b' class InteractiveShell(Component, Magic):'
353 375 def _ipython_dir_changed(self, name, new):
354 376 if not os.path.isdir(new):
355 377 os.makedirs(new, mode = 0777)
356 if not os.path.isdir(self.ipython_extension_dir):
357 os.makedirs(self.ipython_extension_dir, mode = 0777)
358
359 @property
360 def ipython_extension_dir(self):
361 return os.path.join(self.ipython_dir, 'extensions')
362 378
363 379 @property
364 380 def usable_screen_length(self):
@@ -494,7 +510,7 b' class InteractiveShell(Component, Magic):'
494 510 self.magic_logstart()
495 511
496 512 def init_builtins(self):
497 self.builtin_trap = BuiltinTrap(self)
513 self.builtin_trap = BuiltinTrap(shell=self)
498 514
499 515 def init_inspector(self):
500 516 # Object inspector
@@ -523,7 +539,7 b' class InteractiveShell(Component, Magic):'
523 539 pass
524 540
525 541 def init_displayhook(self):
526 self.display_trap = DisplayTrap(self, self.outputcache)
542 self.display_trap = DisplayTrap(hook=self.outputcache)
527 543
528 544 def init_reload_doctest(self):
529 545 # Do a proper resetting of doctest, including the necessary displayhook
@@ -1743,10 +1759,20 b' class InteractiveShell(Component, Magic):'
1743 1759 #-------------------------------------------------------------------------
1744 1760
1745 1761 def init_alias(self):
1746 self.alias_manager = AliasManager(self, config=self.config)
1762 self.alias_manager = AliasManager(shell=self, config=self.config)
1747 1763 self.ns_table['alias'] = self.alias_manager.alias_table,
1748 1764
1749 1765 #-------------------------------------------------------------------------
1766 # Things related to extensions and plugins
1767 #-------------------------------------------------------------------------
1768
1769 def init_extension_manager(self):
1770 self.extension_manager = ExtensionManager(shell=self, config=self.config)
1771
1772 def init_plugin_manager(self):
1773 self.plugin_manager = PluginManager(config=self.config)
1774
1775 #-------------------------------------------------------------------------
1750 1776 # Things related to the running of code
1751 1777 #-------------------------------------------------------------------------
1752 1778
@@ -2340,101 +2366,11 b' class InteractiveShell(Component, Magic):'
2340 2366 return lineout
2341 2367
2342 2368 #-------------------------------------------------------------------------
2343 # Working with components
2344 #-------------------------------------------------------------------------
2345
2346 def get_component(self, name=None, klass=None):
2347 """Fetch a component by name and klass in my tree."""
2348 c = Component.get_instances(root=self, name=name, klass=klass)
2349 if len(c) == 0:
2350 return None
2351 if len(c) == 1:
2352 return c[0]
2353 else:
2354 return c
2355
2356 #-------------------------------------------------------------------------
2357 # IPython extensions
2358 #-------------------------------------------------------------------------
2359
2360 def load_extension(self, module_str):
2361 """Load an IPython extension by its module name.
2362
2363 An IPython extension is an importable Python module that has
2364 a function with the signature::
2365
2366 def load_ipython_extension(ipython):
2367 # Do things with ipython
2368
2369 This function is called after your extension is imported and the
2370 currently active :class:`InteractiveShell` instance is passed as
2371 the only argument. You can do anything you want with IPython at
2372 that point, including defining new magic and aliases, adding new
2373 components, etc.
2374
2375 The :func:`load_ipython_extension` will be called again is you
2376 load or reload the extension again. It is up to the extension
2377 author to add code to manage that.
2378
2379 You can put your extension modules anywhere you want, as long as
2380 they can be imported by Python's standard import mechanism. However,
2381 to make it easy to write extensions, you can also put your extensions
2382 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
2383 is added to ``sys.path`` automatically.
2384
2385 If :func:`load_ipython_extension` returns anything, this function
2386 will return that object.
2387 """
2388 from IPython.utils.syspathcontext import prepended_to_syspath
2389
2390 if module_str not in sys.modules:
2391 with prepended_to_syspath(self.ipython_extension_dir):
2392 __import__(module_str)
2393 mod = sys.modules[module_str]
2394 return self._call_load_ipython_extension(mod)
2395
2396 def unload_extension(self, module_str):
2397 """Unload an IPython extension by its module name.
2398
2399 This function looks up the extension's name in ``sys.modules`` and
2400 simply calls ``mod.unload_ipython_extension(self)``.
2401 """
2402 if module_str in sys.modules:
2403 mod = sys.modules[module_str]
2404 self._call_unload_ipython_extension(mod)
2405
2406 def reload_extension(self, module_str):
2407 """Reload an IPython extension by calling reload.
2408
2409 If the module has not been loaded before,
2410 :meth:`InteractiveShell.load_extension` is called. Otherwise
2411 :func:`reload` is called and then the :func:`load_ipython_extension`
2412 function of the module, if it exists is called.
2413 """
2414 from IPython.utils.syspathcontext import prepended_to_syspath
2415
2416 with prepended_to_syspath(self.ipython_extension_dir):
2417 if module_str in sys.modules:
2418 mod = sys.modules[module_str]
2419 reload(mod)
2420 self._call_load_ipython_extension(mod)
2421 else:
2422 self.load_extension(module_str)
2423
2424 def _call_load_ipython_extension(self, mod):
2425 if hasattr(mod, 'load_ipython_extension'):
2426 return mod.load_ipython_extension(self)
2427
2428 def _call_unload_ipython_extension(self, mod):
2429 if hasattr(mod, 'unload_ipython_extension'):
2430 return mod.unload_ipython_extension(self)
2431
2432 #-------------------------------------------------------------------------
2433 2369 # Things related to the prefilter
2434 2370 #-------------------------------------------------------------------------
2435 2371
2436 2372 def init_prefilter(self):
2437 self.prefilter_manager = PrefilterManager(self, config=self.config)
2373 self.prefilter_manager = PrefilterManager(shell=self, config=self.config)
2438 2374 # Ultimately this will be refactored in the new interpreter code, but
2439 2375 # for now, we should expose the main prefilter method (there's legacy
2440 2376 # code out there that may rely on this).
@@ -2580,3 +2516,8 b' class InteractiveShell(Component, Magic):'
2580 2516 self.restore_sys_module_state()
2581 2517
2582 2518
2519 class InteractiveShellABC(object):
2520 """An abstract base class for InteractiveShell."""
2521 __metaclass__ = abc.ABCMeta
2522
2523 InteractiveShellABC.register(InteractiveShell)
@@ -97,11 +97,11 b' def compress_dhist(dh):'
97 97
98 98 # XXX - for some odd reason, if Magic is made a new-style class, we get errors
99 99 # on construction of the main InteractiveShell object. Something odd is going
100 # on with super() calls, Component and the MRO... For now leave it as-is, but
100 # on with super() calls, Configurable and the MRO... For now leave it as-is, but
101 101 # eventually this needs to be clarified.
102 102 # BG: This is because InteractiveShell inherits from this, but is itself a
103 # Component. This messes up the MRO in some way. The fix is that we need to
104 # make Magic a component that InteractiveShell does not subclass.
103 # Configurable. This messes up the MRO in some way. The fix is that we need to
104 # make Magic a configurable that InteractiveShell does not subclass.
105 105
106 106 class Magic:
107 107 """Magic functions for InteractiveShell.
@@ -3586,15 +3586,15 b' Defaulting color scheme to \'NoColor\'"""'
3586 3586
3587 3587 def magic_load_ext(self, module_str):
3588 3588 """Load an IPython extension by its module name."""
3589 return self.load_extension(module_str)
3589 return self.extension_manager.load_extension(module_str)
3590 3590
3591 3591 def magic_unload_ext(self, module_str):
3592 3592 """Unload an IPython extension by its module name."""
3593 self.unload_extension(module_str)
3593 self.extension_manager.unload_extension(module_str)
3594 3594
3595 3595 def magic_reload_ext(self, module_str):
3596 3596 """Reload an IPython extension by its module name."""
3597 self.reload_extension(module_str)
3597 self.extension_manager.reload_extension(module_str)
3598 3598
3599 3599 @testdec.skip_doctest
3600 3600 def magic_install_profiles(self, s):
@@ -31,11 +31,11 b' import re'
31 31
32 32 from IPython.core.alias import AliasManager
33 33 from IPython.core.autocall import IPyAutocall
34 from IPython.core.component import Component
34 from IPython.config.configurable import Configurable
35 35 from IPython.core.splitinput import split_user_input
36 36 from IPython.core.page import page
37 37
38 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool
38 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool, Instance
39 39 from IPython.utils.io import Term
40 40 from IPython.utils.text import make_quoted_expr
41 41 from IPython.utils.autoattr import auto_attr
@@ -169,7 +169,7 b' class LineInfo(object):'
169 169 #-----------------------------------------------------------------------------
170 170
171 171
172 class PrefilterManager(Component):
172 class PrefilterManager(Configurable):
173 173 """Main prefilter component.
174 174
175 175 The IPython prefilter is run on all user input before it is run. The
@@ -210,19 +210,15 b' class PrefilterManager(Component):'
210 210 """
211 211
212 212 multi_line_specials = CBool(True, config=True)
213 shell = Instance('IPython.core.iplib.InteractiveShellABC')
213 214
214 def __init__(self, parent, config=None):
215 super(PrefilterManager, self).__init__(parent, config=config)
215 def __init__(self, shell=None, config=None):
216 super(PrefilterManager, self).__init__(shell=shell, config=config)
217 self.shell = shell
216 218 self.init_transformers()
217 219 self.init_handlers()
218 220 self.init_checkers()
219 221
220 @auto_attr
221 def shell(self):
222 return Component.get_instances(
223 root=self.root,
224 klass='IPython.core.iplib.InteractiveShell')[0]
225
226 222 #-------------------------------------------------------------------------
227 223 # API for managing transformers
228 224 #-------------------------------------------------------------------------
@@ -231,7 +227,9 b' class PrefilterManager(Component):'
231 227 """Create the default transformers."""
232 228 self._transformers = []
233 229 for transformer_cls in _default_transformers:
234 transformer_cls(self, config=self.config)
230 transformer_cls(
231 shell=self.shell, prefilter_manager=self, config=self.config
232 )
235 233
236 234 def sort_transformers(self):
237 235 """Sort the transformers by priority.
@@ -265,7 +263,9 b' class PrefilterManager(Component):'
265 263 """Create the default checkers."""
266 264 self._checkers = []
267 265 for checker in _default_checkers:
268 checker(self, config=self.config)
266 checker(
267 shell=self.shell, prefilter_manager=self, config=self.config
268 )
269 269
270 270 def sort_checkers(self):
271 271 """Sort the checkers by priority.
@@ -300,7 +300,9 b' class PrefilterManager(Component):'
300 300 self._handlers = {}
301 301 self._esc_handlers = {}
302 302 for handler in _default_handlers:
303 handler(self, config=self.config)
303 handler(
304 shell=self.shell, prefilter_manager=self, config=self.config
305 )
304 306
305 307 @property
306 308 def handlers(self):
@@ -445,28 +447,22 b' class PrefilterManager(Component):'
445 447 #-----------------------------------------------------------------------------
446 448
447 449
448 class PrefilterTransformer(Component):
450 class PrefilterTransformer(Configurable):
449 451 """Transform a line of user input."""
450 452
451 453 priority = Int(100, config=True)
452 shell = Any
453 prefilter_manager = Any
454 # Transformers don't currently use shell or prefilter_manager, but as we
455 # move away from checkers and handlers, they will need them.
456 shell = Instance('IPython.core.iplib.InteractiveShellABC')
457 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
454 458 enabled = Bool(True, config=True)
455 459
456 def __init__(self, parent, config=None):
457 super(PrefilterTransformer, self).__init__(parent, config=config)
460 def __init__(self, shell=None, prefilter_manager=None, config=None):
461 super(PrefilterTransformer, self).__init__(
462 shell=shell, prefilter_manager=prefilter_manager, config=config
463 )
458 464 self.prefilter_manager.register_transformer(self)
459 465
460 @auto_attr
461 def shell(self):
462 return Component.get_instances(
463 root=self.root,
464 klass='IPython.core.iplib.InteractiveShell')[0]
465
466 @auto_attr
467 def prefilter_manager(self):
468 return PrefilterManager.get_instances(root=self.root)[0]
469
470 466 def transform(self, line, continue_prompt):
471 467 """Transform a line, returning the new one."""
472 468 return None
@@ -561,28 +557,20 b' class IPyPromptTransformer(PrefilterTransformer):'
561 557 #-----------------------------------------------------------------------------
562 558
563 559
564 class PrefilterChecker(Component):
560 class PrefilterChecker(Configurable):
565 561 """Inspect an input line and return a handler for that line."""
566 562
567 563 priority = Int(100, config=True)
568 shell = Any
569 prefilter_manager = Any
564 shell = Instance('IPython.core.iplib.InteractiveShellABC')
565 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
570 566 enabled = Bool(True, config=True)
571 567
572 def __init__(self, parent, config=None):
573 super(PrefilterChecker, self).__init__(parent, config=config)
568 def __init__(self, shell=None, prefilter_manager=None, config=None):
569 super(PrefilterChecker, self).__init__(
570 shell=shell, prefilter_manager=prefilter_manager, config=config
571 )
574 572 self.prefilter_manager.register_checker(self)
575 573
576 @auto_attr
577 def shell(self):
578 return Component.get_instances(
579 root=self.root,
580 klass='IPython.core.iplib.InteractiveShell')[0]
581
582 @auto_attr
583 def prefilter_manager(self):
584 return PrefilterManager.get_instances(root=self.root)[0]
585
586 574 def check(self, line_info):
587 575 """Inspect line_info and return a handler instance or None."""
588 576 return None
@@ -709,16 +697,12 b' class AliasChecker(PrefilterChecker):'
709 697
710 698 priority = Int(800, config=True)
711 699
712 @auto_attr
713 def alias_manager(self):
714 return AliasManager.get_instances(root=self.root)[0]
715
716 700 def check(self, line_info):
717 701 "Check if the initital identifier on the line is an alias."
718 702 # Note: aliases can not contain '.'
719 703 head = line_info.ifun.split('.',1)[0]
720 if line_info.ifun not in self.alias_manager \
721 or head not in self.alias_manager \
704 if line_info.ifun not in self.shell.alias_manager \
705 or head not in self.shell.alias_manager \
722 706 or is_shadowed(head, self.shell):
723 707 return None
724 708
@@ -766,31 +750,23 b' class AutocallChecker(PrefilterChecker):'
766 750 #-----------------------------------------------------------------------------
767 751
768 752
769 class PrefilterHandler(Component):
753 class PrefilterHandler(Configurable):
770 754
771 755 handler_name = Str('normal')
772 756 esc_strings = List([])
773 shell = Any
774 prefilter_manager = Any
757 shell = Instance('IPython.core.iplib.InteractiveShellABC')
758 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
775 759
776 def __init__(self, parent, config=None):
777 super(PrefilterHandler, self).__init__(parent, config=config)
760 def __init__(self, shell=None, prefilter_manager=None, config=None):
761 super(PrefilterHandler, self).__init__(
762 shell=shell, prefilter_manager=prefilter_manager, config=config
763 )
778 764 self.prefilter_manager.register_handler(
779 765 self.handler_name,
780 766 self,
781 767 self.esc_strings
782 768 )
783 769
784 @auto_attr
785 def shell(self):
786 return Component.get_instances(
787 root=self.root,
788 klass='IPython.core.iplib.InteractiveShell')[0]
789
790 @auto_attr
791 def prefilter_manager(self):
792 return PrefilterManager.get_instances(root=self.root)[0]
793
794 770 def handle(self, line_info):
795 771 # print "normal: ", line_info
796 772 """Handle normal input lines. Use as a template for handlers."""
@@ -827,13 +803,9 b' class AliasHandler(PrefilterHandler):'
827 803
828 804 handler_name = Str('alias')
829 805
830 @auto_attr
831 def alias_manager(self):
832 return AliasManager.get_instances(root=self.root)[0]
833
834 806 def handle(self, line_info):
835 807 """Handle alias input lines. """
836 transformed = self.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)
837 809 # pre is needed, because it carries the leading whitespace. Otherwise
838 810 # aliases won't work in indented sections.
839 811 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
@@ -894,7 +866,7 b' class AutoHandler(PrefilterHandler):'
894 866 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
895 867
896 868 def handle(self, line_info):
897 """Hande lines which can be auto-executed, quoting if requested."""
869 """Handle lines which can be auto-executed, quoting if requested."""
898 870 line = line_info.line
899 871 ifun = line_info.ifun
900 872 the_rest = line_info.the_rest
@@ -23,19 +23,25 b' from IPython.core import ipapi'
23 23 #-----------------------------------------------------------------------------
24 24 # Globals
25 25 #-----------------------------------------------------------------------------
26 ip = ipapi.get()
27 26
28 if not '_refbug_cache' in ip.user_ns:
29 ip.user_ns['_refbug_cache'] = []
27 # This needs to be here because nose and other test runners will import
28 # this module. Importing this module has potential side effects that we
29 # want to prevent.
30 if __name__ == '__main__':
30 31
32 ip = ipapi.get()
31 33
32 aglobal = 'Hello'
33 def f():
34 return aglobal
34 if not '_refbug_cache' in ip.user_ns:
35 ip.user_ns['_refbug_cache'] = []
35 36
36 cache = ip.user_ns['_refbug_cache']
37 cache.append(f)
38 37
39 def call_f():
40 for func in cache:
41 print 'lowercased:',func().lower()
38 aglobal = 'Hello'
39 def f():
40 return aglobal
41
42 cache = ip.user_ns['_refbug_cache']
43 cache.append(f)
44
45 def call_f():
46 for func in cache:
47 print 'lowercased:',func().lower()
@@ -1,13 +1,2 b''
1 1 # -*- coding: utf-8 -*-
2 """This directory is meant for special-purpose extensions to IPython.
3
4 This can include things which alter the syntax processing stage (see
5 PhysicalQ_Input for an example of how to do this).
6
7 Any file located here can be called with an 'execfile =' option as
8
9 execfile = extensions/filename.py
10
11 since the IPython directory itself is already part of the search path for
12 files listed as 'execfile ='.
13 """
2 """This directory is meant for IPython extensions."""
@@ -16,8 +16,8 b''
16 16
17 17 import new
18 18
19 from IPython.core.component import Component
20 from IPython.utils.traitlets import Bool, Any
19 from IPython.core.plugin import Plugin
20 from IPython.utils.traitlets import Bool, Any, Instance
21 21 from IPython.utils.autoattr import auto_attr
22 22 from IPython.testing import decorators as testdec
23 23
@@ -31,28 +31,19 b' Use activate() on a MultiEngineClient object to activate it for magics.'
31 31 """
32 32
33 33
34 class ParalleMagicComponent(Component):
34 class ParalleMagic(Plugin):
35 35 """A component to manage the %result, %px and %autopx magics."""
36 36
37 37 active_multiengine_client = Any()
38 38 verbose = Bool(False, config=True)
39 shell = Instance('IPython.core.iplib.InteractiveShellABC')
39 40
40 def __init__(self, parent, name=None, config=None):
41 super(ParalleMagicComponent, self).__init__(parent, name=name, config=config)
41 def __init__(self, shell=None, config=None):
42 super(ParalleMagic, self).__init__(shell=shell, config=config)
42 43 self._define_magics()
43 44 # A flag showing if autopx is activated or not
44 45 self.autopx = False
45 46
46 # Access other components like this rather than by a regular attribute.
47 # This won't lookup the InteractiveShell object until it is used and
48 # then it is cached. This is both efficient and couples this class
49 # more loosely to InteractiveShell.
50 @auto_attr
51 def shell(self):
52 return Component.get_instances(
53 root=self.root,
54 klass='IPython.core.iplib.InteractiveShell')[0]
55
56 47 def _define_magics(self):
57 48 """Define the magic functions."""
58 49 self.shell.define_magic('result', self.magic_result)
@@ -204,6 +195,7 b' def load_ipython_extension(ip):'
204 195 """Load the extension in IPython."""
205 196 global _loaded
206 197 if not _loaded:
207 prd = ParalleMagicComponent(ip, name='parallel_magic')
198 plugin = ParalleMagic(shell=ip, config=ip.config)
199 ip.plugin_manager.register_plugin('parallel_magic', plugin)
208 200 _loaded = True
209 201
@@ -37,8 +37,8 b' by doing::'
37 37
38 38 from IPython.core.error import TryNext
39 39 from IPython.external import pretty
40 from IPython.core.component import Component
41 from IPython.utils.traitlets import Bool, List
40 from IPython.core.plugin import Plugin
41 from IPython.utils.traitlets import Bool, List, Instance
42 42 from IPython.utils.io import Term
43 43 from IPython.utils.autoattr import auto_attr
44 44 from IPython.utils.importstring import import_item
@@ -51,10 +51,11 b' from IPython.utils.importstring import import_item'
51 51 _loaded = False
52 52
53 53
54 class PrettyResultDisplay(Component):
54 class PrettyResultDisplay(Plugin):
55 55 """A component for pretty printing on steroids."""
56 56
57 57 verbose = Bool(False, config=True)
58 shell = Instance('IPython.core.iplib.InteractiveShellABC')
58 59
59 60 # A list of (type, func_name), like
60 61 # [(dict, 'my_dict_printer')]
@@ -66,8 +67,8 b' class PrettyResultDisplay(Component):'
66 67 # The final argument can also be a callable
67 68 defaults_for_type_by_name = List(default_value=[], config=True)
68 69
69 def __init__(self, parent, name=None, config=None):
70 super(PrettyResultDisplay, self).__init__(parent, name=name, config=config)
70 def __init__(self, shell=None, config=None):
71 super(PrettyResultDisplay, self).__init__(shell=shell, config=config)
71 72 self._setup_defaults()
72 73
73 74 def _setup_defaults(self):
@@ -87,16 +88,6 b' class PrettyResultDisplay(Component):'
87 88 else:
88 89 raise TypeError('func_name must be a str or callable, got: %r' % func_name)
89 90
90 # Access other components like this rather than by a regular attribute.
91 # This won't lookup the InteractiveShell object until it is used and
92 # then it is cached. This is both efficient and couples this class
93 # more loosely to InteractiveShell.
94 @auto_attr
95 def shell(self):
96 return Component.get_instances(
97 root=self.root,
98 klass='IPython.core.iplib.InteractiveShell')[0]
99
100 91 def __call__(self, otherself, arg):
101 92 """Uber-pretty-printing display hook.
102 93
@@ -132,10 +123,10 b' def load_ipython_extension(ip):'
132 123 """Load the extension in IPython as a hook."""
133 124 global _loaded
134 125 if not _loaded:
135 prd = PrettyResultDisplay(ip, name='pretty_result_display')
136 ip.set_hook('result_display', prd, priority=99)
126 plugin = PrettyResultDisplay(shell=ip, config=ip.config)
127 ip.set_hook('result_display', plugin, priority=99)
137 128 _loaded = True
138 return prd
129 ip.plugin_manager.register_plugin('pretty_result_display', plugin)
139 130
140 131 def unload_ipython_extension(ip):
141 132 """Unload the extension."""
@@ -17,8 +17,8 b' Simple tests for :mod:`IPython.extensions.pretty`.'
17 17
18 18 from unittest import TestCase
19 19
20 from IPython.core.component import Component, masquerade_as
21 from IPython.core.iplib import InteractiveShell
20 from IPython.config.configurable import Configurable
21 from IPython.core.iplib import InteractiveShellABC
22 22 from IPython.extensions import pretty as pretty_ext
23 23 from IPython.external import pretty
24 24 from IPython.testing import decorators as dec
@@ -29,9 +29,11 b' from IPython.utils.traitlets import Bool'
29 29 # Tests
30 30 #-----------------------------------------------------------------------------
31 31
32 class InteractiveShellStub(Component):
32 class InteractiveShellStub(Configurable):
33 33 pprint = Bool(True)
34 34
35 InteractiveShellABC.register(InteractiveShellStub)
36
35 37 class A(object):
36 38 pass
37 39
@@ -41,12 +43,8 b' def a_pprinter(o, p, c):'
41 43 class TestPrettyResultDisplay(TestCase):
42 44
43 45 def setUp(self):
44 self.ip = InteractiveShellStub(None)
45 # This allows our stub to be retrieved instead of the real
46 # InteractiveShell
47 masquerade_as(self.ip, InteractiveShell)
48 self.prd = pretty_ext.PrettyResultDisplay(self.ip,
49 name='pretty_result_display')
46 self.ip = InteractiveShellStub()
47 self.prd = pretty_ext.PrettyResultDisplay(shell=self.ip, config=None)
50 48
51 49 def test_for_type(self):
52 50 self.prd.for_type(A, a_pprinter)
@@ -77,7 +75,8 b' a'
77 75 b
78 76
79 77 ip = get_ipython()
80 prd = ip.load_extension('pretty')
78 ip.extension_manager.load_extension('pretty')
79 prd = ip.plugin_manager.get_plugin('pretty_result_display')
81 80 prd.for_type(A, a_pretty_printer)
82 81 prd.for_type_by_name(B.__module__, B.__name__, b_pretty_printer)
83 82
@@ -26,7 +26,7 b' from twisted.python import log'
26 26
27 27 from IPython.config.loader import PyFileConfigLoader
28 28 from IPython.core.application import Application, BaseAppConfigLoader
29 from IPython.core.component import Component
29 from IPython.config.configurable import Configurable
30 30 from IPython.core.crashhandler import CrashHandler
31 31 from IPython.core import release
32 32 from IPython.utils.path import (
@@ -63,7 +63,7 b' class PIDFileError(Exception):'
63 63 # Class for managing cluster directories
64 64 #-----------------------------------------------------------------------------
65 65
66 class ClusterDir(Component):
66 class ClusterDir(Configurable):
67 67 """An object to manage the cluster directory and its resources.
68 68
69 69 The cluster directory is used by :command:`ipcontroller`,
@@ -82,9 +82,8 b' class ClusterDir(Component):'
82 82 pid_dir = Unicode(u'')
83 83 location = Unicode(u'')
84 84
85 def __init__(self, location):
86 super(ClusterDir, self).__init__(None)
87 self.location = location
85 def __init__(self, location=u''):
86 super(ClusterDir, self).__init__(location=location)
88 87
89 88 def _location_changed(self, name, old, new):
90 89 if not os.path.isdir(new):
@@ -166,7 +165,7 b' class ClusterDir(Component):'
166 165 The full path to the cluster directory. If it does exist, it will
167 166 be used. If not, it will be created.
168 167 """
169 return ClusterDir(cluster_dir)
168 return ClusterDir(location=cluster_dir)
170 169
171 170 @classmethod
172 171 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
@@ -183,7 +182,7 b' class ClusterDir(Component):'
183 182 if not os.path.isdir(path):
184 183 raise ClusterDirError('Directory not found: %s' % path)
185 184 cluster_dir = os.path.join(path, u'cluster_' + profile)
186 return ClusterDir(cluster_dir)
185 return ClusterDir(location=cluster_dir)
187 186
188 187 @classmethod
189 188 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
@@ -216,7 +215,7 b' class ClusterDir(Component):'
216 215 for p in paths:
217 216 cluster_dir = os.path.join(p, dirname)
218 217 if os.path.isdir(cluster_dir):
219 return ClusterDir(cluster_dir)
218 return ClusterDir(location=cluster_dir)
220 219 else:
221 220 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
222 221
@@ -235,7 +234,7 b' class ClusterDir(Component):'
235 234 cluster_dir = expand_path(cluster_dir)
236 235 if not os.path.isdir(cluster_dir):
237 236 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
238 return ClusterDir(cluster_dir)
237 return ClusterDir(location=cluster_dir)
239 238
240 239
241 240 #-----------------------------------------------------------------------------
@@ -18,7 +18,7 b' configuration system.'
18 18
19 19 import zope.interface as zi
20 20
21 from IPython.core.component import Component
21 from IPython.config.configurable import Configurable
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Code
@@ -29,7 +29,7 b' class IConfiguredObjectFactory(zi.Interface):'
29 29 """I am a component that creates a configured object.
30 30
31 31 This class is useful if you want to configure a class that is not a
32 subclass of :class:`IPython.core.component.Component`.
32 subclass of :class:`IPython.config.configurable.Configurable`.
33 33 """
34 34
35 35 def __init__(config):
@@ -39,12 +39,12 b' class IConfiguredObjectFactory(zi.Interface):'
39 39 """Return an instance of the configured object."""
40 40
41 41
42 class ConfiguredObjectFactory(Component):
42 class ConfiguredObjectFactory(Configurable):
43 43
44 44 zi.implements(IConfiguredObjectFactory)
45 45
46 def __init__(self, config):
47 super(ConfiguredObjectFactory, self).__init__(None, config=config)
46 def __init__(self, config=None):
47 super(ConfiguredObjectFactory, self).__init__(config=config)
48 48
49 49 def create(self):
50 50 raise NotImplementedError('create must be implemented in a subclass')
@@ -56,24 +56,24 b' class IAdaptedConfiguredObjectFactory(zi.Interface):'
56 56 This class is useful if you have the adapt an instance and configure it.
57 57 """
58 58
59 def __init__(config, adaptee=None):
59 def __init__(config=None, adaptee=None):
60 60 """Get ready to adapt adaptee and then configure it using config."""
61 61
62 62 def create():
63 63 """Return an instance of the adapted and configured object."""
64 64
65 65
66 class AdaptedConfiguredObjectFactory(Component):
66 class AdaptedConfiguredObjectFactory(Configurable):
67 67
68 68 # zi.implements(IAdaptedConfiguredObjectFactory)
69 69
70 def __init__(self, config, adaptee):
70 def __init__(self, config=None, adaptee=None):
71 71 # print
72 72 # print "config pre:", config
73 super(AdaptedConfiguredObjectFactory, self).__init__(None, config=config)
73 super(AdaptedConfiguredObjectFactory, self).__init__(config=config)
74 74 # print
75 75 # print "config post:", config
76 76 self.adaptee = adaptee
77 77
78 78 def create(self):
79 raise NotImplementedError('create must be implemented in a subclass') No newline at end of file
79 raise NotImplementedError('create must be implemented in a subclass')
@@ -191,9 +191,9 b' class FCServiceFactory(AdaptedConfiguredObjectFactory):'
191 191 """This class creates a tub with various services running in it.
192 192
193 193 The basic idea is that :meth:`create` returns a running :class:`Tub`
194 instance that has a number of Foolscap references registered in it.
195 This class is a subclass of :class:`IPython.core.component.Component`
196 so the IPython configuration and component system are used.
194 instance that has a number of Foolscap references registered in it. This
195 class is a subclass of :class:`IPython.config.configurable.Configurable`
196 so the IPython configuration system is used.
197 197
198 198 Attributes
199 199 ----------
@@ -19,7 +19,7 b' import os'
19 19 import re
20 20 import sys
21 21
22 from IPython.core.component import Component
22 from IPython.config.configurable import Configurable
23 23 from IPython.external import Itpl
24 24 from IPython.utils.traitlets import Str, Int, List, Unicode
25 25 from IPython.utils.path import get_ipython_module_path
@@ -77,7 +77,7 b' class UnknownStatus(LauncherError):'
77 77 pass
78 78
79 79
80 class BaseLauncher(Component):
80 class BaseLauncher(Configurable):
81 81 """An asbtraction for starting, stopping and signaling a process."""
82 82
83 83 # In all of the launchers, the work_dir is where child processes will be
@@ -89,9 +89,8 b' class BaseLauncher(Component):'
89 89 # the --work-dir option.
90 90 work_dir = Unicode(u'')
91 91
92 def __init__(self, work_dir, parent=None, name=None, config=None):
93 super(BaseLauncher, self).__init__(parent, name, config)
94 self.work_dir = work_dir
92 def __init__(self, work_dir=u'', config=None):
93 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config)
95 94 self.state = 'before' # can be before, running, after
96 95 self.stop_deferreds = []
97 96 self.start_data = None
@@ -265,9 +264,9 b' class LocalProcessLauncher(BaseLauncher):'
265 264 # spawnProcess.
266 265 cmd_and_args = List([])
267 266
268 def __init__(self, work_dir, parent=None, name=None, config=None):
267 def __init__(self, work_dir=u'', config=None):
269 268 super(LocalProcessLauncher, self).__init__(
270 work_dir, parent, name, config
269 work_dir=work_dir, config=config
271 270 )
272 271 self.process_protocol = None
273 272 self.start_deferred = None
@@ -356,9 +355,9 b' class LocalEngineSetLauncher(BaseLauncher):'
356 355 ['--log-to-file','--log-level', '40'], config=True
357 356 )
358 357
359 def __init__(self, work_dir, parent=None, name=None, config=None):
358 def __init__(self, work_dir=u'', config=None):
360 359 super(LocalEngineSetLauncher, self).__init__(
361 work_dir, parent, name, config
360 work_dir=work_dir, config=config
362 361 )
363 362 self.launchers = []
364 363
@@ -367,7 +366,7 b' class LocalEngineSetLauncher(BaseLauncher):'
367 366 self.cluster_dir = unicode(cluster_dir)
368 367 dlist = []
369 368 for i in range(n):
370 el = LocalEngineLauncher(self.work_dir, self)
369 el = LocalEngineLauncher(work_dir=self.work_dir, config=self.config)
371 370 # Copy the engine args over to each engine launcher.
372 371 import copy
373 372 el.engine_args = copy.deepcopy(self.engine_args)
@@ -560,9 +559,9 b' class WindowsHPCLauncher(BaseLauncher):'
560 559 scheduler = Str('', config=True)
561 560 job_cmd = Str(find_job_cmd(), config=True)
562 561
563 def __init__(self, work_dir, parent=None, name=None, config=None):
562 def __init__(self, work_dir=u'', config=None):
564 563 super(WindowsHPCLauncher, self).__init__(
565 work_dir, parent, name, config
564 work_dir=work_dir, config=config
566 565 )
567 566
568 567 @property
@@ -633,9 +632,9 b' class WindowsHPCControllerLauncher(WindowsHPCLauncher):'
633 632 extra_args = List([], config=False)
634 633
635 634 def write_job_file(self, n):
636 job = IPControllerJob(self)
635 job = IPControllerJob(config=self.config)
637 636
638 t = IPControllerTask(self)
637 t = IPControllerTask(config=self.config)
639 638 # The tasks work directory is *not* the actual work directory of
640 639 # the controller. It is used as the base path for the stdout/stderr
641 640 # files that the scheduler redirects to.
@@ -664,10 +663,10 b' class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):'
664 663 extra_args = List([], config=False)
665 664
666 665 def write_job_file(self, n):
667 job = IPEngineSetJob(self)
666 job = IPEngineSetJob(config=self.config)
668 667
669 668 for i in range(n):
670 t = IPEngineTask(self)
669 t = IPEngineTask(config=self.config)
671 670 # The tasks work directory is *not* the actual work directory of
672 671 # the engine. It is used as the base path for the stdout/stderr
673 672 # files that the scheduler redirects to.
@@ -725,9 +724,9 b' class BatchSystemLauncher(BaseLauncher):'
725 724 # The full path to the instantiated batch script.
726 725 batch_file = Unicode(u'')
727 726
728 def __init__(self, work_dir, parent=None, name=None, config=None):
727 def __init__(self, work_dir=u'', config=None):
729 728 super(BatchSystemLauncher, self).__init__(
730 work_dir, parent, name, config
729 work_dir=work_dir, config=config
731 730 )
732 731 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
733 732 self.context = {}
@@ -24,14 +24,14 b' import uuid'
24 24
25 25 from xml.etree import ElementTree as ET
26 26
27 from IPython.core.component import Component
27 from IPython.config.configurable import Configurable
28 28 from IPython.utils.traitlets import (
29 29 Str, Int, List, Instance,
30 30 Enum, Bool, CStr
31 31 )
32 32
33 33 #-----------------------------------------------------------------------------
34 # Job and Task Component
34 # Job and Task classes
35 35 #-----------------------------------------------------------------------------
36 36
37 37
@@ -74,7 +74,7 b' def find_username():'
74 74 return '%s\\%s' % (domain, username)
75 75
76 76
77 class WinHPCJob(Component):
77 class WinHPCJob(Configurable):
78 78
79 79 job_id = Str('')
80 80 job_name = Str('MyJob', config=True)
@@ -165,7 +165,7 b' class WinHPCJob(Component):'
165 165 self.tasks.append(task)
166 166
167 167
168 class WinHPCTask(Component):
168 class WinHPCTask(Configurable):
169 169
170 170 task_id = Str('')
171 171 task_name = Str('')
@@ -261,8 +261,8 b' class IPControllerTask(WinHPCTask):'
261 261 unit_type = Str("Core", config=False)
262 262 work_directory = CStr('', config=False)
263 263
264 def __init__(self, parent, name=None, config=None):
265 super(IPControllerTask, self).__init__(parent, name, config)
264 def __init__(self, config=None):
265 super(IPControllerTask, self).__init__(config=config)
266 266 the_uuid = uuid.uuid1()
267 267 self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid)
268 268 self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid)
@@ -289,8 +289,8 b' class IPEngineTask(WinHPCTask):'
289 289 unit_type = Str("Core", config=False)
290 290 work_directory = CStr('', config=False)
291 291
292 def __init__(self, parent, name=None, config=None):
293 super(IPEngineTask,self).__init__(parent, name, config)
292 def __init__(self, config=None):
293 super(IPEngineTask,self).__init__(config=config)
294 294 the_uuid = uuid.uuid1()
295 295 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
296 296 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
@@ -136,8 +136,8 b' def start_ipython():'
136 136 config = tools.default_config()
137 137
138 138 # Create and initialize our test-friendly IPython instance.
139 shell = iplib.InteractiveShell(
140 parent=None, config=config,
139 shell = iplib.InteractiveShell.instance(
140 config=config,
141 141 user_ns=ipnsdict(), user_global_ns={}
142 142 )
143 143
@@ -360,6 +360,13 b' class TestHasTraits(TestCase):'
360 360 traits = a.traits(config_key=lambda v: True)
361 361 self.assertEquals(traits, dict(i=A.i, f=A.f, j=A.j))
362 362
363 def test_init(self):
364 class A(HasTraits):
365 i = Int()
366 x = Float()
367 a = A(i=1, x=10.0)
368 self.assertEquals(a.i, 1)
369 self.assertEquals(a.x, 10.0)
363 370
364 371 #-----------------------------------------------------------------------------
365 372 # Tests for specific trait types
@@ -373,14 +373,14 b' class HasTraits(object):'
373 373
374 374 __metaclass__ = MetaHasTraits
375 375
376 def __new__(cls, *args, **kw):
376 def __new__(cls, **kw):
377 377 # This is needed because in Python 2.6 object.__new__ only accepts
378 378 # the cls argument.
379 379 new_meth = super(HasTraits, cls).__new__
380 380 if new_meth is object.__new__:
381 381 inst = new_meth(cls)
382 382 else:
383 inst = new_meth(cls, *args, **kw)
383 inst = new_meth(cls, **kw)
384 384 inst._trait_values = {}
385 385 inst._trait_notifiers = {}
386 386 # Here we tell all the TraitType instances to set their default
@@ -399,9 +399,12 b' class HasTraits(object):'
399 399
400 400 return inst
401 401
402 # def __init__(self):
403 # self._trait_values = {}
404 # self._trait_notifiers = {}
402 def __init__(self, **kw):
403 # Allow trait values to be set using keyword arguments.
404 # We need to use setattr for this to trigger validation and
405 # notifications.
406 for key, value in kw.iteritems():
407 setattr(self, key, value)
405 408
406 409 def _notify_trait(self, name, old_value, new_value):
407 410
@@ -1023,3 +1026,25 b' class List(Instance):'
1023 1026
1024 1027 super(List,self).__init__(klass=list, args=args,
1025 1028 allow_none=allow_none, **metadata)
1029
1030
1031 class Dict(Instance):
1032 """An instance of a Python dict."""
1033
1034 def __init__(self, default_value=None, allow_none=True, **metadata):
1035 """Create a dict trait type from a dict.
1036
1037 The default value is created by doing ``dict(default_value)``,
1038 which creates a copy of the ``default_value``.
1039 """
1040 if default_value is None:
1041 args = ((),)
1042 elif isinstance(default_value, dict):
1043 args = (default_value,)
1044 elif isinstance(default_value, SequenceTypes):
1045 args = (default_value,)
1046 else:
1047 raise TypeError('default value of Dict was %s' % default_value)
1048
1049 super(Dict,self).__init__(klass=dict, args=args,
1050 allow_none=allow_none, **metadata)
@@ -8,6 +8,8 b' Configuration and customization'
8 8 :maxdepth: 2
9 9
10 10 overview.txt
11 extensions.txt
12 plugins.txt
11 13 ipython.txt
12 14 editors.txt
13 15 old.txt
@@ -133,4 +133,4 b' attributes::'
133 133
134 134 c.AliasManager.user_aliases = [
135 135 ('la', 'ls -al')
136 ] No newline at end of file
136 ]
@@ -42,29 +42,26 b' Application: :class:`~IPython.core.application.Application`'
42 42 application is the :command:`ipython` command line program. Each
43 43 application reads a *single* configuration file and command line options
44 44 and then produces a master configuration object for the application. This
45 configuration object is then passed to the components that the application
46 creates. Components implement the actual logic of the application and know
47 how to configure themselves given the configuration object.
48
49 Component: :class:`~IPython.core.component.Component`
50 A component is a regular Python class that serves as a base class for all
51 main classes in an application. The
52 :class:`~IPython.core.component.Component` base class is lightweight and
53 only does two main things.
45 configuration object is then passed to the configurable objects that the
46 application creates. These configurable objects implement the actual logic
47 of the application and know how to configure themselves given the
48 configuration object.
49
50 Component: :class:`~IPython.config.configurable.Configurable`
51 A configurable is a regular Python class that serves as a base class for
52 all main classes in an application. The
53 :class:`~IPython.config.configurable.Configurable` base class is
54 lightweight and only does one things.
55
56 This :class:`~IPython.config.configurable.Configurable` is a subclass
57 of :class:`~IPython.utils.traitlets.HasTraits` that knows how to configure
58 itself. Class level traits with the metadata ``config=True`` become
59 values that can be configured from the command line and configuration
60 files.
54 61
55 First, it keeps track of all instances of itself and provides an
56 interfaces for querying those instances. This enables components to get
57 references to other components, even though they are not "nearby" in the
58 runtime object graph.
59
60 Second, it declares what class attributes are configurable and specifies
61 the default types and values of those attributes. This information is used
62 to automatically configure instances given the applications configuration
63 object.
64
65 Developers create :class:`~IPython.core.component.Component` subclasses
66 that implement all of the logic in the application. Each of these
67 subclasses has its own configuration information that controls how
62 Developers create :class:`~IPython.config.configurable.Configurable`
63 subclasses that implement all of the logic in the application. Each of
64 these subclasses has its own configuration information that controls how
68 65 instances are created.
69 66
70 67 Having described these main concepts, we can now state the main idea in our
@@ -73,7 +70,9 b' attributes to be controlled on a class by class basis*. Thus all instances of'
73 70 a given class are configured in the same way. Furthermore, if two instances
74 71 need to be configured differently, they need to be instances of two different
75 72 classes. While this model may seem a bit restrictive, we have found that it
76 expresses most things that need to be configured extremely well.
73 expresses most things that need to be configured extremely well. However, it
74 is possible to create two instances of the same class that have different
75 trait values. This is done by overriding the configuration.
77 76
78 77 Now, we show what our configuration objects and files look like.
79 78
@@ -98,33 +97,34 b' attributes on it. All you have to know is:'
98 97 * The type of each attribute.
99 98
100 99 The answers to these two questions are provided by the various
101 :class:`~IPython.core.component.Component` subclasses that an application
102 uses. Let's look at how this would work for a simple component subclass::
100 :class:`~IPython.config.configurable.Configurable` subclasses that an
101 application uses. Let's look at how this would work for a simple component
102 subclass::
103 103
104 104 # Sample component that can be configured.
105 from IPython.core.component import Component
105 from IPython.config.configurable import Configurable
106 106 from IPython.utils.traitlets import Int, Float, Str, Bool
107 107
108 class MyComponent(Component):
108 class MyClass(Configurable):
109 109 name = Str('defaultname', config=True)
110 110 ranking = Int(0, config=True)
111 111 value = Float(99.0)
112 112 # The rest of the class implementation would go here..
113 113
114 In this example, we see that :class:`MyComponent` has three attributes, two
114 In this example, we see that :class:`MyClass` has three attributes, two
115 115 of whom (``name``, ``ranking``) can be configured. All of the attributes
116 are given types and default values. If a :class:`MyComponent` is instantiated,
116 are given types and default values. If a :class:`MyClass` is instantiated,
117 117 but not configured, these default values will be used. But let's see how
118 118 to configure this class in a configuration file::
119 119
120 120 # Sample config file
121 121 c = get_config()
122 122
123 c.MyComponent.name = 'coolname'
124 c.MyComponent.ranking = 10
123 c.MyClass.name = 'coolname'
124 c.MyClass.ranking = 10
125 125
126 126 After this configuration file is loaded, the values set in it will override
127 the class defaults anytime a :class:`MyComponent` is created. Furthermore,
127 the class defaults anytime a :class:`MyClass` is created. Furthermore,
128 128 these attributes will be type checked and validated anytime they are set.
129 129 This type checking is handled by the :mod:`IPython.utils.traitlets` module,
130 130 which provides the :class:`Str`, :class:`Int` and :class:`Float` types. In
@@ -133,7 +133,7 b' traitlets for a number of other types.'
133 133
134 134 .. note::
135 135
136 Underneath the hood, the :class:`Component` base class is a subclass of
136 Underneath the hood, the :class:`Configurable` base class is a subclass of
137 137 :class:`IPython.utils.traitlets.HasTraits`. The
138 138 :mod:`IPython.utils.traitlets` module is a lightweight version of
139 139 :mod:`enthought.traits`. Our implementation is a pure Python subset
@@ -157,7 +157,7 b' attribute of ``c`` is not the actual class, but instead is another'
157 157
158 158 .. note::
159 159
160 The careful reader may wonder how the ``ClassName`` (``MyComponent`` in
160 The careful reader may wonder how the ``ClassName`` (``MyClass`` in
161 161 the above example) attribute of the configuration object ``c`` gets
162 162 created. These attributes are created on the fly by the
163 163 :class:`~IPython.config.loader.Config` instance, using a simple naming
@@ -165,8 +165,7 b' attribute of ``c`` is not the actual class, but instead is another'
165 165 instance whose name begins with an uppercase character is assumed to be a
166 166 sub-configuration and a new empty :class:`~IPython.config.loader.Config`
167 167 instance is dynamically created for that attribute. This allows deeply
168 hierarchical information created easily (``c.Foo.Bar.value``) on the
169 fly.
168 hierarchical information created easily (``c.Foo.Bar.value``) on the fly.
170 169
171 170 Configuration files inheritance
172 171 ===============================
@@ -179,8 +178,8 b' example that loads all of the values from the file :file:`base_config.py`::'
179 178
180 179 # base_config.py
181 180 c = get_config()
182 c.MyComponent.name = 'coolname'
183 c.MyComponent.ranking = 100
181 c.MyClass.name = 'coolname'
182 c.MyClass.ranking = 100
184 183
185 184 into the configuration file :file:`main_config.py`::
186 185
@@ -191,7 +190,7 b' into the configuration file :file:`main_config.py`::'
191 190 load_subconfig('base_config.py')
192 191
193 192 # Now override one of the values
194 c.MyComponent.name = 'bettername'
193 c.MyClass.name = 'bettername'
195 194
196 195 In a situation like this the :func:`load_subconfig` makes sure that the
197 196 search path for sub-configuration files is inherited from that of the parent.
@@ -205,10 +204,10 b' There is another aspect of configuration where inheritance comes into play.'
205 204 Sometimes, your classes will have an inheritance hierarchy that you want
206 205 to be reflected in the configuration system. Here is a simple example::
207 206
208 from IPython.core.component import Component
207 from IPython.config.configurable import Configurable
209 208 from IPython.utils.traitlets import Int, Float, Str, Bool
210 209
211 class Foo(Component):
210 class Foo(Configurable):
212 211 name = Str('fooname', config=True)
213 212 value = Float(100.0, config=True)
214 213
@@ -328,4 +327,3 b' Here are the main requirements we wanted our configuration system to have:'
328 327 dynamic language and you don't always know everything that needs to be
329 328 configured when a program starts.
330 329
331
@@ -220,7 +220,7 b' class EmbeddedSphinxShell(object):'
220 220 config.InteractiveShell.colors = 'NoColor'
221 221
222 222 # Create and initialize ipython, but don't start its mainloop
223 IP = InteractiveShell(parent=None, config=config)
223 IP = InteractiveShell.instance(config=config)
224 224
225 225 # Store a few parts of IPython we'll need.
226 226 self.IP = IP
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now