Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions tests/integrations/test_pydantic.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Literal

import pytest
from pydantic import BaseModel, ValidationError

from typeid.integrations.pydantic import TypeIDField
from typeid import TypeID

from typeid.integrations.pydantic import TypeIDField

USER_TYPEID_STR = str(TypeID("user"))
ORDER_TYPEID_STR = str(TypeID("order"))
Expand Down Expand Up @@ -34,3 +34,53 @@ def test_json_serializes_as_string():
m = M(id=USER_TYPEID_STR)
data = m.model_dump_json()
assert '"id":"' in data


def test_json_schema_generation():
"""Test that model_json_schema() works and produces correct schema."""
schema = M.model_json_schema()

# Verify the schema structure exists
assert "properties" in schema
assert "id" in schema["properties"]

id_schema = schema["properties"]["id"]

# Verify it matches the documented expectations
assert id_schema["type"] == "string"
assert id_schema["format"] == "typeid"
assert "user" in id_schema.get("description", "")
assert "examples" in id_schema


def test_json_schema_with_generate_definitions():
"""
Test that TypeIDField works with Pydantic's generate_definitions().

This mimics how FastAPI generates OpenAPI schemas and would catch
the bug where __get_pydantic_json_schema__ was passing the wrong
schema to the handler, causing FastAPI's OpenAPI generation to fail.
"""
from pydantic.json_schema import GenerateJsonSchema

# Use the same method FastAPI uses internally
generator = GenerateJsonSchema()
_, definitions = generator.generate_definitions(
inputs=[(M, "validation", M.__pydantic_core_schema__)],
)

# Verify M is in definitions
assert "M" in definitions

# Check the id field schema
m_schema = definitions["M"]
assert "properties" in m_schema
assert "id" in m_schema["properties"]

id_schema = m_schema["properties"]["id"]

# Verify TypeID-specific schema properties (same as test_json_schema_generation)
assert id_schema["type"] == "string"
assert id_schema["format"] == "typeid"
assert "user" in id_schema.get("description", "")
assert "examples" in id_schema
5 changes: 4 additions & 1 deletion typeid/integrations/pydantic/v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def __get_pydantic_core_schema__(cls, source_type: Any, handler: Any) -> core_sc
# Using a plain validator keeps it simple and fast.
return core_schema.no_info_plain_validator_function(
cls._validate,
json_schema_input_schema=core_schema.str_schema(),
serialization=core_schema.plain_serializer_function_ser_schema(
lambda v: str(v),
when_used="json",
Expand All @@ -73,7 +74,9 @@ def __get_pydantic_core_schema__(cls, source_type: Any, handler: Any) -> core_sc

@classmethod
def __get_pydantic_json_schema__(cls, core_schema_: core_schema.CoreSchema, handler: Any) -> JsonSchemaValue:
schema = handler(core_schema_)
# Pass the json_schema_input_schema to the handler instead of the validator function schema
# This allows Pydantic to generate a proper JSON schema from the string type
schema = handler(core_schema_.get("json_schema_input_schema", core_schema_))

# Ensure JSON schema is "string"
schema.update(
Expand Down