16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

pydantic で利用可能な型を追加する

Last updated at Posted at 2021-11-29

はじめに

pydantic という便利な validation ライブラリが python にはありますが、こちらでは validation 可能な型が限られています。それを他の型を拡張しないといけない時があったので、メモがてらまとめました。

どうやるのか

このあたりに詳しく書かれていますが、重要なのは __get_validators__ と、そこで yield される関数たちです。pydantic で validation を行う時には、まずは、 __get_validators__ が呼ばれます。これは、ジェネレータになっていて、記された実際の validation 関数を返し、一つ一つ実行していきます。

実際にやってみる。

上記の例を題材に、日本の郵便番号の validator を作ってみます。なお、実際に動かした環境は以下の通りです。

  • Python 3.9.7
  • pydantic 1.8.2
import re

from pydantic import BaseModel


class PostalCodeJP(str):
    @classmethod
    def __get_validators__(cls):
        yield cls.postal_code_should_be_string
        yield cls.remove_hyphen_if_exists
        yield cls.postal_code_length_should_be_7
        yield cls.postal_code_should_be_numeric_string

    @classmethod
    def postal_code_should_be_string(cls, v: str):
        if not isinstance(v, str):
            raise TypeError('postal code should be string')
        return v

    @classmethod
    def remove_hyphen_if_exists(cls, v: str):
        if '-' in v:
            v = v.replace('-', '')
        return v

    @classmethod
    def posta_code_length_should_be_7(cls, v: str):
        if len(v) != 7:
            raise ValueError('postal code should be 7 length string')
        return v

    @classmethod
    def postal_code_should_be_numeric_string(cls, v: str):
        regex = r'[0-9]+'
        if not re.fullmatch(regex, v):
            raise ValueError('postal code should be numeric string')
        return v


class PostalCodeValueObject(BaseModel):
    postal_code: PostalCodeJP

それでは __get_validators__ の一番上から順番に ValidationError を発生させてみます。まずは、郵便番号に文字列以外を用いた場合

p = PostalCodeValueObject(postal_code=1111111)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for PostalCodeValueObject
postal_code
  postal code should be string (type=type_error)

次に - を除いた文字列が 7 文字以外になっている場合

p = PostalCodeValueObject(postal_code='111-11111')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for PostalCodeValueObject
postal_code
  postal code should be 7 length string (type=value_error)

最後に、全ての文字が数字文字列以外になっている場合

p = PostalCodeValueObject(postal_code='111-111l')  # 最後の文字が L の小文字になっている
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for PostalCodeValueObject
postal_code
  postal code should be numeric string (type=value_error)

まとめ

  • pydantic で validation に用いる型を追加したい場合を記しました。
  • __get_validators__ に validation したい関数を yield する。
  • 公式ドキュメントには重要なことが書かれているので、よく読もう。
16
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
16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?