_schema_generation_shared.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. """Types and utility functions used by various other internal tools."""
  2. from __future__ import annotations
  3. from typing import TYPE_CHECKING, Any, Callable
  4. from pydantic_core import core_schema
  5. from typing_extensions import Literal
  6. from ..annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler
  7. if TYPE_CHECKING:
  8. from ..json_schema import GenerateJsonSchema, JsonSchemaValue
  9. from ._core_utils import CoreSchemaOrField
  10. from ._generate_schema import GenerateSchema
  11. from ._namespace_utils import NamespacesTuple
  12. GetJsonSchemaFunction = Callable[[CoreSchemaOrField, GetJsonSchemaHandler], JsonSchemaValue]
  13. HandlerOverride = Callable[[CoreSchemaOrField], JsonSchemaValue]
  14. class GenerateJsonSchemaHandler(GetJsonSchemaHandler):
  15. """JsonSchemaHandler implementation that doesn't do ref unwrapping by default.
  16. This is used for any Annotated metadata so that we don't end up with conflicting
  17. modifications to the definition schema.
  18. Used internally by Pydantic, please do not rely on this implementation.
  19. See `GetJsonSchemaHandler` for the handler API.
  20. """
  21. def __init__(self, generate_json_schema: GenerateJsonSchema, handler_override: HandlerOverride | None) -> None:
  22. self.generate_json_schema = generate_json_schema
  23. self.handler = handler_override or generate_json_schema.generate_inner
  24. self.mode = generate_json_schema.mode
  25. def __call__(self, core_schema: CoreSchemaOrField, /) -> JsonSchemaValue:
  26. return self.handler(core_schema)
  27. def resolve_ref_schema(self, maybe_ref_json_schema: JsonSchemaValue) -> JsonSchemaValue:
  28. """Resolves `$ref` in the json schema.
  29. This returns the input json schema if there is no `$ref` in json schema.
  30. Args:
  31. maybe_ref_json_schema: The input json schema that may contains `$ref`.
  32. Returns:
  33. Resolved json schema.
  34. Raises:
  35. LookupError: If it can't find the definition for `$ref`.
  36. """
  37. if '$ref' not in maybe_ref_json_schema:
  38. return maybe_ref_json_schema
  39. ref = maybe_ref_json_schema['$ref']
  40. json_schema = self.generate_json_schema.get_schema_from_definitions(ref)
  41. if json_schema is None:
  42. raise LookupError(
  43. f'Could not find a ref for {ref}.'
  44. ' Maybe you tried to call resolve_ref_schema from within a recursive model?'
  45. )
  46. return json_schema
  47. class CallbackGetCoreSchemaHandler(GetCoreSchemaHandler):
  48. """Wrapper to use an arbitrary function as a `GetCoreSchemaHandler`.
  49. Used internally by Pydantic, please do not rely on this implementation.
  50. See `GetCoreSchemaHandler` for the handler API.
  51. """
  52. def __init__(
  53. self,
  54. handler: Callable[[Any], core_schema.CoreSchema],
  55. generate_schema: GenerateSchema,
  56. ref_mode: Literal['to-def', 'unpack'] = 'to-def',
  57. ) -> None:
  58. self._handler = handler
  59. self._generate_schema = generate_schema
  60. self._ref_mode = ref_mode
  61. def __call__(self, source_type: Any, /) -> core_schema.CoreSchema:
  62. schema = self._handler(source_type)
  63. ref = schema.get('ref')
  64. if self._ref_mode == 'to-def':
  65. if ref is not None:
  66. self._generate_schema.defs.definitions[ref] = schema
  67. return core_schema.definition_reference_schema(ref)
  68. return schema
  69. else: # ref_mode = 'unpack
  70. return self.resolve_ref_schema(schema)
  71. def _get_types_namespace(self) -> NamespacesTuple:
  72. return self._generate_schema._types_namespace
  73. def generate_schema(self, source_type: Any, /) -> core_schema.CoreSchema:
  74. return self._generate_schema.generate_schema(source_type)
  75. @property
  76. def field_name(self) -> str | None:
  77. return self._generate_schema.field_name_stack.get()
  78. def resolve_ref_schema(self, maybe_ref_schema: core_schema.CoreSchema) -> core_schema.CoreSchema:
  79. """Resolves reference in the core schema.
  80. Args:
  81. maybe_ref_schema: The input core schema that may contains reference.
  82. Returns:
  83. Resolved core schema.
  84. Raises:
  85. LookupError: If it can't find the definition for reference.
  86. """
  87. if maybe_ref_schema['type'] == 'definition-ref':
  88. ref = maybe_ref_schema['schema_ref']
  89. if ref not in self._generate_schema.defs.definitions:
  90. raise LookupError(
  91. f'Could not find a ref for {ref}.'
  92. ' Maybe you tried to call resolve_ref_schema from within a recursive model?'
  93. )
  94. return self._generate_schema.defs.definitions[ref]
  95. elif maybe_ref_schema['type'] == 'definitions':
  96. return self.resolve_ref_schema(maybe_ref_schema['schema'])
  97. return maybe_ref_schema