【文字列や整数だけではない】オプション解析ライブラリClickのtype指定

OSWindows 10 64bit
Python3.10.2
Click8.1.3

概要

clickは、シンプルでありながら高機能なオプション解析ライブラリです。
clickのインストールと基本的な使い方は以下の記事をご覧ください。

【シンプル&高機能】オプション解析ライブラリClickのご紹介【シンプル&高機能】オプション解析ライブラリClickのご紹介

clickのtypeはオプションの引数に対して、どのようなtypeを持つかを指定できます。パース結果に対してもそのtypeに変換されて格納されます。

本記事ではclickのオプションのtype指定についてご紹介します。なお、本記事ではオプションのみご紹介します。

type指定方法

clickのtype指定は@click.option()の引数typeに型を指定します。
以下の例は、文字列を指定しています。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.STRING)
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()

typeに型を指定すると、オプションに渡されたオプション引数は、指定されたtypeに変換されて格納されます。

Shell
> python test.py -opt 18
option='18', type(option)=<class 'str'>

clickのtype一覧

clickでは、多くの型が用意されています。以下に一覧として載せます。

type説明
click.STRING文字列型
デフォルト
click.INT整数型
click.FLOAT浮動小数点数型
click.BOOLブール型
click.UUIDUUID型
UUIDの形式に変換
click.UNPROCESSED強制的な型変換をさせない型
click.FileFile型
ファイルとして変換
click.PathPath型
ファイルパス名として変換
click.Choice選択肢型
click.IntRange整数範囲型
click.FloatRange浮動小数点数範囲型
click.DateTimeDateTime型
click.TupleTuple型
click.ParamTypeParamType型
独自のtypeを作成する際に使用
type一覧

click.STRING

文字列型に変換します。デフォルトのオプション引数変換です。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.STRING)
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 18      
option='18', type(option)=<class 'str'>

click.INT

整数型に変換します。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.INT)
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 18      
option=18, type(option)=<class 'int'>

click.FLOAT

浮動小数点数型に変換します。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.FLOAT)
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 18
option=18.0, type(option)=<class 'float'>

click.BOOL

bool型に変換します。bool型TrueやFalseに自動的に変換される値は以下です。

TrueFalse
10
TrueFalse
truefalse
tf
YesNo
yesno
yn
onoff
TrueまたはFalseに自動変換される値
Python
import click

@click.command()
@click.option('-opt', '--option', type=click.BOOL)
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt y  
option=True, type(option)=<class 'bool'>

click.UUID

uuid.UUIDに変換されます。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.UUID)
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 12345678-1234-5678-1234-567812345678

option=UUID('12345678-1234-5678-1234-567812345678'), type(option)=<class 'uuid.UUID'>

click.UNPROCESSED

clickの型変換をスキップしたい場合に指定します。

click.File

指定されたオプション引数をファイルとして開きます。開かれたファイルはコンテキストが破棄された後自動的に閉じられます。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.File())
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt test.py
option=<_io.TextIOWrapper name='test.py' mode='r' encoding='cp932'>, type(option)=<class '_io.TextIOWrapper'>

click.Fileメソッドに渡せる引数は以下です。

引数説明
modeファイルをどのモードで開くか指定します。
デフォルトは'r'('rt')です。
encodingファイルのエンコード名を指定します。
テキストモードでのみ指定してください。
errors文字列でエラーハンドラを指定します。
'strict'はエンコーディングエラーがあると例外ValueErrorを発生させます。デフォルトの動作です。
'ignore'はエラーを無視します。
'replace'は不正なデータの個所に置換マーカを挿入します。
'surrogateescape'は不正なバイトをlow surrogate codeで置き換えます。
'xmlcharrefreplace'は不正なデータを、XMLの&#番号で置き換えます。書き込み時のみサポート。
'backslashreplace'は不正なデータをバックスラッシュエスケープシーケンスで置き換えます。
'namereplace‘は不正なデータを'\N{ユニコード名}'に置き換えます。
lazyファイルをすぐ開く(Falseの場合)か最初のIO時に開く(Trueの場合)か指定できます。
デフォルトでは標準入出力または読込みモードではすぐ開き(False)、それ以外は最初のIO時に開きます(True)。
atomicアトミックなファイル操作を行うかどうか指定できます。デフォルトはFalseです。
Trueの場合、書込み時にファイルが存在するフォルダに一時ファイルを作成し書き込みます。完了すれば一時ファイルは元のファイルに移動します。
click.Fileメソッドの引数

