Coverage for pydantic/json_schema.py: 94.65%

1105 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-15 15:02 +0000

1"""!!! abstract "Usage Documentation" 

2 [JSON Schema](../concepts/json_schema.md) 

3 

4The `json_schema` module contains classes and functions to allow the way [JSON Schema](https://json-schema.org/) 

5is generated to be customized. 

6 

7In general you shouldn't need to use this module directly; instead, you can use 

8[`BaseModel.model_json_schema`][pydantic.BaseModel.model_json_schema] and 

9[`TypeAdapter.json_schema`][pydantic.TypeAdapter.json_schema]. 

10""" 

11 

12from __future__ import annotations as _annotations 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

13 

14import dataclasses 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

15import inspect 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

16import math 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

17import os 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

18import re 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

19import warnings 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

20from collections import Counter, defaultdict 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

21from collections.abc import Hashable, Iterable, Sequence 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

22from copy import deepcopy 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

23from enum import Enum 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

24from re import Pattern 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

25from typing import ( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

26 TYPE_CHECKING, 

27 Annotated, 

28 Any, 

29 Callable, 

30 Literal, 

31 NewType, 

32 TypeVar, 

33 Union, 

34 cast, 

35 overload, 

36) 

37 

38import pydantic_core 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

39from pydantic_core import CoreSchema, PydanticOmit, core_schema, to_jsonable_python 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

40from pydantic_core.core_schema import ComputedField 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

41from typing_extensions import TypeAlias, assert_never, deprecated, final 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

42from typing_inspection.introspection import get_literal_values 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

43 

44from pydantic.warnings import PydanticDeprecatedSince26, PydanticDeprecatedSince29 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

45 

46from ._internal import ( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

47 _config, 

48 _core_metadata, 

49 _core_utils, 

50 _decorators, 

51 _internal_dataclass, 

52 _mock_val_ser, 

53 _schema_generation_shared, 

54) 

55from .annotated_handlers import GetJsonSchemaHandler 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

56from .config import JsonDict, JsonValue 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

57from .errors import PydanticInvalidForJsonSchema, PydanticSchemaGenerationError, PydanticUserError 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

58 

59if TYPE_CHECKING: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

60 from . import ConfigDict 

61 from ._internal._core_utils import CoreSchemaField, CoreSchemaOrField 

62 from ._internal._dataclasses import PydanticDataclass 

63 from ._internal._schema_generation_shared import GetJsonSchemaFunction 

64 from .main import BaseModel 

65 

66 

67CoreSchemaOrFieldType = Literal[core_schema.CoreSchemaType, core_schema.CoreSchemaFieldType] 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

68""" 1bdenfogpADOahiqrstuvFGMPcjkwlxmyBHN

69A type alias for defined schema types that represents a union of 

70`core_schema.CoreSchemaType` and 

71`core_schema.CoreSchemaFieldType`. 

72""" 

73 

74JsonSchemaValue = dict[str, Any] 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

75""" 1bdenfogpADOahiqrstuvFGMPcjkwlxmyBHN

76A type alias for a JSON schema value. This is a dictionary of string keys to arbitrary JSON values. 

77""" 

78 

79JsonSchemaMode = Literal['validation', 'serialization'] 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

80""" 1bdenfogpADOahiqrstuvFGMPcjkwlxmyBHN

81A type alias that represents the mode of a JSON schema; either 'validation' or 'serialization'. 

82 

83For some types, the inputs to validation differ from the outputs of serialization. For example, 

84computed fields will only be present when serializing, and should not be provided when 

85validating. This flag provides a way to indicate whether you want the JSON schema required 

86for validation inputs, or that will be matched by serialization outputs. 

87""" 

88 

89_MODE_TITLE_MAPPING: dict[JsonSchemaMode, str] = {'validation': 'Input', 'serialization': 'Output'} 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

90 

91 

92JsonSchemaWarningKind = Literal['skipped-choice', 'non-serializable-default', 'skipped-discriminator'] 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

93""" 1bdenfogpADOahiqrstuvFGMPcjkwlxmyBHN

94A type alias representing the kinds of warnings that can be emitted during JSON schema generation. 

95 

96See [`GenerateJsonSchema.render_warning_message`][pydantic.json_schema.GenerateJsonSchema.render_warning_message] 

97for more details. 

98""" 

99 

100 

101class PydanticJsonSchemaWarning(UserWarning): 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

102 """This class is used to emit warnings produced during JSON schema generation. 

103 See the [`GenerateJsonSchema.emit_warning`][pydantic.json_schema.GenerateJsonSchema.emit_warning] and 

104 [`GenerateJsonSchema.render_warning_message`][pydantic.json_schema.GenerateJsonSchema.render_warning_message] 

105 methods for more details; these can be overridden to control warning behavior. 

106 """ 

107 

108 

109NoDefault = object() 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

110"""A sentinel value used to indicate that no default value should be used when generating a JSON Schema 1bdenfogpADOahiqrstuvFGMPcjkwlxmyBHN

111for a core schema with a default value. 

112""" 

113 

114 

115# ##### JSON Schema Generation ##### 

116DEFAULT_REF_TEMPLATE = '#/$defs/{model}' 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

117"""The default format string used to generate reference names.""" 1bdenfogpADOahiqrstuvFGMPcjkwlxmyBHN

118 

119# There are three types of references relevant to building JSON schemas: 

120# 1. core_schema "ref" values; these are not exposed as part of the JSON schema 

121# * these might look like the fully qualified path of a model, its id, or something similar 

122CoreRef = NewType('CoreRef', str) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

123# 2. keys of the "definitions" object that will eventually go into the JSON schema 

124# * by default, these look like "MyModel", though may change in the presence of collisions 

125# * eventually, we may want to make it easier to modify the way these names are generated 

126DefsRef = NewType('DefsRef', str) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

127# 3. the values corresponding to the "$ref" key in the schema 

128# * By default, these look like "#/$defs/MyModel", as in {"$ref": "#/$defs/MyModel"} 

129JsonRef = NewType('JsonRef', str) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

130 

131CoreModeRef = tuple[CoreRef, JsonSchemaMode] 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

132JsonSchemaKeyT = TypeVar('JsonSchemaKeyT', bound=Hashable) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

133 

134 

135@dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

136class _DefinitionsRemapping: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

137 defs_remapping: dict[DefsRef, DefsRef] 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

138 json_remapping: dict[JsonRef, JsonRef] 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

139 

140 @staticmethod 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

141 def from_prioritized_choices( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

142 prioritized_choices: dict[DefsRef, list[DefsRef]], 

143 defs_to_json: dict[DefsRef, JsonRef], 

144 definitions: dict[DefsRef, JsonSchemaValue], 

145 ) -> _DefinitionsRemapping: 

146 """ 

147 This function should produce a remapping that replaces complex DefsRef with the simpler ones from the 

148 prioritized_choices such that applying the name remapping would result in an equivalent JSON schema. 

149 """ 

150 # We need to iteratively simplify the definitions until we reach a fixed point. 

151 # The reason for this is that outer definitions may reference inner definitions that get simplified 

152 # into an equivalent reference, and the outer definitions won't be equivalent until we've simplified 

153 # the inner definitions. 

154 copied_definitions = deepcopy(definitions) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

155 definitions_schema = {'$defs': copied_definitions} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

156 for _iter in range(100): # prevent an infinite loop in the case of a bug, 100 iterations should be enough 156 ↛ 185line 156 didn't jump to line 185 because the loop on line 156 didn't complete1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

157 # For every possible remapped DefsRef, collect all schemas that that DefsRef might be used for: 

158 schemas_for_alternatives: dict[DefsRef, list[JsonSchemaValue]] = defaultdict(list) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

159 for defs_ref in copied_definitions: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

160 alternatives = prioritized_choices[defs_ref] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

161 for alternative in alternatives: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

162 schemas_for_alternatives[alternative].append(copied_definitions[defs_ref]) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

163 

164 # Deduplicate the schemas for each alternative; the idea is that we only want to remap to a new DefsRef 

165 # if it introduces no ambiguity, i.e., there is only one distinct schema for that DefsRef. 

166 for defs_ref in schemas_for_alternatives: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

167 schemas_for_alternatives[defs_ref] = _deduplicate_schemas(schemas_for_alternatives[defs_ref]) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

168 

169 # Build the remapping 

170 defs_remapping: dict[DefsRef, DefsRef] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

171 json_remapping: dict[JsonRef, JsonRef] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

172 for original_defs_ref in definitions: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

173 alternatives = prioritized_choices[original_defs_ref] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

174 # Pick the first alternative that has only one schema, since that means there is no collision 

175 remapped_defs_ref = next(x for x in alternatives if len(schemas_for_alternatives[x]) == 1) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

176 defs_remapping[original_defs_ref] = remapped_defs_ref 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

177 json_remapping[defs_to_json[original_defs_ref]] = defs_to_json[remapped_defs_ref] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

178 remapping = _DefinitionsRemapping(defs_remapping, json_remapping) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

179 new_definitions_schema = remapping.remap_json_schema({'$defs': copied_definitions}) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

180 if definitions_schema == new_definitions_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

181 # We've reached the fixed point 

182 return remapping 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

183 definitions_schema = new_definitions_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

184 

185 raise PydanticInvalidForJsonSchema('Failed to simplify the JSON schema definitions') 

186 

187 def remap_defs_ref(self, ref: DefsRef) -> DefsRef: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

