Mypy
Pydantic 与 mypy 开箱即用,配合得很好。
然而,Pydantic 也附带了一个 mypy 插件,该插件添加了许多重要的 Pydantic 特定功能,从而提高了其对代码进行类型检查的能力。
例如,请看以下脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
在没有任何特殊配置的情况下,mypy 不会捕获缺失的模型字段注解,并且会对 list_of_ints
参数报错,尽管 Pydantic 能正确解析它。
15: error: List item 1 has incompatible type "str"; expected "int" [list-item]
15: error: List item 2 has incompatible type "bytes"; expected "int" [list-item]
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]
但是启用了插件后,它会给出正确的错误:
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 会捕获任何错误。
请注意,即使不使用 Pydantic 插件,mypy 也已经支持某些功能,例如为 Pydantic 模型和数据类合成 __init__
方法。请参阅 mypy 插件功能列表以了解其他功能。
Pydantic mypy 插件是针对最新的 mypy 版本进行测试的。旧版本可能也能工作,但不会进行测试。
启用插件¶
要启用该插件,只需将 pydantic.mypy
添加到您的mypy 配置文件的插件列表中:
[mypy]
plugins = pydantic.mypy
[tool.mypy]
plugins = ['pydantic.mypy']
注意
如果您正在使用 pydantic.v1
模型,您需要将 pydantic.v1.mypy
添加到您的插件列表中。
有关更多详细信息,请参阅插件配置。
Mypy 插件功能¶
为 Pydantic 模型生成 __init__
签名¶
- 任何没有动态确定别名的必需字段都将作为必需的关键字参数包含在内。
- 如果模型配置值
validate_by_name
设置为True
,则生成的签名将使用字段名称而不是别名。 init_forbid_extra
和init_typed
插件配置值可以进一步微调合成的__init__
方法。
为 model_construct
生成类型化签名¶
- 当输入数据已知有效且不应被解析时,
model_construct
方法是模型验证的替代方案(请参阅文档)。因为此方法不执行运行时验证,所以静态检查对于检测错误非常重要。
支持冻结模型¶
遵循 Field
的 default
和 default_factory
的类型¶
- 同时具有
default
和default_factory
的字段将在静态检查期间导致错误。 default
和default_factory
值的类型必须与字段的类型兼容。
对使用未类型化的字段发出警告¶
- 虽然定义一个没有注解的字段会导致运行时错误,但插件也会发出一个类型检查错误。
防止使用必需的动态别名¶
请参阅 warn_required_dynamic_aliases
插件配置值的文档。
配置插件¶
要更改插件设置的值,请在您的 mypy 配置文件中创建一个名为 [pydantic-mypy]
的部分,并为您想要覆盖的设置添加任何键值对。
一个启用了所有插件严格性标志(以及其他一些 mypy 严格性标志)的配置文件可能如下所示:
[mypy]
plugins = pydantic.mypy
follow_imports = silent
warn_redundant_casts = True
warn_unused_ignores = True
disallow_any_generics = True
no_implicit_reexport = True
disallow_untyped_defs = True
[pydantic-mypy]
init_forbid_extra = True
init_typed = True
warn_required_dynamic_aliases = True
[tool.mypy]
plugins = ["pydantic.mypy"]
follow_imports = "silent"
warn_redundant_casts = true
warn_unused_ignores = true
disallow_any_generics = true
no_implicit_reexport = true
disallow_untyped_defs = true
[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true
init_typed
¶
因为 Pydantic 默认执行数据转换,所以以下代码在运行时仍然是有效的:
class Model(BaseModel):
a: int
Model(a='1')
因此,在合成 __init__
方法时,插件会为字段注解使用 Any
,除非设置了 init_typed
或在模型上启用了严格模式。
init_forbid_extra
¶
默认情况下,Pydantic 允许(并忽略)任何额外提供的参数:
class Model(BaseModel):
a: int = 1
Model(unrelated=2)
因此,在合成 __init__
方法时,插件会添加一个额外的 **kwargs: Any
参数,除非设置了 init_forbid_extra
或者 extra
设置为 'forbid'
。
warn_required_dynamic_aliases
¶
当在 validate_by_name
设置为 False
的模型上使用动态确定的别名或别名生成器时,是否报错。如果存在此类别名,mypy 无法正确地对 __init__
的调用进行类型检查。在这种情况下,它将默认将所有参数视为非必需的。
与禁用 Any
的兼容性
某些 mypy 配置选项(例如 disallow_any_explicit
)会报错,因为合成的 __init__
方法包含 Any
注解。要规避此问题,您必须同时启用 init_forbid_extra
和 init_typed
。