##// END OF EJS Templates
add single '-' prefix for length 1 aliases and flags to help output
MinRK -
Show More
@@ -1,431 +1,434 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 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError
30 KVArgParseConfigLoader, 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 # Ensure my class is in self.classes, so my attributes appear in command line
146 # Ensure my class is in self.classes, so my attributes appear in command line
147 # options and config files.
147 # options and config files.
148 if self.__class__ not in self.classes:
148 if self.__class__ not in self.classes:
149 self.classes.insert(0, self.__class__)
149 self.classes.insert(0, self.__class__)
150
150
151 self.init_logging()
151 self.init_logging()
152
152
153 def _config_changed(self, name, old, new):
153 def _config_changed(self, name, old, new):
154 SingletonConfigurable._config_changed(self, name, old, new)
154 SingletonConfigurable._config_changed(self, name, old, new)
155 self.log.debug('Config changed:')
155 self.log.debug('Config changed:')
156 self.log.debug(repr(new))
156 self.log.debug(repr(new))
157
157
158 def init_logging(self):
158 def init_logging(self):
159 """Start logging for this application.
159 """Start logging for this application.
160
160
161 The default is to log to stdout using a StreaHandler. The log level
161 The default is to log to stdout using a StreaHandler. The log level
162 starts at loggin.WARN, but this can be adjusted by setting the
162 starts at loggin.WARN, but this can be adjusted by setting the
163 ``log_level`` attribute.
163 ``log_level`` attribute.
164 """
164 """
165 self.log = logging.getLogger(self.__class__.__name__)
165 self.log = logging.getLogger(self.__class__.__name__)
166 self.log.setLevel(self.log_level)
166 self.log.setLevel(self.log_level)
167 if sys.executable.endswith('pythonw.exe'):
167 if sys.executable.endswith('pythonw.exe'):
168 # this should really go to a file, but file-logging is only
168 # this should really go to a file, but file-logging is only
169 # hooked up in parallel applications
169 # hooked up in parallel applications
170 self._log_handler = logging.StreamHandler(open(os.devnull, 'w'))
170 self._log_handler = logging.StreamHandler(open(os.devnull, 'w'))
171 else:
171 else:
172 self._log_handler = logging.StreamHandler()
172 self._log_handler = logging.StreamHandler()
173 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
173 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
174 self._log_handler.setFormatter(self._log_formatter)
174 self._log_handler.setFormatter(self._log_formatter)
175 self.log.addHandler(self._log_handler)
175 self.log.addHandler(self._log_handler)
176
176
177 def initialize(self, argv=None):
177 def initialize(self, argv=None):
178 """Do the basic steps to configure me.
178 """Do the basic steps to configure me.
179
179
180 Override in subclasses.
180 Override in subclasses.
181 """
181 """
182 self.parse_command_line(argv)
182 self.parse_command_line(argv)
183
183
184
184
185 def start(self):
185 def start(self):
186 """Start the app mainloop.
186 """Start the app mainloop.
187
187
188 Override in subclasses.
188 Override in subclasses.
189 """
189 """
190 if self.subapp is not None:
190 if self.subapp is not None:
191 return self.subapp.start()
191 return self.subapp.start()
192
192
193 def print_alias_help(self):
193 def print_alias_help(self):
194 """Print the alias part of the help."""
194 """Print the alias part of the help."""
195 if not self.aliases:
195 if not self.aliases:
196 return
196 return
197
197
198 lines = []
198 lines = []
199 classdict = {}
199 classdict = {}
200 for cls in self.classes:
200 for cls in self.classes:
201 # include all parents (up to, but excluding Configurable) in available names
201 # include all parents (up to, but excluding Configurable) in available names
202 for c in cls.mro()[:-3]:
202 for c in cls.mro()[:-3]:
203 classdict[c.__name__] = c
203 classdict[c.__name__] = c
204
204
205 for alias, longname in self.aliases.iteritems():
205 for alias, longname in self.aliases.iteritems():
206 classname, traitname = longname.split('.',1)
206 classname, traitname = longname.split('.',1)
207 cls = classdict[classname]
207 cls = classdict[classname]
208
208
209 trait = cls.class_traits(config=True)[traitname]
209 trait = cls.class_traits(config=True)[traitname]
210 help = cls.class_get_trait_help(trait).splitlines()
210 help = cls.class_get_trait_help(trait).splitlines()
211 # reformat first line
211 # reformat first line
212 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
212 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
213 if len(alias) == 1:
214 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
213 lines.extend(help)
215 lines.extend(help)
214 # lines.append('')
216 # lines.append('')
215 print os.linesep.join(lines)
217 print os.linesep.join(lines)
216
218
217 def print_flag_help(self):
219 def print_flag_help(self):
218 """Print the flag part of the help."""
220 """Print the flag part of the help."""
219 if not self.flags:
221 if not self.flags:
220 return
222 return
221
223
222 lines = []
224 lines = []
223 for m, (cfg,help) in self.flags.iteritems():
225 for m, (cfg,help) in self.flags.iteritems():
224 lines.append('--'+m)
226 prefix = '--' if len(m) > 1 else '-'
227 lines.append(prefix+m)
225 lines.append(indent(dedent(help.strip())))
228 lines.append(indent(dedent(help.strip())))
226 # lines.append('')
229 # lines.append('')
227 print os.linesep.join(lines)
230 print os.linesep.join(lines)
228
231
229 def print_options(self):
232 def print_options(self):
230 if not self.flags and not self.aliases:
233 if not self.flags and not self.aliases:
231 return
234 return
232 lines = ['Options']
235 lines = ['Options']
233 lines.append('-'*len(lines[0]))
236 lines.append('-'*len(lines[0]))
234 lines.append('')
237 lines.append('')
235 for p in wrap_paragraphs(self.option_description):
238 for p in wrap_paragraphs(self.option_description):
236 lines.append(p)
239 lines.append(p)
237 lines.append('')
240 lines.append('')
238 print os.linesep.join(lines)
241 print os.linesep.join(lines)
239 self.print_flag_help()
242 self.print_flag_help()
240 self.print_alias_help()
243 self.print_alias_help()
241 print
244 print
242
245
243 def print_subcommands(self):
246 def print_subcommands(self):
244 """Print the subcommand part of the help."""
247 """Print the subcommand part of the help."""
245 if not self.subcommands:
248 if not self.subcommands:
246 return
249 return
247
250
248 lines = ["Subcommands"]
251 lines = ["Subcommands"]
249 lines.append('-'*len(lines[0]))
252 lines.append('-'*len(lines[0]))
250 lines.append('')
253 lines.append('')
251 for p in wrap_paragraphs(self.subcommand_description):
254 for p in wrap_paragraphs(self.subcommand_description):
252 lines.append(p)
255 lines.append(p)
253 lines.append('')
256 lines.append('')
254 for subc, (cls, help) in self.subcommands.iteritems():
257 for subc, (cls, help) in self.subcommands.iteritems():
255 lines.append(subc)
258 lines.append(subc)
256 if help:
259 if help:
257 lines.append(indent(dedent(help.strip())))
260 lines.append(indent(dedent(help.strip())))
258 lines.append('')
261 lines.append('')
259 print os.linesep.join(lines)
262 print os.linesep.join(lines)
260
263
261 def print_help(self, classes=False):
264 def print_help(self, classes=False):
262 """Print the help for each Configurable class in self.classes.
265 """Print the help for each Configurable class in self.classes.
263
266
264 If classes=False (the default), only flags and aliases are printed.
267 If classes=False (the default), only flags and aliases are printed.
265 """
268 """
266 self.print_subcommands()
269 self.print_subcommands()
267 self.print_options()
270 self.print_options()
268
271
269 if classes:
272 if classes:
270 if self.classes:
273 if self.classes:
271 print "Class parameters"
274 print "Class parameters"
272 print "----------------"
275 print "----------------"
273 print
276 print
274 for p in wrap_paragraphs(self.keyvalue_description):
277 for p in wrap_paragraphs(self.keyvalue_description):
275 print p
278 print p
276 print
279 print
277
280
278 for cls in self.classes:
281 for cls in self.classes:
279 cls.class_print_help()
282 cls.class_print_help()
280 print
283 print
281 else:
284 else:
282 print "To see all available configurables, use `--help-all`"
285 print "To see all available configurables, use `--help-all`"
283 print
286 print
284
287
285 def print_description(self):
288 def print_description(self):
286 """Print the application description."""
289 """Print the application description."""
287 for p in wrap_paragraphs(self.description):
290 for p in wrap_paragraphs(self.description):
288 print p
291 print p
289 print
292 print
290
293
291 def print_examples(self):
294 def print_examples(self):
292 """Print usage and examples.
295 """Print usage and examples.
293
296
294 This usage string goes at the end of the command line help string
297 This usage string goes at the end of the command line help string
295 and should contain examples of the application's usage.
298 and should contain examples of the application's usage.
296 """
299 """
297 if self.examples:
300 if self.examples:
298 print "Examples"
301 print "Examples"
299 print "--------"
302 print "--------"
300 print
303 print
301 print indent(dedent(self.examples.strip()))
304 print indent(dedent(self.examples.strip()))
302 print
305 print
303
306
304 def print_version(self):
307 def print_version(self):
305 """Print the version string."""
308 """Print the version string."""
306 print self.version
309 print self.version
307
310
308 def update_config(self, config):
311 def update_config(self, config):
309 """Fire the traits events when the config is updated."""
312 """Fire the traits events when the config is updated."""
310 # Save a copy of the current config.
313 # Save a copy of the current config.
311 newconfig = deepcopy(self.config)
314 newconfig = deepcopy(self.config)
312 # Merge the new config into the current one.
315 # Merge the new config into the current one.
313 newconfig._merge(config)
316 newconfig._merge(config)
314 # Save the combined config as self.config, which triggers the traits
317 # Save the combined config as self.config, which triggers the traits
315 # events.
318 # events.
316 self.config = newconfig
319 self.config = newconfig
317
320
318 def initialize_subcommand(self, subc, argv=None):
321 def initialize_subcommand(self, subc, argv=None):
319 """Initialize a subcommand with argv."""
322 """Initialize a subcommand with argv."""
320 subapp,help = self.subcommands.get(subc)
323 subapp,help = self.subcommands.get(subc)
321
324
322 if isinstance(subapp, basestring):
325 if isinstance(subapp, basestring):
323 subapp = import_item(subapp)
326 subapp = import_item(subapp)
324
327
325 # clear existing instances
328 # clear existing instances
326 self.__class__.clear_instance()
329 self.__class__.clear_instance()
327 # instantiate
330 # instantiate
328 self.subapp = subapp.instance()
331 self.subapp = subapp.instance()
329 # and initialize subapp
332 # and initialize subapp
330 self.subapp.initialize(argv)
333 self.subapp.initialize(argv)
331
334
332 def parse_command_line(self, argv=None):
335 def parse_command_line(self, argv=None):
333 """Parse the command line arguments."""
336 """Parse the command line arguments."""
334 argv = sys.argv[1:] if argv is None else argv
337 argv = sys.argv[1:] if argv is None else argv
335
338
336 if self.subcommands and len(argv) > 0:
339 if self.subcommands and len(argv) > 0:
337 # we have subcommands, and one may have been specified
340 # we have subcommands, and one may have been specified
338 subc, subargv = argv[0], argv[1:]
341 subc, subargv = argv[0], argv[1:]
339 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
342 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
340 # it's a subcommand, and *not* a flag or class parameter
343 # it's a subcommand, and *not* a flag or class parameter
341 return self.initialize_subcommand(subc, subargv)
344 return self.initialize_subcommand(subc, subargv)
342
345
343 if '-h' in argv or '--help' in argv or '--help-all' in argv:
346 if '-h' in argv or '--help' in argv or '--help-all' in argv:
344 self.print_description()
347 self.print_description()
345 self.print_help('--help-all' in argv)
348 self.print_help('--help-all' in argv)
346 self.print_examples()
349 self.print_examples()
347 self.exit(0)
350 self.exit(0)
348
351
349 if '--version' in argv:
352 if '--version' in argv:
350 self.print_version()
353 self.print_version()
351 self.exit(0)
354 self.exit(0)
352
355
353 loader = KVArgParseConfigLoader(argv=argv, aliases=self.aliases,
356 loader = KVArgParseConfigLoader(argv=argv, aliases=self.aliases,
354 flags=self.flags)
357 flags=self.flags)
355 try:
358 try:
356 config = loader.load_config()
359 config = loader.load_config()
357 self.update_config(config)
360 self.update_config(config)
358 except (TraitError, ArgumentError) as e:
361 except (TraitError, ArgumentError) as e:
359 self.print_description()
362 self.print_description()
360 self.print_help()
363 self.print_help()
361 self.print_examples()
364 self.print_examples()
362 self.log.fatal(str(e))
365 self.log.fatal(str(e))
363 self.exit(1)
366 self.exit(1)
364 # store unparsed args in extra_args
367 # store unparsed args in extra_args
365 self.extra_args = loader.extra_args
368 self.extra_args = loader.extra_args
366
369
367 def load_config_file(self, filename, path=None):
370 def load_config_file(self, filename, path=None):
368 """Load a .py based config file by filename and path."""
371 """Load a .py based config file by filename and path."""
369 loader = PyFileConfigLoader(filename, path=path)
372 loader = PyFileConfigLoader(filename, path=path)
370 try:
373 try:
371 config = loader.load_config()
374 config = loader.load_config()
372 except IOError:
375 except IOError:
373 # problem with the file (probably doesn't exist), raise
376 # problem with the file (probably doesn't exist), raise
374 raise
377 raise
375 except Exception:
378 except Exception:
376 # problem while running the file
379 # problem while running the file
377 self.log.error("Exception while loading config file %s [path=%s]"%
380 self.log.error("Exception while loading config file %s [path=%s]"%
378 (filename, path), exc_info=True)
381 (filename, path), exc_info=True)
379 else:
382 else:
380 self.update_config(config)
383 self.update_config(config)
381
384
382 def generate_config_file(self):
385 def generate_config_file(self):
383 """generate default config file from Configurables"""
386 """generate default config file from Configurables"""
384 lines = ["# Configuration file for %s."%self.name]
387 lines = ["# Configuration file for %s."%self.name]
385 lines.append('')
388 lines.append('')
386 lines.append('c = get_config()')
389 lines.append('c = get_config()')
387 lines.append('')
390 lines.append('')
388 for cls in self.classes:
391 for cls in self.classes:
389 lines.append(cls.class_config_section())
392 lines.append(cls.class_config_section())
390 return '\n'.join(lines)
393 return '\n'.join(lines)
391
394
392 def exit(self, exit_status=0):
395 def exit(self, exit_status=0):
393 self.log.debug("Exiting application: %s" % self.name)
396 self.log.debug("Exiting application: %s" % self.name)
394 sys.exit(exit_status)
397 sys.exit(exit_status)
395
398
396 #-----------------------------------------------------------------------------
399 #-----------------------------------------------------------------------------
397 # utility functions, for convenience
400 # utility functions, for convenience
398 #-----------------------------------------------------------------------------
401 #-----------------------------------------------------------------------------
399
402
400 def boolean_flag(name, configurable, set_help='', unset_help=''):
403 def boolean_flag(name, configurable, set_help='', unset_help=''):
401 """Helper for building basic --trait, --no-trait flags.
404 """Helper for building basic --trait, --no-trait flags.
402
405
403 Parameters
406 Parameters
404 ----------
407 ----------
405
408
406 name : str
409 name : str
407 The name of the flag.
410 The name of the flag.
408 configurable : str
411 configurable : str
409 The 'Class.trait' string of the trait to be set/unset with the flag
412 The 'Class.trait' string of the trait to be set/unset with the flag
410 set_help : unicode
413 set_help : unicode
411 help string for --name flag
414 help string for --name flag
412 unset_help : unicode
415 unset_help : unicode
413 help string for --no-name flag
416 help string for --no-name flag
414
417
415 Returns
418 Returns
416 -------
419 -------
417
420
418 cfg : dict
421 cfg : dict
419 A dict with two keys: 'name', and 'no-name', for setting and unsetting
422 A dict with two keys: 'name', and 'no-name', for setting and unsetting
420 the trait, respectively.
423 the trait, respectively.
421 """
424 """
422 # default helpstrings
425 # default helpstrings
423 set_help = set_help or "set %s=True"%configurable
426 set_help = set_help or "set %s=True"%configurable
424 unset_help = unset_help or "set %s=False"%configurable
427 unset_help = unset_help or "set %s=False"%configurable
425
428
426 cls,trait = configurable.split('.')
429 cls,trait = configurable.split('.')
427
430
428 setter = {cls : {trait : True}}
431 setter = {cls : {trait : True}}
429 unsetter = {cls : {trait : False}}
432 unsetter = {cls : {trait : False}}
430 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
433 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
431
434
General Comments 0
You need to be logged in to leave comments. Login now