188 return self.defs_remapping.get(ref, ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

189 

190 def remap_json_ref(self, ref: JsonRef) -> JsonRef: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

191 return self.json_remapping.get(ref, ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

192 

193 def remap_json_schema(self, schema: Any) -> Any: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

194 """ 

195 Recursively update the JSON schema replacing all $refs 

196 """ 

197 if isinstance(schema, str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

198 # Note: this may not really be a JsonRef; we rely on having no collisions between JsonRefs and other strings 

199 return self.remap_json_ref(JsonRef(schema)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

200 elif isinstance(schema, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

201 return [self.remap_json_schema(item) for item in schema] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

202 elif isinstance(schema, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

203 for key, value in schema.items(): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

204 if key == '$ref' and isinstance(value, str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

205 schema['$ref'] = self.remap_json_ref(JsonRef(value)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

206 elif key == '$defs': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

207 schema['$defs'] = { 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

208 self.remap_defs_ref(DefsRef(key)): self.remap_json_schema(value) 

209 for key, value in schema['$defs'].items() 

210 } 

211 else: 

212 schema[key] = self.remap_json_schema(value) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

213 return schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

214 

215 

216class GenerateJsonSchema: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

217 """!!! abstract "Usage Documentation" 

218 [Customizing the JSON Schema Generation Process](../concepts/json_schema.md#customizing-the-json-schema-generation-process) 

219 

220 A class for generating JSON schemas. 

221 

222 This class generates JSON schemas based on configured parameters. The default schema dialect 

223 is [https://json-schema.org/draft/2020-12/schema](https://json-schema.org/draft/2020-12/schema). 

224 The class uses `by_alias` to configure how fields with 

225 multiple names are handled and `ref_template` to format reference names. 

226 

227 Attributes: 

228 schema_dialect: The JSON schema dialect used to generate the schema. See 

229 [Declaring a Dialect](https://json-schema.org/understanding-json-schema/reference/schema.html#id4) 

230 in the JSON Schema documentation for more information about dialects. 

231 ignored_warning_kinds: Warnings to ignore when generating the schema. `self.render_warning_message` will 

232 do nothing if its argument `kind` is in `ignored_warning_kinds`; 

233 this value can be modified on subclasses to easily control which warnings are emitted. 

234 by_alias: Whether to use field aliases when generating the schema. 

235 ref_template: The format string used when generating reference names. 

236 core_to_json_refs: A mapping of core refs to JSON refs. 

237 core_to_defs_refs: A mapping of core refs to definition refs. 

238 defs_to_core_refs: A mapping of definition refs to core refs. 

239 json_to_defs_refs: A mapping of JSON refs to definition refs. 

240 definitions: Definitions in the schema. 

241 

242 Args: 

243 by_alias: Whether to use field aliases in the generated schemas. 

244 ref_template: The format string to use when generating reference names. 

245 

246 Raises: 

247 JsonSchemaError: If the instance of the class is inadvertently reused after generating a schema. 

248 """ 

249 

250 schema_dialect = 'https://json-schema.org/draft/2020-12/schema' 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

251 

252 # `self.render_warning_message` will do nothing if its argument `kind` is in `ignored_warning_kinds`; 

253 # this value can be modified on subclasses to easily control which warnings are emitted 

254 ignored_warning_kinds: set[JsonSchemaWarningKind] = {'skipped-choice'} 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

255 

256 def __init__(self, by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE): 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

257 self.by_alias = by_alias 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

258 self.ref_template = ref_template 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

259 

260 self.core_to_json_refs: dict[CoreModeRef, JsonRef] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

261 self.core_to_defs_refs: dict[CoreModeRef, DefsRef] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

262 self.defs_to_core_refs: dict[DefsRef, CoreModeRef] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

263 self.json_to_defs_refs: dict[JsonRef, DefsRef] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

264 

265 self.definitions: dict[DefsRef, JsonSchemaValue] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

266 self._config_wrapper_stack = _config.ConfigWrapperStack(_config.ConfigWrapper({})) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

267 

268 self._mode: JsonSchemaMode = 'validation' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

269 

270 # The following includes a mapping of a fully-unique defs ref choice to a list of preferred 

271 # alternatives, which are generally simpler, such as only including the class name. 

272 # At the end of schema generation, we use these to produce a JSON schema with more human-readable 

273 # definitions, which would also work better in a generated OpenAPI client, etc. 

274 self._prioritized_defsref_choices: dict[DefsRef, list[DefsRef]] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

275 self._collision_counter: dict[str, int] = defaultdict(int) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

276 self._collision_index: dict[str, int] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

277 

278 self._schema_type_to_method = self.build_schema_type_to_method() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

279 

280 # When we encounter definitions we need to try to build them immediately 

281 # so that they are available schemas that reference them 

282 # But it's possible that CoreSchema was never going to be used 

283 # (e.g. because the CoreSchema that references short circuits is JSON schema generation without needing 

284 # the reference) so instead of failing altogether if we can't build a definition we 

285 # store the error raised and re-throw it if we end up needing that def 

286 self._core_defs_invalid_for_json_schema: dict[DefsRef, PydanticInvalidForJsonSchema] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

287 

288 # This changes to True after generating a schema, to prevent issues caused by accidental reuse 

289 # of a single instance of a schema generator 

290 self._used = False 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

291 

292 @property 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

293 def _config(self) -> _config.ConfigWrapper: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

294 return self._config_wrapper_stack.tail 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

295 

296 @property 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

297 def mode(self) -> JsonSchemaMode: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

298 if self._config.json_schema_mode_override is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

299 return self._config.json_schema_mode_override 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

300 else: 

301 return self._mode 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

302 

303 def build_schema_type_to_method( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

304 self, 

305 ) -> dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]]: 

306 """Builds a dictionary mapping fields to methods for generating JSON schemas. 

307 

308 Returns: 

309 A dictionary containing the mapping of `CoreSchemaOrFieldType` to a handler method. 

310 

311 Raises: 

312 TypeError: If no method has been defined for generating a JSON schema for a given pydantic core schema type. 

313 """ 

314 mapping: dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

315 core_schema_types: list[CoreSchemaOrFieldType] = list(get_literal_values(CoreSchemaOrFieldType)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

316 for key in core_schema_types: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

317 method_name = f'{key.replace("-", "_")}_schema' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

318 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

319 mapping[key] = getattr(self, method_name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

320 except AttributeError as e: # pragma: no cover 

321 if os.getenv('PYDANTIC_PRIVATE_ALLOW_UNHANDLED_SCHEMA_TYPES'): 

322 continue 

323 raise TypeError( 

324 f'No method for generating JsonSchema for core_schema.type={key!r} ' 

325 f'(expected: {type(self).__name__}.{method_name})' 

326 ) from e 

327 return mapping 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

328 

329 def generate_definitions( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

330 self, inputs: Sequence[tuple[JsonSchemaKeyT, JsonSchemaMode, core_schema.CoreSchema]] 

331 ) -> tuple[dict[tuple[JsonSchemaKeyT, JsonSchemaMode], JsonSchemaValue], dict[DefsRef, JsonSchemaValue]]: 

332 """Generates JSON schema definitions from a list of core schemas, pairing the generated definitions with a 

333 mapping that links the input keys to the definition references. 

334 

335 Args: 

336 inputs: A sequence of tuples, where: 

337 

338 - The first element is a JSON schema key type. 

339 - The second element is the JSON mode: either 'validation' or 'serialization'. 

340 - The third element is a core schema. 

341 

342 Returns: 

343 A tuple where: 

344 

345 - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and 

346 whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have 

347 JsonRef references to definitions that are defined in the second returned element.) 

348 - The second element is a dictionary whose keys are definition references for the JSON schemas 

349 from the first returned element, and whose values are the actual JSON schema definitions. 

350 

351 Raises: 

352 PydanticUserError: Raised if the JSON schema generator has already been used to generate a JSON schema. 

353 """ 

354 if self._used: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

355 raise PydanticUserError( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

356 'This JSON schema generator has already been used to generate a JSON schema. ' 

357 f'You must create a new instance of {type(self).__name__} to generate a new JSON schema.', 

358 code='json-schema-already-used', 

359 ) 

360 

361 for _, mode, schema in inputs: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

362 self._mode = mode 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

363 self.generate_inner(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

364 

365 definitions_remapping = self._build_definitions_remapping() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

366 

367 json_schemas_map: dict[tuple[JsonSchemaKeyT, JsonSchemaMode], DefsRef] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

368 for key, mode, schema in inputs: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

369 self._mode = mode 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

370 json_schema = self.generate_inner(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

371 json_schemas_map[(key, mode)] = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

372 

373 json_schema = {'$defs': self.definitions} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

374 json_schema = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

375 self._used = True 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

376 return json_schemas_map, self.sort(json_schema['$defs']) # type: ignore 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

377 

378 def generate(self, schema: CoreSchema, mode: JsonSchemaMode = 'validation') -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

379 """Generates a JSON schema for a specified schema in a specified mode. 

380 

381 Args: 

382 schema: A Pydantic model. 

383 mode: The mode in which to generate the schema. Defaults to 'validation'. 

384 

385 Returns: 

386 A JSON schema representing the specified schema. 

387 

388 Raises: 

389 PydanticUserError: If the JSON schema generator has already been used to generate a JSON schema. 

390 """ 

391 self._mode = mode 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

392 if self._used: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

393 raise PydanticUserError( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

394 'This JSON schema generator has already been used to generate a JSON schema. ' 

395 f'You must create a new instance of {type(self).__name__} to generate a new JSON schema.', 

396 code='json-schema-already-used', 

397 ) 

398 

399 json_schema: JsonSchemaValue = self.generate_inner(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

400 json_ref_counts = self.get_json_ref_counts(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

401 

402 ref = cast(JsonRef, json_schema.get('$ref')) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

403 while ref is not None: # may need to unpack multiple levels 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

404 ref_json_schema = self.get_schema_from_definitions(ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

405 if json_ref_counts[ref] == 1 and ref_json_schema is not None and len(json_schema) == 1: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

406 # "Unpack" the ref since this is the only reference and there are no sibling keys 

407 json_schema = ref_json_schema.copy() # copy to prevent recursive dict reference 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

408 json_ref_counts[ref] -= 1 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

409 ref = cast(JsonRef, json_schema.get('$ref')) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

410 ref = None 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

411 

412 self._garbage_collect_definitions(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

413 definitions_remapping = self._build_definitions_remapping() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

414 

415 if self.definitions: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

416 json_schema['$defs'] = self.definitions 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

417 

418 json_schema = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

419 

420 # For now, we will not set the $schema key. However, if desired, this can be easily added by overriding 

421 # this method and adding the following line after a call to super().generate(schema): 

422 # json_schema['$schema'] = self.schema_dialect 

423 

424 self._used = True 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

425 return self.sort(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

426 

427 def generate_inner(self, schema: CoreSchemaOrField) -> JsonSchemaValue: # noqa: C901 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

428 """Generates a JSON schema for a given core schema. 

429 

430 Args: 

431 schema: The given core schema. 

432 

433 Returns: 

434 The generated JSON schema. 

435 

436 TODO: the nested function definitions here seem like bad practice, I'd like to unpack these 

437 in a future PR. It'd be great if we could shorten the call stack a bit for JSON schema generation, 

438 and I think there's potential for that here. 

439 """ 

440 # If a schema with the same CoreRef has been handled, just return a reference to it 

441 # Note that this assumes that it will _never_ be the case that the same CoreRef is used 

442 # on types that should have different JSON schemas 

443 if 'ref' in schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

444 core_ref = CoreRef(schema['ref']) # type: ignore[typeddict-item] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

445 core_mode_ref = (core_ref, self.mode) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

446 if core_mode_ref in self.core_to_defs_refs and self.core_to_defs_refs[core_mode_ref] in self.definitions: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

447 return {'$ref': self.core_to_json_refs[core_mode_ref]} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

448 

449 def populate_defs(core_schema: CoreSchema, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

450 if 'ref' in core_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

451 core_ref = CoreRef(core_schema['ref']) # type: ignore[typeddict-item] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

452 defs_ref, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

453 json_ref = JsonRef(ref_json_schema['$ref']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

454 # Replace the schema if it's not a reference to itself 

455 # What we want to avoid is having the def be just a ref to itself 

456 # which is what would happen if we blindly assigned any 

457 if json_schema.get('$ref', None) != json_ref: 457 ↛ 460line 457 didn't jump to line 460 because the condition on line 457 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

458 self.definitions[defs_ref] = json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

459 self._core_defs_invalid_for_json_schema.pop(defs_ref, None) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

460 json_schema = ref_json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

461 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

462 

463 def handler_func(schema_or_field: CoreSchemaOrField) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

464 """Generate a JSON schema based on the input schema. 

465 

466 Args: 

467 schema_or_field: The core schema to generate a JSON schema from. 

468 

469 Returns: 

470 The generated JSON schema. 

471 

472 Raises: 

473 TypeError: If an unexpected schema type is encountered. 

474 """ 

475 # Generate the core-schema-type-specific bits of the schema generation: 

476 json_schema: JsonSchemaValue | None = None 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

477 if self.mode == 'serialization' and 'serialization' in schema_or_field: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

478 # In this case, we skip the JSON Schema generation of the schema 

479 # and use the `'serialization'` schema instead (canonical example: 

480 # `Annotated[int, PlainSerializer(str)]`). 

481 ser_schema = schema_or_field['serialization'] # type: ignore 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

482 json_schema = self.ser_schema(ser_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

483 

484 # It might be that the 'serialization'` is skipped depending on `when_used`. 

485 # This is only relevant for `nullable` schemas though, so we special case here. 

486 if ( 1zCEa

487 json_schema is not None 

488 and ser_schema.get('when_used') in ('unless-none', 'json-unless-none') 

489 and schema_or_field['type'] == 'nullable' 

490 ): 

491 json_schema = self.get_flattened_anyof([{'type': 'null'}, json_schema]) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

492 if json_schema is None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

493 if _core_utils.is_core_schema(schema_or_field) or _core_utils.is_core_schema_field(schema_or_field): 493 ↛ 497line 493 didn't jump to line 497 because the condition on line 493 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

494 generate_for_schema_type = self._schema_type_to_method[schema_or_field['type']] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

495 json_schema = generate_for_schema_type(schema_or_field) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

496 else: 

497 raise TypeError(f'Unexpected schema type: schema={schema_or_field}') 

498 

499 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

500 

501 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, handler_func) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

502 

503 metadata = cast(_core_metadata.CoreMetadata, schema.get('metadata', {})) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

504 

505 # TODO: I dislike that we have to wrap these basic dict updates in callables, is there any way around this? 

506 

507 if js_updates := metadata.get('pydantic_js_updates'): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

508 

509 def js_updates_handler_func( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

510 schema_or_field: CoreSchemaOrField, 

511 current_handler: GetJsonSchemaHandler = current_handler, 

512 ) -> JsonSchemaValue: 

513 json_schema = {**current_handler(schema_or_field), **js_updates} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

514 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

515 

516 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, js_updates_handler_func) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

517 

518 if js_extra := metadata.get('pydantic_js_extra'): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

519 

520 def js_extra_handler_func( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

521 schema_or_field: CoreSchemaOrField, 

522 current_handler: GetJsonSchemaHandler = current_handler, 

523 ) -> JsonSchemaValue: 

524 json_schema = current_handler(schema_or_field) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

525 if isinstance(js_extra, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

526 json_schema.update(to_jsonable_python(js_extra)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

527 elif callable(js_extra): 527 ↛ 530line 527 didn't jump to line 530 because the condition on line 527 was always true1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

528 # similar to typing issue in _update_class_schema when we're working with callable js extra 

529 js_extra(json_schema) # type: ignore 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

530 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

531 

532 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, js_extra_handler_func) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

533 

534 for js_modify_function in metadata.get('pydantic_js_functions', ()): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

535 

536 def new_handler_func( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

537 schema_or_field: CoreSchemaOrField, 

538 current_handler: GetJsonSchemaHandler = current_handler, 

539 js_modify_function: GetJsonSchemaFunction = js_modify_function, 

540 ) -> JsonSchemaValue: 

541 json_schema = js_modify_function(schema_or_field, current_handler) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

542 if _core_utils.is_core_schema(schema_or_field): 542 ↛ 544line 542 didn't jump to line 544 because the condition on line 542 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

543 json_schema = populate_defs(schema_or_field, json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

544 original_schema = current_handler.resolve_ref_schema(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

545 ref = json_schema.pop('$ref', None) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

546 if ref and json_schema: 546 ↛ 547line 546 didn't jump to line 547 because the condition on line 546 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

547 original_schema.update(json_schema) 

548 return original_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

549 

550 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

551 

552 for js_modify_function in metadata.get('pydantic_js_annotation_functions', ()): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

553 

554 def new_handler_func( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

555 schema_or_field: CoreSchemaOrField, 

556 current_handler: GetJsonSchemaHandler = current_handler, 

557 js_modify_function: GetJsonSchemaFunction = js_modify_function, 

558 ) -> JsonSchemaValue: 

559 return js_modify_function(schema_or_field, current_handler) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

560 

561 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

562 

563 json_schema = current_handler(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

564 if _core_utils.is_core_schema(schema): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

565 json_schema = populate_defs(schema, json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

566 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

567 

568 def sort(self, value: JsonSchemaValue, parent_key: str | None = None) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

569 """Override this method to customize the sorting of the JSON schema (e.g., don't sort at all, sort all keys unconditionally, etc.) 

570 

571 By default, alphabetically sort the keys in the JSON schema, skipping the 'properties' and 'default' keys to preserve field definition order. 

572 This sort is recursive, so it will sort all nested dictionaries as well. 

573 """ 

574 sorted_dict: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

575 keys = value.keys() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

576 if parent_key not in ('properties', 'default'): 576 ↛ 578line 576 didn't jump to line 578 because the condition on line 576 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

577 keys = sorted(keys) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

578 for key in keys: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

579 sorted_dict[key] = self._sort_recursive(value[key], parent_key=key) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

580 return sorted_dict 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

581 

582 def _sort_recursive(self, value: Any, parent_key: str | None = None) -> Any: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

583 """Recursively sort a JSON schema value.""" 

584 if isinstance(value, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

585 sorted_dict: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

586 keys = value.keys() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

587 if parent_key not in ('properties', 'default'): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

588 keys = sorted(keys) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

589 for key in keys: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

590 sorted_dict[key] = self._sort_recursive(value[key], parent_key=key) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

591 return sorted_dict 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

592 elif isinstance(value, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

593 sorted_list: list[JsonSchemaValue] = [] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

594 for item in value: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

595 sorted_list.append(self._sort_recursive(item, parent_key)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

596 return sorted_list 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

597 else: 

598 return value 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

599 

600 # ### Schema generation methods 

601 

602 def invalid_schema(self, schema: core_schema.InvalidSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

603 """Placeholder - should never be called.""" 

604 

605 raise RuntimeError('Cannot generate schema for invalid_schema. This is a bug! Please report it.') 

606 

607 def any_schema(self, schema: core_schema.AnySchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

608 """Generates a JSON schema that matches any value. 

609 

610 Args: 

611 schema: The core schema. 

612 

613 Returns: 

614 The generated JSON schema. 

615 """ 

616 return {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

617 

618 def none_schema(self, schema: core_schema.NoneSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

619 """Generates a JSON schema that matches `None`. 

620 

621 Args: 

622 schema: The core schema. 

623 

624 Returns: 

625 The generated JSON schema. 

626 """ 

627 return {'type': 'null'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

628 

629 def bool_schema(self, schema: core_schema.BoolSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

630 """Generates a JSON schema that matches a bool value. 

631 

632 Args: 

633 schema: The core schema. 

634 

635 Returns: 

636 The generated JSON schema. 

637 """ 

638 return {'type': 'boolean'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

639 

640 def int_schema(self, schema: core_schema.IntSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

641 """Generates a JSON schema that matches an int value. 

642 

643 Args: 

644 schema: The core schema. 

645 

646 Returns: 

647 The generated JSON schema. 

648 """ 

649 json_schema: dict[str, Any] = {'type': 'integer'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

650 self.update_with_validations(json_schema, schema, self.ValidationsMapping.numeric) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

651 json_schema = {k: v for k, v in json_schema.items() if v not in {math.inf, -math.inf}} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

652 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

653 

654 def float_schema(self, schema: core_schema.FloatSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

655 """Generates a JSON schema that matches a float value. 

656 

657 Args: 

658 schema: The core schema. 

659 

660 Returns: 

661 The generated JSON schema. 

662 """ 

663 json_schema: dict[str, Any] = {'type': 'number'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

664 self.update_with_validations(json_schema, schema, self.ValidationsMapping.numeric) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

665 json_schema = {k: v for k, v in json_schema.items() if v not in {math.inf, -math.inf}} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

666 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

667 

668 def decimal_schema(self, schema: core_schema.DecimalSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

669 """Generates a JSON schema that matches a decimal value. 

670 

671 Args: 

672 schema: The core schema. 

673 

674 Returns: 

675 The generated JSON schema. 

676 """ 

677 

678 def get_decimal_pattern(schema: core_schema.DecimalSchema) -> str: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

679 max_digits = schema.get('max_digits') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

680 decimal_places = schema.get('decimal_places') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

681 

682 pattern = ( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

683 r'^(?!^[-+.]*$)[+-]?0*' # check it is not empty string and not one or sequence of ".+-" characters. 

684 ) 

685 

686 # Case 1: Both max_digits and decimal_places are set 

687 if max_digits is not None and decimal_places is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

688 integer_places = max(0, max_digits - decimal_places) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

689 pattern += ( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

690 rf'(?:' 

691 rf'\d{{0,{integer_places}}}' 

692 rf'|' 

693 rf'(?=[\d.]{{1,{max_digits + 1}}}0*$)' 

694 rf'\d{{0,{integer_places}}}\.\d{{0,{decimal_places}}}0*$' 

695 rf')' 

696 ) 

697 

698 # Case 2: Only max_digits is set 

699 elif max_digits is not None and decimal_places is None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

700 pattern += ( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

701 rf'(?:' 

702 rf'\d{{0,{max_digits}}}' 

703 rf'|' 

704 rf'(?=[\d.]{{1,{max_digits + 1}}}0*$)' 

705 rf'\d*\.\d*0*$' 

706 rf')' 

707 ) 

708 

709 # Case 3: Only decimal_places is set 

710 elif max_digits is None and decimal_places is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

711 pattern += rf'\d*\.?\d{{0,{decimal_places}}}0*$' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

712 

713 # Case 4: Both are None (no restrictions) 

714 else: 

715 pattern += r'\d*\.?\d*$' # look for arbitrary integer or decimal 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

716 

717 return pattern 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

718 

719 json_schema = self.str_schema(core_schema.str_schema(pattern=get_decimal_pattern(schema))) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

720 if self.mode == 'validation': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

721 multiple_of = schema.get('multiple_of') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

722 le = schema.get('le') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

723 ge = schema.get('ge') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

724 lt = schema.get('lt') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

725 gt = schema.get('gt') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

726 json_schema = { 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

727 'anyOf': [ 

728 self.float_schema( 

729 core_schema.float_schema( 

730 allow_inf_nan=schema.get('allow_inf_nan'), 

731 multiple_of=None if multiple_of is None else float(multiple_of), 

732 le=None if le is None else float(le), 

733 ge=None if ge is None else float(ge), 

734 lt=None if lt is None else float(lt), 

735 gt=None if gt is None else float(gt), 

736 ) 

737 ), 

738 json_schema, 

739 ], 

740 } 

741 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

742 

743 def str_schema(self, schema: core_schema.StringSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

744 """Generates a JSON schema that matches a string value. 

745 

746 Args: 

747 schema: The core schema. 

748 

749 Returns: 

750 The generated JSON schema. 

751 """ 

752 json_schema = {'type': 'string'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

753 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

754 if isinstance(json_schema.get('pattern'), Pattern): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

755 # TODO: should we add regex flags to the pattern? 

756 json_schema['pattern'] = json_schema.get('pattern').pattern # type: ignore 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

757 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

758 

759 def bytes_schema(self, schema: core_schema.BytesSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

760 """Generates a JSON schema that matches a bytes value. 

761 

762 Args: 

763 schema: The core schema. 

764 

765 Returns: 

766 The generated JSON schema. 

767 """ 

768 json_schema = {'type': 'string', 'format': 'base64url' if self._config.ser_json_bytes == 'base64' else 'binary'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

769 self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

770 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

771 

772 def date_schema(self, schema: core_schema.DateSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

773 """Generates a JSON schema that matches a date value. 

774 

775 Args: 

776 schema: The core schema. 

777 

778 Returns: 

779 The generated JSON schema. 

780 """ 

781 return {'type': 'string', 'format': 'date'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

782 

783 def time_schema(self, schema: core_schema.TimeSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

784 """Generates a JSON schema that matches a time value. 

785 

786 Args: 

787 schema: The core schema. 

788 

789 Returns: 

790 The generated JSON schema. 

791 """ 

792 return {'type': 'string', 'format': 'time'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

793 

794 def datetime_schema(self, schema: core_schema.DatetimeSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

795 """Generates a JSON schema that matches a datetime value. 

796 

797 Args: 

798 schema: The core schema. 

799 

800 Returns: 

801 The generated JSON schema. 

802 """ 

803 return {'type': 'string', 'format': 'date-time'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

804 

805 def timedelta_schema(self, schema: core_schema.TimedeltaSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

806 """Generates a JSON schema that matches a timedelta value. 

807 

808 Args: 

809 schema: The core schema. 

810 

811 Returns: 

812 The generated JSON schema. 

813 """ 

814 if self._config.ser_json_timedelta == 'float': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

815 return {'type': 'number'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

816 return {'type': 'string', 'format': 'duration'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

817 

818 def literal_schema(self, schema: core_schema.LiteralSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

819 """Generates a JSON schema that matches a literal value. 

820 

821 Args: 

822 schema: The core schema. 

823 

824 Returns: 

825 The generated JSON schema. 

826 """ 

827 expected = [to_jsonable_python(v.value if isinstance(v, Enum) else v) for v in schema['expected']] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

828 

829 result: dict[str, Any] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

830 if len(expected) == 1: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

831 result['const'] = expected[0] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

832 else: 

833 result['enum'] = expected 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

834 

835 types = {type(e) for e in expected} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

836 if types == {str}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

837 result['type'] = 'string' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

838 elif types == {int}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

839 result['type'] = 'integer' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

840 elif types == {float}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

841 result['type'] = 'number' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

842 elif types == {bool}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

843 result['type'] = 'boolean' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

844 elif types == {list}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

845 result['type'] = 'array' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

846 elif types == {type(None)}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

847 result['type'] = 'null' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

848 return result 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

849 

850 def enum_schema(self, schema: core_schema.EnumSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

851 """Generates a JSON schema that matches an Enum value. 

852 

853 Args: 

854 schema: The core schema. 

855 

856 Returns: 

857 The generated JSON schema. 

858 """ 

859 enum_type = schema['cls'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

860 description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

861 if ( 1zCEa

862 description == 'An enumeration.' 

863 ): # This is the default value provided by enum.EnumMeta.__new__; don't use it 

864 description = None 1zCbdEaJKhiILcj

865 result: dict[str, Any] = {'title': enum_type.__name__, 'description': description} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

866 result = {k: v for k, v in result.items() if v is not None} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

867 

868 expected = [to_jsonable_python(v.value) for v in schema['members']] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

869 

870 result['enum'] = expected 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

871 

872 types = {type(e) for e in expected} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

873 if isinstance(enum_type, str) or types == {str}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

874 result['type'] = 'string' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

875 elif isinstance(enum_type, int) or types == {int}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

876 result['type'] = 'integer' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

877 elif isinstance(enum_type, float) or types == {float}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

878 result['type'] = 'number' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

879 elif types == {bool}: 879 ↛ 880line 879 didn't jump to line 880 because the condition on line 879 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

880 result['type'] = 'boolean' 

881 elif types == {list}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

882 result['type'] = 'array' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

883 

884 return result 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

885 

886 def is_instance_schema(self, schema: core_schema.IsInstanceSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

887 """Handles JSON schema generation for a core schema that checks if a value is an instance of a class. 

888 

889 Unless overridden in a subclass, this raises an error. 

890 

891 Args: 

892 schema: The core schema. 

893 

894 Returns: 

895 The generated JSON schema. 

896 """ 

897 return self.handle_invalid_for_json_schema(schema, f'core_schema.IsInstanceSchema ({schema["cls"]})') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

898 

899 def is_subclass_schema(self, schema: core_schema.IsSubclassSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

900 """Handles JSON schema generation for a core schema that checks if a value is a subclass of a class. 

901 

902 For backwards compatibility with v1, this does not raise an error, but can be overridden to change this. 

903 

904 Args: 

905 schema: The core schema. 

906 

907 Returns: 

908 The generated JSON schema. 

909 """ 

910 # Note: This is for compatibility with V1; you can override if you want different behavior. 

911 return {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

912 

913 def callable_schema(self, schema: core_schema.CallableSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

914 """Generates a JSON schema that matches a callable value. 

915 

916 Unless overridden in a subclass, this raises an error. 

917 

918 Args: 

919 schema: The core schema. 

920 

921 Returns: 

922 The generated JSON schema. 

923 """ 

924 return self.handle_invalid_for_json_schema(schema, 'core_schema.CallableSchema') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

925 

926 def list_schema(self, schema: core_schema.ListSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

927 """Returns a schema that matches a list schema. 

928 

929 Args: 

930 schema: The core schema. 

931 

932 Returns: 

933 The generated JSON schema. 

934 """ 

935 items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

936 json_schema = {'type': 'array', 'items': items_schema} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

937 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

938 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

939 

940 @deprecated('`tuple_positional_schema` is deprecated. Use `tuple_schema` instead.', category=None) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

941 @final 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

942 def tuple_positional_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

943 """Replaced by `tuple_schema`.""" 

944 warnings.warn( 

945 '`tuple_positional_schema` is deprecated. Use `tuple_schema` instead.', 

946 PydanticDeprecatedSince26, 

947 stacklevel=2, 

948 ) 

949 return self.tuple_schema(schema) 

950 

951 @deprecated('`tuple_variable_schema` is deprecated. Use `tuple_schema` instead.', category=None) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

952 @final 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

953 def tuple_variable_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

954 """Replaced by `tuple_schema`.""" 

955 warnings.warn( 

956 '`tuple_variable_schema` is deprecated. Use `tuple_schema` instead.', 

957 PydanticDeprecatedSince26, 

958 stacklevel=2, 

959 ) 

960 return self.tuple_schema(schema) 

961 

962 def tuple_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

963 """Generates a JSON schema that matches a tuple schema e.g. `tuple[int, 

964 str, bool]` or `tuple[int, ...]`. 

965 

966 Args: 

967 schema: The core schema. 

968 

969 Returns: 

970 The generated JSON schema. 

971 """ 

972 json_schema: JsonSchemaValue = {'type': 'array'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

973 if 'variadic_item_index' in schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

974 variadic_item_index = schema['variadic_item_index'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

975 if variadic_item_index > 0: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

976 json_schema['minItems'] = variadic_item_index 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

977 json_schema['prefixItems'] = [ 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

978 self.generate_inner(item) for item in schema['items_schema'][:variadic_item_index] 

979 ] 

980 if variadic_item_index + 1 == len(schema['items_schema']): 980 ↛ 987line 980 didn't jump to line 987 because the condition on line 980 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

981 # if the variadic item is the last item, then represent it faithfully 

982 json_schema['items'] = self.generate_inner(schema['items_schema'][variadic_item_index]) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

983 else: 

984 # otherwise, 'items' represents the schema for the variadic 

985 # item plus the suffix, so just allow anything for simplicity 

986 # for now 

987 json_schema['items'] = True 

988 else: 

989 prefixItems = [self.generate_inner(item) for item in schema['items_schema']] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

990 if prefixItems: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

991 json_schema['prefixItems'] = prefixItems 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

992 json_schema['minItems'] = len(prefixItems) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

993 json_schema['maxItems'] = len(prefixItems) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

994 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

995 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

996 

997 def set_schema(self, schema: core_schema.SetSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

998 """Generates a JSON schema that matches a set schema. 

999 

1000 Args: 

1001 schema: The core schema. 

1002 

1003 Returns: 

1004 The generated JSON schema. 

1005 """ 

1006 return self._common_set_schema(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1007 

1008 def frozenset_schema(self, schema: core_schema.FrozenSetSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1009 """Generates a JSON schema that matches a frozenset schema. 

1010 

1011 Args: 

1012 schema: The core schema. 

1013 

1014 Returns: 

1015 The generated JSON schema. 

1016 """ 

1017 return self._common_set_schema(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1018 

1019 def _common_set_schema(self, schema: core_schema.SetSchema | core_schema.FrozenSetSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1020 items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1021 json_schema = {'type': 'array', 'uniqueItems': True, 'items': items_schema} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1022 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1023 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1024 

1025 def generator_schema(self, schema: core_schema.GeneratorSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1026 """Returns a JSON schema that represents the provided GeneratorSchema. 

1027 

1028 Args: 

1029 schema: The schema. 

1030 

1031 Returns: 

1032 The generated JSON schema. 

1033 """ 

1034 items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1035 json_schema = {'type': 'array', 'items': items_schema} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1036 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1037 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1038 

1039 def dict_schema(self, schema: core_schema.DictSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1040 """Generates a JSON schema that matches a dict schema. 

1041 

1042 Args: 

1043 schema: The core schema. 

1044 

1045 Returns: 

1046 The generated JSON schema. 

1047 """ 

1048 json_schema: JsonSchemaValue = {'type': 'object'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1049 

1050 keys_schema = self.generate_inner(schema['keys_schema']).copy() if 'keys_schema' in schema else {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1051 if '$ref' not in keys_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1052 keys_pattern = keys_schema.pop('pattern', None) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1053 # Don't give a title to patternProperties/propertyNames: 

1054 keys_schema.pop('title', None) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1055 else: 

1056 # Here, we assume that if the keys schema is a definition reference, 

1057 # it can't be a simple string core schema (and thus no pattern can exist). 

1058 # However, this is only in practice (in theory, a definition reference core 

1059 # schema could be generated for a simple string schema). 

1060 # Note that we avoid calling `self.resolve_ref_schema`, as it might not exist yet. 

1061 keys_pattern = None 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1062 

1063 values_schema = self.generate_inner(schema['values_schema']).copy() if 'values_schema' in schema else {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1064 # don't give a title to additionalProperties: 

1065 values_schema.pop('title', None) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1066 

1067 if values_schema or keys_pattern is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1068 if keys_pattern is None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1069 json_schema['additionalProperties'] = values_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1070 else: 

1071 json_schema['patternProperties'] = {keys_pattern: values_schema} 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1072 else: # for `dict[str, Any]`, we allow any key and any value, since `str` is the default key type 

1073 json_schema['additionalProperties'] = True 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1074 

1075 if ( 1zCEa

1076 # The len check indicates that constraints are probably present: 

1077 (keys_schema.get('type') == 'string' and len(keys_schema) > 1) 

1078 # If this is a definition reference schema, it most likely has constraints: 

1079 or '$ref' in keys_schema 

1080 ): 

1081 keys_schema.pop('type', None) 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1082 json_schema['propertyNames'] = keys_schema 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1083 

1084 self.update_with_validations(json_schema, schema, self.ValidationsMapping.object) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1085 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1086 

1087 def function_before_schema(self, schema: core_schema.BeforeValidatorFunctionSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1088 """Generates a JSON schema that matches a function-before schema. 

1089 

1090 Args: 

1091 schema: The core schema. 

1092 

1093 Returns: 

1094 The generated JSON schema. 

1095 """ 

1096 if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1097 return self.generate_inner(input_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1098 

1099 return self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1100 

1101 def function_after_schema(self, schema: core_schema.AfterValidatorFunctionSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1102 """Generates a JSON schema that matches a function-after schema. 

1103 

1104 Args: 

1105 schema: The core schema. 

1106 

1107 Returns: 

1108 The generated JSON schema. 

1109 """ 

1110 return self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1111 

1112 def function_plain_schema(self, schema: core_schema.PlainValidatorFunctionSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1113 """Generates a JSON schema that matches a function-plain schema. 

1114 

1115 Args: 

1116 schema: The core schema. 

1117 

1118 Returns: 

1119 The generated JSON schema. 

1120 """ 

1121 if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): 1121 ↛ 1124line 1121 didn't jump to line 1124 because the condition on line 1121 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1122 return self.generate_inner(input_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1123 

1124 return self.handle_invalid_for_json_schema( 

1125 schema, f'core_schema.PlainValidatorFunctionSchema ({schema["function"]})' 

1126 ) 

1127 

1128 def function_wrap_schema(self, schema: core_schema.WrapValidatorFunctionSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1129 """Generates a JSON schema that matches a function-wrap schema. 

1130 

1131 Args: 

1132 schema: The core schema. 

1133 

1134 Returns: 

1135 The generated JSON schema. 

1136 """ 

1137 if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1138 return self.generate_inner(input_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1139 

1140 return self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1141 

1142 def default_schema(self, schema: core_schema.WithDefaultSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1143 """Generates a JSON schema that matches a schema with a default value. 

1144 

1145 Args: 

1146 schema: The core schema. 

1147 

1148 Returns: 

1149 The generated JSON schema. 

1150 """ 

1151 json_schema = self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1152 

1153 default = self.get_default_value(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1154 if default is NoDefault: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1155 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1156 

1157 # we reflect the application of custom plain, no-info serializers to defaults for 

1158 # JSON Schemas viewed in serialization mode: 

1159 # TODO: improvements along with https://github.com/pydantic/pydantic/issues/8208 

1160 if self.mode == 'serialization': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1161 # `_get_ser_schema_for_default_value()` is used to unpack potentially nested validator schemas: 

1162 ser_schema = _get_ser_schema_for_default_value(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1163 if ( 1zCEaJKIL

1164 ser_schema is not None 

1165 and (ser_func := ser_schema.get('function')) 

1166 and not (default is None and ser_schema.get('when_used') in ('unless-none', 'json-unless-none')) 

1167 ): 

1168 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1169 default = ser_func(default) # type: ignore 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1170 except Exception: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1171 # It might be that the provided default needs to be validated (read: parsed) first 

1172 # (assuming `validate_default` is enabled). However, we can't perform 

1173 # such validation during JSON Schema generation so we don't support 

1174 # this pattern for now. 

1175 # (One example is when using `foo: ByteSize = '1MB'`, which validates and 

1176 # serializes as an int. In this case, `ser_func` is `int` and `int('1MB')` fails). 

1177 self.emit_warning( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1178 'non-serializable-default', 

1179 f'Unable to serialize value {default!r} with the plain serializer; excluding default from JSON schema', 

1180 ) 

1181 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1182 

1183 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1184 encoded_default = self.encode_default(default) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1185 except pydantic_core.PydanticSerializationError: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1186 self.emit_warning( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1187 'non-serializable-default', 

1188 f'Default value {default} is not JSON serializable; excluding default from JSON schema', 

1189 ) 

1190 # Return the inner schema, as though there was no default 

1191 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1192 

1193 json_schema['default'] = encoded_default 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1194 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1195 

1196 def get_default_value(self, schema: core_schema.WithDefaultSchema) -> Any: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1197 """Get the default value to be used when generating a JSON Schema for a core schema with a default. 

1198 

1199 The default implementation is to use the statically defined default value. This method can be overridden 

1200 if you want to make use of the default factory. 

1201 

1202 Args: 

1203 schema: The `'with-default'` core schema. 

1204 

1205 Returns: 

1206 The default value to use, or [`NoDefault`][pydantic.json_schema.NoDefault] if no default 

1207 value is available. 

1208 """ 

1209 return schema.get('default', NoDefault) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1210 

1211 def nullable_schema(self, schema: core_schema.NullableSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1212 """Generates a JSON schema that matches a schema that allows null values. 

1213 

1214 Args: 

1215 schema: The core schema. 

1216 

1217 Returns: 

1218 The generated JSON schema. 

1219 """ 

1220 null_schema = {'type': 'null'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1221 inner_json_schema = self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1222 

1223 if inner_json_schema == null_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1224 return null_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1225 else: 

1226 # Thanks to the equality check against `null_schema` above, I think 'oneOf' would also be valid here; 

1227 # I'll use 'anyOf' for now, but it could be changed it if it would work better with some external tooling 

1228 return self.get_flattened_anyof([inner_json_schema, null_schema]) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1229 

1230 def union_schema(self, schema: core_schema.UnionSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1231 """Generates a JSON schema that matches a schema that allows values matching any of the given schemas. 

1232 

1233 Args: 

1234 schema: The core schema. 

1235 

1236 Returns: 

1237 The generated JSON schema. 

1238 """ 

1239 generated: list[JsonSchemaValue] = [] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1240 

1241 choices = schema['choices'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1242 for choice in choices: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1243 # choice will be a tuple if an explicit label was provided 

1244 choice_schema = choice[0] if isinstance(choice, tuple) else choice 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1245 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1246 generated.append(self.generate_inner(choice_schema)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1247 except PydanticOmit: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1248 continue 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1249 except PydanticInvalidForJsonSchema as exc: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1250 self.emit_warning('skipped-choice', exc.message) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1251 if len(generated) == 1: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1252 return generated[0] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1253 return self.get_flattened_anyof(generated) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1254 

1255 def tagged_union_schema(self, schema: core_schema.TaggedUnionSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1256 """Generates a JSON schema that matches a schema that allows values matching any of the given schemas, where 

1257 the schemas are tagged with a discriminator field that indicates which schema should be used to validate 

1258 the value. 

1259 

1260 Args: 

1261 schema: The core schema. 

1262 

1263 Returns: 

1264 The generated JSON schema. 

1265 """ 

1266 generated: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1267 for k, v in schema['choices'].items(): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1268 if isinstance(k, Enum): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1269 k = k.value 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1270 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1271 # Use str(k) since keys must be strings for json; while not technically correct, 

1272 # it's the closest that can be represented in valid JSON 

1273 generated[str(k)] = self.generate_inner(v).copy() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1274 except PydanticOmit: 

1275 continue 

1276 except PydanticInvalidForJsonSchema as exc: 

1277 self.emit_warning('skipped-choice', exc.message) 

1278 

1279 one_of_choices = _deduplicate_schemas(generated.values()) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1280 json_schema: JsonSchemaValue = {'oneOf': one_of_choices} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1281 

1282 # This reflects the v1 behavior; TODO: we should make it possible to exclude OpenAPI stuff from the JSON schema 

1283 openapi_discriminator = self._extract_discriminator(schema, one_of_choices) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1284 if openapi_discriminator is not None: 1284 ↛ 1290line 1284 didn't jump to line 1290 because the condition on line 1284 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1285 json_schema['discriminator'] = { 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1286 'propertyName': openapi_discriminator, 

1287 'mapping': {k: v.get('$ref', v) for k, v in generated.items()}, 

1288 } 

1289 

1290 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1291 

1292 def _extract_discriminator( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1293 self, schema: core_schema.TaggedUnionSchema, one_of_choices: list[JsonDict] 

1294 ) -> str | None: 

1295 """Extract a compatible OpenAPI discriminator from the schema and one_of choices that end up in the final 

1296 schema.""" 

1297 openapi_discriminator: str | None = None 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1298 

1299 if isinstance(schema['discriminator'], str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1300 return schema['discriminator'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1301 

1302 if isinstance(schema['discriminator'], list): 1302 ↛ 1335line 1302 didn't jump to line 1335 because the condition on line 1302 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1303 # If the discriminator is a single item list containing a string, that is equivalent to the string case 

1304 if len(schema['discriminator']) == 1 and isinstance(schema['discriminator'][0], str): 1304 ↛ 1305line 1304 didn't jump to line 1305 because the condition on line 1304 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1305 return schema['discriminator'][0] 

1306 # When an alias is used that is different from the field name, the discriminator will be a list of single 

1307 # str lists, one for the attribute and one for the actual alias. The logic here will work even if there is 

1308 # more than one possible attribute, and looks for whether a single alias choice is present as a documented 

1309 # property on all choices. If so, that property will be used as the OpenAPI discriminator. 

1310 for alias_path in schema['discriminator']: 1310 ↛ 1335line 1310 didn't jump to line 1335 because the loop on line 1310 didn't complete1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1311 if not isinstance(alias_path, list): 1311 ↛ 1312line 1311 didn't jump to line 1312 because the condition on line 1311 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1312 break # this means that the discriminator is not a list of alias paths 

1313 if len(alias_path) != 1: 1313 ↛ 1314line 1313 didn't jump to line 1314 because the condition on line 1313 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1314 continue # this means that the "alias" does not represent a single field 

1315 alias = alias_path[0] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1316 if not isinstance(alias, str): 1316 ↛ 1317line 1316 didn't jump to line 1317 because the condition on line 1316 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1317 continue # this means that the "alias" does not represent a field 

1318 alias_is_present_on_all_choices = True 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1319 for choice in one_of_choices: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1320 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1321 choice = self.resolve_ref_schema(choice) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1322 except RuntimeError as exc: 

1323 # TODO: fixme - this is a workaround for the fact that we can't always resolve refs 

1324 # for tagged union choices at this point in the schema gen process, we might need to do 

1325 # another pass at the end like we do for core schemas 

1326 self.emit_warning('skipped-discriminator', str(exc)) 

1327 choice = {} 

1328 properties = choice.get('properties', {}) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1329 if not isinstance(properties, dict) or alias not in properties: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1330 alias_is_present_on_all_choices = False 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1331 break 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1332 if alias_is_present_on_all_choices: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1333 openapi_discriminator = alias 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1334 break 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1335 return openapi_discriminator 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1336 

1337 def chain_schema(self, schema: core_schema.ChainSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1338 """Generates a JSON schema that matches a core_schema.ChainSchema. 

1339 

1340 When generating a schema for validation, we return the validation JSON schema for the first step in the chain. 

1341 For serialization, we return the serialization JSON schema for the last step in the chain. 

1342 

1343 Args: 

1344 schema: The core schema. 

1345 

1346 Returns: 

1347 The generated JSON schema. 

1348 """ 

1349 step_index = 0 if self.mode == 'validation' else -1 # use first step for validation, last for serialization 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1350 return self.generate_inner(schema['steps'][step_index]) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1351 

1352 def lax_or_strict_schema(self, schema: core_schema.LaxOrStrictSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1353 """Generates a JSON schema that matches a schema that allows values matching either the lax schema or the 

1354 strict schema. 

1355 

1356 Args: 

1357 schema: The core schema. 

1358 

1359 Returns: 

1360 The generated JSON schema. 

1361 """ 

1362 # TODO: Need to read the default value off of model config or whatever 

1363 use_strict = schema.get('strict', False) # TODO: replace this default False 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1364 # If your JSON schema fails to generate it is probably 

1365 # because one of the following two branches failed. 

1366 if use_strict: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1367 return self.generate_inner(schema['strict_schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1368 else: 

1369 return self.generate_inner(schema['lax_schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1370 

1371 def json_or_python_schema(self, schema: core_schema.JsonOrPythonSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1372 """Generates a JSON schema that matches a schema that allows values matching either the JSON schema or the 

1373 Python schema. 

1374 

1375 The JSON schema is used instead of the Python schema. If you want to use the Python schema, you should override 

1376 this method. 

1377 

1378 Args: 

1379 schema: The core schema. 

1380 

1381 Returns: 

1382 The generated JSON schema. 

1383 """ 

1384 return self.generate_inner(schema['json_schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1385 

1386 def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1387 """Generates a JSON schema that matches a schema that defines a typed dict. 

1388 

1389 Args: 

1390 schema: The core schema. 

1391 

1392 Returns: 

1393 The generated JSON schema. 

1394 """ 

1395 total = schema.get('total', True) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1396 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1397 (name, self.field_is_required(field, total), field) 

1398 for name, field in schema['fields'].items() 

1399 if self.field_is_present(field) 

1400 ] 

1401 if self.mode == 'serialization': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1402 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1403 cls = schema.get('cls') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1404 config = _get_typed_dict_config(cls) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1405 with self._config_wrapper_stack.push(config): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1406 json_schema = self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1407 

1408 if cls is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1409 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1410 else: 

1411 extra = config.get('extra') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1412 if extra == 'forbid': 1412 ↛ 1413line 1412 didn't jump to line 1413 because the condition on line 1412 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1413 json_schema['additionalProperties'] = False 

1414 elif extra == 'allow': 1414 ↛ 1415line 1414 didn't jump to line 1415 because the condition on line 1414 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1415 json_schema['additionalProperties'] = True 

1416 

1417 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1418 

1419 @staticmethod 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1420 def _name_required_computed_fields( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1421 computed_fields: list[ComputedField], 

1422 ) -> list[tuple[str, bool, core_schema.ComputedField]]: 

1423 return [(field['property_name'], True, field) for field in computed_fields] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1424 

1425 def _named_required_fields_schema( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1426 self, named_required_fields: Sequence[tuple[str, bool, CoreSchemaField]] 

1427 ) -> JsonSchemaValue: 

1428 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1429 required_fields: list[str] = [] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1430 for name, required, field in named_required_fields: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1431 if self.by_alias: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1432 name = self._get_alias_name(field, name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1433 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1434 field_json_schema = self.generate_inner(field).copy() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1435 except PydanticOmit: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1436 continue 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1437 if 'title' not in field_json_schema and self.field_title_should_be_set(field): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1438 title = self.get_title_from_name(name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1439 field_json_schema['title'] = title 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1440 field_json_schema = self.handle_ref_overrides(field_json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1441 properties[name] = field_json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1442 if required: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1443 required_fields.append(name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1444 

1445 json_schema = {'type': 'object', 'properties': properties} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1446 if required_fields: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1447 json_schema['required'] = required_fields 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1448 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1449 

1450 def _get_alias_name(self, field: CoreSchemaField, name: str) -> str: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1451 if field['type'] == 'computed-field': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1452 alias: Any = field.get('alias', name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1453 elif self.mode == 'validation': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1454 alias = field.get('validation_alias', name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1455 else: 

1456 alias = field.get('serialization_alias', name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1457 if isinstance(alias, str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1458 name = alias 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1459 elif isinstance(alias, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1460 alias = cast('list[str] | str', alias) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1461 for path in alias: 1461 ↛ 1469line 1461 didn't jump to line 1469 because the loop on line 1461 didn't complete1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1462 if isinstance(path, list) and len(path) == 1 and isinstance(path[0], str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1463 # Use the first valid single-item string path; the code that constructs the alias array 

1464 # should ensure the first such item is what belongs in the JSON schema 

1465 name = path[0] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1466 break 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1467 else: 

1468 assert_never(alias) 

1469 return name 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1470 

1471 def typed_dict_field_schema(self, schema: core_schema.TypedDictField) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1472 """Generates a JSON schema that matches a schema that defines a typed dict field. 

1473 

1474 Args: 

1475 schema: The core schema. 

1476 

1477 Returns: 

1478 The generated JSON schema. 

1479 """ 

1480 return self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1481 

1482 def dataclass_field_schema(self, schema: core_schema.DataclassField) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1483 """Generates a JSON schema that matches a schema that defines a dataclass field. 

1484 

1485 Args: 

1486 schema: The core schema. 

1487 

1488 Returns: 

1489 The generated JSON schema. 

1490 """ 

1491 return self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1492 

1493 def model_field_schema(self, schema: core_schema.ModelField) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1494 """Generates a JSON schema that matches a schema that defines a model field. 

1495 

1496 Args: 

1497 schema: The core schema. 

1498 

1499 Returns: 

1500 The generated JSON schema. 

1501 """ 

1502 return self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1503 

1504 def computed_field_schema(self, schema: core_schema.ComputedField) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1505 """Generates a JSON schema that matches a schema that defines a computed field. 

1506 

1507 Args: 

1508 schema: The core schema. 

1509 

1510 Returns: 

1511 The generated JSON schema. 

1512 """ 

1513 return self.generate_inner(schema['return_schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1514 

1515 def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1516 """Generates a JSON schema that matches a schema that defines a model. 

1517 

1518 Args: 

1519 schema: The core schema. 

1520 

1521 Returns: 

1522 The generated JSON schema. 

1523 """ 

1524 # We do not use schema['model'].model_json_schema() here 

1525 # because it could lead to inconsistent refs handling, etc. 

1526 cls = cast('type[BaseModel]', schema['cls']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1527 config = cls.model_config 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1528 

1529 with self._config_wrapper_stack.push(config): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1530 json_schema = self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1531 

1532 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1533 

1534 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1535 

1536 def _update_class_schema(self, json_schema: JsonSchemaValue, cls: type[Any], config: ConfigDict) -> None: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1537 """Update json_schema with the following, extracted from `config` and `cls`: 

1538 

1539 * title 

1540 * description 

1541 * additional properties 

1542 * json_schema_extra 

1543 * deprecated 

1544 

1545 Done in place, hence there's no return value as the original json_schema is mutated. 

1546 No ref resolving is involved here, as that's not appropriate for simple updates. 

1547 """ 

1548 from .main import BaseModel 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1549 from .root_model import RootModel 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1550 

1551 if (config_title := config.get('title')) is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1552 json_schema.setdefault('title', config_title) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1553 elif model_title_generator := config.get('model_title_generator'): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1554 title = model_title_generator(cls) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1555 if not isinstance(title, str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1556 raise TypeError(f'model_title_generator {model_title_generator} must return str, not {title.__class__}') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1557 json_schema.setdefault('title', title) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1558 if 'title' not in json_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1559 json_schema['title'] = cls.__name__ 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1560 

1561 # BaseModel and dataclasses; don't use cls.__doc__ as it will contain the verbose class signature by default 

1562 docstring = None if cls is BaseModel or dataclasses.is_dataclass(cls) else cls.__doc__ 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1563 

1564 if docstring: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1565 json_schema.setdefault('description', inspect.cleandoc(docstring)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1566 elif issubclass(cls, RootModel) and (root_description := cls.__pydantic_fields__['root'].description): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1567 json_schema.setdefault('description', root_description) 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1568 

1569 extra = config.get('extra') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1570 if 'additionalProperties' not in json_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1571 if extra == 'allow': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1572 json_schema['additionalProperties'] = True 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBH

1573 elif extra == 'forbid': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1574 json_schema['additionalProperties'] = False 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1575 

1576 json_schema_extra = config.get('json_schema_extra') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1577 if issubclass(cls, BaseModel) and cls.__pydantic_root_model__: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1578 root_json_schema_extra = cls.model_fields['root'].json_schema_extra 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHN

1579 if json_schema_extra and root_json_schema_extra: 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHN

1580 raise ValueError( 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1581 '"model_config[\'json_schema_extra\']" and "Field.json_schema_extra" on "RootModel.root"' 

1582 ' field must not be set simultaneously' 

1583 ) 

1584 if root_json_schema_extra: 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHN

1585 json_schema_extra = root_json_schema_extra 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1586 

1587 if isinstance(json_schema_extra, (staticmethod, classmethod)): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1588 # In older versions of python, this is necessary to ensure staticmethod/classmethods are callable 

1589 json_schema_extra = json_schema_extra.__get__(cls) 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1590 

1591 if isinstance(json_schema_extra, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1592 json_schema.update(json_schema_extra) 1zCbdenfogpADOEaJKhiqrstuvFGILcjkwlxmyBH

1593 elif callable(json_schema_extra): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1594 # FIXME: why are there type ignores here? We support two signatures for json_schema_extra callables... 

1595 if len(inspect.signature(json_schema_extra).parameters) > 1: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1596 json_schema_extra(json_schema, cls) # type: ignore 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1597 else: 

1598 json_schema_extra(json_schema) # type: ignore 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1599 elif json_schema_extra is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1600 raise ValueError( 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1601 f"model_config['json_schema_extra']={json_schema_extra} should be a dict, callable, or None" 

1602 ) 

1603 

1604 if hasattr(cls, '__deprecated__'): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1605 json_schema['deprecated'] = True 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1606 

1607 def resolve_ref_schema(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1608 """Resolve a JsonSchemaValue to the non-ref schema if it is a $ref schema. 

1609 

1610 Args: 

1611 json_schema: The schema to resolve. 

1612 

1613 Returns: 

1614 The resolved schema. 

1615 

1616 Raises: 

1617 RuntimeError: If the schema reference can't be found in definitions. 

1618 """ 

1619 while '$ref' in json_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1620 ref = json_schema['$ref'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1621 schema_to_update = self.get_schema_from_definitions(JsonRef(ref)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1622 if schema_to_update is None: 1622 ↛ 1623line 1622 didn't jump to line 1623 because the condition on line 1622 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1623 raise RuntimeError(f'Cannot update undefined schema for $ref={ref}') 

1624 json_schema = schema_to_update 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1625 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1626 

1627 def model_fields_schema(self, schema: core_schema.ModelFieldsSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1628 """Generates a JSON schema that matches a schema that defines a model's fields. 

1629 

1630 Args: 

1631 schema: The core schema. 

1632 

1633 Returns: 

1634 The generated JSON schema. 

1635 """ 

1636 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1637 (name, self.field_is_required(field, total=True), field) 

1638 for name, field in schema['fields'].items() 

1639 if self.field_is_present(field) 

1640 ] 

1641 if self.mode == 'serialization': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1642 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1643 json_schema = self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1644 extras_schema = schema.get('extras_schema', None) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1645 if extras_schema is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1646 schema_to_update = self.resolve_ref_schema(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1647 schema_to_update['additionalProperties'] = self.generate_inner(extras_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1648 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1649 

1650 def field_is_present(self, field: CoreSchemaField) -> bool: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1651 """Whether the field should be included in the generated JSON schema. 

1652 

1653 Args: 

1654 field: The schema for the field itself. 

1655 

1656 Returns: 

1657 `True` if the field should be included in the generated JSON schema, `False` otherwise. 

1658 """ 

1659 if self.mode == 'serialization': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1660 # If you still want to include the field in the generated JSON schema, 

1661 # override this method and return True 

1662 return not field.get('serialization_exclude') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1663 elif self.mode == 'validation': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1664 return True 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1665 else: 

1666 assert_never(self.mode) 

1667 

1668 def field_is_required( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1669 self, 

1670 field: core_schema.ModelField | core_schema.DataclassField | core_schema.TypedDictField, 

1671 total: bool, 

1672 ) -> bool: 

1673 """Whether the field should be marked as required in the generated JSON schema. 

1674 (Note that this is irrelevant if the field is not present in the JSON schema.). 

1675 

1676 Args: 

1677 field: The schema for the field itself. 

1678 total: Only applies to `TypedDictField`s. 

1679 Indicates if the `TypedDict` this field belongs to is total, in which case any fields that don't 

1680 explicitly specify `required=False` are required. 

1681 

1682 Returns: 

1683 `True` if the field should be marked as required in the generated JSON schema, `False` otherwise. 

1684 """ 

1685 if self.mode == 'serialization' and self._config.json_schema_serialization_defaults_required: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1686 return not field.get('serialization_exclude') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1687 else: 

1688 if field['type'] == 'typed-dict-field': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1689 return field.get('required', total) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1690 else: 

1691 return field['schema']['type'] != 'default' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1692 

1693 def dataclass_args_schema(self, schema: core_schema.DataclassArgsSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1694 """Generates a JSON schema that matches a schema that defines a dataclass's constructor arguments. 

1695 

1696 Args: 

1697 schema: The core schema. 

1698 

1699 Returns: 

1700 The generated JSON schema. 

1701 """ 

1702 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1703 (field['name'], self.field_is_required(field, total=True), field) 

1704 for field in schema['fields'] 

1705 if self.field_is_present(field) 

1706 ] 

1707 if self.mode == 'serialization': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1708 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1709 return self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1710 

1711 def dataclass_schema(self, schema: core_schema.DataclassSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1712 """Generates a JSON schema that matches a schema that defines a dataclass. 

1713 

1714 Args: 

1715 schema: The core schema. 

1716 

1717 Returns: 

1718 The generated JSON schema. 

1719 """ 

1720 from ._internal._dataclasses import is_stdlib_dataclass 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1721 

1722 cls = schema['cls'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1723 config: ConfigDict = getattr(cls, '__pydantic_config__', cast('ConfigDict', {})) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1724 

1725 with self._config_wrapper_stack.push(config): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1726 json_schema = self.generate_inner(schema['schema']).copy() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1727 

1728 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1729 

1730 # Dataclass-specific handling of description 

1731 if is_stdlib_dataclass(cls): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1732 # vanilla dataclass; don't use cls.__doc__ as it will contain the class signature by default 

1733 description = None 1zCbdenfogpADEaJKhiqrstuvFGMILcjkwlxmyBHN

1734 else: 

1735 description = None if cls.__doc__ is None else inspect.cleandoc(cls.__doc__) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1736 if description: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1737 json_schema['description'] = description 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHN

1738 

1739 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1740 

1741 def arguments_schema(self, schema: core_schema.ArgumentsSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1742 """Generates a JSON schema that matches a schema that defines a function's arguments. 

1743 

1744 Args: 

1745 schema: The core schema. 

1746 

1747 Returns: 

1748 The generated JSON schema. 

1749 """ 

1750 prefer_positional = schema.get('metadata', {}).get('pydantic_js_prefer_positional_arguments') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1751 

1752 arguments = schema['arguments_schema'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1753 kw_only_arguments = [a for a in arguments if a.get('mode') == 'keyword_only'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1754 kw_or_p_arguments = [a for a in arguments if a.get('mode') in {'positional_or_keyword', None}] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1755 p_only_arguments = [a for a in arguments if a.get('mode') == 'positional_only'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1756 var_args_schema = schema.get('var_args_schema') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1757 var_kwargs_schema = schema.get('var_kwargs_schema') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1758 

1759 if prefer_positional: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1760 positional_possible = not kw_only_arguments and not var_kwargs_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1761 if positional_possible: 1761 ↛ 1764line 1761 didn't jump to line 1764 because the condition on line 1761 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1762 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1763 

1764 keyword_possible = not p_only_arguments and not var_args_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1765 if keyword_possible: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1766 return self.kw_arguments_schema(kw_or_p_arguments + kw_only_arguments, var_kwargs_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1767 

1768 if not prefer_positional: 1768 ↛ 1773line 1768 didn't jump to line 1773 because the condition on line 1768 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1769 positional_possible = not kw_only_arguments and not var_kwargs_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1770 if positional_possible: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1771 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1772 

1773 raise PydanticInvalidForJsonSchema( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1774 'Unable to generate JSON schema for arguments validator with positional-only and keyword-only arguments' 

1775 ) 

1776 

1777 def kw_arguments_schema( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1778 self, arguments: list[core_schema.ArgumentsParameter], var_kwargs_schema: CoreSchema | None 

1779 ) -> JsonSchemaValue: 

1780 """Generates a JSON schema that matches a schema that defines a function's keyword arguments. 

1781 

1782 Args: 

1783 arguments: The core schema. 

1784 

1785 Returns: 

1786 The generated JSON schema. 

1787 """ 

1788 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1789 required: list[str] = [] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1790 for argument in arguments: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1791 name = self.get_argument_name(argument) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1792 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1793 argument_schema['title'] = self.get_title_from_name(name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1794 properties[name] = argument_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1795 

1796 if argument['schema']['type'] != 'default': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1797 # This assumes that if the argument has a default value, 

1798 # the inner schema must be of type WithDefaultSchema. 

1799 # I believe this is true, but I am not 100% sure 

1800 required.append(name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1801 

1802 json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1803 if required: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1804 json_schema['required'] = required 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1805 

1806 if var_kwargs_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1807 additional_properties_schema = self.generate_inner(var_kwargs_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1808 if additional_properties_schema: 1808 ↛ 1812line 1808 didn't jump to line 1812 because the condition on line 1808 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1809 json_schema['additionalProperties'] = additional_properties_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1810 else: 

1811 json_schema['additionalProperties'] = False 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1812 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1813 

1814 def p_arguments_schema( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1815 self, arguments: list[core_schema.ArgumentsParameter], var_args_schema: CoreSchema | None 

1816 ) -> JsonSchemaValue: 

1817 """Generates a JSON schema that matches a schema that defines a function's positional arguments. 

1818 

1819 Args: 

1820 arguments: The core schema. 

1821 

1822 Returns: 

1823 The generated JSON schema. 

1824 """ 

1825 prefix_items: list[JsonSchemaValue] = [] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1826 min_items = 0 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1827 

1828 for argument in arguments: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1829 name = self.get_argument_name(argument) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1830 

1831 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1832 argument_schema['title'] = self.get_title_from_name(name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1833 prefix_items.append(argument_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1834 

1835 if argument['schema']['type'] != 'default': 1835 ↛ 1828line 1835 didn't jump to line 1828 because the condition on line 1835 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1836 # This assumes that if the argument has a default value, 

1837 # the inner schema must be of type WithDefaultSchema. 

1838 # I believe this is true, but I am not 100% sure 

1839 min_items += 1 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1840 

1841 json_schema: JsonSchemaValue = {'type': 'array'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1842 if prefix_items: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1843 json_schema['prefixItems'] = prefix_items 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1844 if min_items: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1845 json_schema['minItems'] = min_items 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1846 

1847 if var_args_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1848 items_schema = self.generate_inner(var_args_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1849 if items_schema: 1849 ↛ 1854line 1849 didn't jump to line 1854 because the condition on line 1849 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1850 json_schema['items'] = items_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1851 else: 

1852 json_schema['maxItems'] = len(prefix_items) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1853 

1854 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1855 

1856 def get_argument_name(self, argument: core_schema.ArgumentsParameter | core_schema.ArgumentsV3Parameter) -> str: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1857 """Retrieves the name of an argument. 

1858 

1859 Args: 

1860 argument: The core schema. 

1861 

1862 Returns: 

1863 The name of the argument. 

1864 """ 

1865 name = argument['name'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1866 if self.by_alias: 1866 ↛ 1872line 1866 didn't jump to line 1872 because the condition on line 1866 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1867 alias = argument.get('alias') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1868 if isinstance(alias, str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1869 name = alias 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1870 else: 

1871 pass # might want to do something else? 1bdenfogpADOahiqrstuvFGMcjkwlxmyBHN

1872 return name 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1873 

1874 def arguments_v3_schema(self, schema: core_schema.ArgumentsV3Schema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1875 """Generates a JSON schema that matches a schema that defines a function's arguments. 

1876 

1877 Args: 

1878 schema: The core schema. 

1879 

1880 Returns: 

1881 The generated JSON schema. 

1882 """ 

1883 arguments = schema['arguments_schema'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1884 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1885 required: list[str] = [] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1886 for argument in arguments: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1887 mode = argument.get('mode', 'positional_or_keyword') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1888 name = self.get_argument_name(argument) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1889 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1890 if mode == 'var_args': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1891 argument_schema = {'type': 'array', 'items': argument_schema} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1892 elif mode == 'var_kwargs_uniform': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1893 argument_schema = {'type': 'object', 'additionalProperties': argument_schema} 1zCbdenfogpADEaJKhiqrstuvFGMILcjkwlxmyBH

1894 

1895 argument_schema.setdefault('title', self.get_title_from_name(name)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1896 properties[name] = argument_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1897 

1898 if ( 1zCEa

1899 (mode == 'var_kwargs_unpacked_typed_dict' and 'required' in argument_schema) 

1900 or mode not in {'var_args', 'var_kwargs_uniform', 'var_kwargs_unpacked_typed_dict'} 

1901 and argument['schema']['type'] != 'default' 

1902 ): 

1903 # This assumes that if the argument has a default value, 

1904 # the inner schema must be of type WithDefaultSchema. 

1905 # I believe this is true, but I am not 100% sure 

1906 required.append(name) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1907 

1908 json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1909 if required: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1910 json_schema['required'] = required 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1911 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1912 

1913 def call_schema(self, schema: core_schema.CallSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1914 """Generates a JSON schema that matches a schema that defines a function call. 

1915 

1916 Args: 

1917 schema: The core schema. 

1918 

1919 Returns: 

1920 The generated JSON schema. 

1921 """ 

1922 return self.generate_inner(schema['arguments_schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1923 

1924 def custom_error_schema(self, schema: core_schema.CustomErrorSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1925 """Generates a JSON schema that matches a schema that defines a custom error. 

1926 

1927 Args: 

1928 schema: The core schema. 

1929 

1930 Returns: 

1931 The generated JSON schema. 

1932 """ 

1933 return self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1934 

1935 def json_schema(self, schema: core_schema.JsonSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1936 """Generates a JSON schema that matches a schema that defines a JSON object. 

1937 

1938 Args: 

1939 schema: The core schema. 

1940 

1941 Returns: 

1942 The generated JSON schema. 

1943 """ 

1944 content_core_schema = schema.get('schema') or core_schema.any_schema() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1945 content_json_schema = self.generate_inner(content_core_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1946 if self.mode == 'validation': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1947 return {'type': 'string', 'contentMediaType': 'application/json', 'contentSchema': content_json_schema} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1948 else: 

1949 # self.mode == 'serialization' 

1950 return content_json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1951 

1952 def url_schema(self, schema: core_schema.UrlSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1953 """Generates a JSON schema that matches a schema that defines a URL. 

1954 

1955 Args: 

1956 schema: The core schema. 

1957 

1958 Returns: 

1959 The generated JSON schema. 

1960 """ 

1961 json_schema = {'type': 'string', 'format': 'uri', 'minLength': 1} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1962 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1963 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1964 

1965 def multi_host_url_schema(self, schema: core_schema.MultiHostUrlSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1966 """Generates a JSON schema that matches a schema that defines a URL that can be used with multiple hosts. 

1967 

1968 Args: 

1969 schema: The core schema. 

1970 

1971 Returns: 

1972 The generated JSON schema. 

1973 """ 

1974 # Note: 'multi-host-uri' is a custom/pydantic-specific format, not part of the JSON Schema spec 

1975 json_schema = {'type': 'string', 'format': 'multi-host-uri', 'minLength': 1} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1976 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1977 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1978 

1979 def uuid_schema(self, schema: core_schema.UuidSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1980 """Generates a JSON schema that matches a UUID. 

1981 

1982 Args: 

1983 schema: The core schema. 

1984 

1985 Returns: 

1986 The generated JSON schema. 

1987 """ 

1988 return {'type': 'string', 'format': 'uuid'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

1989 

1990 def definitions_schema(self, schema: core_schema.DefinitionsSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

1991 """Generates a JSON schema that matches a schema that defines a JSON object with definitions. 

1992 

1993 Args: 

1994 schema: The core schema. 

1995 

1996 Returns: 

1997 The generated JSON schema. 

1998 """ 

1999 for definition in schema['definitions']: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2000 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2001 self.generate_inner(definition) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2002 except PydanticInvalidForJsonSchema as e: 

2003 core_ref: CoreRef = CoreRef(definition['ref']) # type: ignore 

2004 self._core_defs_invalid_for_json_schema[self.get_defs_ref((core_ref, self.mode))] = e 

2005 continue 

2006 return self.generate_inner(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2007 

2008 def definition_ref_schema(self, schema: core_schema.DefinitionReferenceSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2009 """Generates a JSON schema that matches a schema that references a definition. 

2010 

2011 Args: 

2012 schema: The core schema. 

2013 

2014 Returns: 

2015 The generated JSON schema. 

2016 """ 

2017 core_ref = CoreRef(schema['schema_ref']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2018 _, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2019 return ref_json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2020 

2021 def ser_schema( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2022 self, schema: core_schema.SerSchema | core_schema.IncExSeqSerSchema | core_schema.IncExDictSerSchema 

2023 ) -> JsonSchemaValue | None: 

2024 """Generates a JSON schema that matches a schema that defines a serialized object. 

2025 

2026 Args: 

2027 schema: The core schema. 

2028 

2029 Returns: 

2030 The generated JSON schema. 

2031 """ 

2032 schema_type = schema['type'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2033 if schema_type == 'function-plain' or schema_type == 'function-wrap': 2033 ↛ 2038line 2033 didn't jump to line 2038 because the condition on line 2033 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2034 # PlainSerializerFunctionSerSchema or WrapSerializerFunctionSerSchema 

2035 return_schema = schema.get('return_schema') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2036 if return_schema is not None: 2036 ↛ 2044line 2036 didn't jump to line 2044 because the condition on line 2036 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2037 return self.generate_inner(return_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2038 elif schema_type == 'format' or schema_type == 'to-string': 

2039 # FormatSerSchema or ToStringSerSchema 

2040 return self.str_schema(core_schema.str_schema()) 

2041 elif schema['type'] == 'model': 

2042 # ModelSerSchema 

2043 return self.generate_inner(schema['schema']) 

2044 return None 

2045 

2046 def complex_schema(self, schema: core_schema.ComplexSchema) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2047 """Generates a JSON schema that matches a complex number. 

2048 

2049 JSON has no standard way to represent complex numbers. Complex number is not a numeric 

2050 type. Here we represent complex number as strings following the rule defined by Python. 

2051 For instance, '1+2j' is an accepted complex string. Details can be found in 

2052 [Python's `complex` documentation][complex]. 

2053 

2054 Args: 

2055 schema: The core schema. 

2056 

2057 Returns: 

2058 The generated JSON schema. 

2059 """ 

2060 return {'type': 'string'} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2061 

2062 # ### Utility methods 

2063 

2064 def get_title_from_name(self, name: str) -> str: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2065 """Retrieves a title from a name. 

2066 

2067 Args: 

2068 name: The name to retrieve a title from. 

2069 

2070 Returns: 

2071 The title. 

2072 """ 

2073 return name.title().replace('_', ' ').strip() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2074 

2075 def field_title_should_be_set(self, schema: CoreSchemaOrField) -> bool: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2076 """Returns true if a field with the given schema should have a title set based on the field name. 

2077 

2078 Intuitively, we want this to return true for schemas that wouldn't otherwise provide their own title 

2079 (e.g., int, float, str), and false for those that would (e.g., BaseModel subclasses). 

2080 

2081 Args: 

2082 schema: The schema to check. 

2083 

2084 Returns: 

2085 `True` if the field should have a title set, `False` otherwise. 

2086 """ 

2087 if _core_utils.is_core_schema_field(schema): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2088 if schema['type'] == 'computed-field': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2089 field_schema = schema['return_schema'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2090 else: 

2091 field_schema = schema['schema'] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2092 return self.field_title_should_be_set(field_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2093 

2094 elif _core_utils.is_core_schema(schema): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2095 if schema.get('ref'): # things with refs, such as models and enums, should not have titles set 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2096 return False 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2097 if schema['type'] in {'default', 'nullable', 'definitions'}: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2098 return self.field_title_should_be_set(schema['schema']) # type: ignore[typeddict-item] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2099 if _core_utils.is_function_with_inner_schema(schema): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2100 return self.field_title_should_be_set(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2101 if schema['type'] == 'definition-ref': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2102 # Referenced schemas should not have titles set for the same reason 

2103 # schemas with refs should not 

2104 return False 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2105 return True # anything else should have title set 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2106 

2107 else: 

2108 raise PydanticInvalidForJsonSchema(f'Unexpected schema type: schema={schema}') # pragma: no cover 

2109 

2110 def normalize_name(self, name: str) -> str: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2111 """Normalizes a name to be used as a key in a dictionary. 

2112 

2113 Args: 

2114 name: The name to normalize. 

2115 

2116 Returns: 

2117 The normalized name. 

2118 """ 

2119 return re.sub(r'[^a-zA-Z0-9.\-_]', '_', name).replace('.', '__') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2120 

2121 def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2122 """Override this method to change the way that definitions keys are generated from a core reference. 

2123 

2124 Args: 

2125 core_mode_ref: The core reference. 

2126 

2127 Returns: 

2128 The definitions key. 

2129 """ 

2130 # Split the core ref into "components"; generic origins and arguments are each separate components 

2131 core_ref, mode = core_mode_ref 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2132 components = re.split(r'([\][,])', core_ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2133 # Remove IDs from each component 

2134 components = [x.rsplit(':', 1)[0] for x in components] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2135 core_ref_no_id = ''.join(components) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2136 # Remove everything before the last period from each "component" 

2137 components = [re.sub(r'(?:[^.[\]]+\.)+((?:[^.[\]]+))', r'\1', x) for x in components] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2138 short_ref = ''.join(components) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2139 

2140 mode_title = _MODE_TITLE_MAPPING[mode] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2141 

2142 # It is important that the generated defs_ref values be such that at least one choice will not 

2143 # be generated for any other core_ref. Currently, this should be the case because we include 

2144 # the id of the source type in the core_ref 

2145 name = DefsRef(self.normalize_name(short_ref)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2146 name_mode = DefsRef(self.normalize_name(short_ref) + f'-{mode_title}') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2147 module_qualname = DefsRef(self.normalize_name(core_ref_no_id)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2148 module_qualname_mode = DefsRef(f'{module_qualname}-{mode_title}') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2149 module_qualname_id = DefsRef(self.normalize_name(core_ref)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2150 occurrence_index = self._collision_index.get(module_qualname_id) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2151 if occurrence_index is None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2152 self._collision_counter[module_qualname] += 1 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2153 occurrence_index = self._collision_index[module_qualname_id] = self._collision_counter[module_qualname] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2154 

2155 module_qualname_occurrence = DefsRef(f'{module_qualname}__{occurrence_index}') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2156 module_qualname_occurrence_mode = DefsRef(f'{module_qualname_mode}__{occurrence_index}') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2157 

2158 self._prioritized_defsref_choices[module_qualname_occurrence_mode] = [ 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2159 name, 

2160 name_mode, 

2161 module_qualname, 

2162 module_qualname_mode, 

2163 module_qualname_occurrence, 

2164 module_qualname_occurrence_mode, 

2165 ] 

2166 

2167 return module_qualname_occurrence_mode 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2168 

2169 def get_cache_defs_ref_schema(self, core_ref: CoreRef) -> tuple[DefsRef, JsonSchemaValue]: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2170 """This method wraps the get_defs_ref method with some cache-lookup/population logic, 

2171 and returns both the produced defs_ref and the JSON schema that will refer to the right definition. 

2172 

2173 Args: 

2174 core_ref: The core reference to get the definitions reference for. 

2175 

2176 Returns: 

2177 A tuple of the definitions reference and the JSON schema that will refer to it. 

2178 """ 

2179 core_mode_ref = (core_ref, self.mode) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2180 maybe_defs_ref = self.core_to_defs_refs.get(core_mode_ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2181 if maybe_defs_ref is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2182 json_ref = self.core_to_json_refs[core_mode_ref] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2183 return maybe_defs_ref, {'$ref': json_ref} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2184 

2185 defs_ref = self.get_defs_ref(core_mode_ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2186 

2187 # populate the ref translation mappings 

2188 self.core_to_defs_refs[core_mode_ref] = defs_ref 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2189 self.defs_to_core_refs[defs_ref] = core_mode_ref 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2190 

2191 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2192 self.core_to_json_refs[core_mode_ref] = json_ref 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2193 self.json_to_defs_refs[json_ref] = defs_ref 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2194 ref_json_schema = {'$ref': json_ref} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2195 return defs_ref, ref_json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2196 

2197 def handle_ref_overrides(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2198 """Remove any sibling keys that are redundant with the referenced schema. 

2199 

2200 Args: 

2201 json_schema: The schema to remove redundant sibling keys from. 

2202 

2203 Returns: 

2204 The schema with redundant sibling keys removed. 

2205 """ 

2206 if '$ref' in json_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2207 # prevent modifications to the input; this copy may be safe to drop if there is significant overhead 

2208 json_schema = json_schema.copy() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2209 

2210 referenced_json_schema = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2211 if referenced_json_schema is None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2212 # This can happen when building schemas for models with not-yet-defined references. 

2213 # It may be a good idea to do a recursive pass at the end of the generation to remove 

2214 # any redundant override keys. 

2215 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2216 for k, v in list(json_schema.items()): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2217 if k == '$ref': 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2218 continue 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2219 if k in referenced_json_schema and referenced_json_schema[k] == v: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2220 del json_schema[k] # redundant key 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2221 

2222 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2223 

2224 def get_schema_from_definitions(self, json_ref: JsonRef) -> JsonSchemaValue | None: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2225 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2226 def_ref = self.json_to_defs_refs[json_ref] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2227 if def_ref in self._core_defs_invalid_for_json_schema: 2227 ↛ 2228line 2227 didn't jump to line 2228 because the condition on line 2227 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2228 raise self._core_defs_invalid_for_json_schema[def_ref] 

2229 return self.definitions.get(def_ref, None) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2230 except KeyError: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2231 if json_ref.startswith(('http://', 'https://')): 2231 ↛ 2233line 2231 didn't jump to line 2233 because the condition on line 2231 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2232 return None 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2233 raise 

2234 

2235 def encode_default(self, dft: Any) -> Any: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2236 """Encode a default value to a JSON-serializable value. 

2237 

2238 This is used to encode default values for fields in the generated JSON schema. 

2239 

2240 Args: 

2241 dft: The default value to encode. 

2242 

2243 Returns: 

2244 The encoded default value. 

2245 """ 

2246 from .type_adapter import TypeAdapter, _type_has_config 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2247 

2248 config = self._config 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2249 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2250 default = ( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2251 dft 

2252 if _type_has_config(type(dft)) 

2253 else TypeAdapter(type(dft), config=config.config_dict).dump_python( 

2254 dft, by_alias=self.by_alias, mode='json' 

2255 ) 

2256 ) 

2257 except PydanticSchemaGenerationError: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2258 raise pydantic_core.PydanticSerializationError(f'Unable to encode default value {dft}') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2259 

2260 return pydantic_core.to_jsonable_python( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2261 default, timedelta_mode=config.ser_json_timedelta, bytes_mode=config.ser_json_bytes, by_alias=self.by_alias 

2262 ) 

2263 

2264 def update_with_validations( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2265 self, json_schema: JsonSchemaValue, core_schema: CoreSchema, mapping: dict[str, str] 

2266 ) -> None: 

2267 """Update the json_schema with the corresponding validations specified in the core_schema, 

2268 using the provided mapping to translate keys in core_schema to the appropriate keys for a JSON schema. 

2269 

2270 Args: 

2271 json_schema: The JSON schema to update. 

2272 core_schema: The core schema to get the validations from. 

2273 mapping: A mapping from core_schema attribute names to the corresponding JSON schema attribute names. 

2274 """ 

2275 for core_key, json_schema_key in mapping.items(): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2276 if core_key in core_schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2277 json_schema[json_schema_key] = core_schema[core_key] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2278 

2279 class ValidationsMapping: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2280 """This class just contains mappings from core_schema attribute names to the corresponding 

2281 JSON schema attribute names. While I suspect it is unlikely to be necessary, you can in 

2282 principle override this class in a subclass of GenerateJsonSchema (by inheriting from 

2283 GenerateJsonSchema.ValidationsMapping) to change these mappings. 

2284 """ 

2285 

2286 numeric = { 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2287 'multiple_of': 'multipleOf', 

2288 'le': 'maximum', 

2289 'ge': 'minimum', 

2290 'lt': 'exclusiveMaximum', 

2291 'gt': 'exclusiveMinimum', 

2292 } 

2293 bytes = { 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2294 'min_length': 'minLength', 

2295 'max_length': 'maxLength', 

2296 } 

2297 string = { 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2298 'min_length': 'minLength', 

2299 'max_length': 'maxLength', 

2300 'pattern': 'pattern', 

2301 } 

2302 array = { 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2303 'min_length': 'minItems', 

2304 'max_length': 'maxItems', 

2305 } 

2306 object = { 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2307 'min_length': 'minProperties', 

2308 'max_length': 'maxProperties', 

2309 } 

2310 

2311 def get_flattened_anyof(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2312 members = [] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2313 for schema in schemas: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2314 if len(schema) == 1 and 'anyOf' in schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2315 members.extend(schema['anyOf']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2316 else: 

2317 members.append(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2318 members = _deduplicate_schemas(members) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2319 if len(members) == 1: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2320 return members[0] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2321 return {'anyOf': members} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2322 

2323 def get_json_ref_counts(self, json_schema: JsonSchemaValue) -> dict[JsonRef, int]: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2324 """Get all values corresponding to the key '$ref' anywhere in the json_schema.""" 

2325 json_refs: dict[JsonRef, int] = Counter() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2326 

2327 def _add_json_refs(schema: Any) -> None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2328 if isinstance(schema, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2329 if '$ref' in schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2330 json_ref = JsonRef(schema['$ref']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2331 if not isinstance(json_ref, str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2332 return # in this case, '$ref' might have been the name of a property 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2333 already_visited = json_ref in json_refs 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2334 json_refs[json_ref] += 1 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2335 if already_visited: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2336 return # prevent recursion on a definition that was already visited 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2337 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2338 defs_ref = self.json_to_defs_refs[json_ref] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2339 if defs_ref in self._core_defs_invalid_for_json_schema: 2339 ↛ 2340line 2339 didn't jump to line 2340 because the condition on line 2339 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2340 raise self._core_defs_invalid_for_json_schema[defs_ref] 

2341 _add_json_refs(self.definitions[defs_ref]) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2342 except KeyError: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2343 if not json_ref.startswith(('http://', 'https://')): 2343 ↛ 2344line 2343 didn't jump to line 2344 because the condition on line 2343 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2344 raise 

2345 

2346 for k, v in schema.items(): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2347 if k == 'examples' and isinstance(v, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2348 # Skip examples that may contain arbitrary values and references 

2349 # (see the comment in `_get_all_json_refs` for more details). 

2350 continue 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2351 _add_json_refs(v) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2352 elif isinstance(schema, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2353 for v in schema: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2354 _add_json_refs(v) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2355 

2356 _add_json_refs(json_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2357 return json_refs 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2358 

2359 def handle_invalid_for_json_schema(self, schema: CoreSchemaOrField, error_info: str) -> JsonSchemaValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2360 raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2361 

2362 def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2363 """This method simply emits PydanticJsonSchemaWarnings based on handling in the `warning_message` method.""" 

2364 message = self.render_warning_message(kind, detail) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2365 if message is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2366 warnings.warn(message, PydanticJsonSchemaWarning) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2367 

2368 def render_warning_message(self, kind: JsonSchemaWarningKind, detail: str) -> str | None: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2369 """This method is responsible for ignoring warnings as desired, and for formatting the warning messages. 

2370 

2371 You can override the value of `ignored_warning_kinds` in a subclass of GenerateJsonSchema 

2372 to modify what warnings are generated. If you want more control, you can override this method; 

2373 just return None in situations where you don't want warnings to be emitted. 

2374 

2375 Args: 

2376 kind: The kind of warning to render. It can be one of the following: 

2377 

2378 - 'skipped-choice': A choice field was skipped because it had no valid choices. 

2379 - 'non-serializable-default': A default value was skipped because it was not JSON-serializable. 

2380 detail: A string with additional details about the warning. 

2381 

2382 Returns: 

2383 The formatted warning message, or `None` if no warning should be emitted. 

2384 """ 

2385 if kind in self.ignored_warning_kinds: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2386 return None 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2387 return f'{detail} [{kind}]' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2388 

2389 def _build_definitions_remapping(self) -> _DefinitionsRemapping: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2390 defs_to_json: dict[DefsRef, JsonRef] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2391 for defs_refs in self._prioritized_defsref_choices.values(): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2392 for defs_ref in defs_refs: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2393 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2394 defs_to_json[defs_ref] = json_ref 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2395 

2396 return _DefinitionsRemapping.from_prioritized_choices( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2397 self._prioritized_defsref_choices, defs_to_json, self.definitions 

2398 ) 

2399 

2400 def _garbage_collect_definitions(self, schema: JsonSchemaValue) -> None: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2401 visited_defs_refs: set[DefsRef] = set() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2402 unvisited_json_refs = _get_all_json_refs(schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2403 while unvisited_json_refs: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2404 next_json_ref = unvisited_json_refs.pop() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2405 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2406 next_defs_ref = self.json_to_defs_refs[next_json_ref] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2407 if next_defs_ref in visited_defs_refs: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2408 continue 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2409 visited_defs_refs.add(next_defs_ref) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2410 unvisited_json_refs.update(_get_all_json_refs(self.definitions[next_defs_ref])) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2411 except KeyError: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2412 if not next_json_ref.startswith(('http://', 'https://')): 2412 ↛ 2413line 2412 didn't jump to line 2413 because the condition on line 2412 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2413 raise 

2414 

2415 self.definitions = {k: v for k, v in self.definitions.items() if k in visited_defs_refs} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2416 

2417 

2418# ##### Start JSON Schema Generation Functions ##### 

2419 

2420 

2421def model_json_schema( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2422 cls: type[BaseModel] | type[PydanticDataclass], 

2423 by_alias: bool = True, 

2424 ref_template: str = DEFAULT_REF_TEMPLATE, 

2425 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2426 mode: JsonSchemaMode = 'validation', 

2427) -> dict[str, Any]: 

2428 """Utility function to generate a JSON Schema for a model. 

2429 

2430 Args: 

2431 cls: The model class to generate a JSON Schema for. 

2432 by_alias: If `True` (the default), fields will be serialized according to their alias. 

2433 If `False`, fields will be serialized according to their attribute name. 

2434 ref_template: The template to use for generating JSON Schema references. 

2435 schema_generator: The class to use for generating the JSON Schema. 

2436 mode: The mode to use for generating the JSON Schema. It can be one of the following: 

2437 

2438 - 'validation': Generate a JSON Schema for validating data. 

2439 - 'serialization': Generate a JSON Schema for serializing data. 

2440 

2441 Returns: 

2442 The generated JSON Schema. 

2443 """ 

2444 from .main import BaseModel 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2445 

2446 schema_generator_instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2447 

2448 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2449 cls.__pydantic_core_schema__.rebuild() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2450 

2451 if cls is BaseModel: 2451 ↛ 2452line 2451 didn't jump to line 2452 because the condition on line 2451 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2452 raise AttributeError('model_json_schema() must be called on a subclass of BaseModel, not BaseModel itself.') 

2453 

2454 assert not isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2455 return schema_generator_instance.generate(cls.__pydantic_core_schema__, mode=mode) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2456 

2457 

2458def models_json_schema( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2459 models: Sequence[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode]], 

2460 *, 

2461 by_alias: bool = True, 

2462 title: str | None = None, 

2463 description: str | None = None, 

2464 ref_template: str = DEFAULT_REF_TEMPLATE, 

2465 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2466) -> tuple[dict[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: 

2467 """Utility function to generate a JSON Schema for multiple models. 

2468 

2469 Args: 

2470 models: A sequence of tuples of the form (model, mode). 

2471 by_alias: Whether field aliases should be used as keys in the generated JSON Schema. 

2472 title: The title of the generated JSON Schema. 

2473 description: The description of the generated JSON Schema. 

2474 ref_template: The reference template to use for generating JSON Schema references. 

2475 schema_generator: The schema generator to use for generating the JSON Schema. 

2476 

2477 Returns: 

2478 A tuple where: 

2479 - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and 

2480 whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have 

2481 JsonRef references to definitions that are defined in the second returned element.) 

2482 - The second element is a JSON schema containing all definitions referenced in the first returned 

2483 element, along with the optional title and description keys. 

2484 """ 

2485 for cls, _ in models: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2486 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 2486 ↛ 2487line 2486 didn't jump to line 2487 because the condition on line 2486 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2487 cls.__pydantic_core_schema__.rebuild() 

2488 

2489 instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2490 inputs: list[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode, CoreSchema]] = [ 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2491 (m, mode, m.__pydantic_core_schema__) for m, mode in models 

2492 ] 

2493 json_schemas_map, definitions = instance.generate_definitions(inputs) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2494 

2495 json_schema: dict[str, Any] = {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2496 if definitions: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2497 json_schema['$defs'] = definitions 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2498 if title: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2499 json_schema['title'] = title 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2500 if description: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2501 json_schema['description'] = description 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

2502 

2503 return json_schemas_map, json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2504 

2505 

2506# ##### End JSON Schema Generation Functions ##### 

2507 

2508 

2509_HashableJsonValue: TypeAlias = Union[ 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2510 int, float, str, bool, None, tuple['_HashableJsonValue', ...], tuple[tuple[str, '_HashableJsonValue'], ...] 

2511] 

2512 

2513 

2514def _deduplicate_schemas(schemas: Iterable[JsonDict]) -> list[JsonDict]: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2515 return list({_make_json_hashable(schema): schema for schema in schemas}.values()) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2516 

2517 

2518def _make_json_hashable(value: JsonValue) -> _HashableJsonValue: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2519 if isinstance(value, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2520 return tuple(sorted((k, _make_json_hashable(v)) for k, v in value.items())) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2521 elif isinstance(value, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2522 return tuple(_make_json_hashable(v) for v in value) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2523 else: 

2524 return value 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2525 

2526 

2527@dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2528class WithJsonSchema: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2529 """!!! abstract "Usage Documentation" 

2530 [`WithJsonSchema` Annotation](../concepts/json_schema.md#withjsonschema-annotation) 

2531 

2532 Add this as an annotation on a field to override the (base) JSON schema that would be generated for that field. 

2533 This provides a way to set a JSON schema for types that would otherwise raise errors when producing a JSON schema, 

2534 such as Callable, or types that have an is-instance core schema, without needing to go so far as creating a 

2535 custom subclass of pydantic.json_schema.GenerateJsonSchema. 

2536 Note that any _modifications_ to the schema that would normally be made (such as setting the title for model fields) 

2537 will still be performed. 

2538 

2539 If `mode` is set this will only apply to that schema generation mode, allowing you 

2540 to set different json schemas for validation and serialization. 

2541 """ 

2542 

2543 json_schema: JsonSchemaValue | None 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2544 mode: Literal['validation', 'serialization'] | None = None 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2545 

2546 def __get_pydantic_json_schema__( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2547 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2548 ) -> JsonSchemaValue: 

2549 mode = self.mode or handler.mode 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2550 if mode != handler.mode: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2551 return handler(core_schema) 1zbefgAIcklmB

2552 if self.json_schema is None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2553 # This exception is handled in pydantic.json_schema.GenerateJsonSchema._named_required_fields_schema 

2554 raise PydanticOmit 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2555 else: 

2556 return self.json_schema.copy() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2557 

2558 def __hash__(self) -> int: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2559 return hash(type(self.mode)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2560 

2561 

2562class Examples: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2563 """Add examples to a JSON schema. 

2564 

2565 If the JSON Schema already contains examples, the provided examples 

2566 will be appended. 

2567 

2568 If `mode` is set this will only apply to that schema generation mode, 

2569 allowing you to add different examples for validation and serialization. 

2570 """ 

2571 

2572 @overload 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2573 @deprecated('Using a dict for `examples` is deprecated since v2.9 and will be removed in v3.0. Use a list instead.') 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2574 def __init__( 1zCbdenfogpADOJKhiqrstuvFGMPILcjkwlxmyBHN

2575 self, examples: dict[str, Any], mode: Literal['validation', 'serialization'] | None = None 1bdenfogpEahiqrstuvPcjkwlxmy

2576 ) -> None: ... 1fogpEastuvPlxmy

2577 

2578 @overload 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2579 def __init__(self, examples: list[Any], mode: Literal['validation', 'serialization'] | None = None) -> None: ... 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2580 

2581 def __init__( 1zCbdenfogpADOJKhiqrstuvFGMPILcjkwlxmyBHN

2582 self, examples: dict[str, Any] | list[Any], mode: Literal['validation', 'serialization'] | None = None 

2583 ) -> None: 

2584 if isinstance(examples, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2585 warnings.warn( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2586 'Using a dict for `examples` is deprecated, use a list instead.', 

2587 PydanticDeprecatedSince29, 

2588 stacklevel=2, 

2589 ) 

2590 self.examples = examples 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2591 self.mode = mode 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2592 

2593 def __get_pydantic_json_schema__( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2594 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2595 ) -> JsonSchemaValue: 

2596 mode = self.mode or handler.mode 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2597 json_schema = handler(core_schema) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2598 if mode != handler.mode: 2598 ↛ 2599line 2598 didn't jump to line 2599 because the condition on line 2598 was never true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2599 return json_schema 

2600 examples = json_schema.get('examples') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2601 if examples is None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2602 json_schema['examples'] = to_jsonable_python(self.examples) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2603 if isinstance(examples, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2604 if isinstance(self.examples, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2605 warnings.warn( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2606 'Updating existing JSON Schema examples of type dict with examples of type list. ' 

2607 'Only the existing examples values will be retained. Note that dict support for ' 

2608 'examples is deprecated and will be removed in v3.0.', 

2609 UserWarning, 

2610 ) 

2611 json_schema['examples'] = to_jsonable_python( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2612 [ex for value in examples.values() for ex in value] + self.examples 

2613 ) 

2614 else: 

2615 json_schema['examples'] = to_jsonable_python({**examples, **self.examples}) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2616 if isinstance(examples, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2617 if isinstance(self.examples, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2618 json_schema['examples'] = to_jsonable_python(examples + self.examples) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2619 elif isinstance(self.examples, dict): 2619 ↛ 2630line 2619 didn't jump to line 2630 because the condition on line 2619 was always true1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2620 warnings.warn( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2621 'Updating existing JSON Schema examples of type list with examples of type dict. ' 

2622 'Only the examples values will be retained. Note that dict support for ' 

2623 'examples is deprecated and will be removed in v3.0.', 

2624 UserWarning, 

2625 ) 

2626 json_schema['examples'] = to_jsonable_python( 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2627 examples + [ex for value in self.examples.values() for ex in value] 

2628 ) 

2629 

2630 return json_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2631 

2632 def __hash__(self) -> int: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2633 return hash(type(self.mode)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2634 

2635 

2636def _get_all_json_refs(item: Any) -> set[JsonRef]: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2637 """Get all the definitions references from a JSON schema.""" 

2638 refs: set[JsonRef] = set() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2639 stack = [item] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2640 

2641 while stack: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2642 current = stack.pop() 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2643 if isinstance(current, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2644 for key, value in current.items(): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2645 if key == 'examples' and isinstance(value, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2646 # Skip examples that may contain arbitrary values and references 

2647 # (e.g. `{"examples": [{"$ref": "..."}]}`). Note: checking for value 

2648 # of type list is necessary to avoid skipping valid portions of the schema, 

2649 # for instance when "examples" is used as a property key. A more robust solution 

2650 # could be found, but would require more advanced JSON Schema parsing logic. 

2651 continue 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2652 if key == '$ref' and isinstance(value, str): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2653 refs.add(JsonRef(value)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2654 elif isinstance(value, dict): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2655 stack.append(value) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2656 elif isinstance(value, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2657 stack.extend(value) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2658 elif isinstance(current, list): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2659 stack.extend(current) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2660 

2661 return refs 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2662 

2663 

2664AnyType = TypeVar('AnyType') 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2665 

2666if TYPE_CHECKING: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2667 SkipJsonSchema = Annotated[AnyType, ...] 

2668else: 

2669 

2670 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2671 class SkipJsonSchema: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2672 """!!! abstract "Usage Documentation" 

2673 [`SkipJsonSchema` Annotation](../concepts/json_schema.md#skipjsonschema-annotation) 

2674 

2675 Add this as an annotation on a field to skip generating a JSON schema for that field. 

2676 

2677 Example: 

2678 ```python 

2679 from pprint import pprint 

2680 from typing import Union 

2681 

2682 from pydantic import BaseModel 

2683 from pydantic.json_schema import SkipJsonSchema 

2684 

2685 class Model(BaseModel): 

2686 a: Union[int, None] = None # (1)! 

2687 b: Union[int, SkipJsonSchema[None]] = None # (2)! 

2688 c: SkipJsonSchema[Union[int, None]] = None # (3)! 

2689 

2690 pprint(Model.model_json_schema()) 

2691 ''' 

2692 { 

2693 'properties': { 

2694 'a': { 

2695 'anyOf': [ 

2696 {'type': 'integer'}, 

2697 {'type': 'null'} 

2698 ], 

2699 'default': None, 

2700 'title': 'A' 

2701 }, 

2702 'b': { 

2703 'default': None, 

2704 'title': 'B', 

2705 'type': 'integer' 

2706 } 

2707 }, 

2708 'title': 'Model', 

2709 'type': 'object' 

2710 } 

2711 ''' 

2712 ``` 

2713 

2714 1. The integer and null types are both included in the schema for `a`. 

2715 2. The integer type is the only type included in the schema for `b`. 

2716 3. The entirety of the `c` field is omitted from the schema. 

2717 """ 

2718 

2719 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2720 return Annotated[item, cls()] 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2721 

2722 def __get_pydantic_json_schema__( 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2723 self, core_schema: CoreSchema, handler: GetJsonSchemaHandler 

2724 ) -> JsonSchemaValue: 

2725 raise PydanticOmit 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2726 

2727 def __hash__(self) -> int: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2728 return hash(type(self)) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2729 

2730 

2731def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2732 if cls is not None: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2733 try: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2734 return _decorators.get_attribute_from_bases(cls, '__pydantic_config__') 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2735 except AttributeError: 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBH

2736 pass 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBH

2737 return {} 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2738 

2739 

2740def _get_ser_schema_for_default_value(schema: CoreSchema) -> core_schema.PlainSerializerFunctionSerSchema | None: 1zCbdenfogpADOEaJKhiqrstuvFGMPILcjkwlxmyBHN

2741 """Get a `'function-plain'` serialization schema that can be used to serialize a default value. 

2742 

2743 This takes into account having the serialization schema nested under validation schema(s). 

2744 """ 

2745 if ( 1zCbdenEaJKhiqrILcjkw

2746 (ser_schema := schema.get('serialization')) 

2747 and ser_schema['type'] == 'function-plain' 

2748 and not ser_schema.get('info_arg') 

2749 ): 

2750 return ser_schema 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2751 if _core_utils.is_function_with_inner_schema(schema): 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN

2752 return _get_ser_schema_for_default_value(schema['schema']) 1zCbdenfogpADOEaJKhiqrstuvFGMILcjkwlxmyBHN