Coverage for pydantic/json_schema.py: 94.32%

1065 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-13 19:35 +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 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

13 

14import dataclasses 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

15import inspect 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

16import math 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

17import os 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

18import re 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

19import warnings 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

20from collections import Counter, defaultdict 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

22from copy import deepcopy 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

23from enum import Enum 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

24from re import Pattern 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

25from typing import ( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

40from pydantic_core.core_schema import ComputedField 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

42 

43from pydantic.warnings import PydanticDeprecatedSince26, PydanticDeprecatedSince29 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

44 

45from ._internal import ( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

46 _config, 

47 _core_metadata, 

48 _core_utils, 

49 _decorators, 

50 _internal_dataclass, 

51 _mock_val_ser, 

52 _schema_generation_shared, 

53 _typing_extra, 

54) 

55from .annotated_handlers import GetJsonSchemaHandler 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

56from .config import JsonDict, JsonValue 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

58 

59if TYPE_CHECKING: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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] 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

68""" 1akgwblcmhnoxypqrsKLGHIJdtizeufv

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] 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

75""" 1akgwblcmhnoxypqrsKLGHIJdtizeufv

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'] 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

80""" 1akgwblcmhnoxypqrsKLGHIJdtizeufv

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'} 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

90 

91 

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

93""" 1akgwblcmhnoxypqrsKLGHIJdtizeufv

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): 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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 

109# ##### JSON Schema Generation ##### 

110DEFAULT_REF_TEMPLATE = '#/$defs/{model}' 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

111"""The default format string used to generate reference names.""" 1akgwblcmhnoxypqrsKLGHIJdtizeufv

112 

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

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

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

116CoreRef = NewType('CoreRef', str) 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

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

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

120DefsRef = NewType('DefsRef', str) 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

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

123JsonRef = NewType('JsonRef', str) 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

124 

125CoreModeRef = tuple[CoreRef, JsonSchemaMode] 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

126JsonSchemaKeyT = TypeVar('JsonSchemaKeyT', bound=Hashable) 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

127 

128 

129@dataclasses.dataclass(**_internal_dataclass.slots_true) 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

130class _DefinitionsRemapping: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

131 defs_remapping: dict[DefsRef, DefsRef] 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

132 json_remapping: dict[JsonRef, JsonRef] 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

133 

134 @staticmethod 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

135 def from_prioritized_choices( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

137 defs_to_json: dict[DefsRef, JsonRef], 

138 definitions: dict[DefsRef, JsonSchemaValue], 

139 ) -> _DefinitionsRemapping: 

140 """ 

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

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

143 """ 

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

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

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

147 # the inner definitions. 

148 copied_definitions = deepcopy(definitions) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

149 definitions_schema = {'$defs': copied_definitions} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

152 schemas_for_alternatives: dict[DefsRef, list[JsonSchemaValue]] = defaultdict(list) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

153 for defs_ref in copied_definitions: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

154 alternatives = prioritized_choices[defs_ref] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

155 for alternative in alternatives: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

156 schemas_for_alternatives[alternative].append(copied_definitions[defs_ref]) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

157 

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

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

160 for defs_ref in schemas_for_alternatives: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

161 schemas_for_alternatives[defs_ref] = _deduplicate_schemas(schemas_for_alternatives[defs_ref]) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

162 

163 # Build the remapping 

164 defs_remapping: dict[DefsRef, DefsRef] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

165 json_remapping: dict[JsonRef, JsonRef] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

166 for original_defs_ref in definitions: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

167 alternatives = prioritized_choices[original_defs_ref] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

169 remapped_defs_ref = next(x for x in alternatives if len(schemas_for_alternatives[x]) == 1) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

170 defs_remapping[original_defs_ref] = remapped_defs_ref 1jBakgwblcmChDEnoxypqrsAFdtizeufv

171 json_remapping[defs_to_json[original_defs_ref]] = defs_to_json[remapped_defs_ref] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

172 remapping = _DefinitionsRemapping(defs_remapping, json_remapping) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

173 new_definitions_schema = remapping.remap_json_schema({'$defs': copied_definitions}) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

174 if definitions_schema == new_definitions_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

175 # We've reached the fixed point 

176 return remapping 1jBakgwblcmChDEnoxypqrsAFdtizeufv

177 definitions_schema = new_definitions_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

178 

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

180 

181 def remap_defs_ref(self, ref: DefsRef) -> DefsRef: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

