Skip to content

Commit eb98edf

Browse files
fix(ai): Handle Pydantic model classes in _normalize_data (#5143)
### Description Previously, `_normalize_data()` would attempt to call `model_dump()` on Pydantic model classes (types) when they were passed as arguments, which would fail. This commonly occurs when model classes are used in schema definitions, such as when passing response format schemas to AI SDKs. This change adds an `inspect.isclass()` check to detect when a class type is passed instead of an instance. For classes, we now return a string representation `"<ClassType: ClassName>"` instead of attempting to call `model_dump()`. **Changes:** - Added `inspect` import to `sentry_sdk/ai/utils.py` - Added class type detection in `_normalize_data()` before calling `model_dump()` - Added comprehensive test coverage for both class types and instances in `tests/utils/test_general.py` **Behavior:** - Pydantic model **instances**: Still normalized via `model_dump()` (existing behavior) - Pydantic model **classes**: Now serialized as `"<ClassType: ClassName>"` (new behavior) - Mixed data structures: Classes within dicts/lists are properly handled #### Issues <!-- No specific issue linked - this was discovered during development --> --------- Co-authored-by: Ivana Kellyer <[email protected]>
1 parent 5de66e2 commit eb98edf

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

sentry_sdk/ai/utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import inspect
12
import json
23
from collections import deque
34
from typing import TYPE_CHECKING
@@ -38,6 +39,11 @@ def _normalize_data(data, unpack=True):
3839
# type: (Any, bool) -> Any
3940
# convert pydantic data (e.g. OpenAI v1+) to json compatible format
4041
if hasattr(data, "model_dump"):
42+
# Check if it's a class (type) rather than an instance
43+
# Model classes can be passed as arguments (e.g., for schema definitions)
44+
if inspect.isclass(data):
45+
return f"<ClassType: {data.__name__}>"
46+
4147
try:
4248
return _normalize_data(data.model_dump(), unpack=unpack)
4349
except Exception as e:

tests/utils/test_general.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33

44
import pytest
5+
from sentry_sdk.ai.utils import _normalize_data
56

67

78
from sentry_sdk.utils import (
@@ -621,3 +622,29 @@ def test_failed_base64_conversion(input):
621622
)
622623
def test_strip_string(input, max_length, result):
623624
assert strip_string(input, max_length) == result
625+
626+
627+
def test_normalize_data_with_pydantic_class():
628+
"""Test that _normalize_data handles Pydantic model classes"""
629+
630+
class TestClass:
631+
name: str = None
632+
633+
def __init__(self, name: str):
634+
self.name = name
635+
636+
def model_dump(self):
637+
return {"name": self.name}
638+
639+
# Test with class (should NOT call model_dump())
640+
result = _normalize_data(TestClass)
641+
assert result == "<ClassType: TestClass>"
642+
643+
# Test with instance (should call model_dump())
644+
instance = TestClass(name="test")
645+
result = _normalize_data(instance)
646+
assert result == {"name": "test"}
647+
648+
# Test with dict containing class
649+
result = _normalize_data({"schema": TestClass, "count": 5})
650+
assert result == {"schema": "<ClassType: TestClass>", "count": 5}

0 commit comments

Comments
 (0)