LoginSignup
4
3

More than 3 years have passed since last update.

【備忘録】PythonでCLIを作成

Last updated at Posted at 2019-08-06

PythondでCLIを作成するときの備忘録です。

環境は以下の通りです。

環境

  • Python 3.7

argparseモジュール

通常

コマンドライン引数のグループ化

add_argument_groupで、コマンドライン引数をグループ化できます。
共通のオプションなどは、グループ化するとヘルプ表示が見やすくなります。

    group = parser.add_argument_group("global optional arguments")
    group.add_argument('--yes', action="store_true", help="処理中に現れる問い合わせに対して、常に'yes'と回答します。")
    group.add_argument('--logdir', type=str, default=".log", help="ログファイルを保存するディレクトリを指定します。")

$ python test_command.py -h
optional arguments:
  -h, --help       show this help message and exit

global optional arguments:
  --yes            処理中に現れる問い合わせに対して、常に'yes'と回答します。
  --logdir LOGDIR  ログファイルを保存するディレクトリを指定します。

相互排他

オプション--foo--barを同時に指定することを禁止する場合、add_mutually_exclusive_groupメソッドを使います。
https://docs.python.org/ja/3/library/argparse.html#mutual-exclusion

共通のオプション引数

各コマンドで共通の引数を指定したい場合、ArgumentParserparents引数を利用します。
https://docs.python.org/ja/3/library/argparse.html#parents

version情報の表示

action="version"を指定します。

import argparse
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--version', action='version', version='%(prog)s 2.0')
parser.parse_args(['--version'])

https://docs.python.org/ja/3/library/argparse.html#action 引用

デフォルトで、長いオプションは先頭の一文字に短縮可能

parse_args() メソッドは、デフォルトで、長いオプションに曖昧さがない (先頭の文字が一意である) かぎり、先頭の一文字に短縮して指定できます

allow_abbrevFalseをすることで、この機能は無効化されます。

サブコマンド関係

1階層のサブコマンド

gitコマンドのように、my_git pushmy_git pullのようなサブコマンドを作成します。

サブコマンドに対応する関数は、set_defaults()で紐づけられます。

my_git.py
import argparse

def push(args):
    print("Execute push command")
    print(args)

def pull(args):
    print("Execute pull command")
    print(args)

def main():
    parser = argparse.ArgumentParser(prog='PROG')
    subparsers = parser.add_subparsers(help='sub-command help')

    # pull コマンドのパーサを作成
    parser_push = subparsers.add_parser('push', help='push help')
    parser_push.add_argument('--bar', type=str, help='bar help')
    parser_push.set_defaults(subcommand_func=push)

    # push コマンドのパーサを作成
    parser_pull = subparsers.add_parser('pull', help='pull help')
    parser_pull.add_argument('--foo', type=str, help='foo help')
    parser_pull.set_defaults(subcommand_func=pull)

    args = parser.parse_args()

    if hasattr(args, 'subcommand_func'):
        # set_defaultsで割り当てた関数を実行する
        args.subcommand_func(args)

    else:
        # pull or pushが指定されない場合
        parser.print_help()

if __name__ == "__main__":
    main()
console
$ python my_git.py push --bar hoge
Execute push command
Namespace(bar='hoge', subcommand_func=<function push at 0x0000027268F4C268>)

$ python my_git.py pull --foo hoge
Execute pull command
Namespace(foo='hoge', subcommand_func=<function pull at 0x000002134792CD90>)

$ python my_git.py
usage: my_git.py [-h] {push,pull} ...

positional arguments:
  {push,pull}  sub-command help
    push       push help
    pull       pull help

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

2階層のサブコマンド

AWS CLIのように、my_aws ec2 waitmy_aws sns publishのようなサブコマンドを作成します。

1つ目のサブコマンド、2つ目のサブコマンドが指定されない場合は、ヘルプを表示するようにしました。

my_aws.py
import argparse

def wait(args):
    print("Execute ec2 wait command")
    print(args)

def publish(args):
    print("Execute sns publish command")
    print(args)

def main():
    parser = argparse.ArgumentParser()
    parser.set_defaults(command_help=parser.print_help)
    subparsers = parser.add_subparsers(help='sub-command help')

    # ec2 コマンドのパーサを作成
    parser_ec2 = subparsers.add_parser('ec2', help='ec2 help')
    parser_ec2.set_defaults(command_help=parser_ec2.print_help)
    subparser_ec2 = parser_ec2.add_subparsers()

    # ec2 wait コマンドのパーサ作成
    parser_ec2_wait = subparser_ec2.add_parser('wait', help='ec2 wait help')
    parser_ec2_wait.set_defaults(subcommand_func=wait)

    # sns コマンドのパーサを作成
    parser_sns = subparsers.add_parser('sns', help='sns help')
    parser_ec2.set_defaults(command_help=parser_ec2.print_help)
    subparser_sns = parser_sns.add_subparsers()

    # sns publish コマンドのパーサ作成
    parser_sns_publish = subparser_sns.add_parser('publish', help='sns publish help')
    parser_sns_publish.set_defaults(subcommand_func=publish)

    args = parser.parse_args()

    if hasattr(args, 'subcommand_func'):
        args.subcommand_func(args)

    else:
        # pull or pushが指定されない場合
        args.command_help()

if __name__ == "__main__":
    main()

Console
$ python my_aws.py
usage: my_aws.py [-h] {ec2,sns} ...

positional arguments:
  {ec2,sns}   sub-command help
    ec2       ec2 help
    sns       sns help

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


$ python my_aws.py ec2
usage: my_aws.py ec2 [-h] {wait} ...

positional arguments:
  {wait}
    wait      ec2 wait help

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


$ python my_aws.py sns publish
Execute sns publish command
Namespace(command_help=<bound method ArgumentParser.print_help of ArgumentParser(prog='my_aws.py', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=True)>, subcommand_func=<function publish at 0x00000286B96BCD90>)

その他

WIP コマンドライン引数 or ファイルで渡す場合

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3