簡體   English   中英

使用 Pydantic 和 FastAPI 的 PurePath 的 JSON 模式無法聲明錯誤值

[英]Error Value not declarable with JSON Schema for PurePath with Pydantic and FastAPI

我正在嘗試將PureWindowsPath類型的字段path添加到我的模型中。 在按照此處建議的https://github.com/samuelcolvin/pydantic/issues/2089#issuecomment-890018075實施自定義驗證器后,嘗試訪問 SwaggerUI 時出現以下錯誤:

INFO:     127.0.0.1:7696 - "GET /api/openapi.json HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 371, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 59, in __call__
    return await self.app(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\fastapi\applications.py", line 208, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\middleware\errors.py", line 181, in __call__
    raise exc from None
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\exceptions.py", line 82, in __call__
    raise exc from None
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\routing.py", line 580, in __call__
    await route.handle(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\routing.py", line 390, in handle
    await self.app(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\fastapi\applications.py", line 208, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\middleware\errors.py", line 181, in __call__
    raise exc from None
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\exceptions.py", line 82, in __call__
    raise exc from None
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\routing.py", line 580, in __call__
    await route.handle(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\routing.py", line 241, in handle
    await self.app(scope, receive, send)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\starlette\routing.py", line 52, in app
    response = await func(request)
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\fastapi\applications.py", line 161, in openapi
    return JSONResponse(self.openapi())
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\fastapi\applications.py", line 136, in openapi
    self.openapi_schema = get_openapi(
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\fastapi\openapi\utils.py", line 387, in get_openapi
    definitions = get_model_definitions(
  File "C:\Users\xxx\.virtualenvs\server-J9mXI7Iu\lib\site-packages\fastapi\utils.py", line 24, in get_model_definitions
    m_schema, m_definitions, m_nested_models = model_process_schema(
  File "pydantic\schema.py", line 548, in pydantic.schema.model_process_schema
  File "pydantic\schema.py", line 589, in pydantic.schema.model_type_schema
  File "pydantic\schema.py", line 241, in pydantic.schema.field_schema
  File "pydantic\schema.py", line 495, in pydantic.schema.field_type_schema
  File "pydantic\schema.py", line 863, in pydantic.schema.field_singleton_schema
ValueError: Value not declarable with JSON Schema, field: name='path' type=PureWindowsPath required=True

我的 Pydantic 配置如下所示:

class CamelModel(BaseModel, ABC):
    class Config:
        alias_generator = camelize
        allow_population_by_field_name = True
        frozen = True
        json_encoders = {
            datetime: lambda dt: dt.isoformat(),
            PureWindowsPath: str,
            PurePath: str
        }
        use_enum_values = True

class Foo(CamelModel, ABC):
    path: PureWindowsPath
    extraction_version: str

class Foo2(Foo):
    pass

您可以使用以下代碼來完成這項工作。 它創建了一個帶有驗證器的子類,因此您可以自定義架構和驗證方式:

這是相關 Github 問題的鏈接: https ://github.com/tiangolo/sqlmodel/issues/235#issuecomment-1162063590

from psycopg2.extras import DateTimeTZRange as DateTimeTZRangeBase
from sqlalchemy.dialects.postgresql import TSTZRANGE
from sqlmodel import (
    Column,
    Field,
    Identity,
    SQLModel,
)

from pydantic.json import ENCODERS_BY_TYPE

ENCODERS_BY_TYPE |= {DateTimeTZRangeBase: str}


class DateTimeTZRange(DateTimeTZRangeBase):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if isinstance(v, str):
            lower = v.split(", ")[0][1:].strip().strip()
            upper = v.split(", ")[1][:-1].strip().strip()
            bounds = v[:1] + v[-1:]
            return DateTimeTZRange(lower, upper, bounds)
        elif isinstance(v, DateTimeTZRangeBase):
            return v
        raise TypeError("Type must be string or DateTimeTZRange")

    @classmethod
    def __modify_schema__(cls, field_schema):
        field_schema.update(type="string", example="[2022,01,01, 2022,02,02)")


class EventBase(SQLModel):
    __tablename__ = "event"
    timestamp_range: DateTimeTZRange = Field(
        sa_column=Column(
            TSTZRANGE(),
            nullable=False,
        ),
    )


class Event(EventBase, table=True):
    id: int | None = Field(
        default=None,
        sa_column_args=(Identity(always=True),),
        primary_key=True,
        nullable=False,
    )


暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM