diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index be5b88d791..d18af9b21c 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -7,6 +7,8 @@ from dataclasses import KW_ONLY, dataclass, field, replace from datetime import datetime from mimetypes import guess_type +from os import PathLike +from pathlib import Path from typing import TYPE_CHECKING, Annotated, Any, Literal, TypeAlias, cast, overload import pydantic @@ -525,6 +527,14 @@ def from_data_uri(cls, data_uri: str) -> Self: media_type, data = data_uri[len(prefix) :].split(';base64,', 1) return cls(data=base64.b64decode(data), media_type=media_type) + @classmethod + def from_path(cls, path: PathLike[str], *, media_type: str) -> Self: + """Create a `BinaryContent` from a path.""" + if not isinstance(path, Path): + path = Path(path) + # TODO(Marcelo): We should be able to infer the `media_type` from the filename. + return cls(data=path.read_bytes(), media_type=media_type) + @pydantic.computed_field @property def identifier(self) -> str: diff --git a/tests/test_messages.py b/tests/test_messages.py index 8508648d44..7479def28e 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -1,5 +1,6 @@ import sys from datetime import datetime, timezone +from pathlib import Path import pytest from inline_snapshot import snapshot @@ -584,3 +585,11 @@ def test_binary_content_validation_with_optional_identifier(): 'identifier': 'foo', } ) + + +def test_binary_content_from_path(tmp_path: Path): + img = tmp_path / 'potato.png' + img.write_bytes(b'fake') + assert BinaryContent.from_path(img, media_type='image/png') == snapshot( + BinaryContent(data=b'fake', media_type='image/png') + )