##// END OF EJS Templates
Work on the config system....
Brian Granger -
Show More
@@ -40,6 +40,7 b' class ConfigLoaderError(ConfigError):'
40 40 #-----------------------------------------------------------------------------
41 41 # Argparse fix
42 42 #-----------------------------------------------------------------------------
43
43 44 # Unfortunately argparse by default prints help messages to stderr instead of
44 45 # stdout. This makes it annoying to capture long help screens at the command
45 46 # line, since one must know how to pipe stderr, which many users don't know how
@@ -200,10 +201,13 b' class ConfigLoader(object):'
200 201 self.config = Config()
201 202
202 203 def load_config(self):
203 """Load a config from somewhere, return a Struct.
204 """Load a config from somewhere, return a :class:`Config` instance.
204 205
205 206 Usually, this will cause self.config to be set and then returned.
207 However, in most cases, :meth:`ConfigLoader.clear` should be called
208 to erase any previous state.
206 209 """
210 self.clear()
207 211 return self.config
208 212
209 213
@@ -242,6 +246,7 b' class PyFileConfigLoader(FileConfigLoader):'
242 246
243 247 def load_config(self):
244 248 """Load the config from a file and return it as a Struct."""
249 self.clear()
245 250 self._find_file()
246 251 self._read_file_as_dict()
247 252 self._convert_to_config()
@@ -292,20 +297,10 b' class CommandLineConfigLoader(ConfigLoader):'
292 297 """
293 298
294 299
295 class __NoConfigDefault(object): pass
296 NoConfigDefault = __NoConfigDefault()
297
298
299 300 class ArgParseConfigLoader(CommandLineConfigLoader):
300 #: Global default for arguments (see argparse docs for details)
301 argument_default = NoConfigDefault
302
303 def __init__(self, argv=None, arguments=(), *args, **kw):
304 """Create a config loader for use with argparse.
305 301
306 With the exception of ``argv`` and ``arguments``, other args and kwargs
307 arguments here are passed onto the constructor of
308 :class:`argparse.ArgumentParser`.
302 def __init__(self, argv=None, arguments=(), *parser_args, **parser_kw):
303 """Create a config loader for use with argparse.
309 304
310 305 Parameters
311 306 ----------
@@ -315,18 +310,27 b' class ArgParseConfigLoader(CommandLineConfigLoader):'
315 310 sys.argv[1:] is used.
316 311
317 312 arguments : optional, tuple
318 Description of valid command-line arguments, to be called in sequence
319 with parser.add_argument() to configure the parser.
313 A tuple of two element tuples each having the form (args, kwargs).
314 Each such pair is passed to parser.add_argument(*args, **kwargs)
315 in sequence to configure the parser.
316
317 parser_args : tuple
318 A tuple of positional arguments that will be passed to the
319 constructor of :class:`argparse.ArgumentParser`.
320
321 parser_kw : dict
322 A tuple of keyword arguments that will be passed to the
323 constructor of :class:`argparse.ArgumentParser`.
320 324 """
321 325 super(CommandLineConfigLoader, self).__init__()
322 326 if argv == None:
323 327 argv = sys.argv[1:]
324 328 self.argv = argv
325 329 self.arguments = arguments
326 self.args = args
327 kwargs = dict(argument_default=self.argument_default)
328 kwargs.update(kw)
329 self.kw = kwargs
330 self.parser_args = parser_args
331 kwargs = dict(argument_default=argparse.SUPPRESS)
332 kwargs.update(parser_kw)
333 self.parser_kw = kwargs
330 334
331 335 def load_config(self, args=None):
332 336 """Parse command line arguments and return as a Struct.
@@ -335,10 +339,10 b' class ArgParseConfigLoader(CommandLineConfigLoader):'
335 339 ----------
336 340
337 341 args : optional, list
338 If given, a list with the structure of sys.argv[1:] to parse arguments
339 from. If not given, the instance's self.argv attribute (given at
340 construction time) is used."""
341
342 If given, a list with the structure of sys.argv[1:] to parse
343 arguments from. If not given, the instance's self.argv attribute
344 (given at construction time) is used."""
345 self.clear()
342 346 if args is None:
343 347 args = self.argv
344 348 self._create_parser()
@@ -353,13 +357,17 b' class ArgParseConfigLoader(CommandLineConfigLoader):'
353 357 return []
354 358
355 359 def _create_parser(self):
356 self.parser = ArgumentParser(*self.args, **self.kw)
360 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
357 361 self._add_arguments()
358 362 self._add_other_arguments()
359 363
360 364 def _add_arguments(self):
361 365 for argument in self.arguments:
362 self.parser.add_argument(*argument[0],**argument[1])
366 # Remove any defaults in case people add them. We can't have
367 # command line default because all default are determined by
368 # traited class attributes.
369 argument[1].pop('default', None)
370 self.parser.add_argument(*argument[0], **argument[1])
363 371
364 372 def _add_other_arguments(self):
365 373 """Meant for subclasses to add their own arguments."""
@@ -372,6 +380,7 b' class ArgParseConfigLoader(CommandLineConfigLoader):'
372 380 def _convert_to_config(self):
373 381 """self.parsed_data->self.config"""
374 382 for k, v in vars(self.parsed_data).items():
375 if v is not NoConfigDefault:
376 exec_str = 'self.config.' + k + '= v'
377 exec exec_str in locals(), globals()
383 exec_str = 'self.config.' + k + '= v'
384 exec exec_str in locals(), globals()
385
386
@@ -62,22 +62,26 b' class TestPyFileCL(TestCase):'
62 62 self.assertEquals(config.D.C.value, 'hi there')
63 63
64 64
65 arguments = (
66 (('-f','--foo'), dict(dest='Global.foo', type=str)),
67 (('-b',), dict(dest='MyClass.bar', type=int)),
68 (('-n',), dict(dest='n', action='store_true')),
69 (('Global.bam',), dict(type=str))
70 )
71
65 72 class TestArgParseCL(TestCase):
66 73
67 74 def test_basic(self):
68
69 arguments = (
70 (('-f','--foo'), dict(dest='Global.foo', type=str)),
71 (('-b',), dict(dest='MyClass.bar', type=int)),
72 (('-n',), dict(dest='n', action='store_true')),
73 (('Global.bam',), dict(type=str))
74 )
75 75 cl = ArgParseConfigLoader(arguments=arguments)
76 76 config = cl.load_config('-f hi -b 10 -n wow'.split())
77 77 self.assertEquals(config.Global.foo, 'hi')
78 78 self.assertEquals(config.MyClass.bar, 10)
79 79 self.assertEquals(config.n, True)
80 80 self.assertEquals(config.Global.bam, 'wow')
81 config = cl.load_config(['wow'])
82 self.assertEquals(config.keys(), ['Global'])
83 self.assertEquals(config.Global.keys(), ['bam'])
84 self.assertEquals(config.Global.bam, 'wow')
81 85
82 86 def test_add_arguments(self):
83 87
@@ -97,6 +101,18 b' class TestArgParseCL(TestCase):'
97 101 self.assertEquals(config.subparser_name, '1')
98 102 self.assertEquals(config.Global.x, 'frobble')
99 103
104 def test_argv(self):
105 cl = ArgParseConfigLoader(
106 argv='-f hi -b 10 -n wow'.split(),
107 arguments=arguments
108 )
109 config = cl.load_config()
110 self.assertEquals(config.Global.foo, 'hi')
111 self.assertEquals(config.MyClass.bar, 10)
112 self.assertEquals(config.n, True)
113 self.assertEquals(config.Global.bam, 'wow')
114
115
100 116 class TestConfig(TestCase):
101 117
102 118 def test_setget(self):
@@ -32,8 +32,7 b' from IPython.core.application import Application'
32 32 from IPython.core.iplib import InteractiveShell
33 33 from IPython.config.loader import (
34 34 Config,
35 PyFileConfigLoader,
36 # NoConfigDefault,
35 PyFileConfigLoader
37 36 )
38 37 from IPython.lib import inputhook
39 38 from IPython.utils.path import filefind, get_ipython_dir
@@ -23,8 +23,8 b" if os.name=='posix':"
23 23 from twisted.scripts._twistd_unix import daemonize
24 24
25 25 from IPython.core import release
26 from IPython.external.argparse import ArgumentParser
27 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
26 from IPython.external.argparse import ArgumentParser, SUPPRESS
27 from IPython.config.loader import ArgParseConfigLoader
28 28 from IPython.utils.importstring import import_item
29 29
30 30 from IPython.kernel.clusterdir import (
@@ -56,7 +56,7 b' class IPClusterCLLoader(ArgParseConfigLoader):'
56 56 def _add_other_arguments(self):
57 57 # This has all the common options that all subcommands use
58 58 parent_parser1 = ArgumentParser(add_help=False,
59 argument_default=NoConfigDefault)
59 argument_default=SUPPRESS)
60 60 parent_parser1.add_argument('--ipython-dir',
61 61 dest='Global.ipython_dir',type=unicode,
62 62 help='Set to override default location of Global.ipython_dir.',
@@ -68,7 +68,7 b' class IPClusterCLLoader(ArgParseConfigLoader):'
68 68
69 69 # This has all the common options that other subcommands use
70 70 parent_parser2 = ArgumentParser(add_help=False,
71 argument_default=NoConfigDefault)
71 argument_default=SUPPRESS)
72 72 parent_parser2.add_argument('-p','--profile',
73 73 dest='Global.profile',type=unicode,
74 74 help='The string name of the profile to be used. This determines '
@@ -112,7 +112,6 b' class IPClusterCLLoader(ArgParseConfigLoader):'
112 112 parser_create.add_argument(
113 113 '--reset-config',
114 114 dest='Global.reset_config', action='store_true',
115 default=NoConfigDefault,
116 115 help='Recopy the default config files to the cluster directory. '
117 116 'You will loose any modifications you have made to these files.'
118 117 )
General Comments 0
You need to be logged in to leave comments. Login now