また、オプション引数として-を渡すと、モードが読込みの場合は標準入力に、書込みの場合は標準出力になります。

Python
import click

@click.command()
@click.option('-i', '--input', type=click.File('r'))
@click.option('-o', '--output', type=click.File('w'))
def main(input, output):
    text = input.read()
    output.write(text)

if __name__ == '__main__':
    main()
Shell
>  python test.py -i - -o test.txt
kotsukotsu san
^Z
> python test.py -i test.txt -o -
kotsukotsu san

click.Path

渡されたオプション引数はファイルパスとして認識します。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.Path())
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt src/test.py
option='src/test.py', type(option)=<class 'str'>

click.Pathメソッドに渡せる引数は以下です。

引数説明
existsTrueが指定されていた場合、与えられたパスが存在するかどうかチェックします。存在しなければエラーで終了します。Falseが指定された存在チェックは行いません。デフォルトはFalseです。
file_okayTrueが指定された場合、ファイルパスを許可します。Falseが指定された場合、ファイルパスは許可しません。ただし、パスが存在する場合にファイルパスチェックは有効になります。デフォルトはTrueです。
dir_okayTrueが指定された場合、ディレクトリパスを許可します。Falseが指定された場合、ディレクトリパスは許可しません。ただし、パスが存在する場合にディレクトリパスチェックは有効になります。デフォルトはTrueです。
writableTrueが指定された場合、パスが書き込み可能かチェックします。デフォルトはFalseです。
readableTrueが指定された場合、パスが読み込み可能かチェックします。デフォルトはTrueです。
executableTrueが指定された場合、パスが実行可能かチェックします。デフォルトはTrueです。
resolve_pathTrueが指定された場合、絶対パスに変換します。symlinkも解決します。ただし~は展開されません。デフォルトはFalseです。
allow_dashTrueが指定された場合、標準入出力としての-を許可します。ただし、オープンはしません。デフォルトはFalseです。
path_typeパスを変換する関数を指定します。例えば、pathlib.Pathが便利です。デフォルトはNoneです。
click.Pathメソッドの引数

絶対パスに変換して、pathlib.Pathに変換したい場合は以下のようにします。

Python
import click
import pathlib

@click.command()
@click.option('-opt', '--option', type=click.Path(exists=True, resolve_path=True, path_type=pathlib.Path))
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt test.py
option=WindowsPath('C:/Users/kotsukotsu/workspace/kotsukotsu_blog/src/test.py'), type(option)=<class 'pathlib.WindowsPath'>

click.Choice

click.Choiceに指定された選択肢からのみ渡されたオプション引数が許可されます。

click.Choiceメソッドに渡せる引数は以下です。

引数説明
choicesリストまたはタプルで選択肢を指定します。各選択肢は文字列で指定してください。
case_sensitiveFalseが指定された場合、選択肢の大文字と小文字を区別しません。デフォルトはTrueです。
click.Choiceメソッドの引数
Python
import click

@click.command()
@click.option('-opt', '--option', type=click.Choice(choices=['17', '18', '19']))
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 18
option='18', type(option)=<class 'str'>

> python test.py -opt 20
Usage: test.py [OPTIONS]
Try 'test.py --help' for help.

Error: Invalid value for '-opt' / '--option': '20' is not one of '17', '18', '19'.

click.IntRange

整数の範囲を指定します。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.IntRange(min=10, max=20))
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 9 
Usage: test.py [OPTIONS]
Try 'test.py --help' for help.

Error: Invalid value for '-opt' / '--option': 9 is not in the range 10<=x<=20.

> python test.py -opt 10
option=10, type(option)=<class 'int'>

> python test.py -opt 20
option=20, type(option)=<class 'int'>

> python test.py -opt 21
Usage: test.py [OPTIONS]
Try 'test.py --help' for help.

Error: Invalid value for '-opt' / '--option': 21 is not in the range 10<=x<=20.

click.IntRangeメソッドに渡せる引数は以下です。

