diff --git a/tests/integrations/test_pydantic.py b/tests/integrations/test_pydantic.py index 8a50be5..9322420 100644 --- a/tests/integrations/test_pydantic.py +++ b/tests/integrations/test_pydantic.py @@ -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")) @@ -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 diff --git a/typeid/integrations/pydantic/v2.py b/typeid/integrations/pydantic/v2.py index 552d146..638cea6 100644 --- a/typeid/integrations/pydantic/v2.py +++ b/typeid/integrations/pydantic/v2.py @@ -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", @@ -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(