简体   繁体   中英

Python argparse: Store parameters not matching any subparser

I am using argparse library to parse arguments to my python script. This is my code:

 parser = argparse.ArgumentParser(
        prog="confgit",
        description="Git overhead for version control of your config files",
        formatter_class=argparse.RawTextHelpFormatter, )

    parser.add_argument(
        "-c", "--config",
        type=str,
        default=DEFAULT_CONFIG_PATH,
        dest="CONFIG_PATH",
        help="load alternative config")

    subparsers = parser.add_subparsers(help="Commands:")

    subparsers.add_parser("include", help="Include file or directory in to repository").add_argument(
        "file_to_include",
        type=str,
        action="store",
        nargs="?",
        const="",
        default=False,
        help="include file or directory in to repository")
    subparsers.add_parser("exclude", help="Exclude file or directory in to repository").add_argument(
        "exclude",
        type=str,
        action="store",
        help="exclude file or directory from repository")

    print(parser.parse_args())

I would like to be able to store parameters not matching any subparser as a string. For example running myprogram include test.txt --config.config/cfg.txt will result in:

Namespace(CONFIG_PATH='.config/cfg.txt', file_to_include='test.txt')

and running myprogram some text here will result in:

Namespace(CONFIG_PATH='.config/default.txt', input="some other text")

How can I achieve this?
Thank you for help

If the user doesn't quote the string "some other text" you will simply have to treat it as 3 different arguments ["some", "other", "text"] . But to handle it as closely as what you seem to desire you simply need to use the nargs option on an argument called input . The argparse page has an example at the very top with the "number accumulator".

    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument('integers', metavar='N', type=int, nargs='+',
                        help='an integer for the accumulator')

Use * for 0 or more arguments instead of + and replace integers with whatever argument name you want.


Upon further investigation what I wrote above won't work when you have subparsers. I would suggest making your include and exclude subcommands into options. Wouldn't it be sensible to want to do both anyway? In your current configuration you could only either include or exclude.

The helps from your code:

1940:~/mypy$ python3 stack65119253.py -h
usage: confgit [-h] [-c CONFIG_PATH] {include,exclude} ...

Git overhead for version control of your config files

positional arguments:
  {include,exclude}     Commands:
    include             Include file or directory in to repository
    exclude             Exclude file or directory in to repository

optional arguments:
  -h, --help            show this help message and exit
  -c CONFIG_PATH, --config CONFIG_PATH
                        load alternative config

So you can provide a optional '-c' with value.

The subparsers argument is a positional with 2 choices . It isn't required, but if you do provide a string it will be tested against those strings.

1941:~/mypy$ python3 stack65119253.py include -h
usage: confgit include [-h] [file_to_include]

positional arguments:
  file_to_include  include file or directory in to repository

optional arguments:
  -h, --help       show this help message and exit
1941:~/mypy$ python3 stack65119253.py exclude -h
usage: confgit exclude [-h] exclude

positional arguments:
  exclude     exclude file or directory from repository

optional arguments:
  -h, --help  show this help message and exit

For example:

1946:~/mypy$ python3 stack65119253.py -c foobar
Namespace(CONFIG_PATH='foobar')

1946:~/mypy$ python3 stack65119253.py -c foobar test
usage: confgit [-h] [-c CONFIG_PATH] {include,exclude} ...
confgit: error: invalid choice: 'test' (choose from 'include', 'exclude')

1947:~/mypy$ python3 stack65119253.py -c foobar include
Namespace(CONFIG_PATH='foobar', file_to_include=False)

argparse assigns strings to positionals by position . It does not assign by value. That is, it does not test for some value, and based on that decide whether it qualifies. The choices testing comes after assignment. Use optionals if you want to assign by value.

parser.add_argument('--include', nargs='?')
parser.add_argument('--exclude')

parse+known_args is a way of dealing with unrecognized arguments, but it doesn't get around the invalid choices error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM