在我的自定义工作包中,我想使用pydantic
验证输入。然而,我的大多数函数的输入不是原生类型,而是来自其他库的类的示例,例如。pandas.DataFrame
或sqlalchemy.Engine
。将这些作为类型提示并添加pydantic.validate_arguments
装饰器会失败。
让我们假设我的函数的输入应该是来自CustomPackage
库的CustomClass
类型。
import CustomPackage
import pydantic
@pydantic.validate_arguments
def custom_function(custom_argument: CustomPackage.CustomClass) -> None:
pass
这将导致以下错误:
RuntimeError:未找到<class 'CustomPackage. CustomClass'>的验证程序,请参阅配置中的arbitrary_types_allowed
为了解决这个问题,我可以使用@pydantic.validate_arguments(config={"arbitrary_types_allowed": True})
来代替,它允许任何东西。这不是我的意图,所以我遵循文档中的自定义类型部分,并创建了以下内容:
import collections.abc
import typing
import CustomPackage
class CustomClassWithValidator(CustomPackage.CustomClass):
@classmethod
def __get_validators__(cls: typing.Type["CustomClassWithValidator"]) -> collections.abc.Iterable[collections.abc.Callable]:
yield cls.validate_custom_class
@classmethod
def validate_custom_class(cls: typing.Type["CustomClassWithValidator"], passed_value: typing.Any) -> CustomPackage.CustomClass:
if isinstance(passed_value, CustomPackage.CustomClass):
return passed_value
raise ValueError
在此之后,以下工作正常:
@pydantic.validate_arguments
def custom_function(custom_argument: CustomClassWithValidator) -> None:
pass
但是我有相当多的第三方依赖项,每个依赖项都有很多我正在使用的自定义类。如上所述,为它们中的每一个创建几乎相同的类将起作用,但这似乎不是最佳的。pydantic
中有没有什么功能可以减少重复性?
1条答案
按热度按时间u2nhd7ah1#
我不知道在版本1中有任何内置的Pydantic方法来做到这一点,除了将
__get_validators__
生成器函数添加到您已经找到的类型中。我认为其中一个主要原因是,* 通常 * 您不仅希望字段类型被验证为正确的类型,而且还希望 * 解析 * 或序列化/反序列化,因为在大多数应用Pydantic的领域中,您要么从Python原语或内置类型的对象,甚至从JSON文本示例化Pydantic模型。
因此Pydantic不仅为最常见的类型提供了默认的验证器,而且还为这些类型提供了合理且灵活的初始化和(反)序列化函数。
这意味着,如果你想使用一些自定义/外来类型,* 你 * 负责告诉Pydantic如何示例化和验证它。
解决方法
选项A:简单混合
如果你想要的只是一个简单的“愚蠢”验证器,只是检查
isinstance
是否为任何给定类型,你可以重写你已经拥有的作为一个不可知的混合类,以最大限度地减少重复:然后,你可以简单地从它和任何你想要的特定类一起继承:
现在的问题是,你的参数现在必须是
MyBar
和MyEggs
类型,而不能只是Bar
和Eggs
类型。选项B:泛型混入
为了允许指定要针对哪个类进行验证,同时将重复保持在最低限度,我们需要发挥创造性。我建议的一种方法是在检查类方面使
ValidatorMixin
通用。你可以做一些魔术,然后自动提取传递给它的类型参数并对其进行验证:(详情请看这里)现在你可以这样使用它:
正如您所看到的,这现在还允许您使用多重继承,但仍然精确地指定要验证的对象。因此,最后一行中的
f
调用将通过验证。然而,这仍然有一个缺陷。静态类型检查器会抱怨这个调用,因为
Eggs
不是MyClass
的子类型(相反),所以这个调用会被视为错误。选项C:对类本身进行Monkey-patch
如果这让你感到困扰,在我看来,唯一合理的替代方案就是对你想要使用的类进行猴子补丁,而不是子类化和混合。就像这样:
现在,这既可以用作对某些第三方类进行monkey-patching的简单函数,也可以用作您自己的类的装饰器。
(You也可以通过可选的
validators
参数自由添加其他验证函数。)用途:
如果你愿意,你可以做一个更复杂的装饰器版本,允许使用或不使用额外的参数: