You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pydantic经纬度验证遇model_type错误及单元测试问题

问题分析与解决

1. 初始 model_type 错误原因及修复

你最初的代码同时混用了Pydantic的BaseModel继承和@dataclass装饰器,这是错误用法——Pydantic的dataclass(来自pydantic.dataclasses)和BaseModel是两种独立的定义数据结构的方式,不能同时使用。

错误代码问题点:

from pydantic import BaseModel, Field
from pydantic.dataclasses import dataclass

@dataclass(frozen=True)
class Location(BaseModel):  # 错误:同时使用dataclass装饰器和继承BaseModel
    longitude: float = Field(None, ge=-180, le=180)
    latitude: float = Field(None, ge=-90, le=90)

修复方案二选一:

方案A:使用BaseModel(适合API场景)

from pydantic import BaseModel, Field

class Location(BaseModel):
    longitude: float | None = Field(None, ge=-180, le=180)
    latitude: float | None = Field(None, ge=-90, le=90)

# 实例化正常
Location(longitude=1.0, latitude=1.0)

方案B:使用Pydantic Dataclass(适合传统数据类场景)

from pydantic import Field
from pydantic.dataclasses import dataclass

@dataclass(frozen=True)
class Location:
    longitude: float | None = Field(None, ge=-180, le=180)
    latitude: float | None = Field(None, ge=-90, le=90)

# 实例化正常
Location(longitude=1.0, latitude=1.0)

2. 单元测试的问题及修复

移除BaseModel后,测试问题有两个核心原因:

  1. Pydantic Dataclass实例化时立即执行验证,所以你第一行创建invalid_location的代码就已经抛出异常,根本不会进入后续的with断言块。
  2. Pydantic默认抛出的是ValidationError(不是ValueError),且错误信息不是你预期的"Location is out of range"。

测试代码的问题点:

def test_when_location_is_not_in_range_then_print_exception(self):
    # 此处已抛出ValidationError,后续代码不会执行
    invalid_location = Location(latitude=200.0, longitude=300.0)

    with self.assertRaises(ValueError) as context:
        location = Location(latitude=invalid_location.latitude, longitude=invalid_location.longitude)

    self.assertEqual(
        str(context.exception), "Location is out of range", "Expected exception message: 'Location is out of range'"
    )

修复后的测试代码:

方案1:捕获ValidationError并断言默认错误内容

from pydantic import ValidationError
import unittest

class TestLocation(unittest.TestCase):
    def test_invalid_location_raises_validation_error(self):
        with self.assertRaises(ValidationError) as context:
            Location(latitude=200.0, longitude=300.0)
        
        # 断言错误信息包含预期的验证提示
        self.assertIn("Input should be less than or equal to 180", str(context.exception))
        self.assertIn("Input should be less than or equal to 90", str(context.exception))

方案2:自定义验证器,抛出指定错误信息

如果需要自定义错误提示,可添加字段验证器:

from pydantic import Field, validator
from pydantic.dataclasses import dataclass

@dataclass(frozen=True)
class Location:
    longitude: float | None = Field(None, ge=-180, le=180)
    latitude: float | None = Field(None, ge=-90, le=90)

    @validator('longitude')
    def validate_longitude(cls, v):
        if v is not None and not (-180 <= v <= 180):
            raise ValueError("Location is out of range")
        return v

    @validator('latitude')
    def validate_latitude(cls, v):
        if v is not None and not (-90 <= v <= 90):
            raise ValueError("Location is out of range")
        return v

对应的测试代码:

def test_invalid_location_raises_custom_error(self):
    with self.assertRaises(ValueError) as context:
        Location(latitude=200.0, longitude=300.0)
    
    self.assertEqual(str(context.exception), "Location is out of range")

关于Unexpected Argument警告

该警告多为IDE误报,因为Pydantic Dataclass的字段是动态生成的。可通过安装Pydantic专属IDE插件(如PyCharm的Pydantic插件)解决,或直接忽略该警告。


内容的提问来源于stack exchange,提问作者PepeLoperena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:18:12