##// END OF EJS Templates
Merge pull request #674 from minrk/argparse...
Fernando Perez -
r4617:832789bd merge
parent child Browse files
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 (
@@ -46,8 +46,6 b' from IPython.utils.text import indent, wrap_paragraphs, dedent'
46
46
47 # merge flags&aliases into options
47 # merge flags&aliases into options
48 option_description = """
48 option_description = """
49 IPython command-line arguments are passed as '--<flag>', or '--<name>=<value>'.
50
51 Arguments that take values are actually convenience aliases to full
49 Arguments that take values are actually convenience aliases to full
52 Configurables, whose aliases are listed on the help line. For more information
50 Configurables, whose aliases are listed on the help line. For more information
53 on full configurables, see '--help-all'.
51 on full configurables, see '--help-all'.
@@ -210,6 +208,8 b' class Application(SingletonConfigurable):'
210 help = cls.class_get_trait_help(trait).splitlines()
208 help = cls.class_get_trait_help(trait).splitlines()
211 # reformat first line
209 # reformat first line
212 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
210 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
211 if len(alias) == 1:
212 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
213 lines.extend(help)
213 lines.extend(help)
214 # lines.append('')
214 # lines.append('')
215 print os.linesep.join(lines)
215 print os.linesep.join(lines)
@@ -221,7 +221,8 b' class Application(SingletonConfigurable):'
221
221
222 lines = []
222 lines = []
223 for m, (cfg,help) in self.flags.iteritems():
223 for m, (cfg,help) in self.flags.iteritems():
224 lines.append('--'+m)
224 prefix = '--' if len(m) > 1 else '-'
225 lines.append(prefix+m)
225 lines.append(indent(dedent(help.strip())))
226 lines.append(indent(dedent(help.strip())))
226 # lines.append('')
227 # lines.append('')
227 print os.linesep.join(lines)
228 print os.linesep.join(lines)
@@ -350,7 +351,7 b' class Application(SingletonConfigurable):'
350 self.print_version()
351 self.print_version()
351 self.exit(0)
352 self.exit(0)
352
353
353 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
354 loader = KVArgParseConfigLoader(argv=argv, aliases=self.aliases,
354 flags=self.flags)
355 flags=self.flags)
355 try:
356 try:
356 config = loader.load_config()
357 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,69 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 exec "self.config.%s = v"%k in locals(), globals()
586 exec exec_str in locals(), globals()
587
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
609 def _convert_to_config(self):
610 """self.parsed_data->self.config"""
611 for k, v in vars(self.parsed_data).iteritems():
612 self._exec_config_str(k, v)
588
613
614 def _add_arguments(self, aliases=None, flags=None):
615 self.alias_flags = {}
616 # print aliases, flags
617 if aliases is None:
618 aliases = self.aliases
619 if flags is None:
620 flags = self.flags
621 paa = self.parser.add_argument
622 for key,value in aliases.iteritems():
623 if key in flags:
624 # flags
625 nargs = '?'
626 else:
627 nargs = None
628 if len(key) is 1:
629 paa('-'+key, '--'+key, type=str, dest=value, nargs=nargs)
630 else:
631 paa('--'+key, type=str, dest=value, nargs=nargs)
632 for key, (value, help) in flags.iteritems():
633 if key in self.aliases:
634 #
635 self.alias_flags[self.aliases[key]] = value
636 continue
637 if len(key) is 1:
638 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
639 else:
640 paa('--'+key, action='append_const', dest='_flags', const=value)
641
642 def _convert_to_config(self):
643 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
644 # remove subconfigs list from namespace before transforming the Namespace
645 if '_flags' in self.parsed_data:
646 subcs = self.parsed_data._flags
647 del self.parsed_data._flags
648 else:
649 subcs = []
650
651 for k, v in vars(self.parsed_data).iteritems():
652 if v is None:
653 # it was a flag that shares the name of an alias
654 subcs.append(self.alias_flags[k])
655 else:
656 # eval the KV assignment
657 self._exec_config_str(k, v)
658
659 for subc in subcs:
660 self._load_flag(subc)
661
662 if self.extra_args:
663 sub_parser = KeyValueConfigLoader()
664 sub_parser.load_config(self.extra_args)
665 self.config._merge(sub_parser.config)
666 self.extra_args = sub_parser.extra_args
@@ -69,7 +69,7 b' class TestPyFileCL(TestCase):'
69 self.assertEquals(config.D.C.value, 'hi there')
69 self.assertEquals(config.D.C.value, 'hi there')
70
70
71 class MyLoader1(ArgParseConfigLoader):
71 class MyLoader1(ArgParseConfigLoader):
72 def _add_arguments(self):
72 def _add_arguments(self, aliases=None, flags=None):
73 p = self.parser
73 p = self.parser
74 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
74 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
75 p.add_argument('-b', dest='MyClass.bar', type=int)
75 p.add_argument('-b', dest='MyClass.bar', type=int)
@@ -77,7 +77,7 b' class MyLoader1(ArgParseConfigLoader):'
77 p.add_argument('Global.bam', type=str)
77 p.add_argument('Global.bam', type=str)
78
78
79 class MyLoader2(ArgParseConfigLoader):
79 class MyLoader2(ArgParseConfigLoader):
80 def _add_arguments(self):
80 def _add_arguments(self, aliases=None, flags=None):
81 subparsers = self.parser.add_subparsers(dest='subparser_name')
81 subparsers = self.parser.add_subparsers(dest='subparser_name')
82 subparser1 = subparsers.add_parser('1')
82 subparser1 = subparsers.add_parser('1')
83 subparser1.add_argument('-x',dest='Global.x')
83 subparser1.add_argument('-x',dest='Global.x')
@@ -386,23 +386,39 b' Is the same as adding:'
386 to your config file. Key/Value arguments *always* take a value, separated by '='
386 to your config file. Key/Value arguments *always* take a value, separated by '='
387 and no spaces.
387 and no spaces.
388
388
389 Common Arguments
390 ****************
391
392 Since the strictness and verbosity of the KVLoader above are not ideal for everyday
393 use, common arguments can be specified as flags_ or aliases_.
394
395 Flags and Aliases are handled by :mod:`argparse` instead, allowing for more flexible
396 parsing. In general, flags and aliases are prefixed by ``--``, except for those
397 that are single characters, in which case they can be specified with a single ``-``, e.g.:
398
399 .. code-block:: bash
400
401 $> ipython -i -c "import numpy; x=numpy.linspace(0,1)" --profile testing --colors=lightbg
402
389 Aliases
403 Aliases
390 -------
404 -------
391
405
392 For convenience, applications have a mapping of commonly
406 For convenience, applications have a mapping of commonly used traits, so you don't have
393 used traits, so you don't have to specify the whole class name. For these **aliases**, the class need not be specified:
407 to specify the whole class name:
394
408
395 .. code-block:: bash
409 .. code-block:: bash
396
410
411 $> ipython --profile myprofile
412 # and
397 $> ipython --profile='myprofile'
413 $> ipython --profile='myprofile'
398 # is equivalent to
414 # are equivalent to
399 $> ipython --BaseIPythonApplication.profile='myprofile'
415 $> ipython --BaseIPythonApplication.profile='myprofile'
400
416
401 Flags
417 Flags
402 -----
418 -----
403
419
404 Applications can also be passed **flags**. Flags are options that take no
420 Applications can also be passed **flags**. Flags are options that take no
405 arguments, and are always prefixed with ``--``. They are simply wrappers for
421 arguments. They are simply wrappers for
406 setting one or more configurables with predefined values, often True/False.
422 setting one or more configurables with predefined values, often True/False.
407
423
408 For instance:
424 For instance:
@@ -412,13 +428,17 b' For instance:'
412 $> ipcontroller --debug
428 $> ipcontroller --debug
413 # is equivalent to
429 # is equivalent to
414 $> ipcontroller --Application.log_level=DEBUG
430 $> ipcontroller --Application.log_level=DEBUG
415 # and
431 # and
416 $> ipython --pylab
432 $> ipython --pylab
417 # is equivalent to
433 # is equivalent to
418 $> ipython --pylab=auto
434 $> ipython --pylab=auto
435 # or
436 $> ipython --no-banner
437 # is equivalent to
438 $> ipython --TerminalIPythonApp.display_banner=False
419
439
420 Subcommands
440 Subcommands
421 -----------
441 ***********
422
442
423
443
424 Some IPython applications have **subcommands**. Subcommands are modeled after
444 Some IPython applications have **subcommands**. Subcommands are modeled after
@@ -83,7 +83,7 b' All options with a [no] prepended can be specified in negated form'
83 ``--[no-]banner``
83 ``--[no-]banner``
84 Print the initial information banner (default on).
84 Print the initial information banner (default on).
85
85
86 ``--c=<command>``
86 ``-c <command>``
87 execute the given command string. This is similar to the -c
87 execute the given command string. This is similar to the -c
88 option in the normal Python interpreter.
88 option in the normal Python interpreter.
89
89
@@ -158,7 +158,7 b' All options with a [no] prepended can be specified in negated form'
158 ipython_log.py in your current directory (which prevents logs
158 ipython_log.py in your current directory (which prevents logs
159 from multiple IPython sessions from trampling each other). You
159 from multiple IPython sessions from trampling each other). You
160 can use this to later restore a session by loading your
160 can use this to later restore a session by loading your
161 logfile with ``ipython --i ipython_log.py``
161 logfile with ``ipython -i ipython_log.py``
162
162
163 ``--logplay=<name>``
163 ``--logplay=<name>``
164
164
@@ -205,7 +205,7 b' simply start a controller and engines on a single host using the'
205 :command:`ipcluster` command. To start a controller and 4 engines on your
205 :command:`ipcluster` command. To start a controller and 4 engines on your
206 localhost, just do::
206 localhost, just do::
207
207
208 $ ipcluster start --n=4
208 $ ipcluster start -n 4
209
209
210 More details about starting the IPython controller and engines can be found
210 More details about starting the IPython controller and engines can be found
211 :ref:`here <parallel_process>`
211 :ref:`here <parallel_process>`
@@ -52,7 +52,7 b' The easiest approach is to use the `MPIExec` Launchers in :command:`ipcluster`,'
52 which will first start a controller and then a set of engines using
52 which will first start a controller and then a set of engines using
53 :command:`mpiexec`::
53 :command:`mpiexec`::
54
54
55 $ ipcluster start --n=4 --elauncher=MPIExecEngineSetLauncher
55 $ ipcluster start -n 4 --elauncher=MPIExecEngineSetLauncher
56
56
57 This approach is best as interrupting :command:`ipcluster` will automatically
57 This approach is best as interrupting :command:`ipcluster` will automatically
58 stop and clean up the controller and engines.
58 stop and clean up the controller and engines.
@@ -105,7 +105,7 b' distributed array. Save the following text in a file called :file:`psum.py`:'
105
105
106 Now, start an IPython cluster::
106 Now, start an IPython cluster::
107
107
108 $ ipcluster start --profile=mpi --n=4
108 $ ipcluster start --profile=mpi -n 4
109
109
110 .. note::
110 .. note::
111
111
@@ -19,7 +19,7 b' To follow along with this tutorial, you will need to start the IPython'
19 controller and four IPython engines. The simplest way of doing this is to use
19 controller and four IPython engines. The simplest way of doing this is to use
20 the :command:`ipcluster` command::
20 the :command:`ipcluster` command::
21
21
22 $ ipcluster start --n=4
22 $ ipcluster start -n 4
23
23
24 For more detailed information about starting the controller and engines, see
24 For more detailed information about starting the controller and engines, see
25 our :ref:`introduction <parallel_overview>` to using IPython for parallel computing.
25 our :ref:`introduction <parallel_overview>` to using IPython for parallel computing.
@@ -109,7 +109,7 b' The simplest way to use ipcluster requires no configuration, and will'
109 launch a controller and a number of engines on the local machine. For instance,
109 launch a controller and a number of engines on the local machine. For instance,
110 to start one controller and 4 engines on localhost, just do::
110 to start one controller and 4 engines on localhost, just do::
111
111
112 $ ipcluster start --n=4
112 $ ipcluster start -n 4
113
113
114 To see other command line options, do::
114 To see other command line options, do::
115
115
@@ -174,7 +174,7 b' There, instruct ipcluster to use the MPIExec launchers by adding the lines:'
174
174
175 If the default MPI configuration is correct, then you can now start your cluster, with::
175 If the default MPI configuration is correct, then you can now start your cluster, with::
176
176
177 $ ipcluster start --n=4 --profile=mpi
177 $ ipcluster start -n 4 --profile=mpi
178
178
179 This does the following:
179 This does the following:
180
180
@@ -324,7 +324,7 b' connections on all its interfaces, by adding in :file:`ipcontroller_config`:'
324
324
325 You can now run the cluster with::
325 You can now run the cluster with::
326
326
327 $ ipcluster start --profile=pbs --n=128
327 $ ipcluster start --profile=pbs -n 128
328
328
329 Additional configuration options can be found in the PBS section of :file:`ipcluster_config`.
329 Additional configuration options can be found in the PBS section of :file:`ipcluster_config`.
330
330
@@ -24,7 +24,7 b' To follow along with this tutorial, you will need to start the IPython'
24 controller and four IPython engines. The simplest way of doing this is to use
24 controller and four IPython engines. The simplest way of doing this is to use
25 the :command:`ipcluster` command::
25 the :command:`ipcluster` command::
26
26
27 $ ipcluster start --n=4
27 $ ipcluster start -n 4
28
28
29 For more detailed information about starting the controller and engines, see
29 For more detailed information about starting the controller and engines, see
30 our :ref:`introduction <parallel_overview>` to using IPython for parallel computing.
30 our :ref:`introduction <parallel_overview>` to using IPython for parallel computing.
@@ -257,7 +257,7 b' Starting the cluster profile'
257 Once a cluster profile has been configured, starting an IPython cluster using
257 Once a cluster profile has been configured, starting an IPython cluster using
258 the profile is simple::
258 the profile is simple::
259
259
260 ipcluster start --profile=mycluster --n=32
260 ipcluster start --profile=mycluster -n 32
261
261
262 The ``-n`` option tells :command:`ipcluster` how many engines to start (in
262 The ``-n`` option tells :command:`ipcluster` how many engines to start (in
263 this case 32). Stopping the cluster is as simple as typing Control-C.
263 this case 32). Stopping the cluster is as simple as typing Control-C.
General Comments 0
You need to be logged in to leave comments. Login now