fix: replace deprecated json_encoders with Pydantic V2 field serializers (#295)

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
This commit is contained in:
Paul Hernandez
2025-09-14 22:19:16 -05:00
committed by GitHub
parent 0499319ded
commit b00e4ff5a1
2 changed files with 48 additions and 22 deletions
+17 -9
View File
@@ -4,7 +4,7 @@ from datetime import datetime
from typing import List, Optional, Annotated, Sequence, Literal, Union
from annotated_types import MinLen, MaxLen
from pydantic import BaseModel, Field, BeforeValidator, TypeAdapter, ConfigDict
from pydantic import BaseModel, Field, BeforeValidator, TypeAdapter, ConfigDict, field_serializer
from basic_memory.schemas.search import SearchItemType
@@ -118,8 +118,6 @@ def memory_url_path(url: memory_url) -> str: # pyright: ignore
class EntitySummary(BaseModel):
"""Simplified entity representation."""
model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
type: Literal["entity"] = "entity"
permalink: Optional[str]
title: str
@@ -127,12 +125,14 @@ class EntitySummary(BaseModel):
file_path: str
created_at: datetime
@field_serializer('created_at')
def serialize_created_at(self, dt: datetime) -> str:
return dt.isoformat()
class RelationSummary(BaseModel):
"""Simplified relation representation."""
model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
type: Literal["relation"] = "relation"
title: str
file_path: str
@@ -142,12 +142,14 @@ class RelationSummary(BaseModel):
to_entity: Optional[str] = None
created_at: datetime
@field_serializer('created_at')
def serialize_created_at(self, dt: datetime) -> str:
return dt.isoformat()
class ObservationSummary(BaseModel):
"""Simplified observation representation."""
model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
type: Literal["observation"] = "observation"
title: str
file_path: str
@@ -156,12 +158,14 @@ class ObservationSummary(BaseModel):
content: str
created_at: datetime
@field_serializer('created_at')
def serialize_created_at(self, dt: datetime) -> str:
return dt.isoformat()
class MemoryMetadata(BaseModel):
"""Simplified response metadata."""
model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
uri: Optional[str] = None
types: Optional[List[SearchItemType]] = None
depth: int
@@ -173,6 +177,10 @@ class MemoryMetadata(BaseModel):
total_relations: Optional[int] = None
total_observations: Optional[int] = None
@field_serializer('generated_at')
def serialize_generated_at(self, dt: datetime) -> str:
return dt.isoformat()
class ContextResult(BaseModel):
"""Context result containing a primary item with its observations and related items."""
+31 -13
View File
@@ -197,18 +197,36 @@ class TestDateTimeSerialization:
assert "T" in datetime_str # Contains date-time separator
assert len(datetime_str) >= 19 # At least YYYY-MM-DDTHH:MM:SS format
def test_all_models_have_json_encoders_configured(self):
"""Test that all memory schema models have datetime json_encoders configured."""
models_to_test = [EntitySummary, RelationSummary, ObservationSummary, MemoryMetadata]
def test_all_models_have_datetime_serializers_configured(self):
"""Test that all memory schema models have datetime field serializers configured."""
models_to_test = [
(EntitySummary, "created_at"),
(RelationSummary, "created_at"),
(ObservationSummary, "created_at"),
(MemoryMetadata, "generated_at")
]
for model_class in models_to_test:
# Check that ConfigDict with json_encoders is configured
assert hasattr(model_class, "model_config")
assert "json_encoders" in model_class.model_config
assert datetime in model_class.model_config["json_encoders"]
# Verify the encoder function produces ISO format
encoder = model_class.model_config["json_encoders"][datetime]
for model_class, datetime_field in models_to_test:
# Create a test instance with a datetime field
test_datetime = datetime(2023, 12, 8, 10, 30, 0)
result = encoder(test_datetime)
assert result == "2023-12-08T10:30:00"
if model_class == EntitySummary:
instance = model_class(
permalink="test", title="Test", file_path="test.md", created_at=test_datetime
)
elif model_class == RelationSummary:
instance = model_class(
title="Test", file_path="test.md", permalink="test",
relation_type="test", created_at=test_datetime
)
elif model_class == ObservationSummary:
instance = model_class(
title="Test", file_path="test.md", permalink="test",
category="test", content="Test", created_at=test_datetime
)
elif model_class == MemoryMetadata:
instance = model_class(depth=1, generated_at=test_datetime)
# Test that model_dump produces ISO format for datetime field
data = instance.model_dump()
assert data[datetime_field] == "2023-12-08T10:30:00"