# `cement.ext.ext_argparse`

The Argparse Extension provides argument handling based on `argparse.ArgumentParser`, and is the default argument handler used by `cement.core.foundation.CementApp`. In addition, this extension also provides `ArgparseController` that enables rapid development via application controllers based on Argparse.

## Requirements

> - Python 2.7+, Python 3+
> - Some features of `ArgparseController` are only available in Python 3 including controller and function/command `aliases` (Python 3+) and controller default functions/command (Python 3.4+).

## Configuration

This extension does not have any application configuration settings.

## Usage

The following is an example application using both the `ArgparseArgumentHandler` and `ArgparseController`. Note that the default `arg_handler` is already set to `ArgparseArgumentHandler`` by `CementApp`.

    from cement.core.foundation import CementApp
    from cement.ext.ext_argparse import ArgparseController, expose

    class BaseController(ArgparseController):
        class Meta:
            label = 'base'
            arguments = [
                (['--base-foo'], dict(help='base foo option')),
            ]

        @expose(hide=True)
        def default(self):
            # Note: Default commands are only available in Python 3.4+
            print('Inside BaseController.default')

            if self.app.pargs.base_foo:
                # do something with self.app.pargs.base_foo
                print('Base Foo > %s' % self.app.pargs.base_foo)

        @expose(
            arguments=[
                (['--command1-opt'],
                 dict(help='option under command1', action='store_true'))
            ],
            aliases=['cmd1'],
            help='command1 is a sub-command under myapp base controller',
        )
        def command1(self):
            print('Inside BaseController.command1')

            if self.app.pargs.command1_opt:
                # do something with self.app.pargs.command1_opt
                pass

    class EmbeddedController(ArgparseController):
        class Meta:
            label = 'embedded_controller'
            stacked_on = 'base'
            stacked_type = 'embedded'

        @expose(help="command2 embedded under base controller")
        def command2(self):
            print('Inside EmbeddedController.command2')

    class NestedController(ArgparseController):
        class Meta:
            label = 'nested_controller'
            stacked_on = 'base'
            stacked_type = 'nested'
            arguments = [
                (['--nested-opt'],
                 dict(help='option under nested-controller')),
            ]

        @expose(help="command3 under nested-controller")
        def command3(self):
            print('Inside NestedController.command3')

    class MyApp(CementApp):
        class Meta:
            label = 'myapp'
            handlers = [
                BaseController,
                EmbeddedController,
                NestedController
            ]

    with MyApp() as app:
        app.run()

The above looks like:

    $ python myapp.py --help
    usage: myapp.py [-h] [--debug] [--quiet] [--base-foo BASE_FOO]
                    {nested-controller,command1,cmd1,default,command2} ...

    optional arguments:
      -h, --help            show this help message and exit
      --debug               toggle debug output
      --quiet               suppress all output
      --base-foo BASE_FOO   base foo option

    sub-commands:
      {nested-controller,command1,cmd1,default,command2}
        nested-controller   nested-controller controller
        command1 (cmd1)     command1 is a sub-command under base controller
        command2            command2 embedded under base controller

    $ python myapp.py --base-foo bar
    Inside BaseController.default
    Base Foo > bar

    $ python myapp.py command1 --help
    usage: myapp.py command1 [-h] [--command1-opt]

    optional arguments:
      -h, --help      show this help message and exit
      --command1-opt  option under command1

    $ python myapp.py command1
    Inside BaseController.command1

    $ python myapp.py command2
    Inside EmbeddedController.command2

    $ python myapp.py nested-controller --help
    usage: myapp.py nested-controller [-h] [--nested-opt] {command3} ...

    optional arguments:
      -h, --help            show this help message and exit
      --nested-opt          option under nested-controller

    sub-commands:
      {command3}
        command3            command3 under nested-controller

    $ python myapp.py nested-controller command3
    Inside NestedController.command3

class `cement.ext.ext_argparse.``ArgParseArgumentHandler`(*args, **kw)

  Bases: `cement.ext.ext_argparse.ArgparseArgumentHandler`

class `cement.ext.ext_argparse.``ArgparseArgumentHandler`(*args, **kw)

  Bases: `argparse.ArgumentParser`, `cement.core.arg.CementArgumentHandler`

  This class implements the `cement.core.arg.IArgument` interface, and sub-classes from `argparse.ArgumentParser`. Please reference the argparse documentation for full usage of the class.

  Arguments and Keyword arguments are passed directly to ArgumentParser on initialization.

  class `Meta`

    Bases: `object`

    Handler meta-data.

    `ignore_unknown_arguments` = False

      Whether or not to ignore any arguments passed that are not defined. Default behavoir by Argparse is to raise an “unknown argument” exception by Argparse.

      This affectively triggers the difference between using `parse_args` and `parse_known_args`. Unknown arguments will be accessible as `unknown_args`.

    `interface`

      alias of `cement.core.arg.IArgument`

    `label` = 'argparse'

      The string identifier of the handler.

  `add_argument`(*args, **kw)

    Add an argument to the parser. Arguments and keyword arguments are passed directly to `ArgumentParser.add_argument()`. See the `argparse.ArgumentParser` documentation for help.

  `parse`(arg_list)

    Parse a list of arguments, and return them as an object. Meaning an argument name of ‘foo’ will be stored as parsed_args.foo.

    Parameters: | arg_list – A list of arguments (generally sys.argv) to be parsed.
    Returns: | object whose members are the arguments parsed.

class `cement.ext.ext_argparse.``ArgparseController`(*args, **kw)

  Bases: `cement.core.handler.CementBaseHandler`

  This is an implementation of the `cement.core.controller.IController` interface, but as a base class that application controllers should subclass from. Registering it directly as a handler is useless.

  NOTE: This handler requires that the applications `arg_handler` be `argparse`. If using an alternative argument handler you will need to write your own controller base class or modify this one.

  NOTE: This is a re-implementation of `cement.core.controller.CementBaseController`. In the future, this class will eventually replace it as the default.

  Usage:

      from cement.ext.ext_argparse import ArgparseController

      class Base(ArgparseController):
          class Meta:
              label = 'base'
              description = 'description at the top of --help'
              epilog = "the text at the bottom of --help."
              arguments = [
                  (['-f', '--foo'], dict(help='my foo option', dest='foo')),
              ]

      class Second(ArgparseController):
          class Meta:
              label = 'second'
              stacked_on = 'base'
              stacked_type = 'embedded'
              arguments = [
                  (['--foo2'], dict(help='my foo2 option', dest='foo2')),
              ]

  class `Meta`

    Bases: `object`

    Controller meta-data (can be passed as keyword arguments to the parent class).

    `aliases` = []

      A list of aliases for the controller/sub-parser. Only available in Python > 3.

    `arguments` = []

      Arguments to pass to the argument_handler. The format is a list of tuples whos items are a ( list, dict ). Meaning:

      `[ ( ['-f', '--foo'], dict(help='foo option', dest='foo') ), ]`

      This is equivelant to manually adding each argument to the argument parser as in the following example:

      `add_argument('-f', '--foo', help='foo option', dest='foo')`

    `config_defaults` = {}

      Configuration defaults (type: dict) that are merged into the applications config object for the config_section mentioned above.

    `config_section` = None

      A config [section] to merge config_defaults into. Cement will default to controller.<label> if None is set.

    `default_func` = 'default'

      Function to call if no sub-command is passed. Note that this can not start with an `_` due to backward compatibility restraints in how Cement discovers and maps commands.

      Note: Currently, default function/sub-command only functions on Python > 3.4. Previous versions of Python/Argparse will throw the exception `error: too few arguments`.

    `description` = None

      Description for the sub-parser group in help output.

    `epilog` = None

      The text that is displayed at the bottom when `--help` is passed.

    `help` = None

      Text for the controller/sub-parser group in help output (for nested stacked controllers only).

    `hide` = False

      Whether or not to hide the controller entirely.

    `interface`

      alias of `cement.core.controller.IController`

    `label` = 'base'

      The string identifier for the controller.

    `parser_options` = {}

      Additional keyword arguments passed when `ArgumentParser.add_parser()` is called to create this controller sub-parser. WARNING: This could break things, use at your own risk. Useful if you need additional features from Argparse that is not built into the controller Meta-data.

    `stacked_on` = 'base'

      A label of another controller to ‘stack’ commands/arguments on top of.

    `stacked_type` = 'embedded'

      Whether to embed commands and arguments within the parent controller’s namespace, or to nest this controller under the parent controller (making it a sub-command). Must be one of `['embedded', 'nested']`.

    `subparser_options` = {}

      Additional keyword arguments passed when `ArgumentParser.add_subparsers()` is called to create this controller namespace. WARNING: This could break things, use at your own risk. Useful if you need additional features from Argparse that is not built into the controller Meta-data.

    `title` = 'sub-commands'

      The title for the sub-parser group in help output.

    `usage` = None

      The text that is displayed at the top when `--help` is passed. Defaults to Argparse standard usage.

  `_post_argument_parsing`()

    Called on every controller just after arguments are parsed (assuming that the parser hasn’t thrown an exception). Provides an alternative means of handling passed arguments. Note that, this function is called on every controller, regardless of what namespace and sub-command is eventually going to be called. Therefore, every controller can handle their arguments if the user passed them.

    For example:

        $ myapp --foo bar some-controller --foo2 bar2 some-command

    In the above, the `base` controller (or a nested controller) would handle `--foo`, while `some-controller` would handle `foo2` before `some-command` is executed.

        class Base(ArgparseController):
            class Meta:
                label = 'base'

                arguments = [
                    (['-f', '--foo'],
                     dict(help='my foo option', dest=foo)),
                ]

            def _post_argument_parsing(self):
                if self.app.pargs.foo:
                    print('Got Foo Option Before Controller Dispatch')

    Note that `self._parser` within a controller is that individual controllers `sub-parser`, and is not the root parser `app.args` (unless you are the `base` controller, in which case `self._parser` is synonymous with `app.args`).

  `_pre_argument_parsing`()

    Called on every controller just before arguments are parsed. Provides an alternative means of adding arguments to the controller, giving more control than using `Meta.arguments`.

        class Base(ArgparseController):
            class Meta:
                label = 'base'

            def _pre_argument_parsing(self):
                p = self._parser
                p.add_argument('-f', '--foo',
                               help='my foo option',
                               dest='foo')

            def _post_argument_parsing(self):
                if self.app.pargs.foo:
                    print('Got Foo Option Before Controller Dispatch')

  `_setup`(app)

    See IController._setup().

class `cement.ext.ext_argparse.``expose`(hide=False, arguments=[], **parser_options)

  Bases: `object`

  Used to expose functions to be listed as sub-commands under the controller namespace. It also decorates the function with meta-data for the argument parser.

  Parameters:

  - hide (`boolean`) – Whether the command should be visible.
  - arguments – List of tuples that define arguments to add to this commands sub-parser.
  - parser_options (`dict`) – Additional options to pass to Argparse.

  Usage:

      from cement.ext.ext_argparse import ArgparseController, expose

      class Base(ArgparseController):
          class Meta:
              label = 'base'

          # Note: Default functions only work in Python > 3.4
          @expose(hide=True)
          def default(self):
              print("In Base.default()")

          @expose(
              help='this is the help message for my_command',
              aliases=['my_cmd'], # only available in Python 3+
              arguments=[
                  (['-f', '--foo'],
                   dict(help='foo option', action='store', dest='foo')),
              ]
          )
          def my_command(self):
              print("In Base.my_command()")