##// END OF EJS Templates
Fixing bugs in BaseIPythonApplication....
Brian Granger -
Show More
@@ -1,241 +1,241 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A base class for a configurable application.
3 A base class for a configurable application.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2011 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 from copy import deepcopy
21 from copy import deepcopy
22 import logging
22 import logging
23 import sys
23 import sys
24
24
25 from IPython.config.configurable import SingletonConfigurable
25 from IPython.config.configurable import SingletonConfigurable
26 from IPython.config.loader import (
26 from IPython.config.loader import (
27 KeyValueConfigLoader, PyFileConfigLoader, Config
27 KeyValueConfigLoader, PyFileConfigLoader, Config
28 )
28 )
29
29
30 from IPython.utils.traitlets import (
30 from IPython.utils.traitlets import (
31 Unicode, List, Int, Enum, Dict
31 Unicode, List, Int, Enum, Dict
32 )
32 )
33 from IPython.utils.text import indent
33 from IPython.utils.text import indent
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Descriptions for
36 # Descriptions for
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 flag_description = """
39 flag_description = """
40 Flags are command-line arguments passed as '--<flag>'.
40 Flags are command-line arguments passed as '--<flag>'.
41 These take no parameters, unlike regular key-value arguments.
41 These take no parameters, unlike regular key-value arguments.
42 They are typically used for setting boolean flags, or enabling
42 They are typically used for setting boolean flags, or enabling
43 modes that involve setting multiple options together.
43 modes that involve setting multiple options together.
44 """.strip() # trim newlines of front and back
44 """.strip() # trim newlines of front and back
45
45
46 alias_description = """
46 alias_description = """
47 These are commonly set parameters, given abbreviated aliases for convenience.
47 These are commonly set parameters, given abbreviated aliases for convenience.
48 They are set in the same `name=value` way as class parameters, where
48 They are set in the same `name=value` way as class parameters, where
49 <name> is replaced by the real parameter for which it is an alias.
49 <name> is replaced by the real parameter for which it is an alias.
50 """.strip() # trim newlines of front and back
50 """.strip() # trim newlines of front and back
51
51
52 keyvalue_description = """
52 keyvalue_description = """
53 Parameters are set from command-line arguments of the form:
53 Parameters are set from command-line arguments of the form:
54 `Class.trait=value`. Parameters will *never* be prefixed with '-'.
54 `Class.trait=value`. Parameters will *never* be prefixed with '-'.
55 This line is evaluated in Python, so simple expressions are allowed, e.g.
55 This line is evaluated in Python, so simple expressions are allowed, e.g.
56 `C.a='range(3)'` For setting C.a=[0,1,2]
56 `C.a='range(3)'` For setting C.a=[0,1,2]
57 """.strip() # trim newlines of front and back
57 """.strip() # trim newlines of front and back
58
58
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60 # Application class
60 # Application class
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62
62
63
63
64 class ApplicationError(Exception):
64 class ApplicationError(Exception):
65 pass
65 pass
66
66
67
67
68 class Application(SingletonConfigurable):
68 class Application(SingletonConfigurable):
69 """A singleton application with full configuration support."""
69 """A singleton application with full configuration support."""
70
70
71 # The name of the application, will usually match the name of the command
71 # The name of the application, will usually match the name of the command
72 # line application
72 # line application
73 app_name = Unicode(u'application')
73 name = Unicode(u'application')
74
74
75 # The description of the application that is printed at the beginning
75 # The description of the application that is printed at the beginning
76 # of the help.
76 # of the help.
77 description = Unicode(u'This is an application.')
77 description = Unicode(u'This is an application.')
78 # default section descriptions
78 # default section descriptions
79 flag_description = Unicode(flag_description)
79 flag_description = Unicode(flag_description)
80 alias_description = Unicode(alias_description)
80 alias_description = Unicode(alias_description)
81 keyvalue_description = Unicode(keyvalue_description)
81 keyvalue_description = Unicode(keyvalue_description)
82
82
83
83
84 # A sequence of Configurable subclasses whose config=True attributes will
84 # A sequence of Configurable subclasses whose config=True attributes will
85 # be exposed at the command line.
85 # be exposed at the command line.
86 classes = List([])
86 classes = List([])
87
87
88 # The version string of this application.
88 # The version string of this application.
89 version = Unicode(u'0.0')
89 version = Unicode(u'0.0')
90
90
91 # The log level for the application
91 # The log level for the application
92 log_level = Enum((0,10,20,30,40,50), default_value=logging.WARN,
92 log_level = Enum((0,10,20,30,40,50), default_value=logging.WARN,
93 config=True,
93 config=True,
94 help="Set the log level (0,10,20,30,40,50).")
94 help="Set the log level (0,10,20,30,40,50).")
95
95
96 # the alias map for configurables
96 # the alias map for configurables
97 aliases = Dict(dict(log_level='Application.log_level'))
97 aliases = Dict(dict(log_level='Application.log_level'))
98
98
99 # flags for loading Configurables or store_const style flags
99 # flags for loading Configurables or store_const style flags
100 # flags are loaded from this dict by '--key' flags
100 # flags are loaded from this dict by '--key' flags
101 # this must be a dict of two-tuples, the first element being the Config/dict
101 # this must be a dict of two-tuples, the first element being the Config/dict
102 # and the second being the help string for the flag
102 # and the second being the help string for the flag
103 flags = Dict()
103 flags = Dict()
104
104
105
105
106 def __init__(self, **kwargs):
106 def __init__(self, **kwargs):
107 SingletonConfigurable.__init__(self, **kwargs)
107 SingletonConfigurable.__init__(self, **kwargs)
108 # Add my class to self.classes so my attributes appear in command line
108 # Add my class to self.classes so my attributes appear in command line
109 # options.
109 # options.
110 self.classes.insert(0, self.__class__)
110 self.classes.insert(0, self.__class__)
111
111
112 # ensure self.flags dict is valid
112 # ensure self.flags dict is valid
113 for key,value in self.flags.iteritems():
113 for key,value in self.flags.iteritems():
114 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
114 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
115 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
115 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
116 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
116 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
117 self.init_logging()
117 self.init_logging()
118
118
119 def _config_changed(self, name, old, new):
119 def _config_changed(self, name, old, new):
120 SingletonConfigurable._config_changed(self, name, old, new)
120 SingletonConfigurable._config_changed(self, name, old, new)
121 self.log.debug('Config changed:')
121 self.log.debug('Config changed:')
122 self.log.debug(repr(new))
122 self.log.debug(repr(new))
123
123
124 def init_logging(self):
124 def init_logging(self):
125 """Start logging for this application.
125 """Start logging for this application.
126
126
127 The default is to log to stdout using a StreaHandler. The log level
127 The default is to log to stdout using a StreaHandler. The log level
128 starts at loggin.WARN, but this can be adjusted by setting the
128 starts at loggin.WARN, but this can be adjusted by setting the
129 ``log_level`` attribute.
129 ``log_level`` attribute.
130 """
130 """
131 self.log = logging.getLogger(self.__class__.__name__)
131 self.log = logging.getLogger(self.__class__.__name__)
132 self.log.setLevel(self.log_level)
132 self.log.setLevel(self.log_level)
133 self._log_handler = logging.StreamHandler()
133 self._log_handler = logging.StreamHandler()
134 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
134 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
135 self._log_handler.setFormatter(self._log_formatter)
135 self._log_handler.setFormatter(self._log_formatter)
136 self.log.addHandler(self._log_handler)
136 self.log.addHandler(self._log_handler)
137
137
138 def _log_level_changed(self, name, old, new):
138 def _log_level_changed(self, name, old, new):
139 """Adjust the log level when log_level is set."""
139 """Adjust the log level when log_level is set."""
140 self.log.setLevel(new)
140 self.log.setLevel(new)
141
141
142 def print_alias_help(self):
142 def print_alias_help(self):
143 """print the alias part of the help"""
143 """print the alias part of the help"""
144 if not self.aliases:
144 if not self.aliases:
145 return
145 return
146
146
147 print "Aliases"
147 print "Aliases"
148 print "-------"
148 print "-------"
149 print self.alias_description
149 print self.alias_description
150 print
150 print
151
151
152 classdict = {}
152 classdict = {}
153 for c in self.classes:
153 for c in self.classes:
154 classdict[c.__name__] = c
154 classdict[c.__name__] = c
155
155
156 for alias, longname in self.aliases.iteritems():
156 for alias, longname in self.aliases.iteritems():
157 classname, traitname = longname.split('.',1)
157 classname, traitname = longname.split('.',1)
158 cls = classdict[classname]
158 cls = classdict[classname]
159
159
160 trait = cls.class_traits(config=True)[traitname]
160 trait = cls.class_traits(config=True)[traitname]
161 help = trait.get_metadata('help')
161 help = trait.get_metadata('help')
162 print alias, "(%s)"%longname, ':', trait.__class__.__name__
162 print alias, "(%s)"%longname, ':', trait.__class__.__name__
163 if help:
163 if help:
164 print indent(help)
164 print indent(help)
165 print
165 print
166
166
167 def print_flag_help(self):
167 def print_flag_help(self):
168 """print the flag part of the help"""
168 """print the flag part of the help"""
169 if not self.flags:
169 if not self.flags:
170 return
170 return
171
171
172 print "Flags"
172 print "Flags"
173 print "-----"
173 print "-----"
174 print self.flag_description
174 print self.flag_description
175 print
175 print
176
176
177 for m, (cfg,help) in self.flags.iteritems():
177 for m, (cfg,help) in self.flags.iteritems():
178 print '--'+m
178 print '--'+m
179 print indent(help)
179 print indent(help)
180 print
180 print
181
181
182 def print_help(self):
182 def print_help(self):
183 """Print the help for each Configurable class in self.classes."""
183 """Print the help for each Configurable class in self.classes."""
184 self.print_flag_help()
184 self.print_flag_help()
185 self.print_alias_help()
185 self.print_alias_help()
186 if self.classes:
186 if self.classes:
187 print "Class parameters"
187 print "Class parameters"
188 print "----------------"
188 print "----------------"
189 print self.keyvalue_description
189 print self.keyvalue_description
190 print
190 print
191
191
192 for cls in self.classes:
192 for cls in self.classes:
193 cls.class_print_help()
193 cls.class_print_help()
194 print
194 print
195
195
196 def print_description(self):
196 def print_description(self):
197 """Print the application description."""
197 """Print the application description."""
198 print self.description
198 print self.description
199 print
199 print
200
200
201 def print_version(self):
201 def print_version(self):
202 """Print the version string."""
202 """Print the version string."""
203 print self.version
203 print self.version
204
204
205 def update_config(self, config):
205 def update_config(self, config):
206 """Fire the traits events when the config is updated."""
206 """Fire the traits events when the config is updated."""
207 # Save a copy of the current config.
207 # Save a copy of the current config.
208 newconfig = deepcopy(self.config)
208 newconfig = deepcopy(self.config)
209 # Merge the new config into the current one.
209 # Merge the new config into the current one.
210 newconfig._merge(config)
210 newconfig._merge(config)
211 # Save the combined config as self.config, which triggers the traits
211 # Save the combined config as self.config, which triggers the traits
212 # events.
212 # events.
213 self.config = newconfig
213 self.config = newconfig
214
214
215 def parse_command_line(self, argv=None):
215 def parse_command_line(self, argv=None):
216 """Parse the command line arguments."""
216 """Parse the command line arguments."""
217 argv = sys.argv[1:] if argv is None else argv
217 argv = sys.argv[1:] if argv is None else argv
218
218
219 if '-h' in argv or '--help' in argv:
219 if '-h' in argv or '--help' in argv:
220 self.print_description()
220 self.print_description()
221 self.print_help()
221 self.print_help()
222 self.exit(1)
222 self.exit(1)
223
223
224 if '--version' in argv:
224 if '--version' in argv:
225 self.print_version()
225 self.print_version()
226 self.exit(1)
226 self.exit(1)
227
227
228 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
228 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
229 flags=self.flags)
229 flags=self.flags)
230 config = loader.load_config()
230 config = loader.load_config()
231 self.update_config(config)
231 self.update_config(config)
232
232
233 def load_config_file(self, filename, path=None):
233 def load_config_file(self, filename, path=None):
234 """Load a .py based config file by filename and path."""
234 """Load a .py based config file by filename and path."""
235 loader = PyFileConfigLoader(filename, path=path)
235 loader = PyFileConfigLoader(filename, path=path)
236 config = loader.load_config()
236 config = loader.load_config()
237 self.update_config(config)
237 self.update_config(config)
238
238
239 def exit(self, exit_status=0):
239 def exit(self, exit_status=0):
240 self.log.debug("Exiting application: %s" % self.name)
240 self.log.debug("Exiting application: %s" % self.name)
241 sys.exit(exit_status)
241 sys.exit(exit_status)
@@ -1,105 +1,105 b''
1 """
1 """
2 Tests for IPython.config.application.Application
2 Tests for IPython.config.application.Application
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2008-2011 The IPython Development Team
10 # Copyright (C) 2008-2011 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 from unittest import TestCase
20 from unittest import TestCase
21
21
22 from IPython.config.configurable import Configurable
22 from IPython.config.configurable import Configurable
23
23
24 from IPython.config.application import (
24 from IPython.config.application import (
25 Application
25 Application
26 )
26 )
27
27
28 from IPython.utils.traitlets import (
28 from IPython.utils.traitlets import (
29 Bool, Unicode, Int, Float, List, Dict
29 Bool, Unicode, Int, Float, List, Dict
30 )
30 )
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Code
33 # Code
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36 class Foo(Configurable):
36 class Foo(Configurable):
37
37
38 i = Int(0, config=True, help="The integer i.")
38 i = Int(0, config=True, help="The integer i.")
39 j = Int(1, config=True, help="The integer j.")
39 j = Int(1, config=True, help="The integer j.")
40 name = Unicode(u'Brian', config=True, help="First name.")
40 name = Unicode(u'Brian', config=True, help="First name.")
41
41
42
42
43 class Bar(Configurable):
43 class Bar(Configurable):
44
44
45 enabled = Bool(True, config=True, help="Enable bar.")
45 enabled = Bool(True, config=True, help="Enable bar.")
46
46
47
47
48 class MyApp(Application):
48 class MyApp(Application):
49
49
50 app_name = Unicode(u'myapp')
50 name = Unicode(u'myapp')
51 running = Bool(False, config=True,
51 running = Bool(False, config=True,
52 help="Is the app running?")
52 help="Is the app running?")
53 classes = List([Bar, Foo])
53 classes = List([Bar, Foo])
54 config_file = Unicode(u'', config=True,
54 config_file = Unicode(u'', config=True,
55 help="Load this config file")
55 help="Load this config file")
56
56
57 aliases = Dict(dict(i='Foo.i',j='Foo.j',name='Foo.name',
57 aliases = Dict(dict(i='Foo.i',j='Foo.j',name='Foo.name',
58 enabled='Bar.enabled', log_level='MyApp.log_level'))
58 enabled='Bar.enabled', log_level='MyApp.log_level'))
59
59
60 flags = Dict(dict(enable=({'Bar': {'enabled' : True}}, "Set Bar.enabled to True"),
60 flags = Dict(dict(enable=({'Bar': {'enabled' : True}}, "Set Bar.enabled to True"),
61 disable=({'Bar': {'enabled' : False}}, "Set Bar.enabled to False")))
61 disable=({'Bar': {'enabled' : False}}, "Set Bar.enabled to False")))
62
62
63 def init_foo(self):
63 def init_foo(self):
64 self.foo = Foo(config=self.config)
64 self.foo = Foo(config=self.config)
65
65
66 def init_bar(self):
66 def init_bar(self):
67 self.bar = Bar(config=self.config)
67 self.bar = Bar(config=self.config)
68
68
69
69
70 class TestApplication(TestCase):
70 class TestApplication(TestCase):
71
71
72 def test_basic(self):
72 def test_basic(self):
73 app = MyApp()
73 app = MyApp()
74 self.assertEquals(app.app_name, u'myapp')
74 self.assertEquals(app.name, u'myapp')
75 self.assertEquals(app.running, False)
75 self.assertEquals(app.running, False)
76 self.assertEquals(app.classes, [MyApp,Bar,Foo])
76 self.assertEquals(app.classes, [MyApp,Bar,Foo])
77 self.assertEquals(app.config_file, u'')
77 self.assertEquals(app.config_file, u'')
78
78
79 def test_config(self):
79 def test_config(self):
80 app = MyApp()
80 app = MyApp()
81 app.parse_command_line(["i=10","Foo.j=10","enabled=False","log_level=0"])
81 app.parse_command_line(["i=10","Foo.j=10","enabled=False","log_level=0"])
82 config = app.config
82 config = app.config
83 self.assertEquals(config.Foo.i, 10)
83 self.assertEquals(config.Foo.i, 10)
84 self.assertEquals(config.Foo.j, 10)
84 self.assertEquals(config.Foo.j, 10)
85 self.assertEquals(config.Bar.enabled, False)
85 self.assertEquals(config.Bar.enabled, False)
86 self.assertEquals(config.MyApp.log_level,0)
86 self.assertEquals(config.MyApp.log_level,0)
87
87
88 def test_config_propagation(self):
88 def test_config_propagation(self):
89 app = MyApp()
89 app = MyApp()
90 app.parse_command_line(["i=10","Foo.j=10","enabled=False","log_level=0"])
90 app.parse_command_line(["i=10","Foo.j=10","enabled=False","log_level=0"])
91 app.init_foo()
91 app.init_foo()
92 app.init_bar()
92 app.init_bar()
93 self.assertEquals(app.foo.i, 10)
93 self.assertEquals(app.foo.i, 10)
94 self.assertEquals(app.foo.j, 10)
94 self.assertEquals(app.foo.j, 10)
95 self.assertEquals(app.bar.enabled, False)
95 self.assertEquals(app.bar.enabled, False)
96
96
97 def test_alias(self):
97 def test_alias(self):
98 app = MyApp()
98 app = MyApp()
99 app.parse_command_line(["--disable"])
99 app.parse_command_line(["--disable"])
100 app.init_bar()
100 app.init_bar()
101 self.assertEquals(app.bar.enabled, False)
101 self.assertEquals(app.bar.enabled, False)
102 app.parse_command_line(["--enable"])
102 app.parse_command_line(["--enable"])
103 app.init_bar()
103 app.init_bar()
104 self.assertEquals(app.bar.enabled, True)
104 self.assertEquals(app.bar.enabled, True)
105
105
@@ -1,132 +1,133 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for IPython.
3 An application for IPython.
4
4
5 All top-level applications should use the classes in this module for
5 All top-level applications should use the classes in this module for
6 handling configuration and creating componenets.
6 handling configuration and creating componenets.
7
7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 object and then create the configurable objects, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10
10
11 Authors:
11 Authors:
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15
15
16 Notes
16 Notes
17 -----
17 -----
18 """
18 """
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Copyright (C) 2008-2009 The IPython Development Team
21 # Copyright (C) 2008-2009 The IPython Development Team
22 #
22 #
23 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Imports
28 # Imports
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 import os
31 import os
32 import sys
32 import sys
33
33
34 from IPython.config.application import Application
34 from IPython.config.application import Application
35 from IPython.core import release, crashhandler
35 from IPython.core import release, crashhandler
36 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
36 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
37 from IPython.utils.traitlets import Tuple, Unicode, Type
37 from IPython.utils.traitlets import Tuple, Unicode, Type
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Classes and functions
40 # Classes and functions
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43
43
44 class BaseIPythonApplication(Application):
44 class BaseIPythonApplication(Application):
45
45
46 app_name = Unicode(u'ipython')
46 name = Unicode(u'ipython')
47 description = Unicode(u'IPython: an enhanced interactive Python shell.')
47 description = Unicode(u'IPython: an enhanced interactive Python shell.')
48 version = Unicode(release.version)
48 version = Unicode(release.version)
49
49
50 # The name of the default config file. Track separately from the actual
50 # The name of the default config file. Track separately from the actual
51 # name because some logic happens only if we aren't using the default.
51 # name because some logic happens only if we aren't using the default.
52 default_config_file_name = Unicode(u'ipython_config.py')
52 default_config_file_name = Unicode(u'ipython_config.py')
53
53
54 # The directory that contains IPython's builtin profiles.
54 # The directory that contains IPython's builtin profiles.
55 builtin_profile_dir = Unicode(
55 builtin_profile_dir = Unicode(
56 os.path.join(get_ipython_package_dir(), u'config', u'profile')
56 os.path.join(get_ipython_package_dir(), u'config', u'profile')
57 )
57 )
58
58
59 config_file_paths = Tuple(Unicode)
59 config_file_paths = Tuple(Unicode, Unicode, Unicode)
60 def _config_file_paths_default(self):
60 def _config_file_paths_default(self):
61 return (os.getcwdu(), self.ipython_dir, self.builtin_profile_dir)
61 return (os.getcwdu(), self.ipython_dir, self.builtin_profile_dir)
62
62
63 profile_name = Unicode(u'', config=True,
63 profile_name = Unicode(u'', config=True,
64 help="""The IPython profile to use."""
64 help="""The IPython profile to use."""
65 )
65 )
66
66
67 ipython_dir = Unicode(get_ipython_dir(), config=True, help=
67 ipython_dir = Unicode(get_ipython_dir(), config=True, help=
68 """
68 """
69 The name of the IPython directory. This directory is used for logging
69 The name of the IPython directory. This directory is used for logging
70 configuration (through profiles), history storage, etc. The default
70 configuration (through profiles), history storage, etc. The default
71 is usually $HOME/.ipython. This options can also be specified through
71 is usually $HOME/.ipython. This options can also be specified through
72 the environment variable IPYTHON_DIR.
72 the environment variable IPYTHON_DIR.
73 """
73 """
74 )
74 )
75
75
76 # The class to use as the crash handler.
76 # The class to use as the crash handler.
77 crash_handler_class = Type(crashhandler.CrashHandler)
77 crash_handler_class = Type(crashhandler.CrashHandler)
78
78
79 #-------------------------------------------------------------------------
79 #-------------------------------------------------------------------------
80 # Various stages of Application creation
80 # Various stages of Application creation
81 #-------------------------------------------------------------------------
81 #-------------------------------------------------------------------------
82
82
83 def init_crash_handler(self):
83 def init_crash_handler(self):
84 """Create a crash handler, typically setting sys.excepthook to it."""
84 """Create a crash handler, typically setting sys.excepthook to it."""
85 self.crash_handler = self.crash_handler_class(self)
85 self.crash_handler = self.crash_handler_class(self)
86 sys.excepthook = self.crash_handler
86 sys.excepthook = self.crash_handler
87
87
88 def _ipython_dir_changed(self, name, old, new):
88 def _ipython_dir_changed(self, name, old, new):
89 if old in sys.path:
89 if old in sys.path:
90 sys.path.remove(old)
90 sys.path.remove(old)
91 sys.path.append(os.path.abspath(new))
91 sys.path.append(os.path.abspath(new))
92 if not os.path.isdir(new):
92 if not os.path.isdir(new):
93 os.makedirs(new, mode=0777)
93 os.makedirs(new, mode=0777)
94 self.config_file_paths = (os.getcwdu(), new, self.builtin_profile_dir)
94 self.config_file_paths = (os.getcwdu(), new, self.builtin_profile_dir)
95 self.log.debug("IPYTHON_DIR set to: %s" % new)
95 self.log.debug("IPYTHON_DIR set to: %s" % new)
96
96
97 @property
97 @property
98 def config_file_name(self):
98 def config_file_name(self):
99 """Find the config file name for this application."""
99 """Find the config file name for this application."""
100 if self.profile_name:
100 if self.profile_name:
101 name_parts = self.default_config_file_name.split('.')
101 name_parts = self.default_config_file_name.split('.')
102 name_parts.insert(1, u'_' + self.profile_name + u'.')
102 name_parts.insert(1, u'_' + self.profile_name + u'.')
103 return ''.join(name_parts)
103 return ''.join(name_parts)
104 else:
104 else:
105 return self.default_config_file_name
105 return self.default_config_file_name
106
106
107 def load_config_file(self, suppress_errors=True):
107 def load_config_file(self, suppress_errors=True):
108 """Load the config file.
108 """Load the config file.
109
109
110 By default, errors in loading config are handled, and a warning
110 By default, errors in loading config are handled, and a warning
111 printed on screen. For testing, the suppress_errors option is set
111 printed on screen. For testing, the suppress_errors option is set
112 to False, so errors will make tests fail.
112 to False, so errors will make tests fail.
113 """
113 """
114 self.log.debug("Attempting to load config file: %s" %
114 self.log.debug("Attempting to load config file: %s" %
115 self.config_file_name)
115 self.config_file_name)
116 try:
116 try:
117 Application.load_config_file(
117 Application.load_config_file(
118 self,
118 self,
119 self.config_file_name,
119 self.config_file_name,
120 path=self.config_file_paths
120 path=self.config_file_paths
121 )
121 )
122 except IOError:
122 except IOError:
123 # Only warn if the default config file was NOT being used.
123 # Only warn if the default config file was NOT being used.
124 if not self.config_file_name == self.default_config_file_name:
124 if not self.config_file_name == self.default_config_file_name:
125 self.log.warn("Config file not found, skipping: %s" %
125 self.log.warn("Config file not found, skipping: %s" %
126 self.config_file_name, exc_info=True)
126 self.config_file_name, exc_info=True)
127 except:
127 except:
128 if not suppress_errors: # For testing purposes
128 # For testing purposes.
129 if not suppress_errors:
129 raise
130 raise
130 self.log.warn("Error loading config file: %s" %
131 self.log.warn("Error loading config file: %s" %
131 self.config_file_name, exc_info=True)
132 self.config_file_name, exc_info=True)
132
133
@@ -1,96 +1,96 b''
1 """A simple example of how to use IPython.config.application.Application.
1 """A simple example of how to use IPython.config.application.Application.
2
2
3 This should serve as a simple example that shows how the IPython config
3 This should serve as a simple example that shows how the IPython config
4 system works. The main classes are:
4 system works. The main classes are:
5
5
6 * IPython.config.configurable.Configurable
6 * IPython.config.configurable.Configurable
7 * IPython.config.configurable.SingletonConfigurable
7 * IPython.config.configurable.SingletonConfigurable
8 * IPython.config.loader.Config
8 * IPython.config.loader.Config
9 * IPython.config.application.Application
9 * IPython.config.application.Application
10
10
11 To see the command line option help, run this program from the command line::
11 To see the command line option help, run this program from the command line::
12
12
13 $ python appconfig.py -h
13 $ python appconfig.py -h
14
14
15 To make one of your classes configurable (from the command line and config
15 To make one of your classes configurable (from the command line and config
16 files) inherit from Configurable and declare class attributes as traits (see
16 files) inherit from Configurable and declare class attributes as traits (see
17 classes Foo and Bar below). To make the traits configurable, you will need
17 classes Foo and Bar below). To make the traits configurable, you will need
18 to set the following options:
18 to set the following options:
19
19
20 * ``config``: set to ``True`` to make the attribute configurable.
20 * ``config``: set to ``True`` to make the attribute configurable.
21 * ``shortname``: by default, configurable attributes are set using the syntax
21 * ``shortname``: by default, configurable attributes are set using the syntax
22 "Classname.attributename". At the command line, this is a bit verbose, so
22 "Classname.attributename". At the command line, this is a bit verbose, so
23 we allow "shortnames" to be declared. Setting a shortname is optional, but
23 we allow "shortnames" to be declared. Setting a shortname is optional, but
24 when you do this, you can set the option at the command line using the
24 when you do this, you can set the option at the command line using the
25 syntax: "shortname=value".
25 syntax: "shortname=value".
26 * ``help``: set the help string to display a help message when the ``-h``
26 * ``help``: set the help string to display a help message when the ``-h``
27 option is given at the command line. The help string should be valid ReST.
27 option is given at the command line. The help string should be valid ReST.
28
28
29 When the config attribute of an Application is updated, it will fire all of
29 When the config attribute of an Application is updated, it will fire all of
30 the trait's events for all of the config=True attributes.
30 the trait's events for all of the config=True attributes.
31 """
31 """
32
32
33 import sys
33 import sys
34
34
35 from IPython.config.configurable import Configurable
35 from IPython.config.configurable import Configurable
36 from IPython.config.application import Application
36 from IPython.config.application import Application
37 from IPython.utils.traitlets import (
37 from IPython.utils.traitlets import (
38 Bool, Unicode, Int, Float, List, Dict
38 Bool, Unicode, Int, Float, List, Dict
39 )
39 )
40
40
41
41
42 class Foo(Configurable):
42 class Foo(Configurable):
43 """A class that has configurable, typed attributes.
43 """A class that has configurable, typed attributes.
44
44
45 """
45 """
46
46
47 i = Int(0, config=True, help="The integer i.")
47 i = Int(0, config=True, help="The integer i.")
48 j = Int(1, config=True, help="The integer j.")
48 j = Int(1, config=True, help="The integer j.")
49 name = Unicode(u'Brian', config=True, help="First name.")
49 name = Unicode(u'Brian', config=True, help="First name.")
50
50
51
51
52 class Bar(Configurable):
52 class Bar(Configurable):
53
53
54 enabled = Bool(True, config=True, help="Enable bar.")
54 enabled = Bool(True, config=True, help="Enable bar.")
55
55
56
56
57 class MyApp(Application):
57 class MyApp(Application):
58
58
59 app_name = Unicode(u'myapp')
59 name = Unicode(u'myapp')
60 running = Bool(False, config=True,
60 running = Bool(False, config=True,
61 help="Is the app running?")
61 help="Is the app running?")
62 classes = List([Bar, Foo])
62 classes = List([Bar, Foo])
63 config_file = Unicode(u'', config=True,
63 config_file = Unicode(u'', config=True,
64 help="Load this config file")
64 help="Load this config file")
65
65
66 aliases = Dict(dict(i='Foo.i',j='Foo.j',name='Foo.name', running='MyApp.running',
66 aliases = Dict(dict(i='Foo.i',j='Foo.j',name='Foo.name', running='MyApp.running',
67 enabled='Bar.enabled', log_level='MyApp.log_level'))
67 enabled='Bar.enabled', log_level='MyApp.log_level'))
68
68
69 flags = Dict(dict(enable=({'Bar': {'enabled' : True}}, "Enable Bar"),
69 flags = Dict(dict(enable=({'Bar': {'enabled' : True}}, "Enable Bar"),
70 disable=({'Bar': {'enabled' : False}}, "Disable Bar"),
70 disable=({'Bar': {'enabled' : False}}, "Disable Bar"),
71 debug=({'MyApp':{'log_level':10}}, "Set loglevel to DEBUG")
71 debug=({'MyApp':{'log_level':10}}, "Set loglevel to DEBUG")
72 ))
72 ))
73
73
74 def init_foo(self):
74 def init_foo(self):
75 # Pass config to other classes for them to inherit the config.
75 # Pass config to other classes for them to inherit the config.
76 self.foo = Foo(config=self.config)
76 self.foo = Foo(config=self.config)
77
77
78 def init_bar(self):
78 def init_bar(self):
79 # Pass config to other classes for them to inherit the config.
79 # Pass config to other classes for them to inherit the config.
80 self.bar = Bar(config=self.config)
80 self.bar = Bar(config=self.config)
81
81
82
82
83
83
84 def main():
84 def main():
85 app = MyApp()
85 app = MyApp()
86 app.parse_command_line()
86 app.parse_command_line()
87 if app.config_file:
87 if app.config_file:
88 app.load_config_file(app.config_file)
88 app.load_config_file(app.config_file)
89 app.init_foo()
89 app.init_foo()
90 app.init_bar()
90 app.init_bar()
91 print "app.config:"
91 print "app.config:"
92 print app.config
92 print app.config
93
93
94
94
95 if __name__ == "__main__":
95 if __name__ == "__main__":
96 main()
96 main()
General Comments 0
You need to be logged in to leave comments. Login now