Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python pydantic constr与mypy检查之间的冲突_Python_Mypy_Pydantic - Fatal编程技术网

Python pydantic constr与mypy检查之间的冲突

Python pydantic constr与mypy检查之间的冲突,python,mypy,pydantic,Python,Mypy,Pydantic,我正在使用pydantic验证Json/Dict输入。但我也在使用mypy来验证代码的类型完整性 当使用pydantic.constr类型(其中包括验证给定字符串是否符合正则表达式)时,我会得到一个mypy错误 代码如下: from typing import List import pydantic Regex = pydantic.constr(regex="[0-9a-z_]*") class Data(pydantic.BaseModel): rege

我正在使用pydantic验证Json/Dict输入。但我也在使用mypy来验证代码的类型完整性

当使用
pydantic.constr
类型(其中包括验证给定字符串是否符合正则表达式)时,我会得到一个mypy错误

代码如下:

from typing import List

import pydantic

Regex = pydantic.constr(regex="[0-9a-z_]*")


class Data(pydantic.BaseModel):
    regex: List[Regex]


data = Data(**{"regex":["abc", "123", "etc"]})
print(data, data.json())
这是mypy的输出:

$ mypy main.py 
main.py:9: error: Variable "main.Regex" is not valid as a type
main.py:9: note: See https://mypy.readthedocs.io/en/latest/common_issues.html#variables-vs-type-aliases
我查看了文档,但找不到处理此问题的方法。我知道我可以为这个正则表达式创建一个静态类型,但这样做有违pydantic的目的。我能通过的唯一方法是使用
#类型:ignore
,这远远不够理想


那么,有没有一种方法可以同时兼顾pydantic和mypy的好处呢?

有几种方法可以实现这一点:

继承自
pydantic.ConstrainedStr
您可以直接从
pydantic.ConstrainedStr
继承,而不是使用
constr
指定正则表达式约束(内部使用
pydantic.ConstrainedStr
):

import re
import pydantic
from pydantic import Field
from typing import List

class Regex(pydantic.ConstrainedStr):
    regex = re.compile("^[0-9a-z_]*$")

class Data(pydantic.BaseModel):
    regex: List[Regex]

data = Data(**{"regex": ["abc", "123", "asdf"]})
print(data)
# regex=['abc', '123', 'asdf']
print(data.json())
# {"regex": ["abc", "123", "asdf"]}
Mypy愉快地接受了这一点,pydantic进行了正确的验证。
data.regex[i]
的类型是
regex
,但由于
pydantic.ConstrainedStr
本身继承自
str
,因此在大多数地方它可以用作字符串

使用
pydantic.Field
regex consraint也可以指定为以下参数:

由于
Regex
不是直接用作pydantic模型中的字段(而是用作示例中列表中的条目),因此我们需要强制引入模型
\uuuu root\uuuu
使
Regex
模型在验证和序列化时充当其单个字段(更多详细信息)

但是它有一个缺点:
data.regex[i]
的类型也是
regex
,但这次不是从
str
继承的。这导致例如,
foo:str=data.regex[0]
未进行类型检查
foo:str=data.regex[0]。\uuuu root\uuuu
必须改用

我仍然在这里提到这一点,因为当约束直接应用于字段而不是列表条目时,这可能是最简单的解决方案(并且
键入。注释的
不可用,请参见下文)。例如:

class DataNotList(pydantic.BaseModel):
    regex: str = Field(regex="^[0-9a-z_]*$")
使用带有
pydantic.Field的
键入.Annotated
与使用
constr
指定正则表达式约束不同,您可以将其指定为参数,然后将其与
键入结合使用。带注释的

import pydantic
from pydantic import Field
from typing import Annotated

Regex = Annotated[str, Field(regex="^[0-9a-z_]*$")]

class DataNotList(pydantic.BaseModel):
    regex: Regex

data = DataNotList(**{"regex": "abc"})
print(data)
# regex='abc'
print(data.json())
# {"regex": "abc"}
Mypy将带注释的[str,Field(regex=“^[0-9a-z\uz]*$”)
视为
str的类型别名。但它也告诉pydantic进行验证。
这在pydantic文档中有描述

不幸的是,它目前不适用于以下情况:

class Data(pydantic.BaseModel):
    regex: List[Regex]
验证根本无法运行。这是一个开放的bug()。一旦bug被修复,这可能是最好的解决方案

请注意,
typing.Annotated
仅在Python 3.9之后才可用。对于较旧的Python版本,可以使用


作为旁注:我对正则表达式使用了
^[0-9a-z.]*$
而不是
[0-9a-z.]*
,因为后者会接受任何有效字符串,例如

class Data(pydantic.BaseModel):
    regex: List[Regex]