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