Show More
@@ -27,7 +27,7 b' from copy import deepcopy' | |||||
27 |
|
27 | |||
28 | from IPython.config.configurable import SingletonConfigurable |
|
28 | from IPython.config.configurable import SingletonConfigurable | |
29 | from IPython.config.loader import ( |
|
29 | from IPython.config.loader import ( | |
30 |
K |
|
30 | KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError | |
31 | ) |
|
31 | ) | |
32 |
|
32 | |||
33 | from IPython.utils.traitlets import ( |
|
33 | from IPython.utils.traitlets import ( | |
@@ -350,7 +350,7 b' class Application(SingletonConfigurable):' | |||||
350 | self.print_version() |
|
350 | self.print_version() | |
351 | self.exit(0) |
|
351 | self.exit(0) | |
352 |
|
352 | |||
353 |
loader = K |
|
353 | loader = KVArgParseConfigLoader(argv=argv, aliases=self.aliases, | |
354 | flags=self.flags) |
|
354 | flags=self.flags) | |
355 | try: |
|
355 | try: | |
356 | config = loader.load_config() |
|
356 | config = loader.load_config() |
@@ -326,6 +326,31 b' class CommandLineConfigLoader(ConfigLoader):' | |||||
326 | here. |
|
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 | # raw --identifier=value pattern |
|
354 | # raw --identifier=value pattern | |
330 | # but *also* accept '-' as wordsep, for aliases |
|
355 | # but *also* accept '-' as wordsep, for aliases | |
331 | # accepts: --foo=a |
|
356 | # accepts: --foo=a | |
@@ -463,29 +488,12 b' class KeyValueConfigLoader(CommandLineConfigLoader):' | |||||
463 | if '.' not in lhs: |
|
488 | if '.' not in lhs: | |
464 | # probably a mistyped alias, but not technically illegal |
|
489 | # probably a mistyped alias, but not technically illegal | |
465 | warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs) |
|
490 | warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs) | |
466 |
|
|
491 | self._exec_config_str(lhs, rhs) | |
467 |
|
|
492 | ||
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() |
|
|||
479 | elif flag_pattern.match(raw): |
|
493 | elif flag_pattern.match(raw): | |
480 | if item in flags: |
|
494 | if item in flags: | |
481 | cfg,help = flags[item] |
|
495 | cfg,help = flags[item] | |
482 | if isinstance(cfg, (dict, Config)): |
|
496 | self._load_flag(cfg) | |
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) |
|
|||
489 | else: |
|
497 | else: | |
490 | raise ArgumentError("Unrecognized flag: '%s'"%raw) |
|
498 | raise ArgumentError("Unrecognized flag: '%s'"%raw) | |
491 | elif raw.startswith('-'): |
|
499 | elif raw.startswith('-'): | |
@@ -503,7 +511,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):' | |||||
503 | class ArgParseConfigLoader(CommandLineConfigLoader): |
|
511 | class ArgParseConfigLoader(CommandLineConfigLoader): | |
504 | """A loader that uses the argparse module to load from the command line.""" |
|
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 | """Create a config loader for use with argparse. |
|
515 | """Create a config loader for use with argparse. | |
508 |
|
516 | |||
509 | Parameters |
|
517 | Parameters | |
@@ -527,16 +535,20 b' class ArgParseConfigLoader(CommandLineConfigLoader):' | |||||
527 | The resulting Config object. |
|
535 | The resulting Config object. | |
528 | """ |
|
536 | """ | |
529 | super(CommandLineConfigLoader, self).__init__() |
|
537 | super(CommandLineConfigLoader, self).__init__() | |
530 | if argv == None: |
|
538 | self.clear() | |
|
539 | if argv is None: | |||
531 | argv = sys.argv[1:] |
|
540 | argv = sys.argv[1:] | |
532 | self.argv = argv |
|
541 | self.argv = argv | |
|
542 | self.aliases = aliases or {} | |||
|
543 | self.flags = flags or {} | |||
|
544 | ||||
533 | self.parser_args = parser_args |
|
545 | self.parser_args = parser_args | |
534 | self.version = parser_kw.pop("version", None) |
|
546 | self.version = parser_kw.pop("version", None) | |
535 | kwargs = dict(argument_default=argparse.SUPPRESS) |
|
547 | kwargs = dict(argument_default=argparse.SUPPRESS) | |
536 | kwargs.update(parser_kw) |
|
548 | kwargs.update(parser_kw) | |
537 | self.parser_kw = kwargs |
|
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 | """Parse command line arguments and return as a Config object. |
|
552 | """Parse command line arguments and return as a Config object. | |
541 |
|
553 | |||
542 | Parameters |
|
554 | Parameters | |
@@ -549,7 +561,11 b' class ArgParseConfigLoader(CommandLineConfigLoader):' | |||||
549 | self.clear() |
|
561 | self.clear() | |
550 | if argv is None: |
|
562 | if argv is None: | |
551 | argv = self.argv |
|
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 | self._parse_args(argv) |
|
569 | self._parse_args(argv) | |
554 | self._convert_to_config() |
|
570 | self._convert_to_config() | |
555 | return self.config |
|
571 | return self.config | |
@@ -560,11 +576,11 b' class ArgParseConfigLoader(CommandLineConfigLoader):' | |||||
560 | else: |
|
576 | else: | |
561 | return [] |
|
577 | return [] | |
562 |
|
578 | |||
563 | def _create_parser(self): |
|
579 | def _create_parser(self, aliases=None, flags=None): | |
564 | self.parser = ArgumentParser(*self.parser_args, **self.parser_kw) |
|
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 | raise NotImplementedError("subclasses must implement _add_arguments") |
|
584 | raise NotImplementedError("subclasses must implement _add_arguments") | |
569 |
|
585 | |||
570 | def _parse_args(self, args): |
|
586 | def _parse_args(self, args): | |
@@ -582,7 +598,63 b' class ArgParseConfigLoader(CommandLineConfigLoader):' | |||||
582 | def _convert_to_config(self): |
|
598 | def _convert_to_config(self): | |
583 | """self.parsed_data->self.config""" |
|
599 | """self.parsed_data->self.config""" | |
584 | for k, v in vars(self.parsed_data).iteritems(): |
|
600 | for k, v in vars(self.parsed_data).iteritems(): | |
585 | exec_str = 'self.config.' + k + '= v' |
|
601 | self._exec_config_str(k, v) | |
586 | exec exec_str in locals(), globals() |
|
602 | ||
587 |
|
603 | class KVArgParseConfigLoader(ArgParseConfigLoader): | ||
588 |
|
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