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 | 27 | from IPython.utils.importstring import import_item |
|
28 | 28 | from loader import Config |
|
29 | 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 | 138 | # shared by all instances, effectively making it a class attribute. |
|
138 | 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 | 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 | 319 | """Create a key value pair config loader. |
|
320 | 320 | |
|
321 | 321 | Parameters |
@@ -324,6 +324,9 class KeyValueConfigLoader(CommandLineConfigLoader): | |||
|
324 | 324 | A list that has the form of sys.argv[1:] which has unicode |
|
325 | 325 | elements of the form u"key=value". If this is None (default), |
|
326 | 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 | 331 | Returns |
|
329 | 332 | ------- |
@@ -338,11 +341,14 class KeyValueConfigLoader(CommandLineConfigLoader): | |||
|
338 | 341 | >>> cl.load_config(["foo='bar'","A.name='brian'","B.number=0"]) |
|
339 | 342 | {'A': {'name': 'brian'}, 'B': {'number': 0}, 'foo': 'bar'} |
|
340 | 343 | """ |
|
341 |
if argv |
|
|
344 | if argv is None: | |
|
342 | 345 | argv = sys.argv[1:] |
|
346 | if classes is None: | |
|
347 | classes = () | |
|
343 | 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 | 352 | """Parse the configuration and generate the Config object. |
|
347 | 353 | |
|
348 | 354 | Parameters |
@@ -350,16 +356,47 class KeyValueConfigLoader(CommandLineConfigLoader): | |||
|
350 | 356 | argv : list, optional |
|
351 | 357 | A list that has the form of sys.argv[1:] which has unicode |
|
352 | 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 | 364 | self.clear() |
|
356 | 365 | if argv is None: |
|
357 | 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 | 386 | for item in argv: |
|
359 | 387 | pair = tuple(item.split("=")) |
|
360 | 388 | if len(pair) == 2: |
|
361 | exec_str = 'self.config.' + pair[0] + '=' + pair[1] | |
|
362 | exec exec_str in locals(), globals() | |
|
389 | lhs = pair[0] | |
|
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 | 400 | return self.config |
|
364 | 401 | |
|
365 | 402 |
@@ -214,7 +214,7 class InteractiveShell(Configurable, Magic): | |||
|
214 | 214 | # We can't do this yet because even runlines uses the autoindent. |
|
215 | 215 | autoindent = CBool(True, config=True, help= |
|
216 | 216 | """ |
|
217 |
|
|
|
217 | Autoindent IPython code entered interactively. | |
|
218 | 218 | """ |
|
219 | 219 | ) |
|
220 | 220 | automagic = CBool(True, config=True, help= |
@@ -222,12 +222,37 class InteractiveShell(Configurable, Magic): | |||
|
222 | 222 | Enable magic commands to be called without the leading %. |
|
223 | 223 | """ |
|
224 | 224 | ) |
|
225 |
cache_size = Int(1000, config=True |
|
|
226 | color_info = CBool(True, config=True) | |
|
225 | cache_size = Int(1000, config=True, help= | |
|
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 | 242 | colors = CaselessStrEnum(('NoColor','LightBG','Linux'), |
|
228 | 243 | default_value=get_default_colors(), config=True) |
|
229 | 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 | 256 | display_formatter = Instance(DisplayFormatter) |
|
232 | 257 | displayhook_class = Type(DisplayHook) |
|
233 | 258 | display_pub_class = Type(DisplayPublisher) |
@@ -245,12 +270,28 class InteractiveShell(Configurable, Magic): | |||
|
245 | 270 | # interactive statements or whole blocks. |
|
246 | 271 | input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter', |
|
247 | 272 | (), {}) |
|
248 |
logstart = CBool(False, config=True |
|
|
249 | logfile = Unicode('', config=True) | |
|
250 | logappend = Unicode('', config=True) | |
|
273 | logstart = CBool(False, config=True, help= | |
|
274 | """ | |
|
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 | 288 | object_info_string_level = Enum((0,1,2), default_value=0, |
|
252 | 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 | 296 | profile = Unicode('', config=True) |
|
256 | 297 | prompt_in1 = Str('In [\\#]: ', config=True) |
@@ -366,6 +366,7 class TestHasTraits(TestCase): | |||
|
366 | 366 | f = Float |
|
367 | 367 | a = A() |
|
368 | 368 | self.assertEquals(a.trait_names(),['i','f']) |
|
369 | self.assertEquals(A.class_trait_names(),['i','f']) | |
|
369 | 370 | |
|
370 | 371 | def test_trait_metadata(self): |
|
371 | 372 | class A(HasTraits): |
@@ -379,6 +380,7 class TestHasTraits(TestCase): | |||
|
379 | 380 | f = Float |
|
380 | 381 | a = A() |
|
381 | 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 | 385 | def test_traits_metadata(self): |
|
384 | 386 | class A(HasTraits): |
@@ -515,6 +515,48 class HasTraits(object): | |||
|
515 | 515 | for n in names: |
|
516 | 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 | 560 | def trait_names(self, **metadata): |
|
519 | 561 | """Get a list of all the names of this classes traits.""" |
|
520 | 562 | return self.traits(**metadata).keys() |
General Comments 0
You need to be logged in to leave comments.
Login now