LoginSignup
13
8

Pydanticに6行書き加えるだけで、ArgumentParserと同じ使い方ができるから便利よ、という小ネタ

Posted at

この記事について

Pythonのバリデーター(Pydantic)を、Pythonの引数のパーサーとして使う方法を紹介します

何が嬉しいの?

  • Pydantic以外のOSSライブラリは不要です
  • Pythonファイルに渡された引数を検証、型変換させることができます
  • Pydanticで定義を書くだけでよいため、ArgumentParserよりも楽です
  • IDEの補完が効くようになります

方法

BaseModelを継承したクラスに、以下の関数を書き加えます

@classmethod
def parse_args(cls):
    parser = ArgumentParser()
    for k in cls.schema()["properties"].keys():
        parser.add_argument(f"-{k[0:1]}", f"--{k}")
    return cls.parse_obj(parser.parse_args().__dict__)

これでpydanticでparse_argsができるようになります

ソースの例

実際のソースで動きを確認します。

app.py
from argparse import ArgumentParser
from pydantic import BaseModel


class Argments(BaseModel):
    """
        Pythonファイルの引数を定義する
    """
    bucketname: str # AWSのバケット名
    filename: str # ファイル名
    timeout: int # タイムアウト時間

    @classmethod
    def parse_args(cls):
        # 付け足した関数
        parser = ArgumentParser()
        for k in cls.schema()["properties"].keys():
            parser.add_argument(f"-{k[0:1]}", f"--{k}")
        return cls.parse_obj(parser.parse_args().__dict__)


# 実行してみる: 引数を検証する
args = Argments.parse_args()
print(args)
print(args.bucketname)
print(args.timeout)
コマンドプロンプトで実行する
python app.py --bucketname=aws-bucket-contents-name --filename=filekey.json --timeout=123
実行結果
bucketname='aws-bucket-contents-name' filename='filekey.json' timeout=123
aws-bucket-contents-name
123

parse_argsが返す変数は、PydanticのBaseModelを継承した変数です
pythonファイルに渡された引数がデータとして入っていることが確認できます

嬉しいこと

Pydanticの型なので、VSCodeの補完の恩恵を受けられます
データ型も定義した型に変換されています

qiita-image-1.png

検証エラーをさせてみる

タイムアウトはint型が期待値なので、以下のようにすればエラーになります

コマンドプロンプトで実行する
python app.py --bucketname=aws-bucket-contents-name --filename=filekey.json --timeout=12.3
実行結果
pydantic.error_wrappers.ValidationError: 1 validation error for Argments
timeout
  value is not a valid integer (type=type_error.integer)

必須になっているファイル名とタイムアウトを渡さないと、エラーになります

コマンドプロンプトで実行する
python app.py --bucketname=aws-bucket-contents-name
実行結果
pydantic.error_wrappers.ValidationError: 2 validation errors for Argments
filename
  none is not an allowed value (type=type_error.none.not_allowed)
timeout
  none is not an allowed value (type=type_error.none.not_allowed)

必須ではない引数を定義したいときは、Optionalを使います

from typing import Optional


class Argments(BaseModel):
    mail: Optional[str] # メールアドレスは必須ではない
    # 中略

この--mailは、引数として渡さなくてもエラーになりません

13
8
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
13
8