Python: модуль argparse – использование субкоманд

Автор: | 06/11/2015
 

PythonВ примере ниже продемонстрировано использование субкоманд (или “подкоманд“) с использованием модуля argparse.

К примеру, в предыдущем проекте скрипт управления приложением имел около 20-ти различных опцией (был написан на BASH с использованием getopts()), при том что букв в английском алфавите – 26.

В новом проекте – имеется аналогичный скрипт, но на Python.

Приложение состоит из нескольких частей, и для каждой хочется иметь возможность вызывать опции --deploy или --makeconf.

Реализуется такое с помощью метода add_subparsers:


import argparse
...
def getopts():

    """Create list from called options"""

    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers(help='Application part to act with')

    # unity options
    # parser.add_argument('-r', '--refresh', nargs='?', const='dev', help=('Refresh modules DLLs and xml files'))
    # parser.add_argument('-r', '--refresh', choices=['dev', 'ci'], help=('Refresh modules DLLs and xml files'))
    ### добавляем новый аргумент `unity`, который будет играть роль "пространства имён" для опций
    # таким образом - мы можем использовать например --deploy или -d в разных аргументах
    # при этом с помощью set_defaults(func=handler_unity) мы определяем, какая функция будет заниматься
    ### обработкой аргументов для этого "пространства имён"
    parser_unity = subparsers.add_parser('unity', help='Unity application')
    parser_unity.set_defaults(func=handler_unity)
    parser_unity.add_argument('-r', '--refresh', action='store_true', dest='unity_refresh', help='Copy necessarry DLLs to MainApplication\Assets\PreparedPlugins and NGUIProject\Assets\PreparedPlugins')
    parser_unity.add_argument('-t', '--tagcheck', action='store_true', dest='unity_tagcheck', help='Check tags in .csproj files')
    parser_unity.add_argument('-b', '--buildtype', nargs='?', choices=['dev', 'ci'], default='dev', dest='unity_buildtype', help='Select unity - for developer or CI server')
    parser_unity.add_argument('-c', '--confgen', action='store_true', dest='unity_confgen', help='Generate config.xml and XMLs for each module with TAG = 'CLOUD'')
    parser_unity.add_argument('-u', '--uuidgen', action='store', dest='unity_uuidgen', help='Generate UUIDs for each module in Plugins.sln. Must be called with 'config_name' as first argument and optionally - with `-b ci` option')
    parser_unity.add_argument('-l', '--configlist', action='store_true', dest='unity_configlist', help='Display configuration names in uuids.ini')
    parser_unity.add_argument('-d', '--deploy', action='store_true', dest='unity_deploy', help='Deploy Unity project to appropriate URL')

    # Cloudlibrary options
    parser_rds = subparsers.add_parser('clc', help='Cloudlibrary options')
    parser_rds.set_defaults(func=handler_clc)
    parser_rds.add_argument('-d', '--deploy', dest='clc_deploy', action='store_true', help='Update RDSmanager from repository')
    # for Clc lib external usage
    parser_rds.add_argument('-u', '--user', action='store', dest='clc_user', help='Username for authorization')
    parser_rds.add_argument('-x', '--password', action='store', dest='clc_password', help='Password for authorization')
    parser_rds.add_argument('-f', '--file', action='store', dest='clc_file', help='Specify local file to save to/upload from')
    # Cloudlibrary requests types
    parser_rds.add_argument('-g', '--get', action='store', dest='clc_get', help='Request type GET')
    parser_rds.add_argument('-p', '--put', action='store', dest='clc_put', help='Request type PUT')
    parser_rds.add_argument('--delete', action='store', dest='clc_del', help='Request type DELETE')

    # RDSmanager own options
    parser_rds = subparsers.add_parser('rds', help='RDSmanager options')
    parser_rds.set_defaults(func=handler_rds)
    parser_rds.add_argument('-s', '--selfupgrade', dest='rds_selfupgrade', action='store_true', help='Update RDSmanager from repository')
    parser_rds.add_argument('-T', '--test', action='store_true', dest='rds_test', help='Temporary test option')

    if len(sys.argv) <= 1:
        parser.print_help()
        sys.exit(1)
    else:
        res = parser.parse_args()
        res.func(res)

