Mypy
Pydantic は、すぐにmypyとうまく連携します。
ただし、Pydantic には、コードの型チェック機能を向上させる、多くの重要な pydantic 固有の機能を mypy に追加する mypy プラグインも付属しています。
たとえば、次のスクリプトについて考えてみましょう。
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel
class Model(BaseModel):
age: int
first_name = 'John'
last_name: Optional[str] = None
signup_ts: Optional[datetime] = None
list_of_ints: List[int]
m = Model(age=42, list_of_ints=[1, '2', b'3'])
print(m.middle_name) # not a model field!
Model() # will raise a validation error for age and list_of_ints
特別な設定がなければ、mypy は欠落しているモデルフィールドのアノテーションを捕捉せず、Pydantic が正しく解析するlist_of_ints
引数について警告します。
test.py:15: error: List item 1 has incompatible type "str"; expected "int" [list-item]
test.py:15: error: List item 2 has incompatible type "bytes"; expected "int" [list-item]
test.py:16: error: "Model" has no attribute "middle_name" [attr-defined]
test.py:17: error: Missing named argument "age" for "Model" [call-arg]
test.py:17: error: Missing named argument "list_of_ints" for "Model" [call-arg]
ただし、プラグインを有効にすると、正しいエラーが表示されます。
9: error: Untyped fields disallowed [pydantic-field]
16: error: "Model" has no attribute "middle_name" [attr-defined]
17: error: Missing named argument "age" for "Model" [call-arg]
17: error: Missing named argument "list_of_ints" for "Model" [call-arg]
pydantic mypy プラグインを使用すると、フィールド名や型が変更された場合に mypy が間違いを検出できるため、恐れることなくモデルをリファクタリングできます。
他にもメリットはあります!詳細については、以下を参照してください。
プラグインなしで mypy を使用する¶
次のようにして、mypy を通じてコードを実行できます。
mypy \
--ignore-missing-imports \
--follow-imports=skip \
--strict-optional \
pydantic_mypy_test.py
厳密なオプション¶
コードを--strict-optional
で渡すには、デフォルトとしてNone
を使用して、すべてのフィールドにOptional[]
またはOptional[]
のエイリアスを使用する必要があります。 (これは mypy の標準です。)
その他の Pydantic インターフェース¶
Pydanticデータクラスとvalidate_call
デコレータも mypy で適切に動作するはずです。
Mypy プラグインの機能¶
Model.__init__
の署名を生成する¶
- 動的に決定される別名を持たない必須フィールドは、必須キーワード引数として含まれます。
Config.populate_by_name=True
の場合、生成された署名はエイリアスではなくフィールド名を使用します。Config.extra='forbid'
で、動的に決定されるエイリアスを使用しない場合、生成された署名は予期しない入力を許可しません。- オプション:
init_forbid_extra
プラグイン設定がTrue
に設定されている場合、Config.extra
が'forbid'
でなくても、__init__
への予期しない入力によってエラーが発生します。 - オプション:
init_typed
プラグイン設定がTrue
に設定されている場合、生成された署名はモデル フィールドのタイプを使用します (それ以外の場合、解析を可能にするためにAny
注釈が付けられます)。
Model.model_construct
の型付き署名を生成する¶
model_construct
メソッドは、入力データが有効であることがわかっており、解析する必要がない場合の__init__
の代替手段です。このメソッドは実行時検証を実行しないため、エラーを検出するには静的チェックが重要です。
Config.frozen
尊重する¶
Config.frozen
がTrue
の場合、モデル フィールドの値を変更しようとすると、mypy エラーが発生します。参照。偽の不変性。
dataclasses
の署名を生成する¶
- で飾られたクラス
@pydantic.dataclasses.dataclass
標準の Python データクラスと同じように型がチェックされます - の
@pydantic.dataclasses.dataclass
デコレーターは、Config
サブクラスと同じ意味を持つconfig
キーワード引数を受け入れます。
Field
のdefault
とdefault_factory
のタイプを尊重します。¶
- フィールドに
default
とdefault_factory
両方が含まれている場合、静的チェック中にエラーが発生します。 default
のタイプとdefault_factory
値は、フィールドのタイプと互換性がある必要があります。
型なしフィールドの使用について警告する¶
- タイプに注釈を付けずにモデルにパブリック属性を割り当てると、必ず mypy エラーが発生します。
- ClassVar を設定することが目的の場合は、typeing.ClassVar を使用してフィールドに明示的に注釈を付ける必要があります。
オプションの機能:¶
必要な動的エイリアスの使用を防止する¶
warn_required_dynamic_aliases
プラグイン設定がTrue
に設定されている場合、Config.populate_by_name=False
のモデルで動的に決定されるエイリアスまたはエイリアス ジェネレーターを使用するたびに、mypy エラーが発生します。- このようなエイリアスが存在すると、 mypy は
__init__
へのチェック呼び出しを適切に入力できないため、これは重要です。この場合、デフォルトではすべての引数がオプションとして扱われます。
プラグインを有効にする¶
プラグインを有効にするには、 mypy 構成ファイル( mypy.ini
、 pyproject.toml
、またはsetup.cfg
など) のプラグインのリストにpydantic.mypy
を追加するだけです。
開始するには、次の内容を含むmypy.ini
ファイルを作成するだけです。
[mypy]
plugins = pydantic.mypy
!!! note pydantic.v1
モデルを使用している場合は、プラグインのリストにpydantic.v1.mypy
を追加する必要があります。
このプラグインは、mypy バージョン>=0.930
と互換性があります。
詳細については、プラグイン設定ドキュメントを参照してください。
プラグインの設定¶
プラグイン設定の値を変更するには、mypy 構成ファイルに[pydantic-mypy]
というセクションを作成し、オーバーライドする設定のキーと値のペアを追加します。
すべてのプラグイン厳密性フラグ (および他の mypy 厳密性フラグも) が有効になっているmypy.ini
ファイルは次のようになります。
[mypy]
plugins = pydantic.mypy
follow_imports = silent
warn_redundant_casts = True
warn_unused_ignores = True
disallow_any_generics = True
check_untyped_defs = True
no_implicit_reexport = True
# for strict mypy: (this is the tricky one :-))
disallow_untyped_defs = True
[pydantic-mypy]
init_forbid_extra = True
init_typed = True
warn_required_dynamic_aliases = True
mypy>=0.900
以降、 mypy config はmypy.ini
ではなくpyproject.toml
ファイルに含まれる場合もあります。上記と同じ構成は次のようになります。
[tool.mypy]
plugins = [
"pydantic.mypy"
]
follow_imports = "silent"
warn_redundant_casts = true
warn_unused_ignores = true
disallow_any_generics = true
check_untyped_defs = true
no_implicit_reexport = true
# for strict mypy: (this is the tricky one :-))
disallow_untyped_defs = true
[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true
--disallow-any-explicit
に関する注意事項¶
--disallow-any-explicit
mypy 構成設定 (またはAny
を禁止するその他の設定) を使用している場合、 BaseModel
拡張するときにno-any-explicit
エラーが発生する可能性があります。これは、デフォルトで、Pydantic のmypy
プラグインが次のようなシグネチャを持つ__init__
メソッドを追加するためです。 def __init__(self, field_1: Any, field_2: Any, **kwargs: Any):
!!! 「なぜ余分な署名が必要なのでしょうか?」 Pydantic mypy
プラグインは、次のようなシグネチャを持つ__init__
メソッドを追加します。 def __init__(self, field_1: Any, field_2: Any, **kwargs: Any):
フィールドの注釈と一致しない型でモデルを初期化するときの型エラーを避けるため。たとえば、 Model(date='2024-01-01')
このAny
シグネチャがないと型エラーを引き起こしますが、Pydantic には文字列'2024-01-01'
をdatetime.date
型に解析する機能があります。
この問題を解決するには、Pydantic mypy プラグインの厳密モード設定を有効にする必要があります。具体的には、次のオプションを[pydantic-mypy]
セクションに追加します。
[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
init_forbid_extra = True
の場合、 **kwargs
生成された__init__
シグネチャから削除されます。 init_typed = True
の場合、フィールドのAny
型は実際の型ヒントに置き換えられます。
この構成により、Pydantic モデルでエラーが発生することなく--disallow-any-explicit
を使用できるようになります。ただし、このより厳格なチェックにより、一部の有効な Pydantic ユースケース (日時フィールドに文字列を渡すなど) が型エラーとしてフラグ付けされる可能性があることに注意してください。
本文总阅读量次