|
1 | 1 | from typing import Any, Dict, Optional, Type, Union |
2 | 2 |
|
3 | | -from pydantic import ConfigDict |
| 3 | +from pydantic import ConfigDict, ValidationError |
4 | 4 | from typing_extensions import override |
5 | 5 |
|
6 | 6 | from pipelex import log |
|
18 | 18 | TextAndImagesContent, |
19 | 19 | TextContent, |
20 | 20 | ) |
21 | | -from pipelex.exceptions import StuffError |
| 21 | +from pipelex.exceptions import StuffContentValidationError, StuffError |
22 | 22 | from pipelex.tools.misc.string_utils import pascal_case_to_snake_case |
23 | | -from pipelex.tools.typing.pydantic_utils import CustomBaseModel |
| 23 | +from pipelex.tools.typing.pydantic_utils import CustomBaseModel, format_pydantic_validation_error |
24 | 24 |
|
25 | 25 |
|
26 | 26 | class Stuff(CustomBaseModel): |
@@ -106,9 +106,25 @@ def is_number(self) -> bool: |
106 | 106 |
|
107 | 107 | def content_as(self, content_type: Type[StuffContentType]) -> StuffContentType: |
108 | 108 | """Get content with proper typing if it's of the expected type.""" |
109 | | - if not isinstance(self.content, content_type): |
110 | | - raise TypeError(f"Content is of type '{type(self.content)}', instead of the expected '{content_type}'") |
111 | | - return self.content |
| 109 | + # First try the direct isinstance check for performance |
| 110 | + if isinstance(self.content, content_type): |
| 111 | + return self.content |
| 112 | + |
| 113 | + # If isinstance failed, try model validation approach |
| 114 | + try: |
| 115 | + # Check if class names match (quick filter before attempting validation) |
| 116 | + if type(self.content).__name__ == content_type.__name__: |
| 117 | + content_dict = self.content.smart_dump() |
| 118 | + validated_content = content_type.model_validate(content_dict) |
| 119 | + log.debug(f"Model validation passed: converted {type(self.content).__name__} to {content_type.__name__}") |
| 120 | + return validated_content |
| 121 | + except ValidationError as exc: |
| 122 | + formatted_error = format_pydantic_validation_error(exc) |
| 123 | + raise StuffContentValidationError( |
| 124 | + original_type=type(self.content).__name__, target_type=content_type.__name__, validation_error=formatted_error |
| 125 | + ) from exc |
| 126 | + |
| 127 | + raise TypeError(f"Content is of type '{type(self.content)}', instead of the expected '{content_type}'") |
112 | 128 |
|
113 | 129 | def as_list_content(self) -> ListContent: # pyright: ignore[reportMissingTypeArgument, reportUnknownParameterType] |
114 | 130 | """Get content as ListContent with items of any type.""" |
|
0 commit comments