Coverage for pydantic/json_schema.py: 94.59%

1092 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-10 09:28 +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 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

13 

14import dataclasses 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

15import inspect 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

16import math 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

17import os 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

18import re 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

19import warnings 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

20from collections import Counter, defaultdict 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

22from copy import deepcopy 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

23from enum import Enum 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

24from re import Pattern 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

25from typing import ( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

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

40from pydantic_core.core_schema import ComputedField 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

42from typing_inspection.introspection import get_literal_values 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

43 

44from pydantic.warnings import PydanticDeprecatedSince26, PydanticDeprecatedSince29 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

45 

46from ._internal import ( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

47 _config, 

48 _core_metadata, 

49 _core_utils, 

50 _decorators, 

51 _internal_dataclass, 

52 _mock_val_ser, 

53 _schema_generation_shared, 

54) 

55from .annotated_handlers import GetJsonSchemaHandler 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

56from .config import JsonDict, JsonValue 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

58 

59if TYPE_CHECKING: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

68""" 1bdenfogpADNahiqrstuvFGOPcjkwlxmyBHM

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

75""" 1bdenfogpADNahiqrstuvFGOPcjkwlxmyBHM

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

80""" 1bdenfogpADNahiqrstuvFGOPcjkwlxmyBHM

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

90 

91 

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

93""" 1bdenfogpADNahiqrstuvFGOPcjkwlxmyBHM

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

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

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

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

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

106 """ 

107 

108 

109NoDefault = object() 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

111for a core schema with a default value. 

112""" 

113 

114 

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

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

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

118 

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

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

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

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

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

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

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

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

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

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

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

130 

131CoreModeRef = tuple[CoreRef, JsonSchemaMode] 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

133 

134 

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

136class _DefinitionsRemapping: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

137 defs_remapping: dict[DefsRef, DefsRef] 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

138 json_remapping: dict[JsonRef, JsonRef] 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

139 

140 @staticmethod 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

141 def from_prioritized_choices( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

143 defs_to_json: dict[DefsRef, JsonRef], 

144 definitions: dict[DefsRef, JsonSchemaValue], 

145 ) -> _DefinitionsRemapping: 

146 """ 

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

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

149 """ 

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

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

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

153 # the inner definitions. 

154 copied_definitions = deepcopy(definitions) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

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

159 for defs_ref in copied_definitions: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

160 alternatives = prioritized_choices[defs_ref] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

161 for alternative in alternatives: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

163 

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

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

166 for defs_ref in schemas_for_alternatives: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

168 

169 # Build the remapping 

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

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

172 for original_defs_ref in definitions: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

173 alternatives = prioritized_choices[original_defs_ref] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

176 defs_remapping[original_defs_ref] = remapped_defs_ref 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

178 remapping = _DefinitionsRemapping(defs_remapping, json_remapping) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

180 if definitions_schema == new_definitions_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

181 # We've reached the fixed point 

182 return remapping 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

183 definitions_schema = new_definitions_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

184 

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

186 

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

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

189 

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

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

192 

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

194 """ 

195 Recursively update the JSON schema replacing all $refs 

196 """ 

197 if isinstance(schema, str): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

200 elif isinstance(schema, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

202 elif isinstance(schema, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

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

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

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

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

210 } 

211 else: 

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

213 return schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

214 

215 

216class GenerateJsonSchema: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

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

219 

220 A class for generating JSON schemas. 

221 

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

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

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

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

226 

227 Attributes: 

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

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

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

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

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

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

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

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

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

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

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

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

240 definitions: Definitions in the schema. 

241 

242 Args: 

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

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

245 

246 Raises: 

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

248 """ 

249 

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

251 

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

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

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

255 

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

257 self.by_alias = by_alias 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

258 self.ref_template = ref_template 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

259 

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

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

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

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

264 

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

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

267 

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

269 

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

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

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

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

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

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

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

277 

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

279 

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

281 # so that they are available schemas that reference them 

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

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

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

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

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

287 

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

289 # of a single instance of a schema generator 

290 self._used = False 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

291 

292 @property 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

294 return self._config_wrapper_stack.tail 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

295 

296 @property 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

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

299 return self._config.json_schema_mode_override 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

300 else: 

301 return self._mode 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

302 

303 def build_schema_type_to_method( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

304 self, 

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

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

307 

308 Returns: 

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

310 

311 Raises: 

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

313 """ 

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

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

316 for key in core_schema_types: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

318 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

320 except AttributeError as e: # pragma: no cover 

321 if os.getenv('PYDANTIC_PRIVATE_ALLOW_UNHANDLED_SCHEMA_TYPES'): 

322 continue 

323 raise TypeError( 

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

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

326 ) from e 

327 return mapping 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

328 

329 def generate_definitions( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

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

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

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

334 

335 Args: 

336 inputs: A sequence of tuples, where: 

337 

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

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

340 - The third element is a core schema. 

341 

342 Returns: 

343 A tuple where: 

344 

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

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

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

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

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

350 

351 Raises: 

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

353 """ 

354 if self._used: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

355 raise PydanticUserError( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

359 ) 

360 

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

362 self._mode = mode 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

363 self.generate_inner(schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

364 

365 definitions_remapping = self._build_definitions_remapping() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

366 

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

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

369 self._mode = mode 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

370 json_schema = self.generate_inner(schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

372 

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

374 json_schema = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

375 self._used = True 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

377 

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

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

380 

381 Args: 

382 schema: A Pydantic model. 

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

384 

385 Returns: 

386 A JSON schema representing the specified schema. 

387 

388 Raises: 

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

390 """ 

391 self._mode = mode 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

392 if self._used: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

393 raise PydanticUserError( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

397 ) 

398 

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

400 json_ref_counts = self.get_json_ref_counts(json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

401 

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

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

404 ref_json_schema = self.get_schema_from_definitions(ref) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

408 json_ref_counts[ref] -= 1 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

410 ref = None 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

411 

412 self._garbage_collect_definitions(json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

413 definitions_remapping = self._build_definitions_remapping() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

414 

415 if self.definitions: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

417 

418 json_schema = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

419 

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

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

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

423 

424 self._used = True 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

425 return self.sort(json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

426 

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

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

429 

430 Args: 

431 schema: The given core schema. 

432 

433 Returns: 

434 The generated JSON schema. 

435 

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

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

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

439 """ 

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

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

442 # on types that should have different JSON schemas 

443 if 'ref' in schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

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

448 

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

450 if 'ref' in core_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

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

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

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

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

458 self.definitions[defs_ref] = json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

460 json_schema = ref_json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

461 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

462 

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

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

465 

466 Args: 

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

468 

469 Returns: 

470 The generated JSON schema. 

471 

472 Raises: 

473 TypeError: If an unexpected schema type is encountered. 

474 """ 

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

476 json_schema: JsonSchemaValue | None = None 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

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

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

482 json_schema = self.ser_schema(ser_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

483 

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

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

486 if ( 1zCEa

487 json_schema is not None 

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

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

490 ): 

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

492 if json_schema is None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

495 json_schema = generate_for_schema_type(schema_or_field) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

496 else: 

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

498 

499 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

500 

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

502 

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

504 

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

506 

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

508 

509 def js_updates_handler_func( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

510 schema_or_field: CoreSchemaOrField, 

511 current_handler: GetJsonSchemaHandler = current_handler, 

512 ) -> JsonSchemaValue: 

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

514 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

515 

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

517 

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

519 

520 def js_extra_handler_func( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

521 schema_or_field: CoreSchemaOrField, 

522 current_handler: GetJsonSchemaHandler = current_handler, 

523 ) -> JsonSchemaValue: 

524 json_schema = current_handler(schema_or_field) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

525 if isinstance(js_extra, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

529 js_extra(json_schema) # type: ignore 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHM

530 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

531 

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

533 

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

535 

536 def new_handler_func( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

537 schema_or_field: CoreSchemaOrField, 

538 current_handler: GetJsonSchemaHandler = current_handler, 

539 js_modify_function: GetJsonSchemaFunction = js_modify_function, 

540 ) -> JsonSchemaValue: 

541 json_schema = js_modify_function(schema_or_field, current_handler) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

543 json_schema = populate_defs(schema_or_field, json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

544 original_schema = current_handler.resolve_ref_schema(json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

547 original_schema.update(json_schema) 

548 return original_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

549 

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

551 

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

553 

554 def new_handler_func( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

555 schema_or_field: CoreSchemaOrField, 

556 current_handler: GetJsonSchemaHandler = current_handler, 

557 js_modify_function: GetJsonSchemaFunction = js_modify_function, 

558 ) -> JsonSchemaValue: 

559 return js_modify_function(schema_or_field, current_handler) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

560 

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

562 

563 json_schema = current_handler(schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

564 if _core_utils.is_core_schema(schema): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

565 json_schema = populate_defs(schema, json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

566 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

567 

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

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

575 keys = value.keys() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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 true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

577 keys = sorted(keys) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

578 for key in keys: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

580 return sorted_dict 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

581 

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

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

584 if isinstance(value, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

586 keys = value.keys() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

588 keys = sorted(keys) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

589 for key in keys: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

591 return sorted_dict 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

592 elif isinstance(value, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

594 for item in value: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

596 return sorted_list 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

597 else: 

598 return value 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

599 

600 # ### Schema generation methods 

601 

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

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

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

617 

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

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

628 

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

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

639 

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

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

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

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

652 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

653 

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

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

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

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

666 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

667 

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

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()) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

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

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

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

684 json_schema = { 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

700 

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

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

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

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

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

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

715 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

716 

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

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

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

728 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

729 

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

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

740 

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

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

751 

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

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

762 

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

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': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

775 

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

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

786 

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

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

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

790 else: 

791 result['enum'] = expected 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

792 

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

794 if types == {str}: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

796 elif types == {int}: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

798 elif types == {float}: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

800 elif types == {bool}: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

802 elif types == {list}: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

806 return result 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

807 

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

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

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

819 if ( 1zCEa

820 description == 'An enumeration.' 

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

822 description = None 1zCbdEaJKhiILcj

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

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

825 

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

827 

828 result['enum'] = expected 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

829 

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

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

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

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

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

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

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

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

838 result['type'] = 'boolean' 

839 elif types == {list}: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

841 

842 return result 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

843 

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

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"]})') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

856 

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

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

870 

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

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') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

883 

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

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']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

896 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

897 

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

899 @final 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

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) 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

910 @final 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

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

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

931 if 'variadic_item_index' in schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

932 variadic_item_index = schema['variadic_item_index'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

933 if variadic_item_index > 0: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

934 json_schema['minItems'] = variadic_item_index 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

935 json_schema['prefixItems'] = [ 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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 true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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]) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

948 if prefixItems: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

949 json_schema['prefixItems'] = prefixItems 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

953 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

954 

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

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) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

965 

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

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) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

976 

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

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

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

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

981 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

982 

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

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']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

995 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

996 

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

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

1007 

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

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

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

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

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

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

1020 

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

1022 # don't give a title to additionalProperties: 

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

1024 

1025 if values_schema or keys_pattern is not None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1026 if keys_pattern is None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1027 json_schema['additionalProperties'] = values_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1028 else: 

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

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

1032 

1033 if ( 1zCEa

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) 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1040 json_schema['propertyNames'] = keys_schema 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1041 

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

1043 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1044 

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

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')): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1055 return self.generate_inner(input_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1056 

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

1058 

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

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']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1069 

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

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 true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1080 return self.generate_inner(input_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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')): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1096 return self.generate_inner(input_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1097 

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

1099 

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

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']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1110 

1111 default = self.get_default_value(schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1112 if default is NoDefault: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1113 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1114 

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

1116 # JSON Schemas viewed in serialization mode: 

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

1118 if self.mode == 'serialization': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1120 ser_schema = _get_ser_schema_for_default_value(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1121 if ( 1zCEaJKIL

1122 ser_schema is not None 

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

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

1125 ): 

1126 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1127 default = ser_func(default) # type: ignore 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1128 except Exception: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

1132 # this pattern for now. 

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

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

1135 self.emit_warning( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1136 'non-serializable-default', 

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

1138 ) 

1139 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1140 

1141 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1142 encoded_default = self.encode_default(default) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1143 except pydantic_core.PydanticSerializationError: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1144 self.emit_warning( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1145 'non-serializable-default', 

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

1147 ) 

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

1149 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1150 

1151 json_schema['default'] = encoded_default 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1152 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1153 

1154 def get_default_value(self, schema: core_schema.WithDefaultSchema) -> Any: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1156 

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

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

1159 

1160 Args: 

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

1162 

1163 Returns: 

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

1165 value is available. 

1166 """ 

1167 return schema.get('default', NoDefault) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1168 

1169 def nullable_schema(self, schema: core_schema.NullableSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1171 

1172 Args: 

1173 schema: The core schema. 

1174 

1175 Returns: 

1176 The generated JSON schema. 

1177 """ 

1178 null_schema = {'type': 'null'} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1179 inner_json_schema = self.generate_inner(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1180 

1181 if inner_json_schema == null_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1182 return null_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1183 else: 

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

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

1186 return self.get_flattened_anyof([inner_json_schema, null_schema]) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1187 

1188 def union_schema(self, schema: core_schema.UnionSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1190 

1191 Args: 

1192 schema: The core schema. 

1193 

1194 Returns: 

1195 The generated JSON schema. 

1196 """ 

1197 generated: list[JsonSchemaValue] = [] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1198 

1199 choices = schema['choices'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1200 for choice in choices: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1202 choice_schema = choice[0] if isinstance(choice, tuple) else choice 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1203 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1204 generated.append(self.generate_inner(choice_schema)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1205 except PydanticOmit: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1206 continue 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1207 except PydanticInvalidForJsonSchema as exc: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1208 self.emit_warning('skipped-choice', exc.message) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1209 if len(generated) == 1: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1210 return generated[0] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1211 return self.get_flattened_anyof(generated) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1212 

1213 def tagged_union_schema(self, schema: core_schema.TaggedUnionSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

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

1216 the value. 

1217 

1218 Args: 

1219 schema: The core schema. 

1220 

1221 Returns: 

1222 The generated JSON schema. 

1223 """ 

1224 generated: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1226 if isinstance(k, Enum): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1227 k = k.value 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1228 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

1231 generated[str(k)] = self.generate_inner(v).copy() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1232 except PydanticOmit: 

1233 continue 

1234 except PydanticInvalidForJsonSchema as exc: 

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

1236 

1237 one_of_choices = _deduplicate_schemas(generated.values()) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1238 json_schema: JsonSchemaValue = {'oneOf': one_of_choices} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1239 

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

1241 openapi_discriminator = self._extract_discriminator(schema, one_of_choices) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1242 if openapi_discriminator is not None: 1242 ↛ 1248line 1242 didn't jump to line 1248 because the condition on line 1242 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1243 json_schema['discriminator'] = { 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1244 'propertyName': openapi_discriminator, 

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

1246 } 

1247 

1248 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1249 

1250 def _extract_discriminator( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1252 ) -> str | None: 

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

1254 schema.""" 

1255 openapi_discriminator: str | None = None 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1256 

1257 if isinstance(schema['discriminator'], str): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1258 return schema['discriminator'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1259 

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

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

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

1263 return schema['discriminator'][0] 

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

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

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

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

1268 for alias_path in schema['discriminator']: 1268 ↛ 1293line 1268 didn't jump to line 1293 because the loop on line 1268 didn't complete1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1269 if not isinstance(alias_path, list): 1269 ↛ 1270line 1269 didn't jump to line 1270 because the condition on line 1269 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1271 if len(alias_path) != 1: 1271 ↛ 1272line 1271 didn't jump to line 1272 because the condition on line 1271 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1273 alias = alias_path[0] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1274 if not isinstance(alias, str): 1274 ↛ 1275line 1274 didn't jump to line 1275 because the condition on line 1274 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1276 alias_is_present_on_all_choices = True 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1277 for choice in one_of_choices: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1278 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1279 choice = self.resolve_ref_schema(choice) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1280 except RuntimeError as exc: 

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

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

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

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

1285 choice = {} 

1286 properties = choice.get('properties', {}) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1287 if not isinstance(properties, dict) or alias not in properties: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1288 alias_is_present_on_all_choices = False 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1289 break 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1290 if alias_is_present_on_all_choices: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1291 openapi_discriminator = alias 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1292 break 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1293 return openapi_discriminator 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1294 

1295 def chain_schema(self, schema: core_schema.ChainSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1297 

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

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

1300 

1301 Args: 

1302 schema: The core schema. 

1303 

1304 Returns: 

1305 The generated JSON schema. 

1306 """ 

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

1308 return self.generate_inner(schema['steps'][step_index]) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1309 

1310 def lax_or_strict_schema(self, schema: core_schema.LaxOrStrictSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1312 strict schema. 

1313 

1314 Args: 

1315 schema: The core schema. 

1316 

1317 Returns: 

1318 The generated JSON schema. 

1319 """ 

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

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

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

1323 # because one of the following two branches failed. 

1324 if use_strict: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1325 return self.generate_inner(schema['strict_schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1326 else: 

1327 return self.generate_inner(schema['lax_schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1328 

1329 def json_or_python_schema(self, schema: core_schema.JsonOrPythonSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1331 Python schema. 

1332 

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

1334 this method. 

1335 

1336 Args: 

1337 schema: The core schema. 

1338 

1339 Returns: 

1340 The generated JSON schema. 

1341 """ 

1342 return self.generate_inner(schema['json_schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1343 

1344 def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1346 

1347 Args: 

1348 schema: The core schema. 

1349 

1350 Returns: 

1351 The generated JSON schema. 

1352 """ 

1353 total = schema.get('total', True) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1354 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

1357 if self.field_is_present(field) 

1358 ] 

1359 if self.mode == 'serialization': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1360 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1361 cls = schema.get('cls') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1362 config = _get_typed_dict_config(cls) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1363 with self._config_wrapper_stack.push(config): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1364 json_schema = self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1365 

1366 if cls is not None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1367 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1368 else: 

1369 extra = config.get('extra') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1370 if extra == 'forbid': 1370 ↛ 1371line 1370 didn't jump to line 1371 because the condition on line 1370 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1371 json_schema['additionalProperties'] = False 

1372 elif extra == 'allow': 1372 ↛ 1373line 1372 didn't jump to line 1373 because the condition on line 1372 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1373 json_schema['additionalProperties'] = True 

1374 

1375 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1376 

1377 @staticmethod 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

1378 def _name_required_computed_fields( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

1379 computed_fields: list[ComputedField], 

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

1381 return [(field['property_name'], True, field) for field in computed_fields] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1382 

1383 def _named_required_fields_schema( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1385 ) -> JsonSchemaValue: 

1386 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1387 required_fields: list[str] = [] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1388 for name, required, field in named_required_fields: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1389 if self.by_alias: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1390 name = self._get_alias_name(field, name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1391 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1392 field_json_schema = self.generate_inner(field).copy() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1393 except PydanticOmit: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1394 continue 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1395 if 'title' not in field_json_schema and self.field_title_should_be_set(field): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1396 title = self.get_title_from_name(name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1397 field_json_schema['title'] = title 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1398 field_json_schema = self.handle_ref_overrides(field_json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1399 properties[name] = field_json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1400 if required: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1401 required_fields.append(name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1402 

1403 json_schema = {'type': 'object', 'properties': properties} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1404 if required_fields: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1405 json_schema['required'] = required_fields 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1406 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1407 

1408 def _get_alias_name(self, field: CoreSchemaField, name: str) -> str: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

1409 if field['type'] == 'computed-field': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1410 alias: Any = field.get('alias', name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1411 elif self.mode == 'validation': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1412 alias = field.get('validation_alias', name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1413 else: 

1414 alias = field.get('serialization_alias', name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1415 if isinstance(alias, str): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1416 name = alias 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1417 elif isinstance(alias, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1418 alias = cast('list[str] | str', alias) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1419 for path in alias: 1419 ↛ 1427line 1419 didn't jump to line 1427 because the loop on line 1419 didn't complete1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

1423 name = path[0] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1424 break 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1425 else: 

1426 assert_never(alias) 

1427 return name 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1428 

1429 def typed_dict_field_schema(self, schema: core_schema.TypedDictField) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1431 

1432 Args: 

1433 schema: The core schema. 

1434 

1435 Returns: 

1436 The generated JSON schema. 

1437 """ 

1438 return self.generate_inner(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1439 

1440 def dataclass_field_schema(self, schema: core_schema.DataclassField) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1442 

1443 Args: 

1444 schema: The core schema. 

1445 

1446 Returns: 

1447 The generated JSON schema. 

1448 """ 

1449 return self.generate_inner(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1450 

1451 def model_field_schema(self, schema: core_schema.ModelField) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1453 

1454 Args: 

1455 schema: The core schema. 

1456 

1457 Returns: 

1458 The generated JSON schema. 

1459 """ 

1460 return self.generate_inner(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1461 

1462 def computed_field_schema(self, schema: core_schema.ComputedField) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1464 

1465 Args: 

1466 schema: The core schema. 

1467 

1468 Returns: 

1469 The generated JSON schema. 

1470 """ 

1471 return self.generate_inner(schema['return_schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1472 

1473 def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1475 

1476 Args: 

1477 schema: The core schema. 

1478 

1479 Returns: 

1480 The generated JSON schema. 

1481 """ 

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

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

1484 cls = cast('type[BaseModel]', schema['cls']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1485 config = cls.model_config 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1486 

1487 with self._config_wrapper_stack.push(config): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1488 json_schema = self.generate_inner(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1489 

1490 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1491 

1492 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1493 

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

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

1496 

1497 * title 

1498 * description 

1499 * additional properties 

1500 * json_schema_extra 

1501 * deprecated 

1502 

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

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

1505 """ 

1506 from .main import BaseModel 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1507 from .root_model import RootModel 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1508 

1509 if (config_title := config.get('title')) is not None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1510 json_schema.setdefault('title', config_title) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1511 elif model_title_generator := config.get('model_title_generator'): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1512 title = model_title_generator(cls) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1513 if not isinstance(title, str): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1515 json_schema.setdefault('title', title) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1516 if 'title' not in json_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1517 json_schema['title'] = cls.__name__ 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1518 

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

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

1521 

1522 if docstring: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1523 json_schema.setdefault('description', inspect.cleandoc(docstring)) 1zCbdenfogpADNEaJKhiqrstuvFGILcjkwlxmyBHM

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

1525 json_schema.setdefault('description', root_description) 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHM

1526 

1527 extra = config.get('extra') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1528 if 'additionalProperties' not in json_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1529 if extra == 'allow': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1530 json_schema['additionalProperties'] = True 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1531 elif extra == 'forbid': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1532 json_schema['additionalProperties'] = False 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1533 

1534 json_schema_extra = config.get('json_schema_extra') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1535 if issubclass(cls, BaseModel) and cls.__pydantic_root_model__: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1536 root_json_schema_extra = cls.model_fields['root'].json_schema_extra 1zCbdenfogpADNEaJKhiqrstuvFGILcjkwlxmyBHM

1537 if json_schema_extra and root_json_schema_extra: 1zCbdenfogpADNEaJKhiqrstuvFGILcjkwlxmyBHM

1538 raise ValueError( 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHM

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

1540 ' field must not be set simultaneously' 

1541 ) 

1542 if root_json_schema_extra: 1zCbdenfogpADNEaJKhiqrstuvFGILcjkwlxmyBHM

1543 json_schema_extra = root_json_schema_extra 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHM

1544 

1545 if isinstance(json_schema_extra, (staticmethod, classmethod)): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1547 json_schema_extra = json_schema_extra.__get__(cls) 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1548 

1549 if isinstance(json_schema_extra, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1550 json_schema.update(json_schema_extra) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1551 elif callable(json_schema_extra): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1553 if len(inspect.signature(json_schema_extra).parameters) > 1: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1554 json_schema_extra(json_schema, cls) # type: ignore 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1555 else: 

1556 json_schema_extra(json_schema) # type: ignore 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1557 elif json_schema_extra is not None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1558 raise ValueError( 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHM

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

1560 ) 

1561 

1562 if hasattr(cls, '__deprecated__'): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1563 json_schema['deprecated'] = True 1zCbdenfogpADNEaJKhiqrstuvFGILcjkwlxmyBHM

1564 

1565 def resolve_ref_schema(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1567 

1568 Args: 

1569 json_schema: The schema to resolve. 

1570 

1571 Returns: 

1572 The resolved schema. 

1573 

1574 Raises: 

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

1576 """ 

1577 while '$ref' in json_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1578 ref = json_schema['$ref'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1579 schema_to_update = self.get_schema_from_definitions(JsonRef(ref)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1580 if schema_to_update is None: 1580 ↛ 1581line 1580 didn't jump to line 1581 because the condition on line 1580 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1582 json_schema = schema_to_update 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1583 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1584 

1585 def model_fields_schema(self, schema: core_schema.ModelFieldsSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1587 

1588 Args: 

1589 schema: The core schema. 

1590 

1591 Returns: 

1592 The generated JSON schema. 

1593 """ 

1594 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

1597 if self.field_is_present(field) 

1598 ] 

1599 if self.mode == 'serialization': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1600 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1601 json_schema = self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1602 extras_schema = schema.get('extras_schema', None) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1603 if extras_schema is not None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1604 schema_to_update = self.resolve_ref_schema(json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1605 schema_to_update['additionalProperties'] = self.generate_inner(extras_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1606 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1607 

1608 def field_is_present(self, field: CoreSchemaField) -> bool: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1610 

1611 Args: 

1612 field: The schema for the field itself. 

1613 

1614 Returns: 

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

1616 """ 

1617 if self.mode == 'serialization': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1619 # override this method and return True 

1620 return not field.get('serialization_exclude') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1621 elif self.mode == 'validation': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1622 return True 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1623 else: 

1624 assert_never(self.mode) 

1625 

1626 def field_is_required( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

1627 self, 

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

1629 total: bool, 

1630 ) -> bool: 

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

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

1633 

1634 Args: 

1635 field: The schema for the field itself. 

1636 total: Only applies to `TypedDictField`s. 

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

1638 explicitly specify `required=False` are required. 

1639 

1640 Returns: 

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

1642 """ 

1643 if self.mode == 'serialization' and self._config.json_schema_serialization_defaults_required: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1644 return not field.get('serialization_exclude') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1645 else: 

1646 if field['type'] == 'typed-dict-field': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1647 return field.get('required', total) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1648 else: 

1649 return field['schema']['type'] != 'default' 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1650 

1651 def dataclass_args_schema(self, schema: core_schema.DataclassArgsSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1653 

1654 Args: 

1655 schema: The core schema. 

1656 

1657 Returns: 

1658 The generated JSON schema. 

1659 """ 

1660 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1662 for field in schema['fields'] 

1663 if self.field_is_present(field) 

1664 ] 

1665 if self.mode == 'serialization': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1666 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1667 return self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1668 

1669 def dataclass_schema(self, schema: core_schema.DataclassSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1671 

1672 Args: 

1673 schema: The core schema. 

1674 

1675 Returns: 

1676 The generated JSON schema. 

1677 """ 

1678 from ._internal._dataclasses import is_stdlib_dataclass 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1679 

1680 cls = schema['cls'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1681 config: ConfigDict = getattr(cls, '__pydantic_config__', cast('ConfigDict', {})) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1682 

1683 with self._config_wrapper_stack.push(config): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1684 json_schema = self.generate_inner(schema['schema']).copy() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1685 

1686 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1687 

1688 # Dataclass-specific handling of description 

1689 if is_stdlib_dataclass(cls): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1691 description = None 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1692 else: 

1693 description = None if cls.__doc__ is None else inspect.cleandoc(cls.__doc__) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1694 if description: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1695 json_schema['description'] = description 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHM

1696 

1697 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1698 

1699 def arguments_schema(self, schema: core_schema.ArgumentsSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1701 

1702 Args: 

1703 schema: The core schema. 

1704 

1705 Returns: 

1706 The generated JSON schema. 

1707 """ 

1708 prefer_positional = schema.get('metadata', {}).get('pydantic_js_prefer_positional_arguments') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1709 

1710 arguments = schema['arguments_schema'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

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

1714 var_args_schema = schema.get('var_args_schema') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1715 var_kwargs_schema = schema.get('var_kwargs_schema') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1716 

1717 if prefer_positional: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1718 positional_possible = not kw_only_arguments and not var_kwargs_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1719 if positional_possible: 1719 ↛ 1722line 1719 didn't jump to line 1722 because the condition on line 1719 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1720 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1721 

1722 keyword_possible = not p_only_arguments and not var_args_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1723 if keyword_possible: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1724 return self.kw_arguments_schema(kw_or_p_arguments + kw_only_arguments, var_kwargs_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1725 

1726 if not prefer_positional: 1726 ↛ 1731line 1726 didn't jump to line 1731 because the condition on line 1726 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1727 positional_possible = not kw_only_arguments and not var_kwargs_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1728 if positional_possible: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1729 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1730 

1731 raise PydanticInvalidForJsonSchema( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1733 ) 

1734 

1735 def kw_arguments_schema( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1737 ) -> JsonSchemaValue: 

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

1739 

1740 Args: 

1741 arguments: The core schema. 

1742 

1743 Returns: 

1744 The generated JSON schema. 

1745 """ 

1746 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1747 required: list[str] = [] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1748 for argument in arguments: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1749 name = self.get_argument_name(argument) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1750 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1751 argument_schema['title'] = self.get_title_from_name(name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1752 properties[name] = argument_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1753 

1754 if argument['schema']['type'] != 'default': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1756 # the inner schema must be of type WithDefaultSchema. 

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

1758 required.append(name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1759 

1760 json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1761 if required: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1762 json_schema['required'] = required 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1763 

1764 if var_kwargs_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1765 additional_properties_schema = self.generate_inner(var_kwargs_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1766 if additional_properties_schema: 1766 ↛ 1770line 1766 didn't jump to line 1770 because the condition on line 1766 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1767 json_schema['additionalProperties'] = additional_properties_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1768 else: 

1769 json_schema['additionalProperties'] = False 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1770 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1771 

1772 def p_arguments_schema( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1774 ) -> JsonSchemaValue: 

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

1776 

1777 Args: 

1778 arguments: The core schema. 

1779 

1780 Returns: 

1781 The generated JSON schema. 

1782 """ 

1783 prefix_items: list[JsonSchemaValue] = [] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1784 min_items = 0 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1785 

1786 for argument in arguments: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1787 name = self.get_argument_name(argument) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1788 

1789 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1790 argument_schema['title'] = self.get_title_from_name(name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1791 prefix_items.append(argument_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1792 

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

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

1795 # the inner schema must be of type WithDefaultSchema. 

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

1797 min_items += 1 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1798 

1799 json_schema: JsonSchemaValue = {'type': 'array'} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1800 if prefix_items: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1801 json_schema['prefixItems'] = prefix_items 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1802 if min_items: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1803 json_schema['minItems'] = min_items 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1804 

1805 if var_args_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1806 items_schema = self.generate_inner(var_args_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1807 if items_schema: 1807 ↛ 1812line 1807 didn't jump to line 1812 because the condition on line 1807 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1808 json_schema['items'] = items_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1809 else: 

1810 json_schema['maxItems'] = len(prefix_items) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1811 

1812 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1813 

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

1815 """Retrieves the name of an argument. 

1816 

1817 Args: 

1818 argument: The core schema. 

1819 

1820 Returns: 

1821 The name of the argument. 

1822 """ 

1823 name = argument['name'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1824 if self.by_alias: 1824 ↛ 1830line 1824 didn't jump to line 1830 because the condition on line 1824 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1825 alias = argument.get('alias') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1826 if isinstance(alias, str): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1827 name = alias 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1828 else: 

1829 pass # might want to do something else? 1bdenfogpADNahiqrstuvFGOcjkwlxmyBHM

1830 return name 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1831 

1832 def arguments_v3_schema(self, schema: core_schema.ArgumentsV3Schema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1834 

1835 Args: 

1836 schema: The core schema. 

1837 

1838 Returns: 

1839 The generated JSON schema. 

1840 """ 

1841 arguments = schema['arguments_schema'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1842 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1843 required: list[str] = [] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1844 for argument in arguments: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1845 mode = argument.get('mode', 'positional_or_keyword') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1846 name = self.get_argument_name(argument) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1847 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1848 if mode == 'var_args': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1849 argument_schema = {'type': 'array', 'items': argument_schema} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1850 elif mode == 'var_kwargs_uniform': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1851 argument_schema = {'type': 'object', 'additionalProperties': argument_schema} 1zCbdenfogpADEaJKhiqrstuvFGOILcjkwlxmyBH

1852 

1853 argument_schema.setdefault('title', self.get_title_from_name(name)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1854 properties[name] = argument_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1855 

1856 if ( 1zCEa

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

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

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

1860 ): 

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

1862 # the inner schema must be of type WithDefaultSchema. 

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

1864 required.append(name) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1865 

1866 json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1867 if required: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1868 json_schema['required'] = required 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1869 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1870 

1871 def call_schema(self, schema: core_schema.CallSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1873 

1874 Args: 

1875 schema: The core schema. 

1876 

1877 Returns: 

1878 The generated JSON schema. 

1879 """ 

1880 return self.generate_inner(schema['arguments_schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1881 

1882 def custom_error_schema(self, schema: core_schema.CustomErrorSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1884 

1885 Args: 

1886 schema: The core schema. 

1887 

1888 Returns: 

1889 The generated JSON schema. 

1890 """ 

1891 return self.generate_inner(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1892 

1893 def json_schema(self, schema: core_schema.JsonSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1895 

1896 Args: 

1897 schema: The core schema. 

1898 

1899 Returns: 

1900 The generated JSON schema. 

1901 """ 

1902 content_core_schema = schema.get('schema') or core_schema.any_schema() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1903 content_json_schema = self.generate_inner(content_core_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1904 if self.mode == 'validation': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1905 return {'type': 'string', 'contentMediaType': 'application/json', 'contentSchema': content_json_schema} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1906 else: 

1907 # self.mode == 'serialization' 

1908 return content_json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1909 

1910 def url_schema(self, schema: core_schema.UrlSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1912 

1913 Args: 

1914 schema: The core schema. 

1915 

1916 Returns: 

1917 The generated JSON schema. 

1918 """ 

1919 json_schema = {'type': 'string', 'format': 'uri', 'minLength': 1} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1920 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1921 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1922 

1923 def multi_host_url_schema(self, schema: core_schema.MultiHostUrlSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1925 

1926 Args: 

1927 schema: The core schema. 

1928 

1929 Returns: 

1930 The generated JSON schema. 

1931 """ 

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

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

1934 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1935 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1936 

1937 def uuid_schema(self, schema: core_schema.UuidSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1939 

1940 Args: 

1941 schema: The core schema. 

1942 

1943 Returns: 

1944 The generated JSON schema. 

1945 """ 

1946 return {'type': 'string', 'format': 'uuid'} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1947 

1948 def definitions_schema(self, schema: core_schema.DefinitionsSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1950 

1951 Args: 

1952 schema: The core schema. 

1953 

1954 Returns: 

1955 The generated JSON schema. 

1956 """ 

1957 for definition in schema['definitions']: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1958 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1959 self.generate_inner(definition) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1960 except PydanticInvalidForJsonSchema as e: 

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

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

1963 continue 

1964 return self.generate_inner(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1965 

1966 def definition_ref_schema(self, schema: core_schema.DefinitionReferenceSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1968 

1969 Args: 

1970 schema: The core schema. 

1971 

1972 Returns: 

1973 The generated JSON schema. 

1974 """ 

1975 core_ref = CoreRef(schema['schema_ref']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1976 _, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1977 return ref_json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1978 

1979 def ser_schema( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

1981 ) -> JsonSchemaValue | None: 

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

1983 

1984 Args: 

1985 schema: The core schema. 

1986 

1987 Returns: 

1988 The generated JSON schema. 

1989 """ 

1990 schema_type = schema['type'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1991 if schema_type == 'function-plain' or schema_type == 'function-wrap': 1991 ↛ 1996line 1991 didn't jump to line 1996 because the condition on line 1991 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1992 # PlainSerializerFunctionSerSchema or WrapSerializerFunctionSerSchema 

1993 return_schema = schema.get('return_schema') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1994 if return_schema is not None: 1994 ↛ 2002line 1994 didn't jump to line 2002 because the condition on line 1994 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

1995 return self.generate_inner(return_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

1997 # FormatSerSchema or ToStringSerSchema 

1998 return self.str_schema(core_schema.str_schema()) 

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

2000 # ModelSerSchema 

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

2002 return None 

2003 

2004 def complex_schema(self, schema: core_schema.ComplexSchema) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

2006 

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

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

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

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

2011 

2012 Args: 

2013 schema: The core schema. 

2014 

2015 Returns: 

2016 The generated JSON schema. 

2017 """ 

2018 return {'type': 'string'} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2019 

2020 # ### Utility methods 

2021 

2022 def get_title_from_name(self, name: str) -> str: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2023 """Retrieves a title from a name. 

2024 

2025 Args: 

2026 name: The name to retrieve a title from. 

2027 

2028 Returns: 

2029 The title. 

2030 """ 

2031 return name.title().replace('_', ' ').strip() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2032 

2033 def field_title_should_be_set(self, schema: CoreSchemaOrField) -> bool: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

2035 

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

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

2038 

2039 Args: 

2040 schema: The schema to check. 

2041 

2042 Returns: 

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

2044 """ 

2045 if _core_utils.is_core_schema_field(schema): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2046 if schema['type'] == 'computed-field': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2047 field_schema = schema['return_schema'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2048 else: 

2049 field_schema = schema['schema'] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2050 return self.field_title_should_be_set(field_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2051 

2052 elif _core_utils.is_core_schema(schema): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

2054 return False 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2055 if schema['type'] in {'default', 'nullable', 'definitions'}: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

2057 if _core_utils.is_function_with_inner_schema(schema): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2058 return self.field_title_should_be_set(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2059 if schema['type'] == 'definition-ref': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

2061 # schemas with refs should not 

2062 return False 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2063 return True # anything else should have title set 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2064 

2065 else: 

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

2067 

2068 def normalize_name(self, name: str) -> str: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

2070 

2071 Args: 

2072 name: The name to normalize. 

2073 

2074 Returns: 

2075 The normalized name. 

2076 """ 

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

2078 

2079 def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

2081 

2082 Args: 

2083 core_mode_ref: The core reference. 

2084 

2085 Returns: 

2086 The definitions key. 

2087 """ 

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

2089 core_ref, mode = core_mode_ref 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2090 components = re.split(r'([\][,])', core_ref) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2091 # Remove IDs from each component 

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

2093 core_ref_no_id = ''.join(components) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

2096 short_ref = ''.join(components) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2097 

2098 mode_title = _MODE_TITLE_MAPPING[mode] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2099 

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

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

2102 # the id of the source type in the core_ref 

2103 name = DefsRef(self.normalize_name(short_ref)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

2105 module_qualname = DefsRef(self.normalize_name(core_ref_no_id)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2106 module_qualname_mode = DefsRef(f'{module_qualname}-{mode_title}') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2107 module_qualname_id = DefsRef(self.normalize_name(core_ref)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2108 occurrence_index = self._collision_index.get(module_qualname_id) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2109 if occurrence_index is None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2110 self._collision_counter[module_qualname] += 1 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2111 occurrence_index = self._collision_index[module_qualname_id] = self._collision_counter[module_qualname] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2112 

2113 module_qualname_occurrence = DefsRef(f'{module_qualname}__{occurrence_index}') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2114 module_qualname_occurrence_mode = DefsRef(f'{module_qualname_mode}__{occurrence_index}') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2115 

2116 self._prioritized_defsref_choices[module_qualname_occurrence_mode] = [ 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2117 name, 

2118 name_mode, 

2119 module_qualname, 

2120 module_qualname_mode, 

2121 module_qualname_occurrence, 

2122 module_qualname_occurrence_mode, 

2123 ] 

2124 

2125 return module_qualname_occurrence_mode 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2126 

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

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

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

2130 

2131 Args: 

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

2133 

2134 Returns: 

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

2136 """ 

2137 core_mode_ref = (core_ref, self.mode) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2138 maybe_defs_ref = self.core_to_defs_refs.get(core_mode_ref) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2139 if maybe_defs_ref is not None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2140 json_ref = self.core_to_json_refs[core_mode_ref] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2141 return maybe_defs_ref, {'$ref': json_ref} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2142 

2143 defs_ref = self.get_defs_ref(core_mode_ref) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2144 

2145 # populate the ref translation mappings 

2146 self.core_to_defs_refs[core_mode_ref] = defs_ref 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2147 self.defs_to_core_refs[defs_ref] = core_mode_ref 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2148 

2149 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2150 self.core_to_json_refs[core_mode_ref] = json_ref 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2151 self.json_to_defs_refs[json_ref] = defs_ref 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2152 ref_json_schema = {'$ref': json_ref} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2153 return defs_ref, ref_json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2154 

2155 def handle_ref_overrides(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

2157 

2158 Args: 

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

2160 

2161 Returns: 

2162 The schema with redundant sibling keys removed. 

2163 """ 

2164 if '$ref' in json_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

2166 json_schema = json_schema.copy() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2167 

2168 referenced_json_schema = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2169 if referenced_json_schema is None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

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

2172 # any redundant override keys. 

2173 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2174 for k, v in list(json_schema.items()): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2175 if k == '$ref': 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2176 continue 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2177 if k in referenced_json_schema and referenced_json_schema[k] == v: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2178 del json_schema[k] # redundant key 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2179 

2180 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2181 

2182 def get_schema_from_definitions(self, json_ref: JsonRef) -> JsonSchemaValue | None: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2183 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2184 def_ref = self.json_to_defs_refs[json_ref] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2185 if def_ref in self._core_defs_invalid_for_json_schema: 2185 ↛ 2186line 2185 didn't jump to line 2186 because the condition on line 2185 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2186 raise self._core_defs_invalid_for_json_schema[def_ref] 

2187 return self.definitions.get(def_ref, None) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2188 except KeyError: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

2190 return None 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2191 raise 

2192 

2193 def encode_default(self, dft: Any) -> Any: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

2195 

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

2197 

2198 Args: 

2199 dft: The default value to encode. 

2200 

2201 Returns: 

2202 The encoded default value. 

2203 """ 

2204 from .type_adapter import TypeAdapter, _type_has_config 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2205 

2206 config = self._config 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2207 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2208 default = ( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2209 dft 

2210 if _type_has_config(type(dft)) 

2211 else TypeAdapter(type(dft), config=config.config_dict).dump_python( 

2212 dft, by_alias=self.by_alias, mode='json' 

2213 ) 

2214 ) 

2215 except PydanticSchemaGenerationError: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

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

2217 

2218 return pydantic_core.to_jsonable_python( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2219 default, timedelta_mode=config.ser_json_timedelta, bytes_mode=config.ser_json_bytes, by_alias=self.by_alias 

2220 ) 

2221 

2222 def update_with_validations( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

2224 ) -> None: 

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

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

2227 

2228 Args: 

2229 json_schema: The JSON schema to update. 

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

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

2232 """ 

2233 for core_key, json_schema_key in mapping.items(): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2234 if core_key in core_schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2235 json_schema[json_schema_key] = core_schema[core_key] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2236 

2237 class ValidationsMapping: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

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

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

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

2241 GenerateJsonSchema.ValidationsMapping) to change these mappings. 

2242 """ 

2243 

2244 numeric = { 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2245 'multiple_of': 'multipleOf', 

2246 'le': 'maximum', 

2247 'ge': 'minimum', 

2248 'lt': 'exclusiveMaximum', 

2249 'gt': 'exclusiveMinimum', 

2250 } 

2251 bytes = { 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2252 'min_length': 'minLength', 

2253 'max_length': 'maxLength', 

2254 } 

2255 string = { 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2256 'min_length': 'minLength', 

2257 'max_length': 'maxLength', 

2258 'pattern': 'pattern', 

2259 } 

2260 array = { 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2261 'min_length': 'minItems', 

2262 'max_length': 'maxItems', 

2263 } 

2264 object = { 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2265 'min_length': 'minProperties', 

2266 'max_length': 'maxProperties', 

2267 } 

2268 

2269 def get_flattened_anyof(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2270 members = [] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2271 for schema in schemas: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2272 if len(schema) == 1 and 'anyOf' in schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2273 members.extend(schema['anyOf']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2274 else: 

2275 members.append(schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2276 members = _deduplicate_schemas(members) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2277 if len(members) == 1: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2278 return members[0] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2279 return {'anyOf': members} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2280 

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

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

2283 json_refs: dict[JsonRef, int] = Counter() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2284 

2285 def _add_json_refs(schema: Any) -> None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2286 if isinstance(schema, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2287 if '$ref' in schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2288 json_ref = JsonRef(schema['$ref']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2289 if not isinstance(json_ref, str): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2290 return # in this case, '$ref' might have been the name of a property 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2291 already_visited = json_ref in json_refs 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2292 json_refs[json_ref] += 1 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2293 if already_visited: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2294 return # prevent recursion on a definition that was already visited 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2295 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2296 defs_ref = self.json_to_defs_refs[json_ref] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2297 if defs_ref in self._core_defs_invalid_for_json_schema: 2297 ↛ 2298line 2297 didn't jump to line 2298 because the condition on line 2297 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2298 raise self._core_defs_invalid_for_json_schema[defs_ref] 

2299 _add_json_refs(self.definitions[defs_ref]) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2300 except KeyError: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2301 if not json_ref.startswith(('http://', 'https://')): 2301 ↛ 2302line 2301 didn't jump to line 2302 because the condition on line 2301 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2302 raise 

2303 

2304 for k, v in schema.items(): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2305 if k == 'examples' and isinstance(v, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2306 # Skip examples that may contain arbitrary values and references 

2307 # (see the comment in `_get_all_json_refs` for more details). 

2308 continue 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2309 _add_json_refs(v) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2310 elif isinstance(schema, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2311 for v in schema: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2312 _add_json_refs(v) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2313 

2314 _add_json_refs(json_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2315 return json_refs 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2316 

2317 def handle_invalid_for_json_schema(self, schema: CoreSchemaOrField, error_info: str) -> JsonSchemaValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2318 raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2319 

2320 def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2321 """This method simply emits PydanticJsonSchemaWarnings based on handling in the `warning_message` method.""" 

2322 message = self.render_warning_message(kind, detail) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2323 if message is not None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2324 warnings.warn(message, PydanticJsonSchemaWarning) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2325 

2326 def render_warning_message(self, kind: JsonSchemaWarningKind, detail: str) -> str | None: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2327 """This method is responsible for ignoring warnings as desired, and for formatting the warning messages. 

2328 

2329 You can override the value of `ignored_warning_kinds` in a subclass of GenerateJsonSchema 

2330 to modify what warnings are generated. If you want more control, you can override this method; 

2331 just return None in situations where you don't want warnings to be emitted. 

2332 

2333 Args: 

2334 kind: The kind of warning to render. It can be one of the following: 

2335 

2336 - 'skipped-choice': A choice field was skipped because it had no valid choices. 

2337 - 'non-serializable-default': A default value was skipped because it was not JSON-serializable. 

2338 detail: A string with additional details about the warning. 

2339 

2340 Returns: 

2341 The formatted warning message, or `None` if no warning should be emitted. 

2342 """ 

2343 if kind in self.ignored_warning_kinds: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2344 return None 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2345 return f'{detail} [{kind}]' 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2346 

2347 def _build_definitions_remapping(self) -> _DefinitionsRemapping: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2348 defs_to_json: dict[DefsRef, JsonRef] = {} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2349 for defs_refs in self._prioritized_defsref_choices.values(): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2350 for defs_ref in defs_refs: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2351 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2352 defs_to_json[defs_ref] = json_ref 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2353 

2354 return _DefinitionsRemapping.from_prioritized_choices( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2355 self._prioritized_defsref_choices, defs_to_json, self.definitions 

2356 ) 

2357 

2358 def _garbage_collect_definitions(self, schema: JsonSchemaValue) -> None: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2359 visited_defs_refs: set[DefsRef] = set() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2360 unvisited_json_refs = _get_all_json_refs(schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2361 while unvisited_json_refs: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2362 next_json_ref = unvisited_json_refs.pop() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2363 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2364 next_defs_ref = self.json_to_defs_refs[next_json_ref] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2365 if next_defs_ref in visited_defs_refs: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2366 continue 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2367 visited_defs_refs.add(next_defs_ref) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2368 unvisited_json_refs.update(_get_all_json_refs(self.definitions[next_defs_ref])) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2369 except KeyError: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2370 if not next_json_ref.startswith(('http://', 'https://')): 2370 ↛ 2371line 2370 didn't jump to line 2371 because the condition on line 2370 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2371 raise 

2372 

2373 self.definitions = {k: v for k, v in self.definitions.items() if k in visited_defs_refs} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2374 

2375 

2376# ##### Start JSON Schema Generation Functions ##### 

2377 

2378 

2379def model_json_schema( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2380 cls: type[BaseModel] | type[PydanticDataclass], 

2381 by_alias: bool = True, 

2382 ref_template: str = DEFAULT_REF_TEMPLATE, 

2383 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2384 mode: JsonSchemaMode = 'validation', 

2385) -> dict[str, Any]: 

2386 """Utility function to generate a JSON Schema for a model. 

2387 

2388 Args: 

2389 cls: The model class to generate a JSON Schema for. 

2390 by_alias: If `True` (the default), fields will be serialized according to their alias. 

2391 If `False`, fields will be serialized according to their attribute name. 

2392 ref_template: The template to use for generating JSON Schema references. 

2393 schema_generator: The class to use for generating the JSON Schema. 

2394 mode: The mode to use for generating the JSON Schema. It can be one of the following: 

2395 

2396 - 'validation': Generate a JSON Schema for validating data. 

2397 - 'serialization': Generate a JSON Schema for serializing data. 

2398 

2399 Returns: 

2400 The generated JSON Schema. 

2401 """ 

2402 from .main import BaseModel 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2403 

2404 schema_generator_instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2405 

2406 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2407 cls.__pydantic_core_schema__.rebuild() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2408 

2409 if cls is BaseModel: 2409 ↛ 2410line 2409 didn't jump to line 2410 because the condition on line 2409 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2410 raise AttributeError('model_json_schema() must be called on a subclass of BaseModel, not BaseModel itself.') 

2411 

2412 assert not isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2413 return schema_generator_instance.generate(cls.__pydantic_core_schema__, mode=mode) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2414 

2415 

2416def models_json_schema( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2417 models: Sequence[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode]], 

2418 *, 

2419 by_alias: bool = True, 

2420 title: str | None = None, 

2421 description: str | None = None, 

2422 ref_template: str = DEFAULT_REF_TEMPLATE, 

2423 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2424) -> tuple[dict[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: 

2425 """Utility function to generate a JSON Schema for multiple models. 

2426 

2427 Args: 

2428 models: A sequence of tuples of the form (model, mode). 

2429 by_alias: Whether field aliases should be used as keys in the generated JSON Schema. 

2430 title: The title of the generated JSON Schema. 

2431 description: The description of the generated JSON Schema. 

2432 ref_template: The reference template to use for generating JSON Schema references. 

2433 schema_generator: The schema generator to use for generating the JSON Schema. 

2434 

2435 Returns: 

2436 A tuple where: 

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

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

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

2440 - The second element is a JSON schema containing all definitions referenced in the first returned 

2441 element, along with the optional title and description keys. 

2442 """ 

2443 for cls, _ in models: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2444 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 2444 ↛ 2445line 2444 didn't jump to line 2445 because the condition on line 2444 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2445 cls.__pydantic_core_schema__.rebuild() 

2446 

2447 instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2448 inputs: list[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode, CoreSchema]] = [ 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2449 (m, mode, m.__pydantic_core_schema__) for m, mode in models 

2450 ] 

2451 json_schemas_map, definitions = instance.generate_definitions(inputs) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2452 

2453 json_schema: dict[str, Any] = {} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2454 if definitions: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2455 json_schema['$defs'] = definitions 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2456 if title: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2457 json_schema['title'] = title 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2458 if description: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2459 json_schema['description'] = description 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

2460 

2461 return json_schemas_map, json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2462 

2463 

2464# ##### End JSON Schema Generation Functions ##### 

2465 

2466 

2467_HashableJsonValue: TypeAlias = Union[ 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2468 int, float, str, bool, None, tuple['_HashableJsonValue', ...], tuple[tuple[str, '_HashableJsonValue'], ...] 

2469] 

2470 

2471 

2472def _deduplicate_schemas(schemas: Iterable[JsonDict]) -> list[JsonDict]: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2473 return list({_make_json_hashable(schema): schema for schema in schemas}.values()) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2474 

2475 

2476def _make_json_hashable(value: JsonValue) -> _HashableJsonValue: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2477 if isinstance(value, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2478 return tuple(sorted((k, _make_json_hashable(v)) for k, v in value.items())) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2479 elif isinstance(value, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2480 return tuple(_make_json_hashable(v) for v in value) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2481 else: 

2482 return value 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2483 

2484 

2485@dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2486class WithJsonSchema: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2487 """!!! abstract "Usage Documentation" 

2488 [`WithJsonSchema` Annotation](../concepts/json_schema.md#withjsonschema-annotation) 

2489 

2490 Add this as an annotation on a field to override the (base) JSON schema that would be generated for that field. 

2491 This provides a way to set a JSON schema for types that would otherwise raise errors when producing a JSON schema, 

2492 such as Callable, or types that have an is-instance core schema, without needing to go so far as creating a 

2493 custom subclass of pydantic.json_schema.GenerateJsonSchema. 

2494 Note that any _modifications_ to the schema that would normally be made (such as setting the title for model fields) 

2495 will still be performed. 

2496 

2497 If `mode` is set this will only apply to that schema generation mode, allowing you 

2498 to set different json schemas for validation and serialization. 

2499 """ 

2500 

2501 json_schema: JsonSchemaValue | None 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2502 mode: Literal['validation', 'serialization'] | None = None 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2503 

2504 def __get_pydantic_json_schema__( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2505 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2506 ) -> JsonSchemaValue: 

2507 mode = self.mode or handler.mode 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2508 if mode != handler.mode: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2509 return handler(core_schema) 1zbefgAIcklmB

2510 if self.json_schema is None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2511 # This exception is handled in pydantic.json_schema.GenerateJsonSchema._named_required_fields_schema 

2512 raise PydanticOmit 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2513 else: 

2514 return self.json_schema.copy() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2515 

2516 def __hash__(self) -> int: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2517 return hash(type(self.mode)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2518 

2519 

2520class Examples: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2521 """Add examples to a JSON schema. 

2522 

2523 If the JSON Schema already contains examples, the provided examples 

2524 will be appended. 

2525 

2526 If `mode` is set this will only apply to that schema generation mode, 

2527 allowing you to add different examples for validation and serialization. 

2528 """ 

2529 

2530 @overload 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2531 @deprecated('Using a dict for `examples` is deprecated since v2.9 and will be removed in v3.0. Use a list instead.') 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2532 def __init__( 1zCbdenfogpADNJKhiqrstuvFGOPILcjkwlxmyBHM

2533 self, examples: dict[str, Any], mode: Literal['validation', 'serialization'] | None = None 1bdenfogpEahiqrstuvPcjkwlxmy

2534 ) -> None: ... 1fogpEastuvPlxmy

2535 

2536 @overload 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2537 def __init__(self, examples: list[Any], mode: Literal['validation', 'serialization'] | None = None) -> None: ... 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2538 

2539 def __init__( 1zCbdenfogpADNJKhiqrstuvFGOPILcjkwlxmyBHM

2540 self, examples: dict[str, Any] | list[Any], mode: Literal['validation', 'serialization'] | None = None 

2541 ) -> None: 

2542 if isinstance(examples, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2543 warnings.warn( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2544 'Using a dict for `examples` is deprecated, use a list instead.', 

2545 PydanticDeprecatedSince29, 

2546 stacklevel=2, 

2547 ) 

2548 self.examples = examples 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2549 self.mode = mode 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2550 

2551 def __get_pydantic_json_schema__( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2552 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2553 ) -> JsonSchemaValue: 

2554 mode = self.mode or handler.mode 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2555 json_schema = handler(core_schema) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2556 if mode != handler.mode: 2556 ↛ 2557line 2556 didn't jump to line 2557 because the condition on line 2556 was never true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2557 return json_schema 

2558 examples = json_schema.get('examples') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2559 if examples is None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2560 json_schema['examples'] = to_jsonable_python(self.examples) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2561 if isinstance(examples, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2562 if isinstance(self.examples, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2563 warnings.warn( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2564 'Updating existing JSON Schema examples of type dict with examples of type list. ' 

2565 'Only the existing examples values will be retained. Note that dict support for ' 

2566 'examples is deprecated and will be removed in v3.0.', 

2567 UserWarning, 

2568 ) 

2569 json_schema['examples'] = to_jsonable_python( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2570 [ex for value in examples.values() for ex in value] + self.examples 

2571 ) 

2572 else: 

2573 json_schema['examples'] = to_jsonable_python({**examples, **self.examples}) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2574 if isinstance(examples, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2575 if isinstance(self.examples, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2576 json_schema['examples'] = to_jsonable_python(examples + self.examples) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2577 elif isinstance(self.examples, dict): 2577 ↛ 2588line 2577 didn't jump to line 2588 because the condition on line 2577 was always true1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2578 warnings.warn( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2579 'Updating existing JSON Schema examples of type list with examples of type dict. ' 

2580 'Only the examples values will be retained. Note that dict support for ' 

2581 'examples is deprecated and will be removed in v3.0.', 

2582 UserWarning, 

2583 ) 

2584 json_schema['examples'] = to_jsonable_python( 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2585 examples + [ex for value in self.examples.values() for ex in value] 

2586 ) 

2587 

2588 return json_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2589 

2590 def __hash__(self) -> int: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2591 return hash(type(self.mode)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2592 

2593 

2594def _get_all_json_refs(item: Any) -> set[JsonRef]: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2595 """Get all the definitions references from a JSON schema.""" 

2596 refs: set[JsonRef] = set() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2597 stack = [item] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2598 

2599 while stack: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2600 current = stack.pop() 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2601 if isinstance(current, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2602 for key, value in current.items(): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2603 if key == 'examples' and isinstance(value, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2604 # Skip examples that may contain arbitrary values and references 

2605 # (e.g. `{"examples": [{"$ref": "..."}]}`). Note: checking for value 

2606 # of type list is necessary to avoid skipping valid portions of the schema, 

2607 # for instance when "examples" is used as a property key. A more robust solution 

2608 # could be found, but would require more advanced JSON Schema parsing logic. 

2609 continue 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2610 if key == '$ref' and isinstance(value, str): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2611 refs.add(JsonRef(value)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2612 elif isinstance(value, dict): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2613 stack.append(value) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2614 elif isinstance(value, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2615 stack.extend(value) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2616 elif isinstance(current, list): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2617 stack.extend(current) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2618 

2619 return refs 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2620 

2621 

2622AnyType = TypeVar('AnyType') 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2623 

2624if TYPE_CHECKING: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2625 SkipJsonSchema = Annotated[AnyType, ...] 

2626else: 

2627 

2628 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2629 class SkipJsonSchema: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2630 """!!! abstract "Usage Documentation" 

2631 [`SkipJsonSchema` Annotation](../concepts/json_schema.md#skipjsonschema-annotation) 

2632 

2633 Add this as an annotation on a field to skip generating a JSON schema for that field. 

2634 

2635 Example: 

2636 ```python 

2637 from pprint import pprint 

2638 from typing import Union 

2639 

2640 from pydantic import BaseModel 

2641 from pydantic.json_schema import SkipJsonSchema 

2642 

2643 class Model(BaseModel): 

2644 a: Union[int, None] = None # (1)! 

2645 b: Union[int, SkipJsonSchema[None]] = None # (2)! 

2646 c: SkipJsonSchema[Union[int, None]] = None # (3)! 

2647 

2648 pprint(Model.model_json_schema()) 

2649 ''' 

2650 { 

2651 'properties': { 

2652 'a': { 

2653 'anyOf': [ 

2654 {'type': 'integer'}, 

2655 {'type': 'null'} 

2656 ], 

2657 'default': None, 

2658 'title': 'A' 

2659 }, 

2660 'b': { 

2661 'default': None, 

2662 'title': 'B', 

2663 'type': 'integer' 

2664 } 

2665 }, 

2666 'title': 'Model', 

2667 'type': 'object' 

2668 } 

2669 ''' 

2670 ``` 

2671 

2672 1. The integer and null types are both included in the schema for `a`. 

2673 2. The integer type is the only type included in the schema for `b`. 

2674 3. The entirety of the `c` field is omitted from the schema. 

2675 """ 

2676 

2677 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2678 return Annotated[item, cls()] 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2679 

2680 def __get_pydantic_json_schema__( 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2681 self, core_schema: CoreSchema, handler: GetJsonSchemaHandler 

2682 ) -> JsonSchemaValue: 

2683 raise PydanticOmit 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2684 

2685 def __hash__(self) -> int: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2686 return hash(type(self)) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2687 

2688 

2689def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2690 if cls is not None: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2691 try: 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2692 return _decorators.get_attribute_from_bases(cls, '__pydantic_config__') 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2693 except AttributeError: 1zCbdenfogpADNEaJKhiqrstuvFGILcjkwlxmyBHM

2694 pass 1zCbdenfogpADNEaJKhiqrstuvFGILcjkwlxmyBHM

2695 return {} 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2696 

2697 

2698def _get_ser_schema_for_default_value(schema: CoreSchema) -> core_schema.PlainSerializerFunctionSerSchema | None: 1zCbdenfogpADNEaJKhiqrstuvFGOPILcjkwlxmyBHM

2699 """Get a `'function-plain'` serialization schema that can be used to serialize a default value. 

2700 

2701 This takes into account having the serialization schema nested under validation schema(s). 

2702 """ 

2703 if ( 1zCbdenEaJKhiqrILcjkw

2704 (ser_schema := schema.get('serialization')) 

2705 and ser_schema['type'] == 'function-plain' 

2706 and not ser_schema.get('info_arg') 

2707 ): 

2708 return ser_schema 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2709 if _core_utils.is_function_with_inner_schema(schema): 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM

2710 return _get_ser_schema_for_default_value(schema['schema']) 1zCbdenfogpADNEaJKhiqrstuvFGOILcjkwlxmyBHM