##// END OF EJS Templates
use argparse to parse aliases & flags
MinRK -
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 KeyValueConfigLoader, PyFileConfigLoader, Config, ArgumentError
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 = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
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 exec_str = 'self.config.' + lhs + '=' + rhs
491 self._exec_config_str(lhs, rhs)
467 try:
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