Show More
@@ -27,7 +27,7 b' from copy import deepcopy' | |||
|
27 | 27 | |
|
28 | 28 | from IPython.config.configurable import SingletonConfigurable |
|
29 | 29 | from IPython.config.loader import ( |
|
30 |
K |
|
|
30 | KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError | |
|
31 | 31 | ) |
|
32 | 32 | |
|
33 | 33 | from IPython.utils.traitlets import ( |
@@ -350,7 +350,7 b' class Application(SingletonConfigurable):' | |||
|
350 | 350 | self.print_version() |
|
351 | 351 | self.exit(0) |
|
352 | 352 | |
|
353 |
loader = K |
|
|
353 | loader = KVArgParseConfigLoader(argv=argv, aliases=self.aliases, | |
|
354 | 354 | flags=self.flags) |
|
355 | 355 | try: |
|
356 | 356 | config = loader.load_config() |
@@ -326,6 +326,31 b' class CommandLineConfigLoader(ConfigLoader):' | |||
|
326 | 326 | here. |
|
327 | 327 | """ |
|
328 | 328 | |
|
329 | def _exec_config_str(self, lhs, rhs): | |
|
330 | exec_str = 'self.config.' + lhs + '=' + rhs | |
|
331 | try: | |
|
332 | # Try to see if regular Python syntax will work. This | |
|
333 | # won't handle strings as the quote marks are removed | |
|
334 | # by the system shell. | |
|
335 | exec exec_str in locals(), globals() | |
|
336 | except (NameError, SyntaxError): | |
|
337 | # This case happens if the rhs is a string but without | |
|
338 | # the quote marks. Use repr, to get quote marks, and | |
|
339 | # 'u' prefix and see if | |
|
340 | # it succeeds. If it still fails, we let it raise. | |
|
341 | exec_str = u'self.config.' + lhs + '=' + repr(rhs) | |
|
342 | exec exec_str in locals(), globals() | |
|
343 | ||
|
344 | def _load_flag(self, cfg): | |
|
345 | """update self.config from a flag, which can be a dict or Config""" | |
|
346 | if isinstance(cfg, (dict, Config)): | |
|
347 | # don't clobber whole config sections, update | |
|
348 | # each section from config: | |
|
349 | for sec,c in cfg.iteritems(): | |
|
350 | self.config[sec].update(c) | |
|
351 | else: | |
|
352 | raise ValueError("Invalid flag: '%s'"%raw) | |
|
353 | ||
|
329 | 354 | # raw --identifier=value pattern |
|
330 | 355 | # but *also* accept '-' as wordsep, for aliases |
|
331 | 356 | # accepts: --foo=a |
@@ -463,29 +488,12 b' class KeyValueConfigLoader(CommandLineConfigLoader):' | |||
|
463 | 488 | if '.' not in lhs: |
|
464 | 489 | # probably a mistyped alias, but not technically illegal |
|
465 | 490 | warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs) |
|
466 |
|
|
|
467 |
|
|
|
468 | # Try to see if regular Python syntax will work. This | |
|
469 | # won't handle strings as the quote marks are removed | |
|
470 | # by the system shell. | |
|
471 | exec exec_str in locals(), globals() | |
|
472 | except (NameError, SyntaxError): | |
|
473 | # This case happens if the rhs is a string but without | |
|
474 | # the quote marks. Use repr, to get quote marks, and | |
|
475 | # 'u' prefix and see if | |
|
476 | # it succeeds. If it still fails, we let it raise. | |
|
477 | exec_str = u'self.config.' + lhs + '=' + repr(rhs) | |
|
478 | exec exec_str in locals(), globals() | |
|
491 | self._exec_config_str(lhs, rhs) | |
|
492 | ||
|
479 | 493 | elif flag_pattern.match(raw): |
|
480 | 494 | if item in flags: |
|
481 | 495 | cfg,help = flags[item] |
|
482 | if isinstance(cfg, (dict, Config)): | |
|
483 | # don't clobber whole config sections, update | |
|
484 | # each section from config: | |
|
485 | for sec,c in cfg.iteritems(): | |
|
486 | self.config[sec].update(c) | |
|
487 | else: | |
|
488 | raise ValueError("Invalid flag: '%s'"%raw) | |
|
496 | self._load_flag(cfg) | |
|
489 | 497 | else: |
|
490 | 498 | raise ArgumentError("Unrecognized flag: '%s'"%raw) |
|
491 | 499 | elif raw.startswith('-'): |
@@ -503,7 +511,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):' | |||
|
503 | 511 | class ArgParseConfigLoader(CommandLineConfigLoader): |
|
504 | 512 | """A loader that uses the argparse module to load from the command line.""" |
|
505 | 513 | |
|
506 | def __init__(self, argv=None, *parser_args, **parser_kw): | |
|
514 | def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw): | |
|
507 | 515 | """Create a config loader for use with argparse. |
|
508 | 516 | |
|
509 | 517 | Parameters |
@@ -527,16 +535,20 b' class ArgParseConfigLoader(CommandLineConfigLoader):' | |||
|
527 | 535 | The resulting Config object. |
|
528 | 536 | """ |
|
529 | 537 | super(CommandLineConfigLoader, self).__init__() |
|
530 | if argv == None: | |
|
538 | self.clear() | |
|
539 | if argv is None: | |
|
531 | 540 | argv = sys.argv[1:] |
|
532 | 541 | self.argv = argv |
|
542 | self.aliases = aliases or {} | |
|
543 | self.flags = flags or {} | |
|
544 | ||
|
533 | 545 | self.parser_args = parser_args |
|
534 | 546 | self.version = parser_kw.pop("version", None) |
|
535 | 547 | kwargs = dict(argument_default=argparse.SUPPRESS) |
|
536 | 548 | kwargs.update(parser_kw) |
|
537 | 549 | self.parser_kw = kwargs |
|
538 | 550 | |
|
539 | def load_config(self, argv=None): | |
|
551 | def load_config(self, argv=None, aliases=None, flags=None): | |
|
540 | 552 | """Parse command line arguments and return as a Config object. |
|
541 | 553 | |
|
542 | 554 | Parameters |
@@ -549,7 +561,11 b' class ArgParseConfigLoader(CommandLineConfigLoader):' | |||
|
549 | 561 | self.clear() |
|
550 | 562 | if argv is None: |
|
551 | 563 | argv = self.argv |
|
552 | self._create_parser() | |
|
564 | if aliases is None: | |
|
565 | aliases = self.aliases | |
|
566 | if flags is None: | |
|
567 | flags = self.flags | |
|
568 | self._create_parser(aliases, flags) | |
|
553 | 569 | self._parse_args(argv) |
|
554 | 570 | self._convert_to_config() |
|
555 | 571 | return self.config |
@@ -560,11 +576,11 b' class ArgParseConfigLoader(CommandLineConfigLoader):' | |||
|
560 | 576 | else: |
|
561 | 577 | return [] |
|
562 | 578 | |
|
563 | def _create_parser(self): | |
|
579 | def _create_parser(self, aliases=None, flags=None): | |
|
564 | 580 | self.parser = ArgumentParser(*self.parser_args, **self.parser_kw) |
|
565 | self._add_arguments() | |
|
581 | self._add_arguments(aliases, flags) | |
|
566 | 582 | |
|
567 | def _add_arguments(self): | |
|
583 | def _add_arguments(self, aliases=None, flags=None): | |
|
568 | 584 | raise NotImplementedError("subclasses must implement _add_arguments") |
|
569 | 585 | |
|
570 | 586 | def _parse_args(self, args): |
@@ -582,7 +598,63 b' class ArgParseConfigLoader(CommandLineConfigLoader):' | |||
|
582 | 598 | def _convert_to_config(self): |
|
583 | 599 | """self.parsed_data->self.config""" |
|
584 | 600 | for k, v in vars(self.parsed_data).iteritems(): |
|
585 | exec_str = 'self.config.' + k + '= v' | |
|
586 | exec exec_str in locals(), globals() | |
|
587 | ||
|
588 | ||
|
601 | self._exec_config_str(k, v) | |
|
602 | ||
|
603 | class KVArgParseConfigLoader(ArgParseConfigLoader): | |
|
604 | """A config loader that loads aliases and flags with argparse, | |
|
605 | but will use KVLoader for the rest. This allows better parsing | |
|
606 | of common args, such as `ipython -c 'print 5'`, but still gets | |
|
607 | arbitrary config with `ipython --InteractiveShell.use_readline=False`""" | |
|
608 | def _add_arguments(self, aliases=None, flags=None): | |
|
609 | self.alias_flags = {} | |
|
610 | # print aliases, flags | |
|
611 | if aliases is None: | |
|
612 | aliases = self.aliases | |
|
613 | if flags is None: | |
|
614 | flags = self.flags | |
|
615 | paa = self.parser.add_argument | |
|
616 | for key,value in aliases.iteritems(): | |
|
617 | if key in flags: | |
|
618 | # flags | |
|
619 | nargs = '?' | |
|
620 | else: | |
|
621 | nargs = None | |
|
622 | if len(key) is 1: | |
|
623 | paa('-'+key, '--'+key, type=str, dest=value, nargs=nargs) | |
|
624 | else: | |
|
625 | paa('--'+key, type=str, dest=value, nargs=nargs) | |
|
626 | for key, (value, help) in flags.iteritems(): | |
|
627 | if key in self.aliases: | |
|
628 | # | |
|
629 | self.alias_flags[self.aliases[key]] = value | |
|
630 | continue | |
|
631 | if len(key) is 1: | |
|
632 | paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value) | |
|
633 | else: | |
|
634 | paa('--'+key, action='append_const', dest='_flags', const=value) | |
|
635 | ||
|
636 | def _convert_to_config(self): | |
|
637 | """self.parsed_data->self.config, parse unrecognized extra args via KVLoader.""" | |
|
638 | # remove subconfigs list from namespace before transforming the Namespace | |
|
639 | if '_flags' in self.parsed_data: | |
|
640 | subcs = self.parsed_data._flags | |
|
641 | del self.parsed_data._flags | |
|
642 | else: | |
|
643 | subcs = [] | |
|
644 | ||
|
645 | for k, v in vars(self.parsed_data).iteritems(): | |
|
646 | if v is None: | |
|
647 | # it was a flag that shares the name of an alias | |
|
648 | subcs.append(self.alias_flags[k]) | |
|
649 | else: | |
|
650 | # eval the KV assignment | |
|
651 | self._exec_config_str(k, v) | |
|
652 | ||
|
653 | for subc in subcs: | |
|
654 | self.config.update(subc) | |
|
655 | ||
|
656 | if self.extra_args: | |
|
657 | sub_parser = KeyValueConfigLoader() | |
|
658 | sub_parser.load_config(self.extra_args) | |
|
659 | self.config.update(sub_parser.config) | |
|
660 | self.extra_args = sub_parser.extra_args |
General Comments 0
You need to be logged in to leave comments.
Login now