def handler_unity(action_list):

    """Check Unity namespace options"""

    if action_list.unity_tagcheck:
        logger.logger.info('Running tagcheck')
        from lib.unity import tag_checker
        tag_checker.main(logger)

    if action_list.unity_refresh:
        logger.logger.info('Running refresh modules')
        from lib.unity import refresh
        refresh.refresh(logger)

    if action_list.unity_confgen:
        logger.logger.info('Running confgen')
        from lib.unity import confgen
        confgen.main(logger, RDS_BASEDIR, action_list.unity_buildtype)

    if action_list.unity_uuidgen:
        logger.logger.info('Running UUID generator with %s' % action_list.unity_uuidgen)
        from lib.unity import uuidgen
        uuidgen.uuidgen(logger, RDS_BASEDIR, action_list.unity_uuidgen, action_list.unity_buildtype)

    if action_list.unity_configlist:
        logger.logger.info('Running configlist')
        from lib.unity import confgen
        confgen.configlist(logger, RDS_BASEDIR)

    if action_list.unity_deploy:
        logger.logger.info('Running DEPLOY buildtype = %s' % action_list.unity_buildtype)
        from lib.unity import deploy
        deploy.main(logger, CLC_USER, CLC_PASSWORD, RDS_BASEDIR, action_list.unity_buildtype)


def handler_clc(action_list):

    """Check Cloudlibrary namespace options"""

    if action_list.clc_deploy:
        from lib.clc import deploy
        deploy.deploy(logger, RDS_BASEDIR)

    if action_list.clc_get:
        from lib.external.rds_clc import RdsClc
        if not action_list.clc_user and not action_list.clc_password:
            logger.logger.info('Nether CLC_USER not CLC_PASSWORD found, using default values')
            action_list.clc_user = CLC_USER
            action_list.clc_password = CLC_PASSWORD

        req = RdsClc(action_list.clc_user, action_list.clc_password)
        req.cloud_get(action_list.clc_get, action_list.clc_file)

    if action_list.clc_put:
        from lib.external.rds_clc import RdsClc
        if not action_list.clc_user and not action_list.clc_password:
            logger.logger.info('Nether CLC_USER not CLC_PASSWORD found, using default values')
            action_list.clc_user = CLC_USER
            action_list.clc_password = CLC_PASSWORD

        req = RdsClc(action_list.clc_user, action_list.clc_password)
        req.cloud_put(action_list.clc_put, action_list.clc_file)

    if action_list.clc_del:
        from lib.external.rds_clc import RdsClc
        if not action_list.clc_user and not action_list.clc_password:
            logger.logger.info('Nether CLC_USER not CLC_PASSWORD found, using default values')
            action_list.clc_user = CLC_USER
            action_list.clc_password = CLC_PASSWORD

        req = RdsClc(action_list.clc_user, action_list.clc_password)
        req.cloud_delete(action_list.clc_del)


def handler_rds(action_list):

    """Check RDS namespace options"""

    if action_list.rds_test:
        logger.logger.info('Running TEST option')
        from lib.external import testing5
        testing5.test(logger)

    if action_list.rds_selfupgrade:
        logger.logger.info('Running self-upgrade')
        from lib.service import manager
        manager.selfupgrade(logger, RDS_BASEDIR)


if __name__ == '__main__':

    logger = Logger(RDS_BASEDIR)
    logger.logger('RDSmanager')
    logger.logger.info('RDSmanager started at %s' % (time.strftime('%d, %b %Y at %H:%M:%S')))

    getopts()

Помощь теперь выглядит так:

d:RDSrdsmanager>RDSmanager.py rds -h
RDSmanager started at 25, Jun 2015 at 18:26:46
usage: RDSmanager.py rds [-h] [-s] [-T]

optional arguments:
  -h, --help         show this help message and exit
  -s, --selfupgrade  Update RDSmanager from repository
  -T, --test         Temporary test option
d:RDSrdsmanager>RDSmanager.py clc -h
RDSmanager started at 25, Jun 2015 at 18:37:04
usage: RDSmanager.py clc [-h] [-d] [-u CLC_USER] [-x CLC_PASSWORD]
                         [-f CLC_FILE] [-g CLC_GET] [-p CLC_PUT]
                         [--delete CLC_DEL]

optional arguments:
  -h, --help            show this help message and exit
  -d, --deploy          Update RDSmanager from repository
  -u CLC_USER, --user CLC_USER
                        Username for authorization
  -x CLC_PASSWORD, --password CLC_PASSWORD
                        Password for authorization
  -f CLC_FILE, --file CLC_FILE
                        Specify local file to save to/upload from
  -g CLC_GET, --get CLC_GET
                        Request type GET
  -p CLC_PUT, --put CLC_PUT
                        Request type PUT
  --delete CLC_DEL      Request type DELETE

И так далее.