182 return self.defs_remapping.get(ref, ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

183 

184 def remap_json_ref(self, ref: JsonRef) -> JsonRef: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

185 return self.json_remapping.get(ref, ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

186 

187 def remap_json_schema(self, schema: Any) -> Any: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

188 """ 

189 Recursively update the JSON schema replacing all $refs 

190 """ 

191 if isinstance(schema, str): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

193 return self.remap_json_ref(JsonRef(schema)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

194 elif isinstance(schema, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

195 return [self.remap_json_schema(item) for item in schema] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

196 elif isinstance(schema, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

197 for key, value in schema.items(): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

198 if key == '$ref' and isinstance(value, str): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

199 schema['$ref'] = self.remap_json_ref(JsonRef(value)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

200 elif key == '$defs': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

201 schema['$defs'] = { 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

204 } 

205 else: 

206 schema[key] = self.remap_json_schema(value) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

207 return schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

208 

209 

210class GenerateJsonSchema: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

211 """!!! abstract "Usage Documentation" 

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

213 

214 A class for generating JSON schemas. 

215 

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

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

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

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

220 

221 Attributes: 

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

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

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

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

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

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

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

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

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

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

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

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

234 definitions: Definitions in the schema. 

235 

236 Args: 

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

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

239 

240 Raises: 

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

242 """ 

243 

244 schema_dialect = 'https://json-schema.org/draft/2020-12/schema' 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

245 

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

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

248 ignored_warning_kinds: set[JsonSchemaWarningKind] = {'skipped-choice'} 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

249 

250 def __init__(self, by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE): 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

251 self.by_alias = by_alias 1jBakgwblcmChDEnoxypqrsAFdtizeufv

252 self.ref_template = ref_template 1jBakgwblcmChDEnoxypqrsAFdtizeufv

253 

254 self.core_to_json_refs: dict[CoreModeRef, JsonRef] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

255 self.core_to_defs_refs: dict[CoreModeRef, DefsRef] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

256 self.defs_to_core_refs: dict[DefsRef, CoreModeRef] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

257 self.json_to_defs_refs: dict[JsonRef, DefsRef] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

258 

259 self.definitions: dict[DefsRef, JsonSchemaValue] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

260 self._config_wrapper_stack = _config.ConfigWrapperStack(_config.ConfigWrapper({})) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

261 

262 self._mode: JsonSchemaMode = 'validation' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

263 

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

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

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

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

268 self._prioritized_defsref_choices: dict[DefsRef, list[DefsRef]] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

269 self._collision_counter: dict[str, int] = defaultdict(int) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

270 self._collision_index: dict[str, int] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

271 

272 self._schema_type_to_method = self.build_schema_type_to_method() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

273 

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

275 # so that they are available schemas that reference them 

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

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

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

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

280 self._core_defs_invalid_for_json_schema: dict[DefsRef, PydanticInvalidForJsonSchema] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

281 

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

283 # of a single instance of a schema generator 

284 self._used = False 1jBakgwblcmChDEnoxypqrsAFdtizeufv

285 

286 @property 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

287 def _config(self) -> _config.ConfigWrapper: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

288 return self._config_wrapper_stack.tail 1jBakgwblcmChDEnoxypqrsAFdtizeufv

289 

290 @property 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

291 def mode(self) -> JsonSchemaMode: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

292 if self._config.json_schema_mode_override is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

293 return self._config.json_schema_mode_override 1jBakgwblcmChDEnoxypqrsAFdtizeufv

294 else: 

295 return self._mode 1jBakgwblcmChDEnoxypqrsAFdtizeufv

296 

297 def build_schema_type_to_method( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

298 self, 

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

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

301 

302 Returns: 

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

304 

305 Raises: 

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

307 """ 

308 mapping: dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

309 core_schema_types: list[CoreSchemaOrFieldType] = _typing_extra.literal_values( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

310 CoreSchemaOrFieldType # type: ignore 

311 ) 

312 for key in core_schema_types: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

314 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

315 mapping[key] = getattr(self, method_name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

316 except AttributeError as e: # pragma: no cover 

317 if os.getenv('PYDANTIC_PRIVATE_ALLOW_UNHANDLED_SCHEMA_TYPES'): 

318 continue 

319 raise TypeError( 

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

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

322 ) from e 

323 return mapping 1jBakgwblcmChDEnoxypqrsAFdtizeufv

324 

325 def generate_definitions( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

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

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

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

330 

331 Args: 

332 inputs: A sequence of tuples, where: 

333 

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

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

336 - The third element is a core schema. 

337 

338 Returns: 

339 A tuple where: 

340 

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

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

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

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

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

346 

347 Raises: 

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

349 """ 

350 if self._used: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

351 raise PydanticUserError( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

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

355 ) 

356 

357 for _, mode, schema in inputs: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

358 self._mode = mode 1jBakgwblcmChDEnoxypqrsAFdtizeufv

359 self.generate_inner(schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

360 

361 definitions_remapping = self._build_definitions_remapping() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

362 

363 json_schemas_map: dict[tuple[JsonSchemaKeyT, JsonSchemaMode], DefsRef] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

364 for key, mode, schema in inputs: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

365 self._mode = mode 1jBakgwblcmChDEnoxypqrsAFdtizeufv

366 json_schema = self.generate_inner(schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

367 json_schemas_map[(key, mode)] = definitions_remapping.remap_json_schema(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

368 

369 json_schema = {'$defs': self.definitions} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

370 json_schema = definitions_remapping.remap_json_schema(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

371 self._used = True 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

373 

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

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

376 

377 Args: 

378 schema: A Pydantic model. 

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

380 

381 Returns: 

382 A JSON schema representing the specified schema. 

383 

384 Raises: 

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

386 """ 

387 self._mode = mode 1jBakgwblcmChDEnoxypqrsAFdtizeufv

388 if self._used: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

389 raise PydanticUserError( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

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

393 ) 

394 

395 json_schema: JsonSchemaValue = self.generate_inner(schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

396 json_ref_counts = self.get_json_ref_counts(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

397 

398 ref = cast(JsonRef, json_schema.get('$ref')) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

399 while ref is not None: # may need to unpack multiple levels 1jBakgwblcmChDEnoxypqrsAFdtizeufv

400 ref_json_schema = self.get_schema_from_definitions(ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

403 json_schema = ref_json_schema.copy() # copy to prevent recursive dict reference 1jBakgwblcmChDEnoxypqrsAFdtizeufv

404 json_ref_counts[ref] -= 1 1jBakgwblcmChDEnoxypqrsAFdtizeufv

405 ref = cast(JsonRef, json_schema.get('$ref')) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

406 ref = None 1jBakgwblcmChDEnoxypqrsAFdtizeufv

407 

408 self._garbage_collect_definitions(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

409 definitions_remapping = self._build_definitions_remapping() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

410 

411 if self.definitions: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

412 json_schema['$defs'] = self.definitions 1jBakgwblcmChDEnoxypqrsAFdtizeufv

413 

414 json_schema = definitions_remapping.remap_json_schema(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

415 

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

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

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

419 

420 self._used = True 1jBakgwblcmChDEnoxypqrsAFdtizeufv

421 return self.sort(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

422 

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

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

425 

426 Args: 

427 schema: The given core schema. 

428 

429 Returns: 

430 The generated JSON schema. 

431 

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

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

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

435 """ 

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

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

438 # on types that should have different JSON schemas 

439 if 'ref' in schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

441 core_mode_ref = (core_ref, self.mode) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

442 if core_mode_ref in self.core_to_defs_refs and self.core_to_defs_refs[core_mode_ref] in self.definitions: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

443 return {'$ref': self.core_to_json_refs[core_mode_ref]} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

444 

445 def populate_defs(core_schema: CoreSchema, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

446 if 'ref' in core_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

448 defs_ref, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

449 json_ref = JsonRef(ref_json_schema['$ref']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

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

453 if json_schema.get('$ref', None) != json_ref: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

454 self.definitions[defs_ref] = json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

455 self._core_defs_invalid_for_json_schema.pop(defs_ref, None) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

456 json_schema = ref_json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

457 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

458 

459 def handler_func(schema_or_field: CoreSchemaOrField) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

461 

462 Args: 

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

464 

465 Returns: 

466 The generated JSON schema. 

467 

468 Raises: 

469 TypeError: If an unexpected schema type is encountered. 

470 """ 

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

472 json_schema: JsonSchemaValue | None = None 1jBakgwblcmChDEnoxypqrsAFdtizeufv

473 if self.mode == 'serialization' and 'serialization' in schema_or_field: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

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

477 ser_schema = schema_or_field['serialization'] # type: ignore 1jBakgwblcmChDEnoxypqrsAFdtizeufv

478 json_schema = self.ser_schema(ser_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

479 

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

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

482 if ( 1jBCh

483 json_schema is not None 

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

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

486 ): 

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

488 if json_schema is None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

490 generate_for_schema_type = self._schema_type_to_method[schema_or_field['type']] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

491 json_schema = generate_for_schema_type(schema_or_field) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

492 else: 

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

494 if _core_utils.is_core_schema(schema_or_field): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

495 json_schema = populate_defs(schema_or_field, json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

496 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

497 

498 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, handler_func) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

499 

500 metadata = cast(_core_metadata.CoreMetadata, schema.get('metadata', {})) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

501 

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

503 

504 if js_updates := metadata.get('pydantic_js_updates'): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

505 

506 def js_updates_handler_func( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

507 schema_or_field: CoreSchemaOrField, 

508 current_handler: GetJsonSchemaHandler = current_handler, 

509 ) -> JsonSchemaValue: 

510 json_schema = {**current_handler(schema_or_field), **js_updates} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

511 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

512 

513 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, js_updates_handler_func) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

514 

515 if js_extra := metadata.get('pydantic_js_extra'): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

516 

517 def js_extra_handler_func( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

518 schema_or_field: CoreSchemaOrField, 

519 current_handler: GetJsonSchemaHandler = current_handler, 

520 ) -> JsonSchemaValue: 

521 json_schema = current_handler(schema_or_field) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

522 if isinstance(js_extra, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

523 json_schema.update(to_jsonable_python(js_extra)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

526 js_extra(json_schema) # type: ignore 1jBakgwblcmChDEnoxypqrsAFdtizeufv

527 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

528 

529 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, js_extra_handler_func) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

530 

531 for js_modify_function in metadata.get('pydantic_js_functions', ()): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

532 

533 def new_handler_func( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

534 schema_or_field: CoreSchemaOrField, 

535 current_handler: GetJsonSchemaHandler = current_handler, 

536 js_modify_function: GetJsonSchemaFunction = js_modify_function, 

537 ) -> JsonSchemaValue: 

538 json_schema = js_modify_function(schema_or_field, current_handler) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

539 if _core_utils.is_core_schema(schema_or_field): 539 ↛ 541line 539 didn't jump to line 541 because the condition on line 539 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

540 json_schema = populate_defs(schema_or_field, json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

541 original_schema = current_handler.resolve_ref_schema(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

542 ref = json_schema.pop('$ref', None) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

543 if ref and json_schema: 543 ↛ 544line 543 didn't jump to line 544 because the condition on line 543 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

544 original_schema.update(json_schema) 

545 return original_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

546 

547 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

548 

549 for js_modify_function in metadata.get('pydantic_js_annotation_functions', ()): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

550 

551 def new_handler_func( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

552 schema_or_field: CoreSchemaOrField, 

553 current_handler: GetJsonSchemaHandler = current_handler, 

554 js_modify_function: GetJsonSchemaFunction = js_modify_function, 

555 ) -> JsonSchemaValue: 

556 json_schema = js_modify_function(schema_or_field, current_handler) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

557 if _core_utils.is_core_schema(schema_or_field): 557 ↛ 559line 557 didn't jump to line 559 because the condition on line 557 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

558 json_schema = populate_defs(schema_or_field, json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

559 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

560 

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

562 

563 json_schema = current_handler(schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

564 if _core_utils.is_core_schema(schema): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

565 json_schema = populate_defs(schema, json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

566 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

567 

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

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] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

575 keys = value.keys() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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 true1jBakgwblcmChDEnoxypqrsAFdtizeufv

577 keys = sorted(keys) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

578 for key in keys: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

580 return sorted_dict 1jBakgwblcmChDEnoxypqrsAFdtizeufv

581 

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

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

584 if isinstance(value, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

586 keys = value.keys() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

588 keys = sorted(keys) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

589 for key in keys: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

591 return sorted_dict 1jBakgwblcmChDEnoxypqrsAFdtizeufv

592 elif isinstance(value, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

594 for item in value: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

596 return sorted_list 1jBakgwblcmChDEnoxypqrsAFdtizeufv

597 else: 

598 return value 1jBakgwblcmChDEnoxypqrsAFdtizeufv

599 

600 # ### Schema generation methods 

601 

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

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: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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 {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

617 

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

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'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

628 

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

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'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

639 

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

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'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

652 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

653 

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

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'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

666 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

667 

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

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 json_schema = self.str_schema(core_schema.str_schema()) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

678 if self.mode == 'validation': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

679 multiple_of = schema.get('multiple_of') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

680 le = schema.get('le') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

681 ge = schema.get('ge') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

682 lt = schema.get('lt') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

683 gt = schema.get('gt') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

684 json_schema = { 1jBakgwblcmChDEnoxypqrsAFdtizeufv

685 'anyOf': [ 

686 self.float_schema( 

687 core_schema.float_schema( 

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

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

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

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

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

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

694 ) 

695 ), 

696 json_schema, 

697 ], 

698 } 

699 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

700 

701 def str_schema(self, schema: core_schema.StringSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

703 

704 Args: 

705 schema: The core schema. 

706 

707 Returns: 

708 The generated JSON schema. 

709 """ 

710 json_schema = {'type': 'string'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

711 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

712 if isinstance(json_schema.get('pattern'), Pattern): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

714 json_schema['pattern'] = json_schema.get('pattern').pattern # type: ignore 1jBakgwblcmChDEnoxypqrsAFdtizeufv

715 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

716 

717 def bytes_schema(self, schema: core_schema.BytesSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

719 

720 Args: 

721 schema: The core schema. 

722 

723 Returns: 

724 The generated JSON schema. 

725 """ 

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

727 self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

728 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

729 

730 def date_schema(self, schema: core_schema.DateSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

732 

733 Args: 

734 schema: The core schema. 

735 

736 Returns: 

737 The generated JSON schema. 

738 """ 

739 return {'type': 'string', 'format': 'date'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

740 

741 def time_schema(self, schema: core_schema.TimeSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

743 

744 Args: 

745 schema: The core schema. 

746 

747 Returns: 

748 The generated JSON schema. 

749 """ 

750 return {'type': 'string', 'format': 'time'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

751 

752 def datetime_schema(self, schema: core_schema.DatetimeSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

754 

755 Args: 

756 schema: The core schema. 

757 

758 Returns: 

759 The generated JSON schema. 

760 """ 

761 return {'type': 'string', 'format': 'date-time'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

762 

763 def timedelta_schema(self, schema: core_schema.TimedeltaSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

765 

766 Args: 

767 schema: The core schema. 

768 

769 Returns: 

770 The generated JSON schema. 

771 """ 

772 if self._config.ser_json_timedelta == 'float': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

773 return {'type': 'number'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

774 return {'type': 'string', 'format': 'duration'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

775 

776 def literal_schema(self, schema: core_schema.LiteralSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

778 

779 Args: 

780 schema: The core schema. 

781 

782 Returns: 

783 The generated JSON schema. 

784 """ 

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

786 

787 result: dict[str, Any] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

788 if len(expected) == 1: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

789 result['const'] = expected[0] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

790 else: 

791 result['enum'] = expected 1jBakgwblcmChDEnoxypqrsAFdtizeufv

792 

793 types = {type(e) for e in expected} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

794 if types == {str}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

795 result['type'] = 'string' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

796 elif types == {int}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

797 result['type'] = 'integer' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

798 elif types == {float}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

799 result['type'] = 'number' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

800 elif types == {bool}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

801 result['type'] = 'boolean' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

802 elif types == {list}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

803 result['type'] = 'array' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

804 elif types == {type(None)}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

805 result['type'] = 'null' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

806 return result 1jBakgwblcmChDEnoxypqrsAFdtizeufv

807 

808 def enum_schema(self, schema: core_schema.EnumSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

810 

811 Args: 

812 schema: The core schema. 

813 

814 Returns: 

815 The generated JSON schema. 

816 """ 

817 enum_type = schema['cls'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

818 description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

819 if ( 1jBCh

820 description == 'An enumeration.' 

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

822 description = None 1jBakChDEnoAFdt

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

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

825 

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

827 

828 result['enum'] = expected 1jBakgwblcmChDEnoxypqrsAFdtizeufv

829 

830 types = {type(e) for e in expected} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

831 if isinstance(enum_type, str) or types == {str}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

832 result['type'] = 'string' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

833 elif isinstance(enum_type, int) or types == {int}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

834 result['type'] = 'integer' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

835 elif isinstance(enum_type, float) or types == {float}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

836 result['type'] = 'number' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

837 elif types == {bool}: 837 ↛ 838line 837 didn't jump to line 838 because the condition on line 837 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

838 result['type'] = 'boolean' 

839 elif types == {list}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

840 result['type'] = 'array' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

841 

842 return result 1jBakgwblcmChDEnoxypqrsAFdtizeufv

843 

844 def is_instance_schema(self, schema: core_schema.IsInstanceSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

846 

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

848 

849 Args: 

850 schema: The core schema. 

851 

852 Returns: 

853 The generated JSON schema. 

854 """ 

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

856 

857 def is_subclass_schema(self, schema: core_schema.IsSubclassSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

859 

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

861 

862 Args: 

863 schema: The core schema. 

864 

865 Returns: 

866 The generated JSON schema. 

867 """ 

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

869 return {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

870 

871 def callable_schema(self, schema: core_schema.CallableSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

873 

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

875 

876 Args: 

877 schema: The core schema. 

878 

879 Returns: 

880 The generated JSON schema. 

881 """ 

882 return self.handle_invalid_for_json_schema(schema, 'core_schema.CallableSchema') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

883 

884 def list_schema(self, schema: core_schema.ListSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

886 

887 Args: 

888 schema: The core schema. 

889 

890 Returns: 

891 The generated JSON schema. 

892 """ 

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

894 json_schema = {'type': 'array', 'items': items_schema} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

895 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

896 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

897 

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

899 @final 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

900 def tuple_positional_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

901 """Replaced by `tuple_schema`.""" 

902 warnings.warn( 

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

904 PydanticDeprecatedSince26, 

905 stacklevel=2, 

906 ) 

907 return self.tuple_schema(schema) 

908 

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

910 @final 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

911 def tuple_variable_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

912 """Replaced by `tuple_schema`.""" 

913 warnings.warn( 

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

915 PydanticDeprecatedSince26, 

916 stacklevel=2, 

917 ) 

918 return self.tuple_schema(schema) 

919 

920 def tuple_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

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

923 

924 Args: 

925 schema: The core schema. 

926 

927 Returns: 

928 The generated JSON schema. 

929 """ 

930 json_schema: JsonSchemaValue = {'type': 'array'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

931 if 'variadic_item_index' in schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

932 variadic_item_index = schema['variadic_item_index'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

933 if variadic_item_index > 0: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

934 json_schema['minItems'] = variadic_item_index 1jBakgwblcmChDEnoxypqrsAFdtizeufv

935 json_schema['prefixItems'] = [ 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

937 ] 

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

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

940 json_schema['items'] = self.generate_inner(schema['items_schema'][variadic_item_index]) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

941 else: 

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

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

944 # for now 

945 json_schema['items'] = True 

946 else: 

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

948 if prefixItems: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

949 json_schema['prefixItems'] = prefixItems 1jBakgwblcmChDEnoxypqrsAFdtizeufv

950 json_schema['minItems'] = len(prefixItems) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

951 json_schema['maxItems'] = len(prefixItems) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

952 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

953 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

954 

955 def set_schema(self, schema: core_schema.SetSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

957 

958 Args: 

959 schema: The core schema. 

960 

961 Returns: 

962 The generated JSON schema. 

963 """ 

964 return self._common_set_schema(schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

965 

966 def frozenset_schema(self, schema: core_schema.FrozenSetSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

968 

969 Args: 

970 schema: The core schema. 

971 

972 Returns: 

973 The generated JSON schema. 

974 """ 

975 return self._common_set_schema(schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

976 

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

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

979 json_schema = {'type': 'array', 'uniqueItems': True, 'items': items_schema} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

980 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

981 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

982 

983 def generator_schema(self, schema: core_schema.GeneratorSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

985 

986 Args: 

987 schema: The schema. 

988 

989 Returns: 

990 The generated JSON schema. 

991 """ 

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

993 json_schema = {'type': 'array', 'items': items_schema} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

995 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

996 

997 def dict_schema(self, schema: core_schema.DictSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

999 

1000 Args: 

1001 schema: The core schema. 

1002 

1003 Returns: 

1004 The generated JSON schema. 

1005 """ 

1006 json_schema: JsonSchemaValue = {'type': 'object'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1007 

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

1009 if '$ref' not in keys_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1010 keys_pattern = keys_schema.pop('pattern', None) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1012 keys_schema.pop('title', None) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1013 else: 

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

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

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

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

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

1019 keys_pattern = None 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1020 

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

1022 # don't give a title to additionalProperties: 

1023 values_schema.pop('title', None) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1024 

1025 if values_schema or keys_pattern is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1026 if keys_pattern is None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1027 json_schema['additionalProperties'] = values_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1028 else: 

1029 json_schema['patternProperties'] = {keys_pattern: values_schema} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1031 json_schema['additionalProperties'] = True 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1032 

1033 if ( 1jBCh

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

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

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

1037 or '$ref' in keys_schema 

1038 ): 

1039 keys_schema.pop('type', None) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1040 json_schema['propertyNames'] = keys_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1041 

1042 self.update_with_validations(json_schema, schema, self.ValidationsMapping.object) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1043 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1044 

1045 def function_before_schema(self, schema: core_schema.BeforeValidatorFunctionSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1047 

1048 Args: 

1049 schema: The core schema. 

1050 

1051 Returns: 

1052 The generated JSON schema. 

1053 """ 

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

1055 return self.generate_inner(input_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1056 

1057 return self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1058 

1059 def function_after_schema(self, schema: core_schema.AfterValidatorFunctionSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1061 

1062 Args: 

1063 schema: The core schema. 

1064 

1065 Returns: 

1066 The generated JSON schema. 

1067 """ 

1068 return self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1069 

1070 def function_plain_schema(self, schema: core_schema.PlainValidatorFunctionSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1072 

1073 Args: 

1074 schema: The core schema. 

1075 

1076 Returns: 

1077 The generated JSON schema. 

1078 """ 

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

1080 return self.generate_inner(input_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1081 

1082 return self.handle_invalid_for_json_schema( 

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

1084 ) 

1085 

1086 def function_wrap_schema(self, schema: core_schema.WrapValidatorFunctionSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1088 

1089 Args: 

1090 schema: The core schema. 

1091 

1092 Returns: 

1093 The generated JSON schema. 

1094 """ 

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

1096 return self.generate_inner(input_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1097 

1098 return self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1099 

1100 def default_schema(self, schema: core_schema.WithDefaultSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1102 

1103 Args: 

1104 schema: The core schema. 

1105 

1106 Returns: 

1107 The generated JSON schema. 

1108 """ 

1109 json_schema = self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1110 

1111 if 'default' not in schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1112 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1113 default = schema['default'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1114 # Note: if you want to include the value returned by the default_factory, 

1115 # override this method and replace the code above with: 

1116 # if 'default' in schema: 

1117 # default = schema['default'] 

1118 # elif 'default_factory' in schema: 

1119 # default = schema['default_factory']() 

1120 # else: 

1121 # return json_schema 

1122 

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

1124 # JSON Schemas viewed in serialization mode: 

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

1126 if ( 1jBChDEAF

1127 self.mode == 'serialization' 

1128 and (ser_schema := schema['schema'].get('serialization')) 

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

1130 and ser_schema.get('type') == 'function-plain' 

1131 and not ser_schema.get('info_arg') 

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

1133 ): 

1134 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1135 default = ser_func(default) # type: ignore 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1136 except Exception: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

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

1140 # this pattern for now. 

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

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

1143 self.emit_warning( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1144 'non-serializable-default', 

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

1146 ) 

1147 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1148 

1149 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1150 encoded_default = self.encode_default(default) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1151 except pydantic_core.PydanticSerializationError: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1152 self.emit_warning( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1153 'non-serializable-default', 

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

1155 ) 

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

1157 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1158 

1159 json_schema['default'] = encoded_default 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1160 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1161 

1162 def nullable_schema(self, schema: core_schema.NullableSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1164 

1165 Args: 

1166 schema: The core schema. 

1167 

1168 Returns: 

1169 The generated JSON schema. 

1170 """ 

1171 null_schema = {'type': 'null'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1172 inner_json_schema = self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1173 

1174 if inner_json_schema == null_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1175 return null_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1176 else: 

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

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

1179 return self.get_flattened_anyof([inner_json_schema, null_schema]) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1180 

1181 def union_schema(self, schema: core_schema.UnionSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1183 

1184 Args: 

1185 schema: The core schema. 

1186 

1187 Returns: 

1188 The generated JSON schema. 

1189 """ 

1190 generated: list[JsonSchemaValue] = [] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1191 

1192 choices = schema['choices'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1193 for choice in choices: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1195 choice_schema = choice[0] if isinstance(choice, tuple) else choice 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1196 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1197 generated.append(self.generate_inner(choice_schema)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1198 except PydanticOmit: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1199 continue 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1200 except PydanticInvalidForJsonSchema as exc: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1201 self.emit_warning('skipped-choice', exc.message) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1202 if len(generated) == 1: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1203 return generated[0] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1204 return self.get_flattened_anyof(generated) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1205 

1206 def tagged_union_schema(self, schema: core_schema.TaggedUnionSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

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

1209 the value. 

1210 

1211 Args: 

1212 schema: The core schema. 

1213 

1214 Returns: 

1215 The generated JSON schema. 

1216 """ 

1217 generated: dict[str, JsonSchemaValue] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1219 if isinstance(k, Enum): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1220 k = k.value 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1221 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

1224 generated[str(k)] = self.generate_inner(v).copy() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1225 except PydanticOmit: 

1226 continue 

1227 except PydanticInvalidForJsonSchema as exc: 

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

1229 

1230 one_of_choices = _deduplicate_schemas(generated.values()) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1231 json_schema: JsonSchemaValue = {'oneOf': one_of_choices} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1232 

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

1234 openapi_discriminator = self._extract_discriminator(schema, one_of_choices) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1235 if openapi_discriminator is not None: 1235 ↛ 1241line 1235 didn't jump to line 1241 because the condition on line 1235 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

1236 json_schema['discriminator'] = { 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1237 'propertyName': openapi_discriminator, 

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

1239 } 

1240 

1241 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1242 

1243 def _extract_discriminator( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1245 ) -> str | None: 

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

1247 schema.""" 

1248 openapi_discriminator: str | None = None 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1249 

1250 if isinstance(schema['discriminator'], str): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1251 return schema['discriminator'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1252 

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

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

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

1256 return schema['discriminator'][0] 

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

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

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

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

1261 for alias_path in schema['discriminator']: 1261 ↛ 1286line 1261 didn't jump to line 1286 because the loop on line 1261 didn't complete1jBakgwblcmChDEnoxypqrsAFdtizeufv

1262 if not isinstance(alias_path, list): 1262 ↛ 1263line 1262 didn't jump to line 1263 because the condition on line 1262 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1264 if len(alias_path) != 1: 1264 ↛ 1265line 1264 didn't jump to line 1265 because the condition on line 1264 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1266 alias = alias_path[0] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1267 if not isinstance(alias, str): 1267 ↛ 1268line 1267 didn't jump to line 1268 because the condition on line 1267 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1269 alias_is_present_on_all_choices = True 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1270 for choice in one_of_choices: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1271 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1272 choice = self.resolve_ref_schema(choice) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1273 except RuntimeError as exc: 

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

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

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

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

1278 choice = {} 

1279 properties = choice.get('properties', {}) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1280 if not isinstance(properties, dict) or alias not in properties: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1281 alias_is_present_on_all_choices = False 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1282 break 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1283 if alias_is_present_on_all_choices: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1284 openapi_discriminator = alias 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1285 break 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1286 return openapi_discriminator 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1287 

1288 def chain_schema(self, schema: core_schema.ChainSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1290 

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

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

1293 

1294 Args: 

1295 schema: The core schema. 

1296 

1297 Returns: 

1298 The generated JSON schema. 

1299 """ 

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

1301 return self.generate_inner(schema['steps'][step_index]) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1302 

1303 def lax_or_strict_schema(self, schema: core_schema.LaxOrStrictSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1305 strict schema. 

1306 

1307 Args: 

1308 schema: The core schema. 

1309 

1310 Returns: 

1311 The generated JSON schema. 

1312 """ 

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

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

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

1316 # because one of the following two branches failed. 

1317 if use_strict: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1318 return self.generate_inner(schema['strict_schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1319 else: 

1320 return self.generate_inner(schema['lax_schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1321 

1322 def json_or_python_schema(self, schema: core_schema.JsonOrPythonSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1324 Python schema. 

1325 

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

1327 this method. 

1328 

1329 Args: 

1330 schema: The core schema. 

1331 

1332 Returns: 

1333 The generated JSON schema. 

1334 """ 

1335 return self.generate_inner(schema['json_schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1336 

1337 def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1339 

1340 Args: 

1341 schema: The core schema. 

1342 

1343 Returns: 

1344 The generated JSON schema. 

1345 """ 

1346 total = schema.get('total', True) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1347 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

1350 if self.field_is_present(field) 

1351 ] 

1352 if self.mode == 'serialization': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1353 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1354 cls = schema.get('cls') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1355 config = _get_typed_dict_config(cls) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1356 with self._config_wrapper_stack.push(config): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1357 json_schema = self._named_required_fields_schema(named_required_fields) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1358 

1359 if cls is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1360 self._update_class_schema(json_schema, cls, config) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1361 else: 

1362 extra = config.get('extra') 1jagbcAdief

1363 if extra == 'forbid': 1363 ↛ 1364line 1363 didn't jump to line 1364 because the condition on line 1363 was never true1jagbcAdief

1364 json_schema['additionalProperties'] = False 

1365 elif extra == 'allow': 1365 ↛ 1366line 1365 didn't jump to line 1366 because the condition on line 1365 was never true1jagbcAdief

1366 json_schema['additionalProperties'] = True 

1367 

1368 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1369 

1370 @staticmethod 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

1371 def _name_required_computed_fields( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

1372 computed_fields: list[ComputedField], 

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

1374 return [(field['property_name'], True, field) for field in computed_fields] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1375 

1376 def _named_required_fields_schema( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1378 ) -> JsonSchemaValue: 

1379 properties: dict[str, JsonSchemaValue] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1380 required_fields: list[str] = [] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1381 for name, required, field in named_required_fields: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1382 if self.by_alias: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1383 name = self._get_alias_name(field, name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1384 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1385 field_json_schema = self.generate_inner(field).copy() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1386 except PydanticOmit: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1387 continue 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1388 if 'title' not in field_json_schema and self.field_title_should_be_set(field): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1389 title = self.get_title_from_name(name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1390 field_json_schema['title'] = title 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1391 field_json_schema = self.handle_ref_overrides(field_json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1392 properties[name] = field_json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1393 if required: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1394 required_fields.append(name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1395 

1396 json_schema = {'type': 'object', 'properties': properties} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1397 if required_fields: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1398 json_schema['required'] = required_fields 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1399 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1400 

1401 def _get_alias_name(self, field: CoreSchemaField, name: str) -> str: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

1402 if field['type'] == 'computed-field': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1403 alias: Any = field.get('alias', name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1404 elif self.mode == 'validation': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1405 alias = field.get('validation_alias', name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1406 else: 

1407 alias = field.get('serialization_alias', name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1408 if isinstance(alias, str): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1409 name = alias 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1410 elif isinstance(alias, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1411 alias = cast('list[str] | str', alias) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1412 for path in alias: 1412 ↛ 1420line 1412 didn't jump to line 1420 because the loop on line 1412 didn't complete1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

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

1416 name = path[0] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1417 break 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1418 else: 

1419 assert_never(alias) 

1420 return name 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1421 

1422 def typed_dict_field_schema(self, schema: core_schema.TypedDictField) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1424 

1425 Args: 

1426 schema: The core schema. 

1427 

1428 Returns: 

1429 The generated JSON schema. 

1430 """ 

1431 return self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1432 

1433 def dataclass_field_schema(self, schema: core_schema.DataclassField) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1435 

1436 Args: 

1437 schema: The core schema. 

1438 

1439 Returns: 

1440 The generated JSON schema. 

1441 """ 

1442 return self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1443 

1444 def model_field_schema(self, schema: core_schema.ModelField) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1446 

1447 Args: 

1448 schema: The core schema. 

1449 

1450 Returns: 

1451 The generated JSON schema. 

1452 """ 

1453 return self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1454 

1455 def computed_field_schema(self, schema: core_schema.ComputedField) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1457 

1458 Args: 

1459 schema: The core schema. 

1460 

1461 Returns: 

1462 The generated JSON schema. 

1463 """ 

1464 return self.generate_inner(schema['return_schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1465 

1466 def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1468 

1469 Args: 

1470 schema: The core schema. 

1471 

1472 Returns: 

1473 The generated JSON schema. 

1474 """ 

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

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

1477 cls = cast('type[BaseModel]', schema['cls']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1478 config = cls.model_config 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1479 

1480 with self._config_wrapper_stack.push(config): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1481 json_schema = self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1482 

1483 self._update_class_schema(json_schema, cls, config) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1484 

1485 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1486 

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

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

1489 

1490 * title 

1491 * description 

1492 * additional properties 

1493 * json_schema_extra 

1494 * deprecated 

1495 

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

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

1498 """ 

1499 from .main import BaseModel 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1500 from .root_model import RootModel 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1501 

1502 if (config_title := config.get('title')) is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1503 json_schema.setdefault('title', config_title) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1504 elif model_title_generator := config.get('model_title_generator'): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1505 title = model_title_generator(cls) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1506 if not isinstance(title, str): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1508 json_schema.setdefault('title', title) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1509 if 'title' not in json_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1510 json_schema['title'] = cls.__name__ 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1511 

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

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

1514 

1515 if docstring: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1516 json_schema.setdefault('description', inspect.cleandoc(docstring)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1518 json_schema.setdefault('description', root_description) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1519 

1520 extra = config.get('extra') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1521 if 'additionalProperties' not in json_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1522 if extra == 'allow': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1523 json_schema['additionalProperties'] = True 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1524 elif extra == 'forbid': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1525 json_schema['additionalProperties'] = False 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1526 

1527 json_schema_extra = config.get('json_schema_extra') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1528 if issubclass(cls, BaseModel) and cls.__pydantic_root_model__: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1529 root_json_schema_extra = cls.model_fields['root'].json_schema_extra 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1530 if json_schema_extra and root_json_schema_extra: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1531 raise ValueError( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1533 ' field must not be set simultaneously' 

1534 ) 

1535 if root_json_schema_extra: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1536 json_schema_extra = root_json_schema_extra 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1537 

1538 if isinstance(json_schema_extra, (staticmethod, classmethod)): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1540 json_schema_extra = json_schema_extra.__get__(cls) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1541 

1542 if isinstance(json_schema_extra, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1543 json_schema.update(json_schema_extra) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1544 elif callable(json_schema_extra): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1546 if len(inspect.signature(json_schema_extra).parameters) > 1: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1547 json_schema_extra(json_schema, cls) # type: ignore 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1548 else: 

1549 json_schema_extra(json_schema) # type: ignore 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1550 elif json_schema_extra is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1551 raise ValueError( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1553 ) 

1554 

1555 if hasattr(cls, '__deprecated__'): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1556 json_schema['deprecated'] = True 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1557 

1558 def resolve_ref_schema(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1560 

1561 Args: 

1562 json_schema: The schema to resolve. 

1563 

1564 Returns: 

1565 The resolved schema. 

1566 

1567 Raises: 

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

1569 """ 

1570 while '$ref' in json_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1571 ref = json_schema['$ref'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1572 schema_to_update = self.get_schema_from_definitions(JsonRef(ref)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1573 if schema_to_update is None: 1573 ↛ 1574line 1573 didn't jump to line 1574 because the condition on line 1573 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1575 json_schema = schema_to_update 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1576 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1577 

1578 def model_fields_schema(self, schema: core_schema.ModelFieldsSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1580 

1581 Args: 

1582 schema: The core schema. 

1583 

1584 Returns: 

1585 The generated JSON schema. 

1586 """ 

1587 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

1590 if self.field_is_present(field) 

1591 ] 

1592 if self.mode == 'serialization': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1593 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1594 json_schema = self._named_required_fields_schema(named_required_fields) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1595 extras_schema = schema.get('extras_schema', None) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1596 if extras_schema is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1597 schema_to_update = self.resolve_ref_schema(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1598 schema_to_update['additionalProperties'] = self.generate_inner(extras_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1599 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1600 

1601 def field_is_present(self, field: CoreSchemaField) -> bool: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1603 

1604 Args: 

1605 field: The schema for the field itself. 

1606 

1607 Returns: 

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

1609 """ 

1610 if self.mode == 'serialization': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1612 # override this method and return True 

1613 return not field.get('serialization_exclude') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1614 elif self.mode == 'validation': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1615 return True 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1616 else: 

1617 assert_never(self.mode) 

1618 

1619 def field_is_required( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

1620 self, 

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

1622 total: bool, 

1623 ) -> bool: 

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

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

1626 

1627 Args: 

1628 field: The schema for the field itself. 

1629 total: Only applies to `TypedDictField`s. 

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

1631 explicitly specify `required=False` are required. 

1632 

1633 Returns: 

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

1635 """ 

1636 if self.mode == 'serialization' and self._config.json_schema_serialization_defaults_required: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1637 return not field.get('serialization_exclude') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1638 else: 

1639 if field['type'] == 'typed-dict-field': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1640 return field.get('required', total) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1641 else: 

1642 return field['schema']['type'] != 'default' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1643 

1644 def dataclass_args_schema(self, schema: core_schema.DataclassArgsSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1646 

1647 Args: 

1648 schema: The core schema. 

1649 

1650 Returns: 

1651 The generated JSON schema. 

1652 """ 

1653 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1655 for field in schema['fields'] 

1656 if self.field_is_present(field) 

1657 ] 

1658 if self.mode == 'serialization': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1659 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1660 return self._named_required_fields_schema(named_required_fields) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1661 

1662 def dataclass_schema(self, schema: core_schema.DataclassSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1664 

1665 Args: 

1666 schema: The core schema. 

1667 

1668 Returns: 

1669 The generated JSON schema. 

1670 """ 

1671 from ._internal._dataclasses import is_builtin_dataclass 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1672 

1673 cls = schema['cls'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1674 config: ConfigDict = getattr(cls, '__pydantic_config__', cast('ConfigDict', {})) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1675 

1676 with self._config_wrapper_stack.push(config): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1677 json_schema = self.generate_inner(schema['schema']).copy() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1678 

1679 self._update_class_schema(json_schema, cls, config) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1680 

1681 # Dataclass-specific handling of description 

1682 if is_builtin_dataclass(cls): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1684 description = None 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1685 else: 

1686 description = None if cls.__doc__ is None else inspect.cleandoc(cls.__doc__) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1687 if description: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1688 json_schema['description'] = description 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1689 

1690 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1691 

1692 def arguments_schema(self, schema: core_schema.ArgumentsSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1694 

1695 Args: 

1696 schema: The core schema. 

1697 

1698 Returns: 

1699 The generated JSON schema. 

1700 """ 

1701 prefer_positional = schema.get('metadata', {}).get('pydantic_js_prefer_positional_arguments') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1702 

1703 arguments = schema['arguments_schema'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

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

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

1707 var_args_schema = schema.get('var_args_schema') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1708 var_kwargs_schema = schema.get('var_kwargs_schema') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1709 

1710 if prefer_positional: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1711 positional_possible = not kw_only_arguments and not var_kwargs_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1712 if positional_possible: 1712 ↛ 1715line 1712 didn't jump to line 1715 because the condition on line 1712 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

1713 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1714 

1715 keyword_possible = not p_only_arguments and not var_args_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1716 if keyword_possible: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1717 return self.kw_arguments_schema(kw_or_p_arguments + kw_only_arguments, var_kwargs_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1718 

1719 if not prefer_positional: 1719 ↛ 1724line 1719 didn't jump to line 1724 because the condition on line 1719 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

1720 positional_possible = not kw_only_arguments and not var_kwargs_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1721 if positional_possible: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1722 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1723 

1724 raise PydanticInvalidForJsonSchema( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1726 ) 

1727 

1728 def kw_arguments_schema( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1730 ) -> JsonSchemaValue: 

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

1732 

1733 Args: 

1734 arguments: The core schema. 

1735 

1736 Returns: 

1737 The generated JSON schema. 

1738 """ 

1739 properties: dict[str, JsonSchemaValue] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1740 required: list[str] = [] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1741 for argument in arguments: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1742 name = self.get_argument_name(argument) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1743 argument_schema = self.generate_inner(argument['schema']).copy() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1744 argument_schema['title'] = self.get_title_from_name(name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1745 properties[name] = argument_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1746 

1747 if argument['schema']['type'] != 'default': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1749 # the inner schema must be of type WithDefaultSchema. 

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

1751 required.append(name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1752 

1753 json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1754 if required: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1755 json_schema['required'] = required 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1756 

1757 if var_kwargs_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1758 additional_properties_schema = self.generate_inner(var_kwargs_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1759 if additional_properties_schema: 1759 ↛ 1763line 1759 didn't jump to line 1763 because the condition on line 1759 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

1760 json_schema['additionalProperties'] = additional_properties_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1761 else: 

1762 json_schema['additionalProperties'] = False 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1763 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1764 

1765 def p_arguments_schema( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1767 ) -> JsonSchemaValue: 

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

1769 

1770 Args: 

1771 arguments: The core schema. 

1772 

1773 Returns: 

1774 The generated JSON schema. 

1775 """ 

1776 prefix_items: list[JsonSchemaValue] = [] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1777 min_items = 0 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1778 

1779 for argument in arguments: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1780 name = self.get_argument_name(argument) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1781 

1782 argument_schema = self.generate_inner(argument['schema']).copy() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1783 argument_schema['title'] = self.get_title_from_name(name) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1784 prefix_items.append(argument_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1785 

1786 if argument['schema']['type'] != 'default': 1786 ↛ 1779line 1786 didn't jump to line 1779 because the condition on line 1786 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1788 # the inner schema must be of type WithDefaultSchema. 

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

1790 min_items += 1 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1791 

1792 json_schema: JsonSchemaValue = {'type': 'array'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1793 if prefix_items: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1794 json_schema['prefixItems'] = prefix_items 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1795 if min_items: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1796 json_schema['minItems'] = min_items 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1797 

1798 if var_args_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1799 items_schema = self.generate_inner(var_args_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1800 if items_schema: 1800 ↛ 1805line 1800 didn't jump to line 1805 because the condition on line 1800 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

1801 json_schema['items'] = items_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1802 else: 

1803 json_schema['maxItems'] = len(prefix_items) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1804 

1805 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1806 

1807 def get_argument_name(self, argument: core_schema.ArgumentsParameter) -> str: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

1808 """Retrieves the name of an argument. 

1809 

1810 Args: 

1811 argument: The core schema. 

1812 

1813 Returns: 

1814 The name of the argument. 

1815 """ 

1816 name = argument['name'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1817 if self.by_alias: 1817 ↛ 1823line 1817 didn't jump to line 1823 because the condition on line 1817 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

1818 alias = argument.get('alias') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1819 if isinstance(alias, str): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1820 name = alias 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1821 else: 

1822 pass # might want to do something else? 1akgwblcmhnoxypqrsdtizeufv

1823 return name 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1824 

1825 def call_schema(self, schema: core_schema.CallSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1827 

1828 Args: 

1829 schema: The core schema. 

1830 

1831 Returns: 

1832 The generated JSON schema. 

1833 """ 

1834 return self.generate_inner(schema['arguments_schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1835 

1836 def custom_error_schema(self, schema: core_schema.CustomErrorSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1838 

1839 Args: 

1840 schema: The core schema. 

1841 

1842 Returns: 

1843 The generated JSON schema. 

1844 """ 

1845 return self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1846 

1847 def json_schema(self, schema: core_schema.JsonSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1849 

1850 Args: 

1851 schema: The core schema. 

1852 

1853 Returns: 

1854 The generated JSON schema. 

1855 """ 

1856 content_core_schema = schema.get('schema') or core_schema.any_schema() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1857 content_json_schema = self.generate_inner(content_core_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1858 if self.mode == 'validation': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1859 return {'type': 'string', 'contentMediaType': 'application/json', 'contentSchema': content_json_schema} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1860 else: 

1861 # self.mode == 'serialization' 

1862 return content_json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1863 

1864 def url_schema(self, schema: core_schema.UrlSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1866 

1867 Args: 

1868 schema: The core schema. 

1869 

1870 Returns: 

1871 The generated JSON schema. 

1872 """ 

1873 json_schema = {'type': 'string', 'format': 'uri', 'minLength': 1} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1874 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1875 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1876 

1877 def multi_host_url_schema(self, schema: core_schema.MultiHostUrlSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1879 

1880 Args: 

1881 schema: The core schema. 

1882 

1883 Returns: 

1884 The generated JSON schema. 

1885 """ 

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

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

1888 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1889 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1890 

1891 def uuid_schema(self, schema: core_schema.UuidSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1893 

1894 Args: 

1895 schema: The core schema. 

1896 

1897 Returns: 

1898 The generated JSON schema. 

1899 """ 

1900 return {'type': 'string', 'format': 'uuid'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1901 

1902 def definitions_schema(self, schema: core_schema.DefinitionsSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1904 

1905 Args: 

1906 schema: The core schema. 

1907 

1908 Returns: 

1909 The generated JSON schema. 

1910 """ 

1911 for definition in schema['definitions']: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1912 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1913 self.generate_inner(definition) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1914 except PydanticInvalidForJsonSchema as e: 

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

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

1917 continue 

1918 return self.generate_inner(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1919 

1920 def definition_ref_schema(self, schema: core_schema.DefinitionReferenceSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1922 

1923 Args: 

1924 schema: The core schema. 

1925 

1926 Returns: 

1927 The generated JSON schema. 

1928 """ 

1929 core_ref = CoreRef(schema['schema_ref']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1930 _, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1931 return ref_json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1932 

1933 def ser_schema( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1935 ) -> JsonSchemaValue | None: 

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

1937 

1938 Args: 

1939 schema: The core schema. 

1940 

1941 Returns: 

1942 The generated JSON schema. 

1943 """ 

1944 schema_type = schema['type'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1945 if schema_type == 'function-plain' or schema_type == 'function-wrap': 1945 ↛ 1950line 1945 didn't jump to line 1950 because the condition on line 1945 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

1946 # PlainSerializerFunctionSerSchema or WrapSerializerFunctionSerSchema 

1947 return_schema = schema.get('return_schema') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1948 if return_schema is not None: 1948 ↛ 1956line 1948 didn't jump to line 1956 because the condition on line 1948 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

1949 return self.generate_inner(return_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

1951 # FormatSerSchema or ToStringSerSchema 

1952 return self.str_schema(core_schema.str_schema()) 

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

1954 # ModelSerSchema 

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

1956 return None 

1957 

1958 def complex_schema(self, schema: core_schema.ComplexSchema) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1960 

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

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

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

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

1965 

1966 Args: 

1967 schema: The core schema. 

1968 

1969 Returns: 

1970 The generated JSON schema. 

1971 """ 

1972 return {'type': 'string'} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1973 

1974 # ### Utility methods 

1975 

1976 def get_title_from_name(self, name: str) -> str: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

1977 """Retrieves a title from a name. 

1978 

1979 Args: 

1980 name: The name to retrieve a title from. 

1981 

1982 Returns: 

1983 The title. 

1984 """ 

1985 return name.title().replace('_', ' ').strip() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

1986 

1987 def field_title_should_be_set(self, schema: CoreSchemaOrField) -> bool: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

1989 

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

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

1992 

1993 Args: 

1994 schema: The schema to check. 

1995 

1996 Returns: 

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

1998 """ 

1999 if _core_utils.is_core_schema_field(schema): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2000 if schema['type'] == 'computed-field': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2001 field_schema = schema['return_schema'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2002 else: 

2003 field_schema = schema['schema'] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2004 return self.field_title_should_be_set(field_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2005 

2006 elif _core_utils.is_core_schema(schema): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

2008 return False 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2009 if schema['type'] in {'default', 'nullable', 'definitions'}: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

2011 if _core_utils.is_function_with_inner_schema(schema): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2012 return self.field_title_should_be_set(schema['schema']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2013 if schema['type'] == 'definition-ref': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

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

2015 # schemas with refs should not 

2016 return False 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2017 return True # anything else should have title set 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2018 

2019 else: 

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

2021 

2022 def normalize_name(self, name: str) -> str: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

2024 

2025 Args: 

2026 name: The name to normalize. 

2027 

2028 Returns: 

2029 The normalized name. 

2030 """ 

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

2032 

2033 def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

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

2035 

2036 Args: 

2037 core_mode_ref: The core reference. 

2038 

2039 Returns: 

2040 The definitions key. 

2041 """ 

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

2043 core_ref, mode = core_mode_ref 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2044 components = re.split(r'([\][,])', core_ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2045 # Remove IDs from each component 

2046 components = [x.rsplit(':', 1)[0] for x in components] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2047 core_ref_no_id = ''.join(components) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2048 # Remove everything before the last period from each "component" 

2049 components = [re.sub(r'(?:[^.[\]]+\.)+((?:[^.[\]]+))', r'\1', x) for x in components] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2050 short_ref = ''.join(components) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2051 

2052 mode_title = _MODE_TITLE_MAPPING[mode] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2053 

2054 # It is important that the generated defs_ref values be such that at least one choice will not 

2055 # be generated for any other core_ref. Currently, this should be the case because we include 

2056 # the id of the source type in the core_ref 

2057 name = DefsRef(self.normalize_name(short_ref)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2058 name_mode = DefsRef(self.normalize_name(short_ref) + f'-{mode_title}') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2059 module_qualname = DefsRef(self.normalize_name(core_ref_no_id)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2060 module_qualname_mode = DefsRef(f'{module_qualname}-{mode_title}') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2061 module_qualname_id = DefsRef(self.normalize_name(core_ref)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2062 occurrence_index = self._collision_index.get(module_qualname_id) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2063 if occurrence_index is None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2064 self._collision_counter[module_qualname] += 1 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2065 occurrence_index = self._collision_index[module_qualname_id] = self._collision_counter[module_qualname] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2066 

2067 module_qualname_occurrence = DefsRef(f'{module_qualname}__{occurrence_index}') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2068 module_qualname_occurrence_mode = DefsRef(f'{module_qualname_mode}__{occurrence_index}') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2069 

2070 self._prioritized_defsref_choices[module_qualname_occurrence_mode] = [ 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2071 name, 

2072 name_mode, 

2073 module_qualname, 

2074 module_qualname_mode, 

2075 module_qualname_occurrence, 

2076 module_qualname_occurrence_mode, 

2077 ] 

2078 

2079 return module_qualname_occurrence_mode 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2080 

2081 def get_cache_defs_ref_schema(self, core_ref: CoreRef) -> tuple[DefsRef, JsonSchemaValue]: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2082 """This method wraps the get_defs_ref method with some cache-lookup/population logic, 

2083 and returns both the produced defs_ref and the JSON schema that will refer to the right definition. 

2084 

2085 Args: 

2086 core_ref: The core reference to get the definitions reference for. 

2087 

2088 Returns: 

2089 A tuple of the definitions reference and the JSON schema that will refer to it. 

2090 """ 

2091 core_mode_ref = (core_ref, self.mode) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2092 maybe_defs_ref = self.core_to_defs_refs.get(core_mode_ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2093 if maybe_defs_ref is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2094 json_ref = self.core_to_json_refs[core_mode_ref] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2095 return maybe_defs_ref, {'$ref': json_ref} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2096 

2097 defs_ref = self.get_defs_ref(core_mode_ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2098 

2099 # populate the ref translation mappings 

2100 self.core_to_defs_refs[core_mode_ref] = defs_ref 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2101 self.defs_to_core_refs[defs_ref] = core_mode_ref 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2102 

2103 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2104 self.core_to_json_refs[core_mode_ref] = json_ref 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2105 self.json_to_defs_refs[json_ref] = defs_ref 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2106 ref_json_schema = {'$ref': json_ref} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2107 return defs_ref, ref_json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2108 

2109 def handle_ref_overrides(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2110 """Remove any sibling keys that are redundant with the referenced schema. 

2111 

2112 Args: 

2113 json_schema: The schema to remove redundant sibling keys from. 

2114 

2115 Returns: 

2116 The schema with redundant sibling keys removed. 

2117 """ 

2118 if '$ref' in json_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2119 # prevent modifications to the input; this copy may be safe to drop if there is significant overhead 

2120 json_schema = json_schema.copy() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2121 

2122 referenced_json_schema = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2123 if referenced_json_schema is None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2124 # This can happen when building schemas for models with not-yet-defined references. 

2125 # It may be a good idea to do a recursive pass at the end of the generation to remove 

2126 # any redundant override keys. 

2127 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2128 for k, v in list(json_schema.items()): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2129 if k == '$ref': 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2130 continue 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2131 if k in referenced_json_schema and referenced_json_schema[k] == v: 2131 ↛ 2132line 2131 didn't jump to line 2132 because the condition on line 2131 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2132 del json_schema[k] # redundant key 

2133 

2134 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2135 

2136 def get_schema_from_definitions(self, json_ref: JsonRef) -> JsonSchemaValue | None: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2137 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2138 def_ref = self.json_to_defs_refs[json_ref] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2139 if def_ref in self._core_defs_invalid_for_json_schema: 2139 ↛ 2140line 2139 didn't jump to line 2140 because the condition on line 2139 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2140 raise self._core_defs_invalid_for_json_schema[def_ref] 

2141 return self.definitions.get(def_ref, None) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2142 except KeyError: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2143 if json_ref.startswith(('http://', 'https://')): 2143 ↛ 2145line 2143 didn't jump to line 2145 because the condition on line 2143 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2144 return None 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2145 raise 

2146 

2147 def encode_default(self, dft: Any) -> Any: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2148 """Encode a default value to a JSON-serializable value. 

2149 

2150 This is used to encode default values for fields in the generated JSON schema. 

2151 

2152 Args: 

2153 dft: The default value to encode. 

2154 

2155 Returns: 

2156 The encoded default value. 

2157 """ 

2158 from .type_adapter import TypeAdapter, _type_has_config 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2159 

2160 config = self._config 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2161 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2162 default = ( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2163 dft 

2164 if _type_has_config(type(dft)) 

2165 else TypeAdapter(type(dft), config=config.config_dict).dump_python(dft, mode='json') 

2166 ) 

2167 except PydanticSchemaGenerationError: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2168 raise pydantic_core.PydanticSerializationError(f'Unable to encode default value {dft}') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2169 

2170 return pydantic_core.to_jsonable_python( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2171 default, 

2172 timedelta_mode=config.ser_json_timedelta, 

2173 bytes_mode=config.ser_json_bytes, 

2174 ) 

2175 

2176 def update_with_validations( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2177 self, json_schema: JsonSchemaValue, core_schema: CoreSchema, mapping: dict[str, str] 

2178 ) -> None: 

2179 """Update the json_schema with the corresponding validations specified in the core_schema, 

2180 using the provided mapping to translate keys in core_schema to the appropriate keys for a JSON schema. 

2181 

2182 Args: 

2183 json_schema: The JSON schema to update. 

2184 core_schema: The core schema to get the validations from. 

2185 mapping: A mapping from core_schema attribute names to the corresponding JSON schema attribute names. 

2186 """ 

2187 for core_key, json_schema_key in mapping.items(): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2188 if core_key in core_schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2189 json_schema[json_schema_key] = core_schema[core_key] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2190 

2191 class ValidationsMapping: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2192 """This class just contains mappings from core_schema attribute names to the corresponding 

2193 JSON schema attribute names. While I suspect it is unlikely to be necessary, you can in 

2194 principle override this class in a subclass of GenerateJsonSchema (by inheriting from 

2195 GenerateJsonSchema.ValidationsMapping) to change these mappings. 

2196 """ 

2197 

2198 numeric = { 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2199 'multiple_of': 'multipleOf', 

2200 'le': 'maximum', 

2201 'ge': 'minimum', 

2202 'lt': 'exclusiveMaximum', 

2203 'gt': 'exclusiveMinimum', 

2204 } 

2205 bytes = { 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2206 'min_length': 'minLength', 

2207 'max_length': 'maxLength', 

2208 } 

2209 string = { 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2210 'min_length': 'minLength', 

2211 'max_length': 'maxLength', 

2212 'pattern': 'pattern', 

2213 } 

2214 array = { 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2215 'min_length': 'minItems', 

2216 'max_length': 'maxItems', 

2217 } 

2218 object = { 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2219 'min_length': 'minProperties', 

2220 'max_length': 'maxProperties', 

2221 } 

2222 

2223 def get_flattened_anyof(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2224 members = [] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2225 for schema in schemas: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2226 if len(schema) == 1 and 'anyOf' in schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2227 members.extend(schema['anyOf']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2228 else: 

2229 members.append(schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2230 members = _deduplicate_schemas(members) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2231 if len(members) == 1: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2232 return members[0] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2233 return {'anyOf': members} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2234 

2235 def get_json_ref_counts(self, json_schema: JsonSchemaValue) -> dict[JsonRef, int]: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2236 """Get all values corresponding to the key '$ref' anywhere in the json_schema.""" 

2237 json_refs: dict[JsonRef, int] = Counter() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2238 

2239 def _add_json_refs(schema: Any) -> None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2240 if isinstance(schema, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2241 if '$ref' in schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2242 json_ref = JsonRef(schema['$ref']) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2243 if not isinstance(json_ref, str): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2244 return # in this case, '$ref' might have been the name of a property 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2245 already_visited = json_ref in json_refs 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2246 json_refs[json_ref] += 1 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2247 if already_visited: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2248 return # prevent recursion on a definition that was already visited 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2249 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2250 defs_ref = self.json_to_defs_refs[json_ref] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2251 if defs_ref in self._core_defs_invalid_for_json_schema: 2251 ↛ 2252line 2251 didn't jump to line 2252 because the condition on line 2251 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2252 raise self._core_defs_invalid_for_json_schema[defs_ref] 

2253 _add_json_refs(self.definitions[defs_ref]) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2254 except KeyError: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2255 if not json_ref.startswith(('http://', 'https://')): 2255 ↛ 2256line 2255 didn't jump to line 2256 because the condition on line 2255 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2256 raise 

2257 

2258 for k, v in schema.items(): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2259 if k == 'examples' and isinstance(v, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2260 # Skip examples that may contain arbitrary values and references 

2261 # (see the comment in `_get_all_json_refs` for more details). 

2262 continue 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2263 _add_json_refs(v) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2264 elif isinstance(schema, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2265 for v in schema: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2266 _add_json_refs(v) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2267 

2268 _add_json_refs(json_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2269 return json_refs 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2270 

2271 def handle_invalid_for_json_schema(self, schema: CoreSchemaOrField, error_info: str) -> JsonSchemaValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2272 raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2273 

2274 def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2275 """This method simply emits PydanticJsonSchemaWarnings based on handling in the `warning_message` method.""" 

2276 message = self.render_warning_message(kind, detail) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2277 if message is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2278 warnings.warn(message, PydanticJsonSchemaWarning) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2279 

2280 def render_warning_message(self, kind: JsonSchemaWarningKind, detail: str) -> str | None: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2281 """This method is responsible for ignoring warnings as desired, and for formatting the warning messages. 

2282 

2283 You can override the value of `ignored_warning_kinds` in a subclass of GenerateJsonSchema 

2284 to modify what warnings are generated. If you want more control, you can override this method; 

2285 just return None in situations where you don't want warnings to be emitted. 

2286 

2287 Args: 

2288 kind: The kind of warning to render. It can be one of the following: 

2289 

2290 - 'skipped-choice': A choice field was skipped because it had no valid choices. 

2291 - 'non-serializable-default': A default value was skipped because it was not JSON-serializable. 

2292 detail: A string with additional details about the warning. 

2293 

2294 Returns: 

2295 The formatted warning message, or `None` if no warning should be emitted. 

2296 """ 

2297 if kind in self.ignored_warning_kinds: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2298 return None 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2299 return f'{detail} [{kind}]' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2300 

2301 def _build_definitions_remapping(self) -> _DefinitionsRemapping: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2302 defs_to_json: dict[DefsRef, JsonRef] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2303 for defs_refs in self._prioritized_defsref_choices.values(): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2304 for defs_ref in defs_refs: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2305 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2306 defs_to_json[defs_ref] = json_ref 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2307 

2308 return _DefinitionsRemapping.from_prioritized_choices( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2309 self._prioritized_defsref_choices, defs_to_json, self.definitions 

2310 ) 

2311 

2312 def _garbage_collect_definitions(self, schema: JsonSchemaValue) -> None: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2313 visited_defs_refs: set[DefsRef] = set() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2314 unvisited_json_refs = _get_all_json_refs(schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2315 while unvisited_json_refs: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2316 next_json_ref = unvisited_json_refs.pop() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2317 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2318 next_defs_ref = self.json_to_defs_refs[next_json_ref] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2319 if next_defs_ref in visited_defs_refs: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2320 continue 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2321 visited_defs_refs.add(next_defs_ref) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2322 unvisited_json_refs.update(_get_all_json_refs(self.definitions[next_defs_ref])) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2323 except KeyError: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2324 if not next_json_ref.startswith(('http://', 'https://')): 2324 ↛ 2325line 2324 didn't jump to line 2325 because the condition on line 2324 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2325 raise 

2326 

2327 self.definitions = {k: v for k, v in self.definitions.items() if k in visited_defs_refs} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2328 

2329 

2330# ##### Start JSON Schema Generation Functions ##### 

2331 

2332 

2333def model_json_schema( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2334 cls: type[BaseModel] | type[PydanticDataclass], 

2335 by_alias: bool = True, 

2336 ref_template: str = DEFAULT_REF_TEMPLATE, 

2337 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2338 mode: JsonSchemaMode = 'validation', 

2339) -> dict[str, Any]: 

2340 """Utility function to generate a JSON Schema for a model. 

2341 

2342 Args: 

2343 cls: The model class to generate a JSON Schema for. 

2344 by_alias: If `True` (the default), fields will be serialized according to their alias. 

2345 If `False`, fields will be serialized according to their attribute name. 

2346 ref_template: The template to use for generating JSON Schema references. 

2347 schema_generator: The class to use for generating the JSON Schema. 

2348 mode: The mode to use for generating the JSON Schema. It can be one of the following: 

2349 

2350 - 'validation': Generate a JSON Schema for validating data. 

2351 - 'serialization': Generate a JSON Schema for serializing data. 

2352 

2353 Returns: 

2354 The generated JSON Schema. 

2355 """ 

2356 from .main import BaseModel 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2357 

2358 schema_generator_instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2359 

2360 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2361 cls.__pydantic_core_schema__.rebuild() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2362 

2363 if cls is BaseModel: 2363 ↛ 2364line 2363 didn't jump to line 2364 because the condition on line 2363 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2364 raise AttributeError('model_json_schema() must be called on a subclass of BaseModel, not BaseModel itself.') 

2365 

2366 assert not isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2367 return schema_generator_instance.generate(cls.__pydantic_core_schema__, mode=mode) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2368 

2369 

2370def models_json_schema( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2371 models: Sequence[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode]], 

2372 *, 

2373 by_alias: bool = True, 

2374 title: str | None = None, 

2375 description: str | None = None, 

2376 ref_template: str = DEFAULT_REF_TEMPLATE, 

2377 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2378) -> tuple[dict[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: 

2379 """Utility function to generate a JSON Schema for multiple models. 

2380 

2381 Args: 

2382 models: A sequence of tuples of the form (model, mode). 

2383 by_alias: Whether field aliases should be used as keys in the generated JSON Schema. 

2384 title: The title of the generated JSON Schema. 

2385 description: The description of the generated JSON Schema. 

2386 ref_template: The reference template to use for generating JSON Schema references. 

2387 schema_generator: The schema generator to use for generating the JSON Schema. 

2388 

2389 Returns: 

2390 A tuple where: 

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

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

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

2394 - The second element is a JSON schema containing all definitions referenced in the first returned 

2395 element, along with the optional title and description keys. 

2396 """ 

2397 for cls, _ in models: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2398 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 2398 ↛ 2399line 2398 didn't jump to line 2399 because the condition on line 2398 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2399 cls.__pydantic_core_schema__.rebuild() 

2400 

2401 instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2402 inputs: list[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode, CoreSchema]] = [ 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2403 (m, mode, m.__pydantic_core_schema__) for m, mode in models 

2404 ] 

2405 json_schemas_map, definitions = instance.generate_definitions(inputs) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2406 

2407 json_schema: dict[str, Any] = {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2408 if definitions: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2409 json_schema['$defs'] = definitions 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2410 if title: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2411 json_schema['title'] = title 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2412 if description: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2413 json_schema['description'] = description 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2414 

2415 return json_schemas_map, json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2416 

2417 

2418# ##### End JSON Schema Generation Functions ##### 

2419 

2420 

2421_HashableJsonValue: TypeAlias = Union[ 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2422 int, float, str, bool, None, tuple['_HashableJsonValue', ...], tuple[tuple[str, '_HashableJsonValue'], ...] 

2423] 

2424 

2425 

2426def _deduplicate_schemas(schemas: Iterable[JsonDict]) -> list[JsonDict]: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2427 return list({_make_json_hashable(schema): schema for schema in schemas}.values()) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2428 

2429 

2430def _make_json_hashable(value: JsonValue) -> _HashableJsonValue: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2431 if isinstance(value, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2432 return tuple(sorted((k, _make_json_hashable(v)) for k, v in value.items())) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2433 elif isinstance(value, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2434 return tuple(_make_json_hashable(v) for v in value) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2435 else: 

2436 return value 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2437 

2438 

2439@dataclasses.dataclass(**_internal_dataclass.slots_true) 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2440class WithJsonSchema: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2441 """!!! abstract "Usage Documentation" 

2442 [`WithJsonSchema` Annotation](../concepts/json_schema.md#withjsonschema-annotation) 

2443 

2444 Add this as an annotation on a field to override the (base) JSON schema that would be generated for that field. 

2445 This provides a way to set a JSON schema for types that would otherwise raise errors when producing a JSON schema, 

2446 such as Callable, or types that have an is-instance core schema, without needing to go so far as creating a 

2447 custom subclass of pydantic.json_schema.GenerateJsonSchema. 

2448 Note that any _modifications_ to the schema that would normally be made (such as setting the title for model fields) 

2449 will still be performed. 

2450 

2451 If `mode` is set this will only apply to that schema generation mode, allowing you 

2452 to set different json schemas for validation and serialization. 

2453 """ 

2454 

2455 json_schema: JsonSchemaValue | None 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2456 mode: Literal['validation', 'serialization'] | None = None 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2457 

2458 def __get_pydantic_json_schema__( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2459 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2460 ) -> JsonSchemaValue: 

2461 mode = self.mode or handler.mode 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2462 if mode != handler.mode: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2463 return handler(core_schema) 1jagbcAdief

2464 if self.json_schema is None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2465 # This exception is handled in pydantic.json_schema.GenerateJsonSchema._named_required_fields_schema 

2466 raise PydanticOmit 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2467 else: 

2468 return self.json_schema.copy() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2469 

2470 def __hash__(self) -> int: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2471 return hash(type(self.mode)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2472 

2473 

2474class Examples: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2475 """Add examples to a JSON schema. 

2476 

2477 If the JSON Schema already contains examples, the provided examples 

2478 will be appended. 

2479 

2480 If `mode` is set this will only apply to that schema generation mode, 

2481 allowing you to add different examples for validation and serialization. 

2482 """ 

2483 

2484 @overload 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2485 @deprecated('Using a dict for `examples` is deprecated since v2.9 and will be removed in v3.0. Use a list instead.') 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2486 def __init__( 1jBakgwblcmDEnoxypqrsMKLGHIJAFdtizeufv

2487 self, examples: dict[str, Any], mode: Literal['validation', 'serialization'] | None = None 1akgwblcmChnoxypqrsKLGHIJdtizeufv

2488 ) -> None: ... 1blcmChpqrsGHIJeufv

2489 

2490 @overload 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2491 def __init__(self, examples: list[Any], mode: Literal['validation', 'serialization'] | None = None) -> None: ... 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2492 

2493 def __init__( 1jBakgwblcmDEnoxypqrsMKLGHIJAFdtizeufv

2494 self, examples: dict[str, Any] | list[Any], mode: Literal['validation', 'serialization'] | None = None 

2495 ) -> None: 

2496 if isinstance(examples, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2497 warnings.warn( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2498 'Using a dict for `examples` is deprecated, use a list instead.', 

2499 PydanticDeprecatedSince29, 

2500 stacklevel=2, 

2501 ) 

2502 self.examples = examples 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2503 self.mode = mode 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2504 

2505 def __get_pydantic_json_schema__( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2506 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2507 ) -> JsonSchemaValue: 

2508 mode = self.mode or handler.mode 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2509 json_schema = handler(core_schema) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2510 if mode != handler.mode: 2510 ↛ 2511line 2510 didn't jump to line 2511 because the condition on line 2510 was never true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2511 return json_schema 

2512 examples = json_schema.get('examples') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2513 if examples is None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2514 json_schema['examples'] = to_jsonable_python(self.examples) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2515 if isinstance(examples, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2516 if isinstance(self.examples, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2517 warnings.warn( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2518 'Updating existing JSON Schema examples of type dict with examples of type list. ' 

2519 'Only the existing examples values will be retained. Note that dict support for ' 

2520 'examples is deprecated and will be removed in v3.0.', 

2521 UserWarning, 

2522 ) 

2523 json_schema['examples'] = to_jsonable_python( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2524 [ex for value in examples.values() for ex in value] + self.examples 

2525 ) 

2526 else: 

2527 json_schema['examples'] = to_jsonable_python({**examples, **self.examples}) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2528 if isinstance(examples, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2529 if isinstance(self.examples, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2530 json_schema['examples'] = to_jsonable_python(examples + self.examples) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2531 elif isinstance(self.examples, dict): 2531 ↛ 2542line 2531 didn't jump to line 2542 because the condition on line 2531 was always true1jBakgwblcmChDEnoxypqrsAFdtizeufv

2532 warnings.warn( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2533 'Updating existing JSON Schema examples of type list with examples of type dict. ' 

2534 'Only the examples values will be retained. Note that dict support for ' 

2535 'examples is deprecated and will be removed in v3.0.', 

2536 UserWarning, 

2537 ) 

2538 json_schema['examples'] = to_jsonable_python( 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2539 examples + [ex for value in self.examples.values() for ex in value] 

2540 ) 

2541 

2542 return json_schema 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2543 

2544 def __hash__(self) -> int: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2545 return hash(type(self.mode)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2546 

2547 

2548def _get_all_json_refs(item: Any) -> set[JsonRef]: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2549 """Get all the definitions references from a JSON schema.""" 

2550 refs: set[JsonRef] = set() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2551 stack = [item] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2552 

2553 while stack: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2554 current = stack.pop() 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2555 if isinstance(current, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2556 for key, value in current.items(): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2557 if key == 'examples' and isinstance(value, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2558 # Skip examples that may contain arbitrary values and references 

2559 # (e.g. `{"examples": [{"$ref": "..."}]}`). Note: checking for value 

2560 # of type list is necessary to avoid skipping valid portions of the schema, 

2561 # for instance when "examples" is used as a property key. A more robust solution 

2562 # could be found, but would require more advanced JSON Schema parsing logic. 

2563 continue 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2564 if key == '$ref' and isinstance(value, str): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2565 refs.add(JsonRef(value)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2566 elif isinstance(value, dict): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2567 stack.append(value) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2568 elif isinstance(value, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2569 stack.extend(value) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2570 elif isinstance(current, list): 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2571 stack.extend(current) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2572 

2573 return refs 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2574 

2575 

2576AnyType = TypeVar('AnyType') 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2577 

2578if TYPE_CHECKING: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2579 SkipJsonSchema = Annotated[AnyType, ...] 

2580else: 

2581 

2582 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2583 class SkipJsonSchema: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2584 """!!! abstract "Usage Documentation" 

2585 [`SkipJsonSchema` Annotation](../concepts/json_schema.md#skipjsonschema-annotation) 

2586 

2587 Add this as an annotation on a field to skip generating a JSON schema for that field. 

2588 

2589 Example: 

2590 ```python 

2591 from pprint import pprint 

2592 from typing import Union 

2593 

2594 from pydantic import BaseModel 

2595 from pydantic.json_schema import SkipJsonSchema 

2596 

2597 class Model(BaseModel): 

2598 a: Union[int, None] = None # (1)! 

2599 b: Union[int, SkipJsonSchema[None]] = None # (2)! 

2600 c: SkipJsonSchema[Union[int, None]] = None # (3)! 

2601 

2602 pprint(Model.model_json_schema()) 

2603 ''' 

2604 { 

2605 'properties': { 

2606 'a': { 

2607 'anyOf': [ 

2608 {'type': 'integer'}, 

2609 {'type': 'null'} 

2610 ], 

2611 'default': None, 

2612 'title': 'A' 

2613 }, 

2614 'b': { 

2615 'default': None, 

2616 'title': 'B', 

2617 'type': 'integer' 

2618 } 

2619 }, 

2620 'title': 'Model', 

2621 'type': 'object' 

2622 } 

2623 ''' 

2624 ``` 

2625 

2626 1. The integer and null types are both included in the schema for `a`. 

2627 2. The integer type is the only type included in the schema for `b`. 

2628 3. The entirety of the `c` field is omitted from the schema. 

2629 """ 

2630 

2631 def __class_getitem__(cls, item: AnyType) -> AnyType: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2632 return Annotated[item, cls()] 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2633 

2634 def __get_pydantic_json_schema__( 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2635 self, core_schema: CoreSchema, handler: GetJsonSchemaHandler 

2636 ) -> JsonSchemaValue: 

2637 raise PydanticOmit 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2638 

2639 def __hash__(self) -> int: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2640 return hash(type(self)) 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2641 

2642 

2643def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict: 1jBakgwblcmChDEnoxypqrsMKLGHIJAFdtizeufv

2644 if cls is not None: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2645 try: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2646 return _decorators.get_attribute_from_bases(cls, '__pydantic_config__') 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2647 except AttributeError: 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2648 pass 1jBakgwblcmChDEnoxypqrsAFdtizeufv

2649 return {} 1jBakgwblcmChDEnoxypqrsAFdtizeufv