##// END OF EJS Templates
Fixing minor bug in config.application.
Brian Granger -
Show More
@@ -1,241 +1,241 b''
1 1 # encoding: utf-8
2 2 """
3 3 A base class for a configurable application.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2008-2011 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 from copy import deepcopy
22 22 import logging
23 23 import sys
24 24
25 25 from IPython.config.configurable import SingletonConfigurable
26 26 from IPython.config.loader import (
27 27 KeyValueConfigLoader, PyFileConfigLoader, Config
28 28 )
29 29
30 30 from IPython.utils.traitlets import (
31 31 Unicode, List, Int, Enum, Dict
32 32 )
33 33 from IPython.utils.text import indent
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Descriptions for
37 37 #-----------------------------------------------------------------------------
38 38
39 39 flag_description = """
40 40 Flags are command-line arguments passed as '--<flag>'.
41 41 These take no parameters, unlike regular key-value arguments.
42 42 They are typically used for setting boolean flags, or enabling
43 43 modes that involve setting multiple options together.
44 44 """.strip() # trim newlines of front and back
45 45
46 46 alias_description = """
47 47 These are commonly set parameters, given abbreviated aliases for convenience.
48 48 They are set in the same `name=value` way as class parameters, where
49 49 <name> is replaced by the real parameter for which it is an alias.
50 50 """.strip() # trim newlines of front and back
51 51
52 52 keyvalue_description = """
53 53 Parameters are set from command-line arguments of the form:
54 54 `Class.trait=value`. Parameters will *never* be prefixed with '-'.
55 55 This line is evaluated in Python, so simple expressions are allowed, e.g.
56 56 `C.a='range(3)'` For setting C.a=[0,1,2]
57 57 """.strip() # trim newlines of front and back
58 58
59 59 #-----------------------------------------------------------------------------
60 60 # Application class
61 61 #-----------------------------------------------------------------------------
62 62
63 63
64 64 class ApplicationError(Exception):
65 65 pass
66 66
67 67
68 68 class Application(SingletonConfigurable):
69 69 """A singleton application with full configuration support."""
70 70
71 71 # The name of the application, will usually match the name of the command
72 72 # line application
73 73 app_name = Unicode(u'application')
74 74
75 75 # The description of the application that is printed at the beginning
76 76 # of the help.
77 77 description = Unicode(u'This is an application.')
78 78 # default section descriptions
79 79 flag_description = Unicode(flag_description)
80 80 alias_description = Unicode(alias_description)
81 81 keyvalue_description = Unicode(keyvalue_description)
82 82
83 83
84 84 # A sequence of Configurable subclasses whose config=True attributes will
85 85 # be exposed at the command line.
86 86 classes = List([])
87 87
88 88 # The version string of this application.
89 89 version = Unicode(u'0.0')
90 90
91 91 # The log level for the application
92 92 log_level = Enum((0,10,20,30,40,50), default_value=logging.WARN,
93 93 config=True,
94 94 help="Set the log level (0,10,20,30,40,50).")
95 95
96 96 # the alias map for configurables
97 97 aliases = Dict(dict(log_level='Application.log_level'))
98 98
99 99 # flags for loading Configurables or store_const style flags
100 100 # flags are loaded from this dict by '--key' flags
101 101 # this must be a dict of two-tuples, the first element being the Config/dict
102 102 # and the second being the help string for the flag
103 103 flags = Dict()
104 104
105 105
106 106 def __init__(self, **kwargs):
107 107 SingletonConfigurable.__init__(self, **kwargs)
108 108 # Add my class to self.classes so my attributes appear in command line
109 109 # options.
110 110 self.classes.insert(0, self.__class__)
111 111
112 112 # ensure self.flags dict is valid
113 113 for key,value in self.flags.iteritems():
114 114 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
115 115 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
116 116 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
117 117 self.init_logging()
118 118
119 119 def _config_changed(self, name, old, new):
120 120 SingletonConfigurable._config_changed(self, name, old, new)
121 121 self.log.debug('Config changed:')
122 122 self.log.debug(repr(new))
123 123
124 124 def init_logging(self):
125 125 """Start logging for this application.
126 126
127 127 The default is to log to stdout using a StreaHandler. The log level
128 128 starts at loggin.WARN, but this can be adjusted by setting the
129 129 ``log_level`` attribute.
130 130 """
131 131 self.log = logging.getLogger(self.__class__.__name__)
132 132 self.log.setLevel(self.log_level)
133 133 self._log_handler = logging.StreamHandler()
134 134 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
135 135 self._log_handler.setFormatter(self._log_formatter)
136 136 self.log.addHandler(self._log_handler)
137 137
138 138 def _log_level_changed(self, name, old, new):
139 139 """Adjust the log level when log_level is set."""
140 140 self.log.setLevel(new)
141 141
142 142 def print_alias_help(self):
143 143 """print the alias part of the help"""
144 144 if not self.aliases:
145 145 return
146 146
147 147 print "Aliases"
148 148 print "-------"
149 149 print self.alias_description
150 150 print
151 151
152 152 classdict = {}
153 153 for c in self.classes:
154 154 classdict[c.__name__] = c
155 155
156 156 for alias, longname in self.aliases.iteritems():
157 157 classname, traitname = longname.split('.',1)
158 158 cls = classdict[classname]
159 159
160 160 trait = cls.class_traits(config=True)[traitname]
161 161 help = trait.get_metadata('help')
162 162 print alias, "(%s)"%longname, ':', trait.__class__.__name__
163 163 if help:
164 164 print indent(help)
165 165 print
166 166
167 167 def print_flag_help(self):
168 168 """print the flag part of the help"""
169 169 if not self.flags:
170 170 return
171 171
172 172 print "Flags"
173 173 print "-----"
174 174 print self.flag_description
175 175 print
176 176
177 177 for m, (cfg,help) in self.flags.iteritems():
178 178 print '--'+m
179 179 print indent(help)
180 180 print
181 181
182 182 def print_help(self):
183 183 """Print the help for each Configurable class in self.classes."""
184 184 self.print_flag_help()
185 185 self.print_alias_help()
186 186 if self.classes:
187 187 print "Class parameters"
188 188 print "----------------"
189 189 print self.keyvalue_description
190 190 print
191 191
192 192 for cls in self.classes:
193 193 cls.class_print_help()
194 194 print
195 195
196 196 def print_description(self):
197 197 """Print the application description."""
198 198 print self.description
199 199 print
200 200
201 201 def print_version(self):
202 202 """Print the version string."""
203 203 print self.version
204 204
205 205 def update_config(self, config):
206 206 """Fire the traits events when the config is updated."""
207 207 # Save a copy of the current config.
208 208 newconfig = deepcopy(self.config)
209 209 # Merge the new config into the current one.
210 210 newconfig._merge(config)
211 211 # Save the combined config as self.config, which triggers the traits
212 212 # events.
213 self.config = config
213 self.config = newconfig
214 214
215 215 def parse_command_line(self, argv=None):
216 216 """Parse the command line arguments."""
217 217 argv = sys.argv[1:] if argv is None else argv
218 218
219 219 if '-h' in argv or '--help' in argv:
220 220 self.print_description()
221 221 self.print_help()
222 222 self.exit(1)
223 223
224 224 if '--version' in argv:
225 225 self.print_version()
226 226 self.exit(1)
227 227
228 228 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
229 229 flags=self.flags)
230 230 config = loader.load_config()
231 231 self.update_config(config)
232 232
233 233 def load_config_file(self, filename, path=None):
234 234 """Load a .py based config file by filename and path."""
235 235 loader = PyFileConfigLoader(filename, path=path)
236 236 config = loader.load_config()
237 237 self.update_config(config)
238 238
239 239 def exit(self, exit_status=0):
240 240 self.log.debug("Exiting application: %s" % self.name)
241 241 sys.exit(exit_status)
General Comments 0
You need to be logged in to leave comments. Login now