Как создать команду дерева, используя библиотеку argparse в Python3? - PullRequest
0 голосов
/ 23 апреля 2019

Я не нахожу способ создать такую ​​структуру аргументов с пакетом argparse:

$ python3 prog.py [ A (a1 VAR | a2 | a3) | Б | C c]

Я бы хотел, чтобы A был корневым для семейства подкоманд, в моем случае это черный список (./prog blacklist [add PATH | rm | ...]), но мне также нужны две другие функции: $ ./prog push FILE и наконец $ ./prog --interactive.

Я уже серьезно посмотрел на argparse документацию . Я пытался использовать add_mutually_exclusive_group() для перегруппировки a1, b1 и c1, но я застрял с этим:

ValueError: mutually exclusive arguments must be optional

Мне удалось получить python3 prog.py (A a1 a2| B | C c1) с использованием групп, но я либо что-то упустил, понял, либо в argparse ничего не включено для этого случая.

Любая помощь будет принята с благодарностью. Спасибо за ваше время!

РЕДАКТИРОВАТЬ: Мне наконец удалось сделать то, что я искал. Однако я не уверен, что это очень чисто. Было бы здорово иметь несколько пакетов, которые делают это лучше, чем я. Благодаря этому сайту я нашел способ достичь своей цели. Я прилагаю код, если когда-либо это кого-то интересует

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import argparse
from sys import argv


class CLI:
    """
    Class which represent the CLI's behaviour.
    Every function describes a subcommands tree and
    how the CLI should respond.
    """
    def __init__(self):
        parser = argparse.ArgumentParser(
            description='',
            usage='''cli <command> [<args>]'

Commands list:

cli blacklist     Interact with the blacklist.
cli interactive   Run an interactive mode for queries.
cli read <path>   Try to extract credentials.
'''
        )
        parser.add_argument('command', help='Subcommand to run')
        # only parsing the subcommand
        args = parser.parse_args(argv[1:2])
        if not hasattr(self, args.command):
            print('Unrecognized command')
            parser.print_help()
            exit(1)
        # use dispatch pattern to invoke method with same name
        getattr(self, args.command)()

    def blacklist(self):
        """
        Parser for blacklist methods.
        """
        parser = argparse.ArgumentParser(
            description='',
            usage='''cli blacklist <subcommand> [<args>]

Subcommands list:

add <domain>          Add <domain> from the blacklist.
export <path>         Export blacklist as csv to <path>.
import <path> [-e]    Import <path> as csv. Erase existing blacklist if -e.
remove <domain>       Remove <domain> from the blacklist.
show                  Print the blacklist.
'''
        )
        parser.add_argument('subcommand')
        args = parser.parse_args(argv[2:3])
        if not hasattr(self, 'bl_%s' % (args.subcommand)):
            print('Unrecognized command')
            parser.print_usage()
            exit(1)
        getattr(self, 'bl_%s' % (args.subcommand))()

    def bl_add(self):
        print('add `%s` to the blacklist' % (argv[3:4][0]))

    def bl_export(self):
        print('export')

    def bl_import(self):
        print('import')

    def bl_remove(self):
        print('remove')

    def bl_show(self):
        print('show')

    def read(self):
        if len(argv) != 3:
            print('Wrong number of arguments')
            print('usage: cli read <path>')
            exit(1)
        print('process %s' % (argv[2:3][0]))

    def interactive(self):
        print('run interactive mode')

CLI()

...