Slide 1

Slide 1 text

モデルの定義に基づくバリデーションを 実現するためのpydantic入門 桂川大輝

Slide 2

Slide 2 text

複数の部品によって構成されるシステムを開発していますか? ● 多くのシステムは複数の部品によって構成 ○ 部品:モジュール・クラス・メソッドなど ● 各部品が役割と責任を持ち連携 ○ 各部品の入出力を把握しておけばシステムの全ての把握は不要 ○ 入出力:int、str、JSON/辞書(構造) 2 部品A 部品B int str 部品Y 部品Z JSON/辞書 JSON/辞書

Slide 3

Slide 3 text

課題①:入出力で扱うデータの定義がわからない(可読性の課題) ● 他の部品の出力を入力として受け取る時、 他の部品の実装を深く見る必要がある場面も… (例:JSON/辞書といった型まではわかるが構造はわからない) 3 部品Y 部品Z JSON ???のデータを 格納したJSONを 渡します。 何が格納されている? キーは?

Slide 4

Slide 4 text

課題②:入出力で扱うデータが正しくない(堅牢性の課題) ● 他の部品の出力を把握しているものの 期待と異なる、正しくないデータを受け取る場面も… (例:年齢が「-1」、型が異なる、約束しているデータがない) 4 部品Y 部品Z JSON ◯△□のデータを 格納したJSONを 渡します。 ドメイン的に ありえないデータが来た

Slide 5

Slide 5 text

課題を解決する“pydantic” ● “pydantic”とは ○ モデルを定義することでデータのバリデーションを実現するライブラリ ○ 辞書型・JSONとの変換も可能であり部品の入出力に有用 ● 課題①:入出力で扱うデータの定義がわからない(可読性の課題) ○ モデルの定義により把握が可能に(規約化) ● 課題②:入出力で扱うデータが正しくない(堅牢性の課題) ○ 定義に基づくバリデーションにより正しいデータのみが存在する状態に 5 !pip install pydantic

Slide 6

Slide 6 text

pydanticの利用例〜Userクラスの定義①〜 6 from pydantic import BaseModel, Field class User(BaseModel): id: int name: str age: int = Field(ge=20) external_data = { 'id': 1, 'name': 'パイソン 太郎', 'age': 20 } user = User.parse_obj(external_data) 型、有効範囲の定義 定義を満たす インスタンスの生成 Userクラスの定義の 読み取りが可能 (例:ageは20以上)

Slide 7

Slide 7 text

pydanticの利用例〜Userクラスの定義②〜 7 from pydantic import BaseModel, Field class User(BaseModel): id: int name: str age: int = Field(ge=20) external_data = { 'id': 1, 'name': 'パイソン 太郎', 'age': 19 } user = User.parse_obj(external_data) 有効範囲外の値 ValidationError

Slide 8

Slide 8 text

pydanticの利用例〜ValidationErrorの中身〜 8 (省略) ValidationError: 1 validation error for User age ensure this value is greater than or equal to 20 (type=value_error.number.not_ge; limit_value=20) エラーの詳細を確認可能 (例:ageの20以上という定義を満たしていない)

Slide 9

Slide 9 text

pydanticの利用例〜Userクラスを引数とする関数①〜 9 from pydantic import validate_arguments @validate_arguments def input_user(user : User) -> None: pass external_data = { 'id': 1, 'name': 'パイソン 太郎', 'age': 20 } input_user(external_data) 引数のバリデーションを 実行するデコレーター pydanticで定義した クラスも引数として指定

Slide 10

Slide 10 text

pydanticの利用例〜Userクラスを引数とする関数②〜 10 from pydantic import validate_arguments @validate_arguments def input_user(user : User) -> None: pass external_data = { 'id': 1, 'name': 'パイソン 太郎', 'age': 19 } input_user(external_data) 有効範囲外の値 ValidationError

Slide 11

Slide 11 text

pydanticの利用例〜Userクラスを返り値(辞書型)とする関数①〜 11 def output_user() -> dict: external_data = { 'id': 1, 'name': 'パイソン 太郎', 'age': 20 } user = User.parse_obj(external_data) return user.dict() output_user() やりとりしやすい形式(辞書型)で出力 {'age': 20, 'id': 1, 'name': 'パイソン 太郎'}

Slide 12

Slide 12 text

pydanticの利用例〜Userクラスを返り値(辞書型)とする関数②〜 12 def output_user() -> dict: external_data = { 'id': 1, 'name': 'パイソン 太郎', 'age': 19 } user = User.parse_obj(external_data) return user.dict() output_user() 有効範囲外の値 ValidationError

Slide 13

Slide 13 text

pydanticの利用例〜デコレーターによる詳細なバリデーションの実現〜 13 from pydantic import BaseModel, Field, validator import unicodedata class User(BaseModel): id: int name: str # 半角空白を含む(※前後以外) age: int = Field(ge=20) @validator("name") def check_contain_space(cls, v): if " " not in v.strip(): # 前後の半角空白を無視 raise ValueError("ensure this value contains spaces") return v.strip() # 前後の半角空白を削除 デコレーターによる詳細な バリデーションの実現も可能 (例:半角空白を含むかを判定)

Slide 14

Slide 14 text

まとめ ● 複数の部品によって構成されるシステムの開発 ○ 部品:モジュール・クラス・メソッドなど ○ 各部品が役割と責任を持ち連携 ○ 課題①:入出力で扱うデータの定義がわからない(可読性の課題) ○ 課題②:入出力で扱うデータが正しくない(堅牢性の課題) ● 課題を解決する“pydantic” ○ モデルを定義することでデータのバリデーションを実現するライブラリ ○ 課題①:モデルの定義により把握が可能に(規約化) ○ 課題②:定義に基づくバリデーションにより正しいデータのみが存在する状態に 14