mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
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:
@@ -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."""
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user