【问题标题】:How to prevent Pydantic from throwing an exception on ValidationError如何防止 Pydantic 在 ValidationError 上抛出异常
【发布时间】:2022-01-07 01:35:00
【问题描述】:

如何防止 Pydantic 在 ValidationError 上抛出异常?

from pydantic import BaseModel, NonNegativeInt


class Person(BaseModel):
    name: str
    age: NonNegativeInt
    details: None


p1: Person = Person(name='Alice', age=30, details=None)
print(p1)
p2: Person = Person(name='Bob', age=40, details={'height': 1.70, 'weight': 91})
print(p1)

我希望这个异常杀死程序并记录警告

name='Alice' age=30
Traceback (most recent call last):
  File "playground/test_pydantic_prevent_exception.py", line 12, in <module>
    p2: Person = Person(name='Bob', age=40, details={'height': 1.70, 'weight': 91})
  File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Person
details
  value is not None (type=type_error.not_none)

解释我为什么需要它的用例如下:

我正在开发一个尚未 100% 完成的产品,因此返回的值可能会在一夜之间发生变化,从返回 None 到我开发时未知的其他对象 {}。

当我查询产品并获得一个对象而不是 None 时,分配可能会失败,但我想记录一个警告,允许程序继续,因为在很多情况下这不是一个阻止程序。

【问题讨论】:

  • try: ... except ValidationError: ...?
  • 问题是在哪里放置try-except。我不想在我的代码中包装每个作业。我希望能够直接在类定义上做到这一点。

标签: python validation pydantic


【解决方案1】:

这是一个完整的脚本,包含一个继承 Pydantic 的 BaseModel 的新类 BaseModelNoException,包装了异常 ValidationError 并改为抛出警告。


import json
from traceback import TracebackException
from typing import no_type_check, Type, Any

from pydantic import BaseModel, NonNegativeInt, ValidationError, StrBytes, Protocol


class BaseModelNoException(BaseModel):
    def __init__(__pydantic_self__, **data: Any) -> None:
        try:
            super(BaseModelNoException, __pydantic_self__).__init__(**data)
        except ValidationError as pve:
            print(f'This is a warning. __init__ failed to validate:\n {json.dumps(data, indent=4)}\n')
            print(f'This is the original exception:\n{pve.json()}')

    @no_type_check
    def __setattr__(self, name, value):
        try:
            return super(BaseModelNoException, self).__setattr__
        except ValidationError as pve:
            print(f'This is a warning. __setattr__ failed to validate:\n {json.dumps({name: value}, indent=4)}')
            print(f'This is the original exception:\n{pve.json()}')
            return None

    @classmethod
    def parse_obj(cls: Type['Model'], obj: Any) -> 'Model':
        try:
            return super(BaseModelNoException, cls).parse_obj(obj)
        except ValidationError as pve:
            print(f'This is a warning. parse_obj failed to validate:\n {json.dumps(obj, indent=4)}')
            print(f'This is the original exception:\n{pve.json()}')
            return None

    @classmethod
    def parse_raw(cls: Type['Model'], b: StrBytes, *, content_type: str = None, encoding: str = 'utf8',
                  proto: Protocol = None, allow_pickle: bool = False, ) -> 'Model':
        try:
            return super(BaseModelNoException, cls).parse_raw(b=b, content_type=content_type, encoding=encoding,
                                                              proto=proto, allow_pickle=allow_pickle)
        except ValidationError as pve:
            print(f'This is a warning. parse_raw failed to validate:\n {b}')
            print(f'This is the original exception:\n{pve.json()}')
            return None


# class Person(BaseModel):
class PersonDetails(BaseModel):
    height: NonNegativeInt
    weight: NonNegativeInt


class Person(BaseModelNoException):
    name: str = ''
    age: NonNegativeInt = 0
    details: PersonDetails


p1: Person = Person(name='Alice', age=30, details=None)
print(p1)

print('-' * 100)

p2: Person = Person(name='Bob', age=40, details={'height': 1.70, 'weight': 91})
print(p2)

print('-' * 100)

p3: Person = Person.parse_obj({'name': 'Alice', 'age': 31, 'details': {'height': 1.70, 'weight': -77}})
print(p3)

print('-' * 100)

print('The End')

这是上面脚本的输出。

/playground/test_pydantic_prevent_exception.py 这是一个警告。 init 验证失败: { “名称”:“爱丽丝”, “年龄”:30, “详细信息”:空 }

This is the original exception:
[
  {
    "loc": [
      "details"
    ],
    "msg": "none is not an allowed value",
    "type": "type_error.none.not_allowed"
  }
]

----------------------------------------------------------------------------------------------------
name='Bob' age=40 details=PersonDetails(height=1, weight=91)
----------------------------------------------------------------------------------------------------
This is a warning. __init__ failed to validate:
 {
    "name": "Alice",
    "age": 31,
    "details": {
        "height": 1.7,
        "weight": -77
    }
}

This is the original exception:
[
  {
    "loc": [
      "details",
      "weight"
    ],
    "msg": "ensure this value is greater than or equal to 0",
    "type": "value_error.number.not_ge",
    "ctx": {
      "limit_value": 0
    }
  }
]

----------------------------------------------------------------------------------------------------
The End

Process finished with exit code 0

【讨论】:

    猜你喜欢
    • 2018-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2017-09-30
    • 2018-01-13
    • 1970-01-01
    相关资源
    最近更新 更多