##// END OF EJS Templates
move shortname to Application...
MinRK -
Show More
@@ -23,13 +23,15 b' import logging'
23 import sys
23 import sys
24
24
25 from IPython.config.configurable import SingletonConfigurable
25 from IPython.config.configurable import SingletonConfigurable
26 from IPython.utils.traitlets import (
27 Unicode, List, Int, Enum
28 )
29 from IPython.config.loader import (
26 from IPython.config.loader import (
30 KeyValueConfigLoader, PyFileConfigLoader
27 KeyValueConfigLoader, PyFileConfigLoader
31 )
28 )
32
29
30 from IPython.utils.traitlets import (
31 Unicode, List, Int, Enum, Dict
32 )
33 from IPython.utils.text import indent
34
33 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
34 # Application class
36 # Application class
35 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
@@ -55,16 +57,33 b' class Application(SingletonConfigurable):'
55
57
56 # The log level for the application
58 # The log level for the application
57 log_level = Enum((0,10,20,30,40,50), default_value=logging.WARN,
59 log_level = Enum((0,10,20,30,40,50), default_value=logging.WARN,
58 config=True, shortname="log_level",
60 config=True,
59 help="Set the log level (0,10,20,30,40,50).")
61 help="Set the log level (0,10,20,30,40,50).")
62
63 # the shortname map for configurables
64 shortnames = Dict(dict(log_level='Application.log_level'))
65
66 # macros for loading Configurables or store_const style flags
67 # macros are loaded from this dict by '--key' flags
68 macros = Dict()
69 # macro_help dict keys must match macros
70 macro_help = Dict()
71
60
72
61 def __init__(self, **kwargs):
73 def __init__(self, **kwargs):
62 SingletonConfigurable.__init__(self, **kwargs)
74 SingletonConfigurable.__init__(self, **kwargs)
63 # Add my class to self.classes so my attributes appear in command line
75 # Add my class to self.classes so my attributes appear in command line
64 # options.
76 # options.
65 self.classes.insert(0, self.__class__)
77 self.classes.insert(0, self.__class__)
78
79 # check that macro_help has the right keys
80 # there is probably a better way to do this that doesn't use 2 dicts
81 keys = set(self.macros.keys())
82 badkeys = keys.difference_update(set(self.macro_help.keys()))
83 if badkeys:
84 raise KeyError("macro %r has no help in `macro_help`!"%badkeys.pop())
66 self.init_logging()
85 self.init_logging()
67
86
68 def init_logging(self):
87 def init_logging(self):
69 """Start logging for this application.
88 """Start logging for this application.
70
89
@@ -82,9 +101,45 b' class Application(SingletonConfigurable):'
82 def _log_level_changed(self, name, old, new):
101 def _log_level_changed(self, name, old, new):
83 """Adjust the log level when log_level is set."""
102 """Adjust the log level when log_level is set."""
84 self.log.setLevel(new)
103 self.log.setLevel(new)
85
104
105 def print_shortname_help(self):
106 """print the shortname part of the help"""
107 if not self.shortnames:
108 return
109
110 print "Aliases"
111 print "-------"
112 classdict = {}
113 for c in self.classes:
114 classdict[c.__name__] = c
115 for shortname, longname in self.shortnames.iteritems():
116 classname, traitname = longname.split('.',1)
117 cls = classdict[classname]
118
119 trait = cls.class_traits(config=True)[traitname]
120 help = trait.get_metadata('help')
121 print shortname, "(%s)"%longname, ':', trait.__class__.__name__
122 if help:
123 print indent(help)
124 print
125
126 def print_macro_help(self):
127 """print the the macro part of the help"""
128 if not self.macros:
129 return
130
131 print "Flags"
132 print "-----"
133
134 for m, cfg in self.macros.iteritems():
135 print '--'+m
136 print indent(self.macro_help[m])
137 print
138
86 def print_help(self):
139 def print_help(self):
87 """Print the help for each Configurable class in self.classes."""
140 """Print the help for each Configurable class in self.classes."""
141 self.print_macro_help()
142 self.print_shortname_help()
88 for cls in self.classes:
143 for cls in self.classes:
89 cls.class_print_help()
144 cls.class_print_help()
90 print
145 print
@@ -112,7 +167,7 b' class Application(SingletonConfigurable):'
112 """Parse the command line arguments."""
167 """Parse the command line arguments."""
113 argv = sys.argv[1:] if argv is None else argv
168 argv = sys.argv[1:] if argv is None else argv
114
169
115 if '-h' in argv or '--h' in argv:
170 if '-h' in argv or '--help' in argv:
116 self.print_description()
171 self.print_description()
117 self.print_help()
172 self.print_help()
118 sys.exit(1)
173 sys.exit(1)
@@ -121,7 +176,8 b' class Application(SingletonConfigurable):'
121 self.print_version()
176 self.print_version()
122 sys.exit(1)
177 sys.exit(1)
123
178
124 loader = KeyValueConfigLoader(argv=argv, classes=self.classes)
179 loader = KeyValueConfigLoader(argv=argv, shortnames=self.shortnames,
180 macros=self.macros)
125 config = loader.load_config()
181 config = loader.load_config()
126 self.update_config(config)
182 self.update_config(config)
127
183
@@ -140,18 +140,6 b' class Configurable(HasTraits):'
140 setattr(self, k, deepcopy(config_value))
140 setattr(self, k, deepcopy(config_value))
141
141
142 @classmethod
142 @classmethod
143 def class_get_shortnames(cls):
144 """Return the shortname to fullname dict for config=True traits."""
145 cls_traits = cls.class_traits(config=True)
146 shortnames = {}
147 for k, v in cls_traits.items():
148 shortname = v.get_metadata('shortname')
149 if shortname is not None:
150 longname = cls.__name__ + '.' + k
151 shortnames[shortname] = longname
152 return shortnames
153
154 @classmethod
155 def class_get_help(cls):
143 def class_get_help(cls):
156 """Get the help string for this class in ReST format."""
144 """Get the help string for this class in ReST format."""
157 cls_traits = cls.class_traits(config=True)
145 cls_traits = cls.class_traits(config=True)
@@ -160,10 +148,7 b' class Configurable(HasTraits):'
160 final_help.append(len(final_help[0])*u'-')
148 final_help.append(len(final_help[0])*u'-')
161 for k, v in cls_traits.items():
149 for k, v in cls_traits.items():
162 help = v.get_metadata('help')
150 help = v.get_metadata('help')
163 shortname = v.get_metadata('shortname')
164 header = "%s.%s : %s" % (cls.__name__, k, v.__class__.__name__)
151 header = "%s.%s : %s" % (cls.__name__, k, v.__class__.__name__)
165 if shortname is not None:
166 header += " (shortname=" + shortname + ")"
167 final_help.append(header)
152 final_help.append(header)
168 if help is not None:
153 if help is not None:
169 final_help.append(indent(help))
154 final_help.append(indent(help))
@@ -18,6 +18,7 b' Authors'
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 import __builtin__
20 import __builtin__
21 import re
21 import sys
22 import sys
22
23
23 from IPython.external import argparse
24 from IPython.external import argparse
@@ -303,6 +304,8 b' class CommandLineConfigLoader(ConfigLoader):'
303 here.
304 here.
304 """
305 """
305
306
307 kv_pattern = re.compile(r'[A-Za-z]\w*(\.\w+)*\=.+')
308 macro_pattern = re.compile(r'\-\-\w+(\-\w)*')
306
309
307 class KeyValueConfigLoader(CommandLineConfigLoader):
310 class KeyValueConfigLoader(CommandLineConfigLoader):
308 """A config loader that loads key value pairs from the command line.
311 """A config loader that loads key value pairs from the command line.
@@ -312,7 +315,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
312 ipython Global.profile="foo" InteractiveShell.autocall=False
315 ipython Global.profile="foo" InteractiveShell.autocall=False
313 """
316 """
314
317
315 def __init__(self, argv=None, classes=None):
318 def __init__(self, argv=None, shortnames=None, macros=None):
316 """Create a key value pair config loader.
319 """Create a key value pair config loader.
317
320
318 Parameters
321 Parameters
@@ -321,9 +324,14 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
321 A list that has the form of sys.argv[1:] which has unicode
324 A list that has the form of sys.argv[1:] which has unicode
322 elements of the form u"key=value". If this is None (default),
325 elements of the form u"key=value". If this is None (default),
323 then sys.argv[1:] will be used.
326 then sys.argv[1:] will be used.
324 classes : (list, tuple) of Configurables
327 shortnames : dict
325 A sequence of Configurable classes that will be used to map
328 A dict of aliases for configurable traits.
326 shortnames to longnames.
329 Keys are the short aliases, Values are the resolved trait.
330 Of the form: `{'shortname' : 'Configurable.trait'}`
331 macros : dict
332 A dict of macros, keyed by str name. Vaues can be Config objects,
333 dicts, or "key=value" strings. If Config or dict, when the macro
334 is triggered, The macro is loaded as `self.config.update(m)`.
327
335
328 Returns
336 Returns
329 -------
337 -------
@@ -340,12 +348,11 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
340 """
348 """
341 if argv is None:
349 if argv is None:
342 argv = sys.argv[1:]
350 argv = sys.argv[1:]
343 if classes is None:
344 classes = ()
345 self.argv = argv
351 self.argv = argv
346 self.classes = classes
352 self.shortnames = shortnames or {}
353 self.macros = macros or {}
347
354
348 def load_config(self, argv=None, classes=None):
355 def load_config(self, argv=None, shortnames=None, macros=None):
349 """Parse the configuration and generate the Config object.
356 """Parse the configuration and generate the Config object.
350
357
351 Parameters
358 Parameters
@@ -354,37 +361,28 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
354 A list that has the form of sys.argv[1:] which has unicode
361 A list that has the form of sys.argv[1:] which has unicode
355 elements of the form u"key=value". If this is None (default),
362 elements of the form u"key=value". If this is None (default),
356 then self.argv will be used.
363 then self.argv will be used.
357 classes : (list, tuple) of Configurables
364 shortnames : dict
358 A sequence of Configurable classes that will be used to map
365 A dict of aliases for configurable traits.
359 shortnames to longnames.
366 Keys are the short aliases, Values are the resolved trait.
367 Of the form: `{'shortname' : 'Configurable.trait'}`
368 macros : dict
369 A dict of macros, keyed by str name. Vaues can be Config objects,
370 dicts, or "key=value" strings. If Config or dict, when the macro
371 is triggered, The macro is loaded as `self.config.update(m)`.
360 """
372 """
361 from IPython.config.configurable import Configurable
373 from IPython.config.configurable import Configurable
362
374
363 self.clear()
375 self.clear()
364 if argv is None:
376 if argv is None:
365 argv = self.argv
377 argv = self.argv
366 if classes is None:
378 if shortnames is None:
367 classes = self.classes
379 shortnames = self.shortnames
368
380 if macros is None:
369 # Create the mapping between shortnames and longnames.
381 macros = self.macros
370 shortnames = {}
371 for cls in classes:
372 if issubclass(cls, Configurable):
373 sn = cls.class_get_shortnames()
374 # Check for duplicate shortnames and raise if found.
375 for k, v in sn.items():
376 if k in shortnames:
377 raise KeyError(
378 'Duplicate shortname: both %s and %s use the shortname: "%s"' %\
379 (v, shortnames[k], k)
380 )
381 shortnames.update(sn)
382
382
383 for item in argv:
383 for item in argv:
384 pair = tuple(item.split("="))
384 if kv_pattern.match(item):
385 if len(pair) == 2:
385 lhs,rhs = item.split('=',1)
386 lhs = pair[0]
387 rhs = pair[1]
388 # Substitute longnames for shortnames.
386 # Substitute longnames for shortnames.
389 if lhs in shortnames:
387 if lhs in shortnames:
390 lhs = shortnames[lhs]
388 lhs = shortnames[lhs]
@@ -400,9 +398,26 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
400 # it succeeds. If it still fails, we let it raise.
398 # it succeeds. If it still fails, we let it raise.
401 exec_str = 'self.config.' + lhs + '="' + rhs + '"'
399 exec_str = 'self.config.' + lhs + '="' + rhs + '"'
402 exec exec_str in locals(), globals()
400 exec exec_str in locals(), globals()
401 elif macro_pattern.match(item):
402 # trim leading '--'
403 m = item[2:]
404 macro = macros.get(m, None)
405 if macro is None:
406 raise ValueError("Unrecognized argument: %r"%item)
407 macro = macros[m]
408 if isinstance(macro, basestring):
409 # macro is simply a 'Class.trait=value' string
410 exec_str = 'self.config.' + macro
411 exec exec_str in locals(), globals()
412 elif isinstance(macro, (dict, Configurable)):
413 # update self.config with Config:
414 self.config.update(macros[m])
415 else:
416 raise ValueError("Invalid macro: %r"%macro)
417 else:
418 raise ValueError("Invalid argument: %r"%item)
403 return self.config
419 return self.config
404
420
405
406 class ArgParseConfigLoader(CommandLineConfigLoader):
421 class ArgParseConfigLoader(CommandLineConfigLoader):
407 """A loader that uses the argparse module to load from the command line."""
422 """A loader that uses the argparse module to load from the command line."""
408
423
@@ -35,14 +35,14 b' from IPython.utils.traitlets import ('
35
35
36 class Foo(Configurable):
36 class Foo(Configurable):
37
37
38 i = Int(0, config=True, shortname='i', help="The integer i.")
38 i = Int(0, config=True, help="The integer i.")
39 j = Int(1, config=True, shortname='j', help="The integer j.")
39 j = Int(1, config=True, help="The integer j.")
40 name = Unicode(u'Brian', config=True, shortname='name', help="First name.")
40 name = Unicode(u'Brian', config=True, help="First name.")
41
41
42
42
43 class Bar(Configurable):
43 class Bar(Configurable):
44
44
45 enabled = Bool(True, config=True, shortname="enabled", help="Enable bar.")
45 enabled = Bool(True, config=True, help="Enable bar.")
46
46
47
47
48 class MyApp(Application):
48 class MyApp(Application):
@@ -54,6 +54,15 b' class MyApp(Application):'
54 config_file = Unicode(u'', config=True, shortname="config_file",
54 config_file = Unicode(u'', config=True, shortname="config_file",
55 help="Load this config file")
55 help="Load this config file")
56
56
57 shortnames = dict(i='Foo.i',j='Foo.j',name='Foo.name',
58 enabled='Bar.enabled', log_level='MyApp.log_level')
59
60 macros = dict(enable='Bar.enabled=True', disable='Bar.enabled=False')
61
62 macro_help = dict(
63 enable="""Enable bar""",
64 disable="""Disable bar"""
65 )
57 def init_foo(self):
66 def init_foo(self):
58 self.foo = Foo(config=self.config)
67 self.foo = Foo(config=self.config)
59
68
@@ -88,3 +97,12 b' class TestApplication(TestCase):'
88 self.assertEquals(app.foo.j, 10)
97 self.assertEquals(app.foo.j, 10)
89 self.assertEquals(app.bar.enabled, False)
98 self.assertEquals(app.bar.enabled, False)
90
99
100 def test_macro(self):
101 app = MyApp()
102 app.parse_command_line(["--disable"])
103 app.init_bar()
104 self.assertEquals(app.bar.enabled, False)
105 app.parse_command_line(["--enable"])
106 app.init_bar()
107 self.assertEquals(app.bar.enabled, True)
108
@@ -40,26 +40,26 b' from IPython.config.loader import Config'
40
40
41
41
42 class MyConfigurable(Configurable):
42 class MyConfigurable(Configurable):
43 a = Int(1, config=True, shortname="a", help="The integer a.")
43 a = Int(1, config=True, help="The integer a.")
44 b = Float(1.0, config=True, shortname="b", help="The integer b.")
44 b = Float(1.0, config=True, help="The integer b.")
45 c = Str('no config')
45 c = Str('no config')
46
46
47
47
48 mc_help=u"""MyConfigurable options
48 mc_help=u"""MyConfigurable options
49 ----------------------
49 ----------------------
50 MyConfigurable.a : Int (shortname=a)
50 MyConfigurable.a : Int
51 The integer a.
51 The integer a.
52 MyConfigurable.b : Float (shortname=b)
52 MyConfigurable.b : Float
53 The integer b."""
53 The integer b."""
54
54
55 class Foo(Configurable):
55 class Foo(Configurable):
56 a = Int(0, config=True, shortname="a", help="The integer a.")
56 a = Int(0, config=True, help="The integer a.")
57 b = Str('nope', config=True)
57 b = Str('nope', config=True)
58
58
59
59
60 class Bar(Foo):
60 class Bar(Foo):
61 b = Str('gotit', config=False, shortname="b", help="The string b.")
61 b = Str('gotit', config=False, help="The string b.")
62 c = Float(config=True, shortname="c", help="The string c.")
62 c = Float(config=True, help="The string c.")
63
63
64
64
65 class TestConfigurable(TestCase):
65 class TestConfigurable(TestCase):
@@ -135,14 +135,6 b' class TestConfigurable(TestCase):'
135 self.assertEquals(c.b, 'and')
135 self.assertEquals(c.b, 'and')
136 self.assertEquals(c.c, 20.0)
136 self.assertEquals(c.c, 20.0)
137
137
138 def test_shortnames(self):
139 sn = MyConfigurable.class_get_shortnames()
140 self.assertEquals(sn, {'a': 'MyConfigurable.a', 'b': 'MyConfigurable.b'})
141 sn = Foo.class_get_shortnames()
142 self.assertEquals(sn, {'a': 'Foo.a'})
143 sn = Bar.class_get_shortnames()
144 self.assertEquals(sn, {'a': 'Bar.a', 'c': 'Bar.c'})
145
146 def test_help(self):
138 def test_help(self):
147 self.assertEquals(MyConfigurable.class_get_help(), mc_help)
139 self.assertEquals(MyConfigurable.class_get_help(), mc_help)
148
140
@@ -124,23 +124,6 b' class TestKeyValueCL(TestCase):'
124 self.assertEquals(config.Foo.Bam.value, range(10))
124 self.assertEquals(config.Foo.Bam.value, range(10))
125 self.assertEquals(config.D.C.value, 'hi there')
125 self.assertEquals(config.D.C.value, 'hi there')
126
126
127 def test_shortname(self):
128 class Foo(Configurable):
129 i = Int(0, config=True, shortname="i")
130 s = Unicode('hi', config=True, shortname="s")
131 cl = KeyValueConfigLoader()
132 config = cl.load_config(["i=20", "s=there"], classes=[Foo])
133 self.assertEquals(config.Foo.i, 20)
134 self.assertEquals(config.Foo.s, "there")
135
136 def test_duplicate(self):
137 class Foo(Configurable):
138 i = Int(0, config=True, shortname="i")
139 class Bar(Configurable):
140 i = Int(0, config=True, shortname="i")
141 cl = KeyValueConfigLoader()
142 self.assertRaises(KeyError, cl.load_config, ["i=20", "s=there"], classes=[Foo, Bar])
143
144
127
145 class TestConfig(TestCase):
128 class TestConfig(TestCase):
146
129
@@ -62,6 +62,15 b' class MyApp(Application):'
62 classes = List([Bar, Foo])
62 classes = List([Bar, Foo])
63 config_file = Unicode(u'', config=True, shortname="config_file",
63 config_file = Unicode(u'', config=True, shortname="config_file",
64 help="Load this config file")
64 help="Load this config file")
65
66 shortnames = dict(i='Foo.i',j='Foo.j',name='Foo.name',
67 enabled='Bar.enabled')
68
69 macros = dict(enable='Bar.enabled=True', disable='Bar.enabled=False')
70 macro_help = dict(
71 enable="""Set Bar.enabled to True""",
72 disable="""Set Bar.enabled to False"""
73 )
65
74
66 def init_foo(self):
75 def init_foo(self):
67 # Pass config to other classes for them to inherit the config.
76 # Pass config to other classes for them to inherit the config.
General Comments 0
You need to be logged in to leave comments. Login now