Show More
@@ -0,0 +1,55 | |||||
|
1 | import sys | |||
|
2 | ||||
|
3 | from IPython.config.configurable import Configurable | |||
|
4 | from IPython.utils.traitlets import ( | |||
|
5 | Bool, Unicode, Int, Float, List | |||
|
6 | ) | |||
|
7 | from IPython.config.loader import KeyValueConfigLoader | |||
|
8 | ||||
|
9 | class Foo(Configurable): | |||
|
10 | ||||
|
11 | i = Int(0, config=True, shortname='i', help="The integer i.") | |||
|
12 | j = Int(1, config=True, shortname='j', help="The integer j.") | |||
|
13 | name = Unicode(u'Brian', config=True, shortname='name', help="First name.") | |||
|
14 | ||||
|
15 | ||||
|
16 | class Bar(Configurable): | |||
|
17 | ||||
|
18 | enabled = Bool(True, config=True, shortname="bar-enabled", help="Enable bar.") | |||
|
19 | ||||
|
20 | ||||
|
21 | class MyApp(Configurable): | |||
|
22 | ||||
|
23 | app_name = Unicode(u'myapp', config=True, shortname="myapp", help="The app name.") | |||
|
24 | running = Bool(False, config=True, shortname="running", help="Is the app running?") | |||
|
25 | classes = List([Bar, Foo]) | |||
|
26 | ||||
|
27 | def __init__(self, **kwargs): | |||
|
28 | Configurable.__init__(self, **kwargs) | |||
|
29 | self.classes.insert(0, self.__class__) | |||
|
30 | ||||
|
31 | def print_help(self): | |||
|
32 | for cls in self.classes: | |||
|
33 | cls.class_print_help() | |||
|
34 | ||||
|
35 | ||||
|
36 | def parse_command_line(self, argv=None): | |||
|
37 | if argv is None: | |||
|
38 | argv = sys.argv[1:] | |||
|
39 | if '-h' in argv or '--h' in argv: | |||
|
40 | self.print_help() | |||
|
41 | sys.exit(1) | |||
|
42 | loader = KeyValueConfigLoader(argv=argv, classes=self.classes) | |||
|
43 | config = loader.load_config() | |||
|
44 | self.config = config | |||
|
45 | ||||
|
46 | ||||
|
47 | def main(): | |||
|
48 | app = MyApp() | |||
|
49 | app.parse_command_line() | |||
|
50 | print "app.config:" | |||
|
51 | print app.config | |||
|
52 | ||||
|
53 | ||||
|
54 | if __name__ == "__main__": | |||
|
55 | main() |
@@ -27,6 +27,7 from weakref import WeakValueDictionary | |||||
27 | from IPython.utils.importstring import import_item |
|
27 | from IPython.utils.importstring import import_item | |
28 | from loader import Config |
|
28 | from loader import Config | |
29 | from IPython.utils.traitlets import HasTraits, Instance |
|
29 | from IPython.utils.traitlets import HasTraits, Instance | |
|
30 | from IPython.utils.text import indent | |||
30 |
|
31 | |||
31 |
|
32 | |||
32 | #----------------------------------------------------------------------------- |
|
33 | #----------------------------------------------------------------------------- | |
@@ -137,3 +138,33 class Configurable(HasTraits): | |||||
137 | # shared by all instances, effectively making it a class attribute. |
|
138 | # shared by all instances, effectively making it a class attribute. | |
138 | setattr(self, k, deepcopy(config_value)) |
|
139 | setattr(self, k, deepcopy(config_value)) | |
139 |
|
140 | |||
|
141 | @classmethod | |||
|
142 | def class_get_shortnames(cls): | |||
|
143 | """Return the shortname to fullname dict for config=True traits.""" | |||
|
144 | cls_traits = cls.class_traits(config=True) | |||
|
145 | shortnames = {} | |||
|
146 | for k, v in cls_traits.items(): | |||
|
147 | shortname = v.get_metadata('shortname') | |||
|
148 | if shortname is not None: | |||
|
149 | longname = cls.__name__ + '.' + k | |||
|
150 | shortnames[shortname] = longname | |||
|
151 | return shortnames | |||
|
152 | ||||
|
153 | @classmethod | |||
|
154 | def class_get_help(cls): | |||
|
155 | cls_traits = cls.class_traits(config=True) | |||
|
156 | final_help = [] | |||
|
157 | final_help.append('%s options' % cls.__name__) | |||
|
158 | final_help.append(len(final_help[0])*'-') | |||
|
159 | for k, v in cls_traits.items(): | |||
|
160 | help = v.get_metadata('help') | |||
|
161 | final_help.append(k + " : " + v.__class__.__name__) | |||
|
162 | if help is not None: | |||
|
163 | final_help.append(indent(help)) | |||
|
164 | return '\n'.join(final_help) | |||
|
165 | ||||
|
166 | @classmethod | |||
|
167 | def class_print_help(cls): | |||
|
168 | print cls.class_get_help() | |||
|
169 | ||||
|
170 | No newline at end of file |
@@ -315,7 +315,7 class KeyValueConfigLoader(CommandLineConfigLoader): | |||||
315 | ipython Global.profile="foo" InteractiveShell.autocall=False |
|
315 | ipython Global.profile="foo" InteractiveShell.autocall=False | |
316 | """ |
|
316 | """ | |
317 |
|
317 | |||
318 | def __init__(self, argv=None): |
|
318 | def __init__(self, argv=None, classes=None): | |
319 | """Create a key value pair config loader. |
|
319 | """Create a key value pair config loader. | |
320 |
|
320 | |||
321 | Parameters |
|
321 | Parameters | |
@@ -324,6 +324,9 class KeyValueConfigLoader(CommandLineConfigLoader): | |||||
324 | 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 | |
325 | 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), | |
326 | then sys.argv[1:] will be used. |
|
326 | then sys.argv[1:] will be used. | |
|
327 | class : (list, tuple) of Configurables | |||
|
328 | A sequence of Configurable classes that will be used to map | |||
|
329 | shortnames to longnames. | |||
327 |
|
330 | |||
328 | Returns |
|
331 | Returns | |
329 | ------- |
|
332 | ------- | |
@@ -338,11 +341,14 class KeyValueConfigLoader(CommandLineConfigLoader): | |||||
338 | >>> cl.load_config(["foo='bar'","A.name='brian'","B.number=0"]) |
|
341 | >>> cl.load_config(["foo='bar'","A.name='brian'","B.number=0"]) | |
339 | {'A': {'name': 'brian'}, 'B': {'number': 0}, 'foo': 'bar'} |
|
342 | {'A': {'name': 'brian'}, 'B': {'number': 0}, 'foo': 'bar'} | |
340 | """ |
|
343 | """ | |
341 |
if argv |
|
344 | if argv is None: | |
342 | argv = sys.argv[1:] |
|
345 | argv = sys.argv[1:] | |
|
346 | if classes is None: | |||
|
347 | classes = () | |||
343 | self.argv = argv |
|
348 | self.argv = argv | |
|
349 | self.classes = classes | |||
344 |
|
350 | |||
345 | def load_config(self, argv=None): |
|
351 | def load_config(self, argv=None, classes=None): | |
346 | """Parse the configuration and generate the Config object. |
|
352 | """Parse the configuration and generate the Config object. | |
347 |
|
353 | |||
348 | Parameters |
|
354 | Parameters | |
@@ -350,16 +356,47 class KeyValueConfigLoader(CommandLineConfigLoader): | |||||
350 | argv : list, optional |
|
356 | argv : list, optional | |
351 | A list that has the form of sys.argv[1:] which has unicode |
|
357 | A list that has the form of sys.argv[1:] which has unicode | |
352 | elements of the form u"key=value". If this is None (default), |
|
358 | elements of the form u"key=value". If this is None (default), | |
353 |
then self.argv will be used. |
|
359 | then self.argv will be used. | |
|
360 | class : (list, tuple) of Configurables | |||
|
361 | A sequence of Configurable classes that will be used to map | |||
|
362 | shortnames to longnames. | |||
354 | """ |
|
363 | """ | |
355 | self.clear() |
|
364 | self.clear() | |
356 | if argv is None: |
|
365 | if argv is None: | |
357 | argv = self.argv |
|
366 | argv = self.argv | |
|
367 | if classes is None: | |||
|
368 | classes = self.classes | |||
|
369 | ||||
|
370 | # print argv | |||
|
371 | ||||
|
372 | shortnames = {} | |||
|
373 | for cls in classes: | |||
|
374 | sn = cls.class_get_shortnames() | |||
|
375 | # Check for duplicate shortnames and raise if found. | |||
|
376 | for k, v in sn.items(): | |||
|
377 | if k in shortnames: | |||
|
378 | raise KeyError( | |||
|
379 | "duplicate shortname: %s and %s both use the shortname: %s" %\ | |||
|
380 | (v, shortnames[k], k) | |||
|
381 | ) | |||
|
382 | shortnames.update(sn) | |||
|
383 | ||||
|
384 | # print shortnames | |||
|
385 | ||||
358 | for item in argv: |
|
386 | for item in argv: | |
359 | pair = tuple(item.split("=")) |
|
387 | pair = tuple(item.split("=")) | |
360 | if len(pair) == 2: |
|
388 | if len(pair) == 2: | |
361 | exec_str = 'self.config.' + pair[0] + '=' + pair[1] |
|
389 | lhs = pair[0] | |
362 | exec exec_str in locals(), globals() |
|
390 | rhs = pair[1] | |
|
391 | # Substitute longnames for shortnames. | |||
|
392 | if lhs in shortnames: | |||
|
393 | lhs = shortnames[lhs] | |||
|
394 | exec_str = 'self.config.' + lhs + '=' + rhs | |||
|
395 | try: | |||
|
396 | exec exec_str in locals(), globals() | |||
|
397 | except (NameError, SyntaxError): | |||
|
398 | exec_str = 'self.config.' + lhs + '="' + rhs + '"' | |||
|
399 | exec exec_str in locals(), globals() | |||
363 | return self.config |
|
400 | return self.config | |
364 |
|
401 | |||
365 |
|
402 |
@@ -214,7 +214,7 class InteractiveShell(Configurable, Magic): | |||||
214 | # We can't do this yet because even runlines uses the autoindent. |
|
214 | # We can't do this yet because even runlines uses the autoindent. | |
215 | autoindent = CBool(True, config=True, help= |
|
215 | autoindent = CBool(True, config=True, help= | |
216 | """ |
|
216 | """ | |
217 |
|
|
217 | Autoindent IPython code entered interactively. | |
218 | """ |
|
218 | """ | |
219 | ) |
|
219 | ) | |
220 | automagic = CBool(True, config=True, help= |
|
220 | automagic = CBool(True, config=True, help= | |
@@ -222,12 +222,37 class InteractiveShell(Configurable, Magic): | |||||
222 | Enable magic commands to be called without the leading %. |
|
222 | Enable magic commands to be called without the leading %. | |
223 | """ |
|
223 | """ | |
224 | ) |
|
224 | ) | |
225 |
cache_size = Int(1000, config=True |
|
225 | cache_size = Int(1000, config=True, help= | |
226 | color_info = CBool(True, config=True) |
|
226 | """ | |
|
227 | Set the size of the output cache. The default is 1000, you can | |||
|
228 | change it permanently in your config file. Setting it to 0 completely | |||
|
229 | disables the caching system, and the minimum value accepted is 20 (if | |||
|
230 | you provide a value less than 20, it is reset to 0 and a warning is | |||
|
231 | issued). This limit is defined because otherwise you'll spend more | |||
|
232 | time re-flushing a too small cache than working | |||
|
233 | """ | |||
|
234 | ) | |||
|
235 | color_info = CBool(True, config=True, help= | |||
|
236 | """ | |||
|
237 | Use colors for displaying information about objects. Because this | |||
|
238 | information is passed through a pager (like 'less'), and some pagers | |||
|
239 | get confused with color codes, this capability can be turned off. | |||
|
240 | """ | |||
|
241 | ) | |||
227 | colors = CaselessStrEnum(('NoColor','LightBG','Linux'), |
|
242 | colors = CaselessStrEnum(('NoColor','LightBG','Linux'), | |
228 | default_value=get_default_colors(), config=True) |
|
243 | default_value=get_default_colors(), config=True) | |
229 | debug = CBool(False, config=True) |
|
244 | debug = CBool(False, config=True) | |
230 |
deep_reload = CBool(False, config=True |
|
245 | deep_reload = CBool(False, config=True, help= | |
|
246 | """ | |||
|
247 | Enable deep (recursive) reloading by default. IPython can use the | |||
|
248 | deep_reload module which reloads changes in modules recursively (it | |||
|
249 | replaces the reload() function, so you don't need to change anything to | |||
|
250 | use it). deep_reload() forces a full reload of modules whose code may | |||
|
251 | have changed, which the default reload() function does not. When | |||
|
252 | deep_reload is off, IPython will use the normal reload(), but | |||
|
253 | deep_reload will still be available as dreload(). | |||
|
254 | """ | |||
|
255 | ) | |||
231 | display_formatter = Instance(DisplayFormatter) |
|
256 | display_formatter = Instance(DisplayFormatter) | |
232 | displayhook_class = Type(DisplayHook) |
|
257 | displayhook_class = Type(DisplayHook) | |
233 | display_pub_class = Type(DisplayPublisher) |
|
258 | display_pub_class = Type(DisplayPublisher) | |
@@ -245,12 +270,28 class InteractiveShell(Configurable, Magic): | |||||
245 | # interactive statements or whole blocks. |
|
270 | # interactive statements or whole blocks. | |
246 | input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter', |
|
271 | input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter', | |
247 | (), {}) |
|
272 | (), {}) | |
248 |
logstart = CBool(False, config=True |
|
273 | logstart = CBool(False, config=True, help= | |
249 | logfile = Unicode('', config=True) |
|
274 | """ | |
250 | logappend = Unicode('', config=True) |
|
275 | Start logging to the default log file. | |
|
276 | """ | |||
|
277 | ) | |||
|
278 | logfile = Unicode('', config=True, help= | |||
|
279 | """ | |||
|
280 | The name of the logfile to use. | |||
|
281 | """ | |||
|
282 | ) | |||
|
283 | logappend = Unicode('', config=True, help= | |||
|
284 | """ | |||
|
285 | Start logging to the given file in append mode. | |||
|
286 | """ | |||
|
287 | ) | |||
251 | object_info_string_level = Enum((0,1,2), default_value=0, |
|
288 | object_info_string_level = Enum((0,1,2), default_value=0, | |
252 | config=True) |
|
289 | config=True) | |
253 |
pdb = CBool(False, config=True |
|
290 | pdb = CBool(False, config=True, help= | |
|
291 | """ | |||
|
292 | Automatically call the pdb debugger after every exception. | |||
|
293 | """ | |||
|
294 | ) | |||
254 |
|
295 | |||
255 | profile = Unicode('', config=True) |
|
296 | profile = Unicode('', config=True) | |
256 | prompt_in1 = Str('In [\\#]: ', config=True) |
|
297 | prompt_in1 = Str('In [\\#]: ', config=True) |
@@ -366,6 +366,7 class TestHasTraits(TestCase): | |||||
366 | f = Float |
|
366 | f = Float | |
367 | a = A() |
|
367 | a = A() | |
368 | self.assertEquals(a.trait_names(),['i','f']) |
|
368 | self.assertEquals(a.trait_names(),['i','f']) | |
|
369 | self.assertEquals(A.class_trait_names(),['i','f']) | |||
369 |
|
370 | |||
370 | def test_trait_metadata(self): |
|
371 | def test_trait_metadata(self): | |
371 | class A(HasTraits): |
|
372 | class A(HasTraits): | |
@@ -379,6 +380,7 class TestHasTraits(TestCase): | |||||
379 | f = Float |
|
380 | f = Float | |
380 | a = A() |
|
381 | a = A() | |
381 | self.assertEquals(a.traits(), dict(i=A.i, f=A.f)) |
|
382 | self.assertEquals(a.traits(), dict(i=A.i, f=A.f)) | |
|
383 | self.assertEquals(A.class_traits(), dict(i=A.i, f=A.f)) | |||
382 |
|
384 | |||
383 | def test_traits_metadata(self): |
|
385 | def test_traits_metadata(self): | |
384 | class A(HasTraits): |
|
386 | class A(HasTraits): |
@@ -515,6 +515,48 class HasTraits(object): | |||||
515 | for n in names: |
|
515 | for n in names: | |
516 | self._add_notifiers(handler, n) |
|
516 | self._add_notifiers(handler, n) | |
517 |
|
517 | |||
|
518 | @classmethod | |||
|
519 | def class_trait_names(cls, **metadata): | |||
|
520 | """Get a list of all the names of this classes traits. | |||
|
521 | ||||
|
522 | This method is just like the :meth:`trait_names` method, but is unbound. | |||
|
523 | """ | |||
|
524 | return cls.class_traits(**metadata).keys() | |||
|
525 | ||||
|
526 | @classmethod | |||
|
527 | def class_traits(cls, **metadata): | |||
|
528 | """Get a list of all the traits of this class. | |||
|
529 | ||||
|
530 | This method is just like the :meth:`traits` method, but is unbound. | |||
|
531 | ||||
|
532 | The TraitTypes returned don't know anything about the values | |||
|
533 | that the various HasTrait's instances are holding. | |||
|
534 | ||||
|
535 | This follows the same algorithm as traits does and does not allow | |||
|
536 | for any simple way of specifying merely that a metadata name | |||
|
537 | exists, but has any value. This is because get_metadata returns | |||
|
538 | None if a metadata key doesn't exist. | |||
|
539 | """ | |||
|
540 | traits = dict([memb for memb in getmembers(cls) if \ | |||
|
541 | isinstance(memb[1], TraitType)]) | |||
|
542 | ||||
|
543 | if len(metadata) == 0: | |||
|
544 | return traits | |||
|
545 | ||||
|
546 | for meta_name, meta_eval in metadata.items(): | |||
|
547 | if type(meta_eval) is not FunctionType: | |||
|
548 | metadata[meta_name] = _SimpleTest(meta_eval) | |||
|
549 | ||||
|
550 | result = {} | |||
|
551 | for name, trait in traits.items(): | |||
|
552 | for meta_name, meta_eval in metadata.items(): | |||
|
553 | if not meta_eval(trait.get_metadata(meta_name)): | |||
|
554 | break | |||
|
555 | else: | |||
|
556 | result[name] = trait | |||
|
557 | ||||
|
558 | return result | |||
|
559 | ||||
518 | def trait_names(self, **metadata): |
|
560 | def trait_names(self, **metadata): | |
519 | """Get a list of all the names of this classes traits.""" |
|
561 | """Get a list of all the names of this classes traits.""" | |
520 | return self.traits(**metadata).keys() |
|
562 | return self.traits(**metadata).keys() |
General Comments 0
You need to be logged in to leave comments.
Login now