引数説明
min整数範囲の最小値を指定。
max整数範囲の最大値を指定。
min_openTrueが指定された場合、minで指定された整数は範囲に含みません。デフォルトはFalseです。
max_openTrueが指定された場合、maxで指定された整数は範囲に含みません。デフォルトはFalseです。
clampTrueが指定された場合、範囲外の整数は範囲内に丸められます。デフォルトはFalseです。
click.IntRangeメソッドの引数

例えば、min_openclampTrueを設定した例は以下となります。1を渡した結果、範囲外かつ範囲の最小値10を含まないので11に丸められています。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.IntRange(min=10, max=20, min_open=True, clamp=True))
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 1 
option=11, type(option)=<class 'int'>

click.FloatRange

浮動小数点数の範囲を指定します。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.FloatRange(min=18.0, max=19.0))
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 18.5
option=18.5, type(option)=<class 'float'>

click.FloatRangeメソッドに渡せる引数は以下です。

引数説明
min浮動小数点数範囲の最小値を指定。
max浮動小数点数範囲の最大値を指定。
min_openTrueが指定された場合、minで指定された浮動小数点数は範囲に含みません。デフォルトはFalseです。
max_openTrueが指定された場合、maxで指定された浮動小数点数は範囲に含みません。デフォルトはFalseです。
clampTrueが指定された場合、範囲外の整数は範囲内に丸められます。デフォルトはFalseです。
ただし、min_openまたはmax_openTrueの場合失敗します。
click.FloatRangeメソッドの引数

click.DateTime

渡されたオプション引数をdatetimeオブジェクトに変換します。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.DateTime())
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 2022-08-29
option=datetime.datetime(2022, 8, 29, 0, 0), type(option)=<class 'datetime.datetime'>

click.DateTimeメソッドに渡せる引数は以下です。

引数説明
formatsリストまたはタプルで日時フォーマットを文字列で指定。デフォルトは"[%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"]にマッチします。
click.DateTimeメソッドの引数

formats["%Y年", "%Y年%m月", "%Y年%m月%d日"]を指定した場合の例です。formats中の最初にマッチしたものが格納されます。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.DateTime(formats=["%Y年", "%Y年%m月", "%Y年%m月%d日"]))
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 2022年08月
option=datetime.datetime(2022, 8, 1, 0, 0), type(option)=<class 'datetime.datetime'>

click.Tuple

複数のtypeを指定する場合に指定します。

以下の例は一つ目のtypeはclick.INT、2つ目はclick.STRINGを指定しています。

Python
import click

@click.command()
@click.option('-opt', '--option', type=click.Tuple([click.INT, click.STRING]))
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt 17 18  
option=(17, '18'), type(option)=<class 'tuple'>

独自のtype変換クラス

独自のtype変換クラスを定義したい場合以下が要求されます。

  • click.ParamTypeを継承
  • クラス属性nameに変換type名を文字列で設定
  • convertメソッドを独自の変換処理にオーバーライド

以下は、入力されたオプション引数を逆順にして返す変換クラスです。
self.failメソッドは引数にエラーメッセージを指定すると変換失敗時にエラーメッセージとして出力してくれます。

Python
import click

class Reverse(click.ParamType):
    name = 'reverse'

    def convert(self, value, param, ctx):
        # 文字列かどうか判定
        if not isinstance(value, str):
            self.fail(f'{value!r}は文字列ではありません。')

        try:
            return value[::-1] # 文字列を逆順にする
        except:
            self.fail(f'{value!r}の変換に失敗しました。')

@click.command()
@click.option('-opt', '--option', type=Reverse())
def main(option):
    click.echo(f'{option=}, {type(option)=}')

if __name__ == '__main__':
    main()
Shell
> python test.py -opt abc
option='cba', type(option)=<class 'str'>

まとめ

本記事では、高機能なオプション解析ライブラリclickのtypeについてご紹介しました。

基本的な型だけでなく、File型やPath型、DateTime型など様々な型が用意されています。特にFile型はオープンからクローズまでサポートされているので非常に便利です。
さらに、独自のtype変換クラスも定義でき、応用の幅は広がります。

clickに関するほかの記事は以下をご覧ください。

参考

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です