From 7a11bd098f4c117df1a25e28ab5a8be3024e4080 Mon Sep 17 00:00:00 2001 From: fzowl Date: Sat, 21 Mar 2026 15:06:24 +0100 Subject: [PATCH] Migrate to Pydantic v2 APIs for Python 3.14 support The previous fix (#46) swapped the pydantic import order but still fell back to the broken pydantic.v1 path since Extra was removed in v2. - Remove pydantic.v1 fallback and Extra import - Replace Extra.forbid with string "forbid" - Replace min_items with min_length (v2 rename) - Replace .parse_obj() with .model_validate() - Replace .dict() with .model_dump() - Bump pydantic lower bound to >=2.7.4 (already required transitively by langchain-text-splitters via langchain-core) Fixes #36 --- pyproject.toml | 4 ++-- voyageai/client.py | 2 +- voyageai/client_async.py | 2 +- voyageai/object/multimodal_embeddings.py | 20 ++++++++------------ 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a7c3664..dc2143f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "voyageai" -version = "0.3.8" +version = "0.3.9" description = "" authors = ["Yujie Qian "] readme = "README.md" @@ -16,7 +16,7 @@ numpy = [ ] aiolimiter = "*" pillow = "*" -pydantic = ">=1.10.8" +pydantic = ">=2.7.4" tokenizers = ">=0.14.0" langchain-text-splitters = ">=0.3.8" ffmpeg-python = "*" diff --git a/voyageai/client.py b/voyageai/client.py index 851cd5d..de058cc 100644 --- a/voyageai/client.py +++ b/voyageai/client.py @@ -170,7 +170,7 @@ def multimodal_embed( truncation=truncation, output_dtype=output_dtype, output_dimension=output_dimension, - ).dict(), + ).model_dump(), **self._params, ) diff --git a/voyageai/client_async.py b/voyageai/client_async.py index cebdaa3..5ae2455 100644 --- a/voyageai/client_async.py +++ b/voyageai/client_async.py @@ -170,7 +170,7 @@ async def multimodal_embed( truncation=truncation, output_dtype=output_dtype, output_dimension=output_dimension, - ).dict(), + ).model_dump(), **self._params, ) if response is None: diff --git a/voyageai/object/multimodal_embeddings.py b/voyageai/object/multimodal_embeddings.py index 1f4013b..a7f5e65 100644 --- a/voyageai/object/multimodal_embeddings.py +++ b/voyageai/object/multimodal_embeddings.py @@ -5,16 +5,12 @@ import PIL.Image import PIL.ImageFile +from pydantic import BaseModel, Field, ValidationError from voyageai import error from voyageai.api_resources import VoyageResponse from voyageai.video_utils import Video -try: - from pydantic import BaseModel, Extra, Field, ValidationError -except ImportError: - from pydantic.v1 import BaseModel, Extra, Field, ValidationError - class MultimodalEmbeddingsObject: def __init__(self, response: Optional[VoyageResponse] = None): @@ -51,7 +47,7 @@ class MultimodalInputSegmentText(BaseModel): text: str class Config: - extra = Extra.forbid + extra = "forbid" class MultimodalInputSegmentImageURL(BaseModel): @@ -59,7 +55,7 @@ class MultimodalInputSegmentImageURL(BaseModel): image_url: str class Config: - extra = Extra.forbid + extra = "forbid" class MultimodalInputSegmentImageBase64(BaseModel): @@ -67,7 +63,7 @@ class MultimodalInputSegmentImageBase64(BaseModel): image_base64: str class Config: - extra = Extra.forbid + extra = "forbid" class MultimodalInputSegmentVideoURL(BaseModel): @@ -75,7 +71,7 @@ class MultimodalInputSegmentVideoURL(BaseModel): video_url: str class Config: - extra = Extra.forbid + extra = "forbid" class MultimodalInputSegmentVideoBase64(BaseModel): @@ -83,7 +79,7 @@ class MultimodalInputSegmentVideoBase64(BaseModel): video_base64: str class Config: - extra = Extra.forbid + extra = "forbid" class MultimodalInput(BaseModel): @@ -98,7 +94,7 @@ class MultimodalInput(BaseModel): ], Field(discriminator="type"), ] - ] = Field(..., min_items=1) + ] = Field(..., min_length=1) class MultimodalInputRequest(BaseModel): @@ -195,7 +191,7 @@ def _process_dict_input(cls, input_data: Dict, idx: int) -> MultimodalInput: raise ValueError(f"Input at index {idx} is missing the 'content' field.") try: - return MultimodalInput.parse_obj(input_data) + return MultimodalInput.model_validate(input_data) except ValidationError as ve: raise ValueError(f"Validation error for input at index {idx}: {ve}") from ve