##// END OF EJS Templates
don't crash on bad config files
MinRK -
Show More
@@ -1,421 +1,426 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 * Min RK
8 * Min RK
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import logging
22 import logging
23 import os
23 import os
24 import re
24 import re
25 import sys
25 import sys
26 from copy import deepcopy
26 from copy import deepcopy
27
27
28 from IPython.config.configurable import SingletonConfigurable
28 from IPython.config.configurable import SingletonConfigurable
29 from IPython.config.loader import (
29 from IPython.config.loader import (
30 KeyValueConfigLoader, PyFileConfigLoader, Config, ArgumentError
30 KeyValueConfigLoader, PyFileConfigLoader, Config, ArgumentError
31 )
31 )
32
32
33 from IPython.utils.traitlets import (
33 from IPython.utils.traitlets import (
34 Unicode, List, Int, Enum, Dict, Instance, TraitError
34 Unicode, List, Int, Enum, Dict, Instance, TraitError
35 )
35 )
36 from IPython.utils.importstring import import_item
36 from IPython.utils.importstring import import_item
37 from IPython.utils.text import indent, wrap_paragraphs, dedent
37 from IPython.utils.text import indent, wrap_paragraphs, dedent
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # function for re-wrapping a helpstring
40 # function for re-wrapping a helpstring
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Descriptions for the various sections
44 # Descriptions for the various sections
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 # merge flags&aliases into options
47 # merge flags&aliases into options
48 option_description = """
48 option_description = """
49 IPython command-line arguments are passed as '--<flag>', or '--<name>=<value>'.
49 IPython command-line arguments are passed as '--<flag>', or '--<name>=<value>'.
50
50
51 Arguments that take values are actually convenience aliases to full
51 Arguments that take values are actually convenience aliases to full
52 Configurables, whose aliases are listed on the help line. For more information
52 Configurables, whose aliases are listed on the help line. For more information
53 on full configurables, see '--help-all'.
53 on full configurables, see '--help-all'.
54 """.strip() # trim newlines of front and back
54 """.strip() # trim newlines of front and back
55
55
56 keyvalue_description = """
56 keyvalue_description = """
57 Parameters are set from command-line arguments of the form:
57 Parameters are set from command-line arguments of the form:
58 `--Class.trait=value`.
58 `--Class.trait=value`.
59 This line is evaluated in Python, so simple expressions are allowed, e.g.::
59 This line is evaluated in Python, so simple expressions are allowed, e.g.::
60 `--C.a='range(3)'` For setting C.a=[0,1,2].
60 `--C.a='range(3)'` For setting C.a=[0,1,2].
61 """.strip() # trim newlines of front and back
61 """.strip() # trim newlines of front and back
62
62
63 subcommand_description = """
63 subcommand_description = """
64 Subcommands are launched as `{app} cmd [args]`. For information on using
64 Subcommands are launched as `{app} cmd [args]`. For information on using
65 subcommand 'cmd', do: `{app} cmd -h`.
65 subcommand 'cmd', do: `{app} cmd -h`.
66 """.strip().format(app=os.path.basename(sys.argv[0]))
66 """.strip().format(app=os.path.basename(sys.argv[0]))
67 # get running program name
67 # get running program name
68
68
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70 # Application class
70 # Application class
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72
72
73
73
74 class ApplicationError(Exception):
74 class ApplicationError(Exception):
75 pass
75 pass
76
76
77
77
78 class Application(SingletonConfigurable):
78 class Application(SingletonConfigurable):
79 """A singleton application with full configuration support."""
79 """A singleton application with full configuration support."""
80
80
81 # The name of the application, will usually match the name of the command
81 # The name of the application, will usually match the name of the command
82 # line application
82 # line application
83 name = Unicode(u'application')
83 name = Unicode(u'application')
84
84
85 # The description of the application that is printed at the beginning
85 # The description of the application that is printed at the beginning
86 # of the help.
86 # of the help.
87 description = Unicode(u'This is an application.')
87 description = Unicode(u'This is an application.')
88 # default section descriptions
88 # default section descriptions
89 option_description = Unicode(option_description)
89 option_description = Unicode(option_description)
90 keyvalue_description = Unicode(keyvalue_description)
90 keyvalue_description = Unicode(keyvalue_description)
91 subcommand_description = Unicode(subcommand_description)
91 subcommand_description = Unicode(subcommand_description)
92
92
93 # The usage and example string that goes at the end of the help string.
93 # The usage and example string that goes at the end of the help string.
94 examples = Unicode()
94 examples = Unicode()
95
95
96 # A sequence of Configurable subclasses whose config=True attributes will
96 # A sequence of Configurable subclasses whose config=True attributes will
97 # be exposed at the command line.
97 # be exposed at the command line.
98 classes = List([])
98 classes = List([])
99
99
100 # The version string of this application.
100 # The version string of this application.
101 version = Unicode(u'0.0')
101 version = Unicode(u'0.0')
102
102
103 # The log level for the application
103 # The log level for the application
104 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
104 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
105 default_value=logging.WARN,
105 default_value=logging.WARN,
106 config=True,
106 config=True,
107 help="Set the log level by value or name.")
107 help="Set the log level by value or name.")
108 def _log_level_changed(self, name, old, new):
108 def _log_level_changed(self, name, old, new):
109 """Adjust the log level when log_level is set."""
109 """Adjust the log level when log_level is set."""
110 if isinstance(new, basestring):
110 if isinstance(new, basestring):
111 new = getattr(logging, new)
111 new = getattr(logging, new)
112 self.log_level = new
112 self.log_level = new
113 self.log.setLevel(new)
113 self.log.setLevel(new)
114
114
115 # the alias map for configurables
115 # the alias map for configurables
116 aliases = Dict({'log-level' : 'Application.log_level'})
116 aliases = Dict({'log-level' : 'Application.log_level'})
117
117
118 # flags for loading Configurables or store_const style flags
118 # flags for loading Configurables or store_const style flags
119 # flags are loaded from this dict by '--key' flags
119 # flags are loaded from this dict by '--key' flags
120 # this must be a dict of two-tuples, the first element being the Config/dict
120 # this must be a dict of two-tuples, the first element being the Config/dict
121 # and the second being the help string for the flag
121 # and the second being the help string for the flag
122 flags = Dict()
122 flags = Dict()
123 def _flags_changed(self, name, old, new):
123 def _flags_changed(self, name, old, new):
124 """ensure flags dict is valid"""
124 """ensure flags dict is valid"""
125 for key,value in new.iteritems():
125 for key,value in new.iteritems():
126 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
126 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
127 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
127 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
128 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
128 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
129
129
130
130
131 # subcommands for launching other applications
131 # subcommands for launching other applications
132 # if this is not empty, this will be a parent Application
132 # if this is not empty, this will be a parent Application
133 # this must be a dict of two-tuples,
133 # this must be a dict of two-tuples,
134 # the first element being the application class/import string
134 # the first element being the application class/import string
135 # and the second being the help string for the subcommand
135 # and the second being the help string for the subcommand
136 subcommands = Dict()
136 subcommands = Dict()
137 # parse_command_line will initialize a subapp, if requested
137 # parse_command_line will initialize a subapp, if requested
138 subapp = Instance('IPython.config.application.Application', allow_none=True)
138 subapp = Instance('IPython.config.application.Application', allow_none=True)
139
139
140 # extra command-line arguments that don't set config values
140 # extra command-line arguments that don't set config values
141 extra_args = List(Unicode)
141 extra_args = List(Unicode)
142
142
143
143
144 def __init__(self, **kwargs):
144 def __init__(self, **kwargs):
145 SingletonConfigurable.__init__(self, **kwargs)
145 SingletonConfigurable.__init__(self, **kwargs)
146 # Add my class to self.classes so my attributes appear in command line
146 # Add my class to self.classes so my attributes appear in command line
147 # options.
147 # options.
148 self.classes.insert(0, self.__class__)
148 self.classes.insert(0, self.__class__)
149
149
150 self.init_logging()
150 self.init_logging()
151
151
152 def _config_changed(self, name, old, new):
152 def _config_changed(self, name, old, new):
153 SingletonConfigurable._config_changed(self, name, old, new)
153 SingletonConfigurable._config_changed(self, name, old, new)
154 self.log.debug('Config changed:')
154 self.log.debug('Config changed:')
155 self.log.debug(repr(new))
155 self.log.debug(repr(new))
156
156
157 def init_logging(self):
157 def init_logging(self):
158 """Start logging for this application.
158 """Start logging for this application.
159
159
160 The default is to log to stdout using a StreaHandler. The log level
160 The default is to log to stdout using a StreaHandler. The log level
161 starts at loggin.WARN, but this can be adjusted by setting the
161 starts at loggin.WARN, but this can be adjusted by setting the
162 ``log_level`` attribute.
162 ``log_level`` attribute.
163 """
163 """
164 self.log = logging.getLogger(self.__class__.__name__)
164 self.log = logging.getLogger(self.__class__.__name__)
165 self.log.setLevel(self.log_level)
165 self.log.setLevel(self.log_level)
166 if sys.executable.endswith('pythonw.exe'):
166 if sys.executable.endswith('pythonw.exe'):
167 # this should really go to a file, but file-logging is only
167 # this should really go to a file, but file-logging is only
168 # hooked up in parallel applications
168 # hooked up in parallel applications
169 self._log_handler = logging.StreamHandler(open(os.devnull, 'w'))
169 self._log_handler = logging.StreamHandler(open(os.devnull, 'w'))
170 else:
170 else:
171 self._log_handler = logging.StreamHandler()
171 self._log_handler = logging.StreamHandler()
172 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
172 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
173 self._log_handler.setFormatter(self._log_formatter)
173 self._log_handler.setFormatter(self._log_formatter)
174 self.log.addHandler(self._log_handler)
174 self.log.addHandler(self._log_handler)
175
175
176 def initialize(self, argv=None):
176 def initialize(self, argv=None):
177 """Do the basic steps to configure me.
177 """Do the basic steps to configure me.
178
178
179 Override in subclasses.
179 Override in subclasses.
180 """
180 """
181 self.parse_command_line(argv)
181 self.parse_command_line(argv)
182
182
183
183
184 def start(self):
184 def start(self):
185 """Start the app mainloop.
185 """Start the app mainloop.
186
186
187 Override in subclasses.
187 Override in subclasses.
188 """
188 """
189 if self.subapp is not None:
189 if self.subapp is not None:
190 return self.subapp.start()
190 return self.subapp.start()
191
191
192 def print_alias_help(self):
192 def print_alias_help(self):
193 """Print the alias part of the help."""
193 """Print the alias part of the help."""
194 if not self.aliases:
194 if not self.aliases:
195 return
195 return
196
196
197 lines = []
197 lines = []
198 classdict = {}
198 classdict = {}
199 for cls in self.classes:
199 for cls in self.classes:
200 # include all parents (up to, but excluding Configurable) in available names
200 # include all parents (up to, but excluding Configurable) in available names
201 for c in cls.mro()[:-3]:
201 for c in cls.mro()[:-3]:
202 classdict[c.__name__] = c
202 classdict[c.__name__] = c
203
203
204 for alias, longname in self.aliases.iteritems():
204 for alias, longname in self.aliases.iteritems():
205 classname, traitname = longname.split('.',1)
205 classname, traitname = longname.split('.',1)
206 cls = classdict[classname]
206 cls = classdict[classname]
207
207
208 trait = cls.class_traits(config=True)[traitname]
208 trait = cls.class_traits(config=True)[traitname]
209 help = cls.class_get_trait_help(trait).splitlines()
209 help = cls.class_get_trait_help(trait).splitlines()
210 # reformat first line
210 # reformat first line
211 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
211 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
212 lines.extend(help)
212 lines.extend(help)
213 # lines.append('')
213 # lines.append('')
214 print os.linesep.join(lines)
214 print os.linesep.join(lines)
215
215
216 def print_flag_help(self):
216 def print_flag_help(self):
217 """Print the flag part of the help."""
217 """Print the flag part of the help."""
218 if not self.flags:
218 if not self.flags:
219 return
219 return
220
220
221 lines = []
221 lines = []
222 for m, (cfg,help) in self.flags.iteritems():
222 for m, (cfg,help) in self.flags.iteritems():
223 lines.append('--'+m)
223 lines.append('--'+m)
224 lines.append(indent(dedent(help.strip())))
224 lines.append(indent(dedent(help.strip())))
225 # lines.append('')
225 # lines.append('')
226 print os.linesep.join(lines)
226 print os.linesep.join(lines)
227
227
228 def print_options(self):
228 def print_options(self):
229 if not self.flags and not self.aliases:
229 if not self.flags and not self.aliases:
230 return
230 return
231 lines = ['Options']
231 lines = ['Options']
232 lines.append('-'*len(lines[0]))
232 lines.append('-'*len(lines[0]))
233 lines.append('')
233 lines.append('')
234 for p in wrap_paragraphs(self.option_description):
234 for p in wrap_paragraphs(self.option_description):
235 lines.append(p)
235 lines.append(p)
236 lines.append('')
236 lines.append('')
237 print os.linesep.join(lines)
237 print os.linesep.join(lines)
238 self.print_flag_help()
238 self.print_flag_help()
239 self.print_alias_help()
239 self.print_alias_help()
240 print
240 print
241
241
242 def print_subcommands(self):
242 def print_subcommands(self):
243 """Print the subcommand part of the help."""
243 """Print the subcommand part of the help."""
244 if not self.subcommands:
244 if not self.subcommands:
245 return
245 return
246
246
247 lines = ["Subcommands"]
247 lines = ["Subcommands"]
248 lines.append('-'*len(lines[0]))
248 lines.append('-'*len(lines[0]))
249 lines.append('')
249 lines.append('')
250 for p in wrap_paragraphs(self.subcommand_description):
250 for p in wrap_paragraphs(self.subcommand_description):
251 lines.append(p)
251 lines.append(p)
252 lines.append('')
252 lines.append('')
253 for subc, (cls, help) in self.subcommands.iteritems():
253 for subc, (cls, help) in self.subcommands.iteritems():
254 lines.append(subc)
254 lines.append(subc)
255 if help:
255 if help:
256 lines.append(indent(dedent(help.strip())))
256 lines.append(indent(dedent(help.strip())))
257 lines.append('')
257 lines.append('')
258 print os.linesep.join(lines)
258 print os.linesep.join(lines)
259
259
260 def print_help(self, classes=False):
260 def print_help(self, classes=False):
261 """Print the help for each Configurable class in self.classes.
261 """Print the help for each Configurable class in self.classes.
262
262
263 If classes=False (the default), only flags and aliases are printed.
263 If classes=False (the default), only flags and aliases are printed.
264 """
264 """
265 self.print_subcommands()
265 self.print_subcommands()
266 self.print_options()
266 self.print_options()
267
267
268 if classes:
268 if classes:
269 if self.classes:
269 if self.classes:
270 print "Class parameters"
270 print "Class parameters"
271 print "----------------"
271 print "----------------"
272 print
272 print
273 for p in wrap_paragraphs(self.keyvalue_description):
273 for p in wrap_paragraphs(self.keyvalue_description):
274 print p
274 print p
275 print
275 print
276
276
277 for cls in self.classes:
277 for cls in self.classes:
278 cls.class_print_help()
278 cls.class_print_help()
279 print
279 print
280 else:
280 else:
281 print "To see all available configurables, use `--help-all`"
281 print "To see all available configurables, use `--help-all`"
282 print
282 print
283
283
284 def print_description(self):
284 def print_description(self):
285 """Print the application description."""
285 """Print the application description."""
286 for p in wrap_paragraphs(self.description):
286 for p in wrap_paragraphs(self.description):
287 print p
287 print p
288 print
288 print
289
289
290 def print_examples(self):
290 def print_examples(self):
291 """Print usage and examples.
291 """Print usage and examples.
292
292
293 This usage string goes at the end of the command line help string
293 This usage string goes at the end of the command line help string
294 and should contain examples of the application's usage.
294 and should contain examples of the application's usage.
295 """
295 """
296 if self.examples:
296 if self.examples:
297 print "Examples"
297 print "Examples"
298 print "--------"
298 print "--------"
299 print
299 print
300 print indent(dedent(self.examples.strip()))
300 print indent(dedent(self.examples.strip()))
301 print
301 print
302
302
303 def print_version(self):
303 def print_version(self):
304 """Print the version string."""
304 """Print the version string."""
305 print self.version
305 print self.version
306
306
307 def update_config(self, config):
307 def update_config(self, config):
308 """Fire the traits events when the config is updated."""
308 """Fire the traits events when the config is updated."""
309 # Save a copy of the current config.
309 # Save a copy of the current config.
310 newconfig = deepcopy(self.config)
310 newconfig = deepcopy(self.config)
311 # Merge the new config into the current one.
311 # Merge the new config into the current one.
312 newconfig._merge(config)
312 newconfig._merge(config)
313 # Save the combined config as self.config, which triggers the traits
313 # Save the combined config as self.config, which triggers the traits
314 # events.
314 # events.
315 self.config = newconfig
315 self.config = newconfig
316
316
317 def initialize_subcommand(self, subc, argv=None):
317 def initialize_subcommand(self, subc, argv=None):
318 """Initialize a subcommand with argv."""
318 """Initialize a subcommand with argv."""
319 subapp,help = self.subcommands.get(subc)
319 subapp,help = self.subcommands.get(subc)
320
320
321 if isinstance(subapp, basestring):
321 if isinstance(subapp, basestring):
322 subapp = import_item(subapp)
322 subapp = import_item(subapp)
323
323
324 # clear existing instances
324 # clear existing instances
325 self.__class__.clear_instance()
325 self.__class__.clear_instance()
326 # instantiate
326 # instantiate
327 self.subapp = subapp.instance()
327 self.subapp = subapp.instance()
328 # and initialize subapp
328 # and initialize subapp
329 self.subapp.initialize(argv)
329 self.subapp.initialize(argv)
330
330
331 def parse_command_line(self, argv=None):
331 def parse_command_line(self, argv=None):
332 """Parse the command line arguments."""
332 """Parse the command line arguments."""
333 argv = sys.argv[1:] if argv is None else argv
333 argv = sys.argv[1:] if argv is None else argv
334
334
335 if self.subcommands and len(argv) > 0:
335 if self.subcommands and len(argv) > 0:
336 # we have subcommands, and one may have been specified
336 # we have subcommands, and one may have been specified
337 subc, subargv = argv[0], argv[1:]
337 subc, subargv = argv[0], argv[1:]
338 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
338 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
339 # it's a subcommand, and *not* a flag or class parameter
339 # it's a subcommand, and *not* a flag or class parameter
340 return self.initialize_subcommand(subc, subargv)
340 return self.initialize_subcommand(subc, subargv)
341
341
342 if '-h' in argv or '--help' in argv or '--help-all' in argv:
342 if '-h' in argv or '--help' in argv or '--help-all' in argv:
343 self.print_description()
343 self.print_description()
344 self.print_help('--help-all' in argv)
344 self.print_help('--help-all' in argv)
345 self.print_examples()
345 self.print_examples()
346 self.exit(0)
346 self.exit(0)
347
347
348 if '--version' in argv:
348 if '--version' in argv:
349 self.print_version()
349 self.print_version()
350 self.exit(0)
350 self.exit(0)
351
351
352 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
352 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
353 flags=self.flags)
353 flags=self.flags)
354 try:
354 try:
355 config = loader.load_config()
355 config = loader.load_config()
356 self.update_config(config)
356 self.update_config(config)
357 except (TraitError, ArgumentError) as e:
357 except (TraitError, ArgumentError) as e:
358 self.print_description()
358 self.print_description()
359 self.print_help()
359 self.print_help()
360 self.print_examples()
360 self.print_examples()
361 self.log.fatal(str(e))
361 self.log.fatal(str(e))
362 self.exit(1)
362 self.exit(1)
363 # store unparsed args in extra_args
363 # store unparsed args in extra_args
364 self.extra_args = loader.extra_args
364 self.extra_args = loader.extra_args
365
365
366 def load_config_file(self, filename, path=None):
366 def load_config_file(self, filename, path=None):
367 """Load a .py based config file by filename and path."""
367 """Load a .py based config file by filename and path."""
368 loader = PyFileConfigLoader(filename, path=path)
368 loader = PyFileConfigLoader(filename, path=path)
369 config = loader.load_config()
369 try:
370 self.update_config(config)
370 config = loader.load_config()
371 except Exception:
372 self.log.error("Exception while loading config file %s [path=%s]"%
373 (filename, path), exc_info=True)
374 else:
375 self.update_config(config)
371
376
372 def generate_config_file(self):
377 def generate_config_file(self):
373 """generate default config file from Configurables"""
378 """generate default config file from Configurables"""
374 lines = ["# Configuration file for %s."%self.name]
379 lines = ["# Configuration file for %s."%self.name]
375 lines.append('')
380 lines.append('')
376 lines.append('c = get_config()')
381 lines.append('c = get_config()')
377 lines.append('')
382 lines.append('')
378 for cls in self.classes:
383 for cls in self.classes:
379 lines.append(cls.class_config_section())
384 lines.append(cls.class_config_section())
380 return '\n'.join(lines)
385 return '\n'.join(lines)
381
386
382 def exit(self, exit_status=0):
387 def exit(self, exit_status=0):
383 self.log.debug("Exiting application: %s" % self.name)
388 self.log.debug("Exiting application: %s" % self.name)
384 sys.exit(exit_status)
389 sys.exit(exit_status)
385
390
386 #-----------------------------------------------------------------------------
391 #-----------------------------------------------------------------------------
387 # utility functions, for convenience
392 # utility functions, for convenience
388 #-----------------------------------------------------------------------------
393 #-----------------------------------------------------------------------------
389
394
390 def boolean_flag(name, configurable, set_help='', unset_help=''):
395 def boolean_flag(name, configurable, set_help='', unset_help=''):
391 """Helper for building basic --trait, --no-trait flags.
396 """Helper for building basic --trait, --no-trait flags.
392
397
393 Parameters
398 Parameters
394 ----------
399 ----------
395
400
396 name : str
401 name : str
397 The name of the flag.
402 The name of the flag.
398 configurable : str
403 configurable : str
399 The 'Class.trait' string of the trait to be set/unset with the flag
404 The 'Class.trait' string of the trait to be set/unset with the flag
400 set_help : unicode
405 set_help : unicode
401 help string for --name flag
406 help string for --name flag
402 unset_help : unicode
407 unset_help : unicode
403 help string for --no-name flag
408 help string for --no-name flag
404
409
405 Returns
410 Returns
406 -------
411 -------
407
412
408 cfg : dict
413 cfg : dict
409 A dict with two keys: 'name', and 'no-name', for setting and unsetting
414 A dict with two keys: 'name', and 'no-name', for setting and unsetting
410 the trait, respectively.
415 the trait, respectively.
411 """
416 """
412 # default helpstrings
417 # default helpstrings
413 set_help = set_help or "set %s=True"%configurable
418 set_help = set_help or "set %s=True"%configurable
414 unset_help = unset_help or "set %s=False"%configurable
419 unset_help = unset_help or "set %s=False"%configurable
415
420
416 cls,trait = configurable.split('.')
421 cls,trait = configurable.split('.')
417
422
418 setter = {cls : {trait : True}}
423 setter = {cls : {trait : True}}
419 unsetter = {cls : {trait : False}}
424 unsetter = {cls : {trait : False}}
420 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
425 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
421
426
General Comments 0
You need to be logged in to leave comments. Login now