##// 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 28 from IPython.config.configurable import SingletonConfigurable
29 29 from IPython.config.loader import (
30 KeyValueConfigLoader, PyFileConfigLoader, Config, ArgumentError
30 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError
31 31 )
32 32
33 33 from IPython.utils.traitlets import (
@@ -46,8 +46,6 b' from IPython.utils.text import indent, wrap_paragraphs, dedent'
46 46
47 47 # merge flags&aliases into options
48 48 option_description = """
49 IPython command-line arguments are passed as '--<flag>', or '--<name>=<value>'.
50
51 49 Arguments that take values are actually convenience aliases to full
52 50 Configurables, whose aliases are listed on the help line. For more information
53 51 on full configurables, see '--help-all'.
@@ -210,6 +208,8 b' class Application(SingletonConfigurable):'
210 208 help = cls.class_get_trait_help(trait).splitlines()
211 209 # reformat first line
212 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 213 lines.extend(help)
214 214 # lines.append('')
215 215 print os.linesep.join(lines)
@@ -221,7 +221,8 b' class Application(SingletonConfigurable):'
221 221
222 222 lines = []
223 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 226 lines.append(indent(dedent(help.strip())))
226 227 # lines.append('')
227 228 print os.linesep.join(lines)
@@ -350,7 +351,7 b' class Application(SingletonConfigurable):'
350 351 self.print_version()
351 352 self.exit(0)
352 353
353 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
354 loader = KVArgParseConfigLoader(argv=argv, aliases=self.aliases,
354 355 flags=self.flags)
355 356 try:
356 357 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 exec_str = 'self.config.' + lhs + '=' + rhs
467 try:
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,69 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()
601 exec "self.config.%s = v"%k in locals(), globals()
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)
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)
587 658
659 for subc in subcs:
660 self._load_flag(subc)
588 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 69 self.assertEquals(config.D.C.value, 'hi there')
70 70
71 71 class MyLoader1(ArgParseConfigLoader):
72 def _add_arguments(self):
72 def _add_arguments(self, aliases=None, flags=None):
73 73 p = self.parser
74 74 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
75 75 p.add_argument('-b', dest='MyClass.bar', type=int)
@@ -77,7 +77,7 b' class MyLoader1(ArgParseConfigLoader):'
77 77 p.add_argument('Global.bam', type=str)
78 78
79 79 class MyLoader2(ArgParseConfigLoader):
80 def _add_arguments(self):
80 def _add_arguments(self, aliases=None, flags=None):
81 81 subparsers = self.parser.add_subparsers(dest='subparser_name')
82 82 subparser1 = subparsers.add_parser('1')
83 83 subparser1.add_argument('-x',dest='Global.x')
@@ -386,23 +386,39 b' Is the same as adding:'
386 386 to your config file. Key/Value arguments *always* take a value, separated by '='
387 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 403 Aliases
390 404 -------
391 405
392 For convenience, applications have a mapping of commonly
393 used traits, so you don't have to specify the whole class name. For these **aliases**, the class need not be specified:
406 For convenience, applications have a mapping of commonly used traits, so you don't have
407 to specify the whole class name:
394 408
395 409 .. code-block:: bash
396 410
411 $> ipython --profile myprofile
412 # and
397 413 $> ipython --profile='myprofile'
398 # is equivalent to
414 # are equivalent to
399 415 $> ipython --BaseIPythonApplication.profile='myprofile'
400 416
401 417 Flags
402 418 -----
403 419
404 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 422 setting one or more configurables with predefined values, often True/False.
407 423
408 424 For instance:
@@ -416,9 +432,13 b' For instance:'
416 432 $> ipython --pylab
417 433 # is equivalent to
418 434 $> ipython --pylab=auto
435 # or
436 $> ipython --no-banner
437 # is equivalent to
438 $> ipython --TerminalIPythonApp.display_banner=False
419 439
420 440 Subcommands
421 -----------
441 ***********
422 442
423 443
424 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 83 ``--[no-]banner``
84 84 Print the initial information banner (default on).
85 85
86 ``--c=<command>``
86 ``-c <command>``
87 87 execute the given command string. This is similar to the -c
88 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 158 ipython_log.py in your current directory (which prevents logs
159 159 from multiple IPython sessions from trampling each other). You
160 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 163 ``--logplay=<name>``
164 164
@@ -205,7 +205,7 b' simply start a controller and engines on a single host using the'
205 205 :command:`ipcluster` command. To start a controller and 4 engines on your
206 206 localhost, just do::
207 207
208 $ ipcluster start --n=4
208 $ ipcluster start -n 4
209 209
210 210 More details about starting the IPython controller and engines can be found
211 211 :ref:`here <parallel_process>`
@@ -52,7 +52,7 b' The easiest approach is to use the `MPIExec` Launchers in :command:`ipcluster`,'
52 52 which will first start a controller and then a set of engines using
53 53 :command:`mpiexec`::
54 54
55 $ ipcluster start --n=4 --elauncher=MPIExecEngineSetLauncher
55 $ ipcluster start -n 4 --elauncher=MPIExecEngineSetLauncher
56 56
57 57 This approach is best as interrupting :command:`ipcluster` will automatically
58 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 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 110 .. note::
111 111
@@ -19,7 +19,7 b' To follow along with this tutorial, you will need to start the IPython'
19 19 controller and four IPython engines. The simplest way of doing this is to use
20 20 the :command:`ipcluster` command::
21 21
22 $ ipcluster start --n=4
22 $ ipcluster start -n 4
23 23
24 24 For more detailed information about starting the controller and engines, see
25 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 109 launch a controller and a number of engines on the local machine. For instance,
110 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 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 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 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 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 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 24 controller and four IPython engines. The simplest way of doing this is to use
25 25 the :command:`ipcluster` command::
26 26
27 $ ipcluster start --n=4
27 $ ipcluster start -n 4
28 28
29 29 For more detailed information about starting the controller and engines, see
30 30 our :ref:`introduction <parallel_overview>` to using IPython for parallel computing.
@@ -257,7 +257,7 b' Starting the cluster profile'
257 257 Once a cluster profile has been configured, starting an IPython cluster using
258 258 the profile is simple::
259 259
260 ipcluster start --profile=mycluster --n=32
260 ipcluster start --profile=mycluster -n 32
261 261
262 262 The ``-n`` option tells :command:`ipcluster` how many engines to start (in
263 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