Coverage for pydantic/json_schema.py: 94.66%

1107 statements  

« prev     ^ index     » next       coverage.py v7.10.0, created at 2025-07-26 11:49 +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 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

13 

14import dataclasses 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

15import inspect 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

16import math 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

17import os 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

18import re 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

19import warnings 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

20from collections import Counter, defaultdict 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

22from copy import deepcopy 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

23from enum import Enum 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

24from re import Pattern 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

25from typing import ( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

39from pydantic_core import MISSING, CoreSchema, PydanticOmit, core_schema, to_jsonable_python 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

40from pydantic_core.core_schema import ComputedField 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

42from typing_inspection.introspection import get_literal_values 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

43 

44from pydantic.warnings import PydanticDeprecatedSince26, PydanticDeprecatedSince29 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

45 

46from ._internal import ( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

56from .config import JsonDict, JsonValue 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

58 

59if TYPE_CHECKING: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

68""" 1bdenfogpADEahiqrstuvGHIPcjkwlxmyBJK

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

75""" 1bdenfogpADEahiqrstuvGHIPcjkwlxmyBJK

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

80""" 1bdenfogpADEahiqrstuvGHIPcjkwlxmyBJK

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

90 

91 

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

93""" 1bdenfogpADEahiqrstuvGHIPcjkwlxmyBJK

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

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

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

111for a core schema with a default value. 

112""" 

113 

114 

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

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

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

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

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

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

130 

131CoreModeRef = tuple[CoreRef, JsonSchemaMode] 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

133 

134 

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

136class _DefinitionsRemapping: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

137 defs_remapping: dict[DefsRef, DefsRef] 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

138 json_remapping: dict[JsonRef, JsonRef] 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

139 

140 @staticmethod 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

141 def from_prioritized_choices( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

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

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 complete1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

159 for defs_ref in copied_definitions: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

160 alternatives = prioritized_choices[defs_ref] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

161 for alternative in alternatives: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

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

168 

169 # Build the remapping 

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

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

172 for original_defs_ref in definitions: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

173 alternatives = prioritized_choices[original_defs_ref] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

176 defs_remapping[original_defs_ref] = remapped_defs_ref 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

178 remapping = _DefinitionsRemapping(defs_remapping, json_remapping) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

180 if definitions_schema == new_definitions_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

181 # We've reached the fixed point 

182 return remapping 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

183 definitions_schema = new_definitions_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

184 

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

186 

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

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

189 

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

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

192 

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

194 """ 

195 Recursively update the JSON schema replacing all $refs 

196 """ 

197 if isinstance(schema, str): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

200 elif isinstance(schema, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

202 elif isinstance(schema, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

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

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

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

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

213 return schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

214 

215 

216class GenerateJsonSchema: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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' 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

255 

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

257 self.by_alias = by_alias 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

258 self.ref_template = ref_template 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

259 

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

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

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

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

264 

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

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

267 

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

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

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

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

277 

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

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

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

291 

292 @property 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

294 return self._config_wrapper_stack.tail 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

295 

296 @property 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

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

299 return self._config.json_schema_mode_override 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

300 else: 

301 return self._mode 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

302 

303 def build_schema_type_to_method( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

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

316 for key in core_schema_types: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

318 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

328 

329 def generate_definitions( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

355 raise PydanticUserError( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

362 self._mode = mode 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

363 self.generate_inner(schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

364 

365 definitions_remapping = self._build_definitions_remapping() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

366 

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

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

369 self._mode = mode 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

370 json_schema = self.generate_inner(schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

372 

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

374 json_schema = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

375 self._used = True 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

377 

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

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

392 if self._used: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

393 raise PydanticUserError( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

400 json_ref_counts = self.get_json_ref_counts(json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

401 

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

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

404 ref_json_schema = self.get_schema_from_definitions(ref) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

408 json_ref_counts[ref] -= 1 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

410 ref = None 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

411 

412 self._garbage_collect_definitions(json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

413 definitions_remapping = self._build_definitions_remapping() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

414 

415 if self.definitions: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

417 

418 json_schema = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

425 return self.sort(json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

426 

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

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

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

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

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

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

448 

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

450 if 'ref' in core_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

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

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 true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

458 self.definitions[defs_ref] = json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

460 json_schema = ref_json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

461 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

462 

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

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

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

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

482 json_schema = self.ser_schema(ser_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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 ( 1zCFa

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

492 if json_schema is None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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 true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

495 json_schema = generate_for_schema_type(schema_or_field) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

496 else: 

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

498 

499 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

500 

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

502 

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

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

508 

509 def js_updates_handler_func( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

510 schema_or_field: CoreSchemaOrField, 

511 current_handler: GetJsonSchemaHandler = current_handler, 

512 ) -> JsonSchemaValue: 

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

514 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

515 

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

517 

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

519 

520 def js_extra_handler_func( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

521 schema_or_field: CoreSchemaOrField, 

522 current_handler: GetJsonSchemaHandler = current_handler, 

523 ) -> JsonSchemaValue: 

524 json_schema = current_handler(schema_or_field) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

525 if isinstance(js_extra, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

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

529 js_extra(json_schema) # type: ignore 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

530 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

531 

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

533 

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

535 

536 def new_handler_func( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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 true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

543 json_schema = populate_defs(schema_or_field, json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

544 original_schema = current_handler.resolve_ref_schema(json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

547 original_schema.update(json_schema) 

548 return original_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

549 

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

551 

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

553 

554 def new_handler_func( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

560 

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

562 

563 json_schema = current_handler(schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

564 if _core_utils.is_core_schema(schema): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

565 json_schema = populate_defs(schema, json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

566 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

567 

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

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

575 keys = value.keys() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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 true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

577 keys = sorted(keys) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

578 for key in keys: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

580 return sorted_dict 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

581 

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

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

584 if isinstance(value, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

586 keys = value.keys() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

588 keys = sorted(keys) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

589 for key in keys: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

591 return sorted_dict 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

592 elif isinstance(value, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

594 for item in value: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

596 return sorted_list 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

597 else: 

598 return value 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

599 

600 # ### Schema generation methods 

601 

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

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

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

617 

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

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

628 

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

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

639 

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

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

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

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

652 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

653 

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

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

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

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

666 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

667 

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

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

670 

671 Args: 

672 schema: The core schema. 

673 

674 Returns: 

675 The generated JSON schema. 

676 """ 

677 

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

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

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

681 

682 pattern = ( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

684 ) 

685 

686 # Case 1: Both max_digits and decimal_places are set 

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

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

689 pattern += ( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

690 rf'(?:' 

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

692 rf'|' 

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

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

695 rf')' 

696 ) 

697 

698 # Case 2: Only max_digits is set 

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

700 pattern += ( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

701 rf'(?:' 

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

703 rf'|' 

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

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

706 rf')' 

707 ) 

708 

709 # Case 3: Only decimal_places is set 

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

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

712 

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

714 else: 

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

716 

717 return pattern 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

718 

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

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

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

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

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

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

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

726 json_schema = { 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

727 'anyOf': [ 

728 self.float_schema( 

729 core_schema.float_schema( 

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

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

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

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

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

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

736 ) 

737 ), 

738 json_schema, 

739 ], 

740 } 

741 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

742 

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

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

745 

746 Args: 

747 schema: The core schema. 

748 

749 Returns: 

750 The generated JSON schema. 

751 """ 

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

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

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

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

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

757 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

758 

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

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

761 

762 Args: 

763 schema: The core schema. 

764 

765 Returns: 

766 The generated JSON schema. 

767 """ 

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

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

770 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

771 

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

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

774 

775 Args: 

776 schema: The core schema. 

777 

778 Returns: 

779 The generated JSON schema. 

780 """ 

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

782 

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

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

785 

786 Args: 

787 schema: The core schema. 

788 

789 Returns: 

790 The generated JSON schema. 

791 """ 

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

793 

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

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

796 

797 Args: 

798 schema: The core schema. 

799 

800 Returns: 

801 The generated JSON schema. 

802 """ 

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

804 

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

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

807 

808 Args: 

809 schema: The core schema. 

810 

811 Returns: 

812 The generated JSON schema. 

813 """ 

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

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

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

817 

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

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

820 

821 Args: 

822 schema: The core schema. 

823 

824 Returns: 

825 The generated JSON schema. 

826 """ 

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

828 

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

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

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

832 else: 

833 result['enum'] = expected 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

834 

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

836 if types == {str}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

838 elif types == {int}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

840 elif types == {float}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

842 elif types == {bool}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

844 elif types == {list}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

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

848 return result 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

849 

850 def missing_sentinel_schema(self, schema: core_schema.MissingSentinelSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

851 """Generates a JSON schema that matches the `MISSING` sentinel value. 

852 

853 Args: 

854 schema: The core schema. 

855 

856 Returns: 

857 The generated JSON schema. 

858 """ 

859 raise PydanticOmit 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

860 

861 def enum_schema(self, schema: core_schema.EnumSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

863 

864 Args: 

865 schema: The core schema. 

866 

867 Returns: 

868 The generated JSON schema. 

869 """ 

870 enum_type = schema['cls'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

871 description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

872 if ( 1zCFa

873 description == 'An enumeration.' 

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

875 description = None 1zCbdFaMNhiLOcj

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

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

878 

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

880 

881 result['enum'] = expected 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

882 

883 types = {type(e) for e in expected} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

884 if isinstance(enum_type, str) or types == {str}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

885 result['type'] = 'string' 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

886 elif isinstance(enum_type, int) or types == {int}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

887 result['type'] = 'integer' 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

888 elif isinstance(enum_type, float) or types == {float}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

889 result['type'] = 'number' 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

890 elif types == {bool}: 890 ↛ 891line 890 didn't jump to line 891 because the condition on line 890 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

891 result['type'] = 'boolean' 

892 elif types == {list}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

893 result['type'] = 'array' 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

894 

895 return result 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

896 

897 def is_instance_schema(self, schema: core_schema.IsInstanceSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

899 

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

901 

902 Args: 

903 schema: The core schema. 

904 

905 Returns: 

906 The generated JSON schema. 

907 """ 

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

909 

910 def is_subclass_schema(self, schema: core_schema.IsSubclassSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

912 

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

914 

915 Args: 

916 schema: The core schema. 

917 

918 Returns: 

919 The generated JSON schema. 

920 """ 

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

922 return {} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

923 

924 def callable_schema(self, schema: core_schema.CallableSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

926 

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

928 

929 Args: 

930 schema: The core schema. 

931 

932 Returns: 

933 The generated JSON schema. 

934 """ 

935 return self.handle_invalid_for_json_schema(schema, 'core_schema.CallableSchema') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

936 

937 def list_schema(self, schema: core_schema.ListSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

939 

940 Args: 

941 schema: The core schema. 

942 

943 Returns: 

944 The generated JSON schema. 

945 """ 

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

947 json_schema = {'type': 'array', 'items': items_schema} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

948 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

949 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

950 

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

952 @final 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

953 def tuple_positional_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

955 warnings.warn( 

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

957 PydanticDeprecatedSince26, 

958 stacklevel=2, 

959 ) 

960 return self.tuple_schema(schema) 

961 

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

963 @final 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

964 def tuple_variable_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

965 """Replaced by `tuple_schema`.""" 

966 warnings.warn( 

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

968 PydanticDeprecatedSince26, 

969 stacklevel=2, 

970 ) 

971 return self.tuple_schema(schema) 

972 

973 def tuple_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

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

976 

977 Args: 

978 schema: The core schema. 

979 

980 Returns: 

981 The generated JSON schema. 

982 """ 

983 json_schema: JsonSchemaValue = {'type': 'array'} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

984 if 'variadic_item_index' in schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

985 variadic_item_index = schema['variadic_item_index'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

986 if variadic_item_index > 0: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

987 json_schema['minItems'] = variadic_item_index 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

988 json_schema['prefixItems'] = [ 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

990 ] 

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

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

993 json_schema['items'] = self.generate_inner(schema['items_schema'][variadic_item_index]) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

994 else: 

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

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

997 # for now 

998 json_schema['items'] = True 

999 else: 

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

1001 if prefixItems: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1002 json_schema['prefixItems'] = prefixItems 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1003 json_schema['minItems'] = len(prefixItems) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1004 json_schema['maxItems'] = len(prefixItems) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1005 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1006 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1007 

1008 def set_schema(self, schema: core_schema.SetSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1010 

1011 Args: 

1012 schema: The core schema. 

1013 

1014 Returns: 

1015 The generated JSON schema. 

1016 """ 

1017 return self._common_set_schema(schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1018 

1019 def frozenset_schema(self, schema: core_schema.FrozenSetSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1021 

1022 Args: 

1023 schema: The core schema. 

1024 

1025 Returns: 

1026 The generated JSON schema. 

1027 """ 

1028 return self._common_set_schema(schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1029 

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

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

1032 json_schema = {'type': 'array', 'uniqueItems': True, 'items': items_schema} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1033 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1034 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1035 

1036 def generator_schema(self, schema: core_schema.GeneratorSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1038 

1039 Args: 

1040 schema: The schema. 

1041 

1042 Returns: 

1043 The generated JSON schema. 

1044 """ 

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

1046 json_schema = {'type': 'array', 'items': items_schema} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1047 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1048 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1049 

1050 def dict_schema(self, schema: core_schema.DictSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1052 

1053 Args: 

1054 schema: The core schema. 

1055 

1056 Returns: 

1057 The generated JSON schema. 

1058 """ 

1059 json_schema: JsonSchemaValue = {'type': 'object'} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1060 

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

1062 if '$ref' not in keys_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1063 keys_pattern = keys_schema.pop('pattern', None) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1065 keys_schema.pop('title', None) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1066 else: 

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

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

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

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

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

1072 keys_pattern = None 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1073 

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

1075 # don't give a title to additionalProperties: 

1076 values_schema.pop('title', None) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1077 

1078 if values_schema or keys_pattern is not None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1079 if keys_pattern is None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1080 json_schema['additionalProperties'] = values_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1081 else: 

1082 json_schema['patternProperties'] = {keys_pattern: values_schema} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1084 json_schema['additionalProperties'] = True 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1085 

1086 if ( 1zCFa

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

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

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

1090 or '$ref' in keys_schema 

1091 ): 

1092 keys_schema.pop('type', None) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1093 json_schema['propertyNames'] = keys_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1094 

1095 self.update_with_validations(json_schema, schema, self.ValidationsMapping.object) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1096 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1097 

1098 def function_before_schema(self, schema: core_schema.BeforeValidatorFunctionSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1100 

1101 Args: 

1102 schema: The core schema. 

1103 

1104 Returns: 

1105 The generated JSON schema. 

1106 """ 

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

1108 return self.generate_inner(input_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1109 

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

1111 

1112 def function_after_schema(self, schema: core_schema.AfterValidatorFunctionSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1114 

1115 Args: 

1116 schema: The core schema. 

1117 

1118 Returns: 

1119 The generated JSON schema. 

1120 """ 

1121 return self.generate_inner(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1122 

1123 def function_plain_schema(self, schema: core_schema.PlainValidatorFunctionSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1125 

1126 Args: 

1127 schema: The core schema. 

1128 

1129 Returns: 

1130 The generated JSON schema. 

1131 """ 

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

1133 return self.generate_inner(input_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1134 

1135 return self.handle_invalid_for_json_schema( 

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

1137 ) 

1138 

1139 def function_wrap_schema(self, schema: core_schema.WrapValidatorFunctionSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1141 

1142 Args: 

1143 schema: The core schema. 

1144 

1145 Returns: 

1146 The generated JSON schema. 

1147 """ 

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

1149 return self.generate_inner(input_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1150 

1151 return self.generate_inner(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1152 

1153 def default_schema(self, schema: core_schema.WithDefaultSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1155 

1156 Args: 

1157 schema: The core schema. 

1158 

1159 Returns: 

1160 The generated JSON schema. 

1161 """ 

1162 json_schema = self.generate_inner(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1163 

1164 default = self.get_default_value(schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1165 if default is NoDefault or default is MISSING: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1166 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1167 

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

1169 # JSON Schemas viewed in serialization mode: 

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

1171 if self.mode == 'serialization': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1173 ser_schema = _get_ser_schema_for_default_value(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1174 if ( 1zCFaMNLO

1175 ser_schema is not None 

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

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

1178 ): 

1179 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1180 default = ser_func(default) # type: ignore 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1181 except Exception: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

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

1185 # this pattern for now. 

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

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

1188 self.emit_warning( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1189 'non-serializable-default', 

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

1191 ) 

1192 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1193 

1194 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1195 encoded_default = self.encode_default(default) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1196 except pydantic_core.PydanticSerializationError: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1197 self.emit_warning( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1198 'non-serializable-default', 

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

1200 ) 

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

1202 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1203 

1204 json_schema['default'] = encoded_default 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1205 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1206 

1207 def get_default_value(self, schema: core_schema.WithDefaultSchema) -> Any: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1209 

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

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

1212 

1213 Args: 

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

1215 

1216 Returns: 

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

1218 value is available. 

1219 """ 

1220 return schema.get('default', NoDefault) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1221 

1222 def nullable_schema(self, schema: core_schema.NullableSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1224 

1225 Args: 

1226 schema: The core schema. 

1227 

1228 Returns: 

1229 The generated JSON schema. 

1230 """ 

1231 null_schema = {'type': 'null'} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1232 inner_json_schema = self.generate_inner(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1233 

1234 if inner_json_schema == null_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1235 return null_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1236 else: 

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

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

1239 return self.get_flattened_anyof([inner_json_schema, null_schema]) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1240 

1241 def union_schema(self, schema: core_schema.UnionSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1243 

1244 Args: 

1245 schema: The core schema. 

1246 

1247 Returns: 

1248 The generated JSON schema. 

1249 """ 

1250 generated: list[JsonSchemaValue] = [] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1251 

1252 choices = schema['choices'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1253 for choice in choices: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1255 choice_schema = choice[0] if isinstance(choice, tuple) else choice 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1256 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1257 generated.append(self.generate_inner(choice_schema)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1258 except PydanticOmit: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1259 continue 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1260 except PydanticInvalidForJsonSchema as exc: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1261 self.emit_warning('skipped-choice', exc.message) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1262 if len(generated) == 1: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1263 return generated[0] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1264 return self.get_flattened_anyof(generated) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1265 

1266 def tagged_union_schema(self, schema: core_schema.TaggedUnionSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

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

1269 the value. 

1270 

1271 Args: 

1272 schema: The core schema. 

1273 

1274 Returns: 

1275 The generated JSON schema. 

1276 """ 

1277 generated: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1279 if isinstance(k, Enum): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1280 k = k.value 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1281 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

1284 generated[str(k)] = self.generate_inner(v).copy() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1285 except PydanticOmit: 

1286 continue 

1287 except PydanticInvalidForJsonSchema as exc: 

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

1289 

1290 one_of_choices = _deduplicate_schemas(generated.values()) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1291 json_schema: JsonSchemaValue = {'oneOf': one_of_choices} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1292 

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

1294 openapi_discriminator = self._extract_discriminator(schema, one_of_choices) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1295 if openapi_discriminator is not None: 1295 ↛ 1301line 1295 didn't jump to line 1301 because the condition on line 1295 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1296 json_schema['discriminator'] = { 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1297 'propertyName': openapi_discriminator, 

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

1299 } 

1300 

1301 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1302 

1303 def _extract_discriminator( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1305 ) -> str | None: 

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

1307 schema.""" 

1308 openapi_discriminator: str | None = None 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1309 

1310 if isinstance(schema['discriminator'], str): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1311 return schema['discriminator'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1312 

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

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

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

1316 return schema['discriminator'][0] 

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

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

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

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

1321 for alias_path in schema['discriminator']: 1321 ↛ 1346line 1321 didn't jump to line 1346 because the loop on line 1321 didn't complete1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1322 if not isinstance(alias_path, list): 1322 ↛ 1323line 1322 didn't jump to line 1323 because the condition on line 1322 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1324 if len(alias_path) != 1: 1324 ↛ 1325line 1324 didn't jump to line 1325 because the condition on line 1324 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1326 alias = alias_path[0] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1327 if not isinstance(alias, str): 1327 ↛ 1328line 1327 didn't jump to line 1328 because the condition on line 1327 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1329 alias_is_present_on_all_choices = True 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1330 for choice in one_of_choices: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1331 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1332 choice = self.resolve_ref_schema(choice) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1333 except RuntimeError as exc: 

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

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

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

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

1338 choice = {} 

1339 properties = choice.get('properties', {}) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1340 if not isinstance(properties, dict) or alias not in properties: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1341 alias_is_present_on_all_choices = False 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1342 break 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1343 if alias_is_present_on_all_choices: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1344 openapi_discriminator = alias 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1345 break 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1346 return openapi_discriminator 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1347 

1348 def chain_schema(self, schema: core_schema.ChainSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1350 

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

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

1353 

1354 Args: 

1355 schema: The core schema. 

1356 

1357 Returns: 

1358 The generated JSON schema. 

1359 """ 

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

1361 return self.generate_inner(schema['steps'][step_index]) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1362 

1363 def lax_or_strict_schema(self, schema: core_schema.LaxOrStrictSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1365 strict schema. 

1366 

1367 Args: 

1368 schema: The core schema. 

1369 

1370 Returns: 

1371 The generated JSON schema. 

1372 """ 

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

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

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

1376 # because one of the following two branches failed. 

1377 if use_strict: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1378 return self.generate_inner(schema['strict_schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1379 else: 

1380 return self.generate_inner(schema['lax_schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1381 

1382 def json_or_python_schema(self, schema: core_schema.JsonOrPythonSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1384 Python schema. 

1385 

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

1387 this method. 

1388 

1389 Args: 

1390 schema: The core schema. 

1391 

1392 Returns: 

1393 The generated JSON schema. 

1394 """ 

1395 return self.generate_inner(schema['json_schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1396 

1397 def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1399 

1400 Args: 

1401 schema: The core schema. 

1402 

1403 Returns: 

1404 The generated JSON schema. 

1405 """ 

1406 total = schema.get('total', True) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1407 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

1410 if self.field_is_present(field) 

1411 ] 

1412 if self.mode == 'serialization': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1413 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1414 cls = schema.get('cls') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1415 config = _get_typed_dict_config(cls) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1416 with self._config_wrapper_stack.push(config): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1417 json_schema = self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1418 

1419 if cls is not None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1420 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1421 else: 

1422 extra = config.get('extra') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1423 if extra == 'forbid': 1423 ↛ 1424line 1423 didn't jump to line 1424 because the condition on line 1423 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1424 json_schema['additionalProperties'] = False 

1425 elif extra == 'allow': 1425 ↛ 1426line 1425 didn't jump to line 1426 because the condition on line 1425 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1426 json_schema['additionalProperties'] = True 

1427 

1428 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1429 

1430 @staticmethod 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

1431 def _name_required_computed_fields( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

1432 computed_fields: list[ComputedField], 

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

1434 return [(field['property_name'], True, field) for field in computed_fields] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1435 

1436 def _named_required_fields_schema( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1438 ) -> JsonSchemaValue: 

1439 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1440 required_fields: list[str] = [] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1441 for name, required, field in named_required_fields: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1442 if self.by_alias: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1443 name = self._get_alias_name(field, name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1444 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1445 field_json_schema = self.generate_inner(field).copy() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1446 except PydanticOmit: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1447 continue 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1448 if 'title' not in field_json_schema and self.field_title_should_be_set(field): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1449 title = self.get_title_from_name(name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1450 field_json_schema['title'] = title 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1451 field_json_schema = self.handle_ref_overrides(field_json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1452 properties[name] = field_json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1453 if required: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1454 required_fields.append(name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1455 

1456 json_schema = {'type': 'object', 'properties': properties} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1457 if required_fields: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1458 json_schema['required'] = required_fields 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1459 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1460 

1461 def _get_alias_name(self, field: CoreSchemaField, name: str) -> str: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

1462 if field['type'] == 'computed-field': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1463 alias: Any = field.get('alias', name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1464 elif self.mode == 'validation': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1465 alias = field.get('validation_alias', name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1466 else: 

1467 alias = field.get('serialization_alias', name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1468 if isinstance(alias, str): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1469 name = alias 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1470 elif isinstance(alias, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1471 alias = cast('list[str] | str', alias) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1472 for path in alias: 1472 ↛ 1480line 1472 didn't jump to line 1480 because the loop on line 1472 didn't complete1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

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

1476 name = path[0] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1477 break 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1478 else: 

1479 assert_never(alias) 

1480 return name 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1481 

1482 def typed_dict_field_schema(self, schema: core_schema.TypedDictField) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1484 

1485 Args: 

1486 schema: The core schema. 

1487 

1488 Returns: 

1489 The generated JSON schema. 

1490 """ 

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

1492 

1493 def dataclass_field_schema(self, schema: core_schema.DataclassField) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1495 

1496 Args: 

1497 schema: The core schema. 

1498 

1499 Returns: 

1500 The generated JSON schema. 

1501 """ 

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

1503 

1504 def model_field_schema(self, schema: core_schema.ModelField) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1506 

1507 Args: 

1508 schema: The core schema. 

1509 

1510 Returns: 

1511 The generated JSON schema. 

1512 """ 

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

1514 

1515 def computed_field_schema(self, schema: core_schema.ComputedField) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1517 

1518 Args: 

1519 schema: The core schema. 

1520 

1521 Returns: 

1522 The generated JSON schema. 

1523 """ 

1524 return self.generate_inner(schema['return_schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1525 

1526 def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1528 

1529 Args: 

1530 schema: The core schema. 

1531 

1532 Returns: 

1533 The generated JSON schema. 

1534 """ 

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

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

1537 cls = cast('type[BaseModel]', schema['cls']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1538 config = cls.model_config 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1539 

1540 with self._config_wrapper_stack.push(config): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1541 json_schema = self.generate_inner(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1542 

1543 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1544 

1545 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1546 

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

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

1549 

1550 * title 

1551 * description 

1552 * additional properties 

1553 * json_schema_extra 

1554 * deprecated 

1555 

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

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

1558 """ 

1559 from .main import BaseModel 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1560 from .root_model import RootModel 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1561 

1562 if (config_title := config.get('title')) is not None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1563 json_schema.setdefault('title', config_title) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1564 elif model_title_generator := config.get('model_title_generator'): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1565 title = model_title_generator(cls) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1566 if not isinstance(title, str): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1568 json_schema.setdefault('title', title) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1569 if 'title' not in json_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1570 json_schema['title'] = cls.__name__ 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1571 

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

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

1574 

1575 if docstring: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1576 json_schema.setdefault('description', inspect.cleandoc(docstring)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1578 json_schema.setdefault('description', root_description) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1579 

1580 extra = config.get('extra') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1581 if 'additionalProperties' not in json_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1582 if extra == 'allow': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1583 json_schema['additionalProperties'] = True 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1584 elif extra == 'forbid': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1585 json_schema['additionalProperties'] = False 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1586 

1587 json_schema_extra = config.get('json_schema_extra') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1588 if issubclass(cls, BaseModel) and cls.__pydantic_root_model__: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1589 root_json_schema_extra = cls.model_fields['root'].json_schema_extra 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1590 if json_schema_extra and root_json_schema_extra: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1591 raise ValueError( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1593 ' field must not be set simultaneously' 

1594 ) 

1595 if root_json_schema_extra: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1596 json_schema_extra = root_json_schema_extra 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1597 

1598 if isinstance(json_schema_extra, (staticmethod, classmethod)): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1600 json_schema_extra = json_schema_extra.__get__(cls) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1601 

1602 if isinstance(json_schema_extra, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1603 json_schema.update(json_schema_extra) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1604 elif callable(json_schema_extra): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1606 if len(inspect.signature(json_schema_extra).parameters) > 1: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1607 json_schema_extra(json_schema, cls) # type: ignore 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1608 else: 

1609 json_schema_extra(json_schema) # type: ignore 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1610 elif json_schema_extra is not None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1611 raise ValueError( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1613 ) 

1614 

1615 if hasattr(cls, '__deprecated__'): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1616 json_schema['deprecated'] = True 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1617 

1618 def resolve_ref_schema(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1620 

1621 Args: 

1622 json_schema: The schema to resolve. 

1623 

1624 Returns: 

1625 The resolved schema. 

1626 

1627 Raises: 

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

1629 """ 

1630 while '$ref' in json_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1631 ref = json_schema['$ref'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1632 schema_to_update = self.get_schema_from_definitions(JsonRef(ref)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1633 if schema_to_update is None: 1633 ↛ 1634line 1633 didn't jump to line 1634 because the condition on line 1633 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1635 json_schema = schema_to_update 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1636 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1637 

1638 def model_fields_schema(self, schema: core_schema.ModelFieldsSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1640 

1641 Args: 

1642 schema: The core schema. 

1643 

1644 Returns: 

1645 The generated JSON schema. 

1646 """ 

1647 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

1650 if self.field_is_present(field) 

1651 ] 

1652 if self.mode == 'serialization': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1653 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1654 json_schema = self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1655 extras_schema = schema.get('extras_schema', None) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1656 if extras_schema is not None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1657 schema_to_update = self.resolve_ref_schema(json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1658 schema_to_update['additionalProperties'] = self.generate_inner(extras_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1659 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1660 

1661 def field_is_present(self, field: CoreSchemaField) -> bool: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1663 

1664 Args: 

1665 field: The schema for the field itself. 

1666 

1667 Returns: 

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

1669 """ 

1670 if self.mode == 'serialization': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1672 # override this method and return True 

1673 return not field.get('serialization_exclude') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1674 elif self.mode == 'validation': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1675 return True 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1676 else: 

1677 assert_never(self.mode) 

1678 

1679 def field_is_required( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

1680 self, 

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

1682 total: bool, 

1683 ) -> bool: 

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

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

1686 

1687 Args: 

1688 field: The schema for the field itself. 

1689 total: Only applies to `TypedDictField`s. 

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

1691 explicitly specify `required=False` are required. 

1692 

1693 Returns: 

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

1695 """ 

1696 if self.mode == 'serialization' and self._config.json_schema_serialization_defaults_required: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1697 return not field.get('serialization_exclude') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1698 else: 

1699 if field['type'] == 'typed-dict-field': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1700 return field.get('required', total) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1701 else: 

1702 return field['schema']['type'] != 'default' 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1703 

1704 def dataclass_args_schema(self, schema: core_schema.DataclassArgsSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1706 

1707 Args: 

1708 schema: The core schema. 

1709 

1710 Returns: 

1711 The generated JSON schema. 

1712 """ 

1713 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1715 for field in schema['fields'] 

1716 if self.field_is_present(field) 

1717 ] 

1718 if self.mode == 'serialization': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1719 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1720 return self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1721 

1722 def dataclass_schema(self, schema: core_schema.DataclassSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1724 

1725 Args: 

1726 schema: The core schema. 

1727 

1728 Returns: 

1729 The generated JSON schema. 

1730 """ 

1731 from ._internal._dataclasses import is_stdlib_dataclass 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1732 

1733 cls = schema['cls'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1734 config: ConfigDict = getattr(cls, '__pydantic_config__', cast('ConfigDict', {})) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1735 

1736 with self._config_wrapper_stack.push(config): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1737 json_schema = self.generate_inner(schema['schema']).copy() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1738 

1739 self._update_class_schema(json_schema, cls, config) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1740 

1741 # Dataclass-specific handling of description 

1742 if is_stdlib_dataclass(cls): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1744 description = None 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1745 else: 

1746 description = None if cls.__doc__ is None else inspect.cleandoc(cls.__doc__) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1747 if description: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1748 json_schema['description'] = description 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1749 

1750 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1751 

1752 def arguments_schema(self, schema: core_schema.ArgumentsSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1754 

1755 Args: 

1756 schema: The core schema. 

1757 

1758 Returns: 

1759 The generated JSON schema. 

1760 """ 

1761 prefer_positional = schema.get('metadata', {}).get('pydantic_js_prefer_positional_arguments') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1762 

1763 arguments = schema['arguments_schema'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

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

1767 var_args_schema = schema.get('var_args_schema') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1768 var_kwargs_schema = schema.get('var_kwargs_schema') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1769 

1770 if prefer_positional: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1771 positional_possible = not kw_only_arguments and not var_kwargs_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1772 if positional_possible: 1772 ↛ 1775line 1772 didn't jump to line 1775 because the condition on line 1772 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1773 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1774 

1775 keyword_possible = not p_only_arguments and not var_args_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1776 if keyword_possible: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1777 return self.kw_arguments_schema(kw_or_p_arguments + kw_only_arguments, var_kwargs_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1778 

1779 if not prefer_positional: 1779 ↛ 1784line 1779 didn't jump to line 1784 because the condition on line 1779 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1780 positional_possible = not kw_only_arguments and not var_kwargs_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1781 if positional_possible: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1782 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1783 

1784 raise PydanticInvalidForJsonSchema( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1786 ) 

1787 

1788 def kw_arguments_schema( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1790 ) -> JsonSchemaValue: 

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

1792 

1793 Args: 

1794 arguments: The core schema. 

1795 

1796 Returns: 

1797 The generated JSON schema. 

1798 """ 

1799 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1800 required: list[str] = [] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1801 for argument in arguments: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1802 name = self.get_argument_name(argument) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1803 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1804 argument_schema['title'] = self.get_title_from_name(name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1805 properties[name] = argument_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1806 

1807 if argument['schema']['type'] != 'default': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1809 # the inner schema must be of type WithDefaultSchema. 

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

1811 required.append(name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1812 

1813 json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1814 if required: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1815 json_schema['required'] = required 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1816 

1817 if var_kwargs_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1818 additional_properties_schema = self.generate_inner(var_kwargs_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1819 if additional_properties_schema: 1819 ↛ 1823line 1819 didn't jump to line 1823 because the condition on line 1819 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1820 json_schema['additionalProperties'] = additional_properties_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1821 else: 

1822 json_schema['additionalProperties'] = False 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1823 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1824 

1825 def p_arguments_schema( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1827 ) -> JsonSchemaValue: 

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

1829 

1830 Args: 

1831 arguments: The core schema. 

1832 

1833 Returns: 

1834 The generated JSON schema. 

1835 """ 

1836 prefix_items: list[JsonSchemaValue] = [] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1837 min_items = 0 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1838 

1839 for argument in arguments: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1840 name = self.get_argument_name(argument) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1841 

1842 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1843 argument_schema['title'] = self.get_title_from_name(name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1844 prefix_items.append(argument_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1845 

1846 if argument['schema']['type'] != 'default': 1846 ↛ 1839line 1846 didn't jump to line 1839 because the condition on line 1846 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

1848 # the inner schema must be of type WithDefaultSchema. 

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

1850 min_items += 1 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1851 

1852 json_schema: JsonSchemaValue = {'type': 'array'} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1853 if prefix_items: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1854 json_schema['prefixItems'] = prefix_items 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1855 if min_items: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1856 json_schema['minItems'] = min_items 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1857 

1858 if var_args_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1859 items_schema = self.generate_inner(var_args_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1860 if items_schema: 1860 ↛ 1865line 1860 didn't jump to line 1865 because the condition on line 1860 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1861 json_schema['items'] = items_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1862 else: 

1863 json_schema['maxItems'] = len(prefix_items) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1864 

1865 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1866 

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

1868 """Retrieves the name of an argument. 

1869 

1870 Args: 

1871 argument: The core schema. 

1872 

1873 Returns: 

1874 The name of the argument. 

1875 """ 

1876 name = argument['name'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1877 if self.by_alias: 1877 ↛ 1883line 1877 didn't jump to line 1883 because the condition on line 1877 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1878 alias = argument.get('alias') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1879 if isinstance(alias, str): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1880 name = alias 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1881 else: 

1882 pass # might want to do something else? 1bdenfogpADEahiqrstuvGHIcjkwlxmyBJK

1883 return name 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1884 

1885 def arguments_v3_schema(self, schema: core_schema.ArgumentsV3Schema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1887 

1888 Args: 

1889 schema: The core schema. 

1890 

1891 Returns: 

1892 The generated JSON schema. 

1893 """ 

1894 arguments = schema['arguments_schema'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1895 properties: dict[str, JsonSchemaValue] = {} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1896 required: list[str] = [] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1897 for argument in arguments: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1898 mode = argument.get('mode', 'positional_or_keyword') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1899 name = self.get_argument_name(argument) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1900 argument_schema = self.generate_inner(argument['schema']).copy() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1901 if mode == 'var_args': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1902 argument_schema = {'type': 'array', 'items': argument_schema} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1903 elif mode == 'var_kwargs_uniform': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1904 argument_schema = {'type': 'object', 'additionalProperties': argument_schema} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1905 

1906 argument_schema.setdefault('title', self.get_title_from_name(name)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1907 properties[name] = argument_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1908 

1909 if ( 1zCFa

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

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

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

1913 ): 

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

1915 # the inner schema must be of type WithDefaultSchema. 

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

1917 required.append(name) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1918 

1919 json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1920 if required: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1921 json_schema['required'] = required 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1922 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1923 

1924 def call_schema(self, schema: core_schema.CallSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1926 

1927 Args: 

1928 schema: The core schema. 

1929 

1930 Returns: 

1931 The generated JSON schema. 

1932 """ 

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

1934 

1935 def custom_error_schema(self, schema: core_schema.CustomErrorSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1937 

1938 Args: 

1939 schema: The core schema. 

1940 

1941 Returns: 

1942 The generated JSON schema. 

1943 """ 

1944 return self.generate_inner(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1945 

1946 def json_schema(self, schema: core_schema.JsonSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1948 

1949 Args: 

1950 schema: The core schema. 

1951 

1952 Returns: 

1953 The generated JSON schema. 

1954 """ 

1955 content_core_schema = schema.get('schema') or core_schema.any_schema() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1956 content_json_schema = self.generate_inner(content_core_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1957 if self.mode == 'validation': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1958 return {'type': 'string', 'contentMediaType': 'application/json', 'contentSchema': content_json_schema} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1959 else: 

1960 # self.mode == 'serialization' 

1961 return content_json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1962 

1963 def url_schema(self, schema: core_schema.UrlSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1965 

1966 Args: 

1967 schema: The core schema. 

1968 

1969 Returns: 

1970 The generated JSON schema. 

1971 """ 

1972 json_schema = {'type': 'string', 'format': 'uri', 'minLength': 1} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1973 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1974 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1975 

1976 def multi_host_url_schema(self, schema: core_schema.MultiHostUrlSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1978 

1979 Args: 

1980 schema: The core schema. 

1981 

1982 Returns: 

1983 The generated JSON schema. 

1984 """ 

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

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

1987 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1988 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

1989 

1990 def uuid_schema(self, schema: core_schema.UuidSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

1992 

1993 Args: 

1994 schema: The core schema. 

1995 

1996 Returns: 

1997 The generated JSON schema. 

1998 """ 

1999 return {'type': 'string', 'format': 'uuid'} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2000 

2001 def definitions_schema(self, schema: core_schema.DefinitionsSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2003 

2004 Args: 

2005 schema: The core schema. 

2006 

2007 Returns: 

2008 The generated JSON schema. 

2009 """ 

2010 for definition in schema['definitions']: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2011 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2012 self.generate_inner(definition) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2013 except PydanticInvalidForJsonSchema as e: 

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

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

2016 continue 

2017 return self.generate_inner(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2018 

2019 def definition_ref_schema(self, schema: core_schema.DefinitionReferenceSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2021 

2022 Args: 

2023 schema: The core schema. 

2024 

2025 Returns: 

2026 The generated JSON schema. 

2027 """ 

2028 core_ref = CoreRef(schema['schema_ref']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2029 _, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2030 return ref_json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2031 

2032 def ser_schema( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2034 ) -> JsonSchemaValue | None: 

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

2036 

2037 Args: 

2038 schema: The core schema. 

2039 

2040 Returns: 

2041 The generated JSON schema. 

2042 """ 

2043 schema_type = schema['type'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2044 if schema_type == 'function-plain' or schema_type == 'function-wrap': 2044 ↛ 2049line 2044 didn't jump to line 2049 because the condition on line 2044 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2045 # PlainSerializerFunctionSerSchema or WrapSerializerFunctionSerSchema 

2046 return_schema = schema.get('return_schema') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2047 if return_schema is not None: 2047 ↛ 2055line 2047 didn't jump to line 2055 because the condition on line 2047 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2048 return self.generate_inner(return_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2050 # FormatSerSchema or ToStringSerSchema 

2051 return self.str_schema(core_schema.str_schema()) 

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

2053 # ModelSerSchema 

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

2055 return None 

2056 

2057 def complex_schema(self, schema: core_schema.ComplexSchema) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2059 

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

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

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

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

2064 

2065 Args: 

2066 schema: The core schema. 

2067 

2068 Returns: 

2069 The generated JSON schema. 

2070 """ 

2071 return {'type': 'string'} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2072 

2073 # ### Utility methods 

2074 

2075 def get_title_from_name(self, name: str) -> str: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2076 """Retrieves a title from a name. 

2077 

2078 Args: 

2079 name: The name to retrieve a title from. 

2080 

2081 Returns: 

2082 The title. 

2083 """ 

2084 return name.title().replace('_', ' ').strip() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2085 

2086 def field_title_should_be_set(self, schema: CoreSchemaOrField) -> bool: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2088 

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

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

2091 

2092 Args: 

2093 schema: The schema to check. 

2094 

2095 Returns: 

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

2097 """ 

2098 if _core_utils.is_core_schema_field(schema): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2099 if schema['type'] == 'computed-field': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2100 field_schema = schema['return_schema'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2101 else: 

2102 field_schema = schema['schema'] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2103 return self.field_title_should_be_set(field_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2104 

2105 elif _core_utils.is_core_schema(schema): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2107 return False 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2108 if schema['type'] in {'default', 'nullable', 'definitions'}: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2110 if _core_utils.is_function_with_inner_schema(schema): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2111 return self.field_title_should_be_set(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2112 if schema['type'] == 'definition-ref': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2114 # schemas with refs should not 

2115 return False 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2116 return True # anything else should have title set 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2117 

2118 else: 

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

2120 

2121 def normalize_name(self, name: str) -> str: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2123 

2124 Args: 

2125 name: The name to normalize. 

2126 

2127 Returns: 

2128 The normalized name. 

2129 """ 

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

2131 

2132 def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2134 

2135 Args: 

2136 core_mode_ref: The core reference. 

2137 

2138 Returns: 

2139 The definitions key. 

2140 """ 

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

2142 core_ref, mode = core_mode_ref 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2143 components = re.split(r'([\][,])', core_ref) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2144 # Remove IDs from each component 

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

2146 core_ref_no_id = ''.join(components) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

2149 short_ref = ''.join(components) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2150 

2151 mode_title = _MODE_TITLE_MAPPING[mode] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2152 

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

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

2155 # the id of the source type in the core_ref 

2156 name = DefsRef(self.normalize_name(short_ref)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2158 module_qualname = DefsRef(self.normalize_name(core_ref_no_id)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2159 module_qualname_mode = DefsRef(f'{module_qualname}-{mode_title}') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2160 module_qualname_id = DefsRef(self.normalize_name(core_ref)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2161 occurrence_index = self._collision_index.get(module_qualname_id) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2162 if occurrence_index is None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2163 self._collision_counter[module_qualname] += 1 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2164 occurrence_index = self._collision_index[module_qualname_id] = self._collision_counter[module_qualname] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2165 

2166 module_qualname_occurrence = DefsRef(f'{module_qualname}__{occurrence_index}') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2167 module_qualname_occurrence_mode = DefsRef(f'{module_qualname_mode}__{occurrence_index}') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2168 

2169 self._prioritized_defsref_choices[module_qualname_occurrence_mode] = [ 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2170 name, 

2171 name_mode, 

2172 module_qualname, 

2173 module_qualname_mode, 

2174 module_qualname_occurrence, 

2175 module_qualname_occurrence_mode, 

2176 ] 

2177 

2178 return module_qualname_occurrence_mode 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2179 

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

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

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

2183 

2184 Args: 

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

2186 

2187 Returns: 

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

2189 """ 

2190 core_mode_ref = (core_ref, self.mode) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2191 maybe_defs_ref = self.core_to_defs_refs.get(core_mode_ref) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2192 if maybe_defs_ref is not None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2193 json_ref = self.core_to_json_refs[core_mode_ref] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2194 return maybe_defs_ref, {'$ref': json_ref} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2195 

2196 defs_ref = self.get_defs_ref(core_mode_ref) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2197 

2198 # populate the ref translation mappings 

2199 self.core_to_defs_refs[core_mode_ref] = defs_ref 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2200 self.defs_to_core_refs[defs_ref] = core_mode_ref 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2201 

2202 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2203 self.core_to_json_refs[core_mode_ref] = json_ref 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2204 self.json_to_defs_refs[json_ref] = defs_ref 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2205 ref_json_schema = {'$ref': json_ref} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2206 return defs_ref, ref_json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2207 

2208 def handle_ref_overrides(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2210 

2211 Args: 

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

2213 

2214 Returns: 

2215 The schema with redundant sibling keys removed. 

2216 """ 

2217 if '$ref' in json_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2219 json_schema = json_schema.copy() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2220 

2221 referenced_json_schema = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2222 if referenced_json_schema is None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

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

2225 # any redundant override keys. 

2226 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2227 for k, v in list(json_schema.items()): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2228 if k == '$ref': 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2229 continue 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2230 if k in referenced_json_schema and referenced_json_schema[k] == v: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2231 del json_schema[k] # redundant key 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2232 

2233 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2234 

2235 def get_schema_from_definitions(self, json_ref: JsonRef) -> JsonSchemaValue | None: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2236 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2237 def_ref = self.json_to_defs_refs[json_ref] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2238 if def_ref in self._core_defs_invalid_for_json_schema: 2238 ↛ 2239line 2238 didn't jump to line 2239 because the condition on line 2238 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2239 raise self._core_defs_invalid_for_json_schema[def_ref] 

2240 return self.definitions.get(def_ref, None) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2241 except KeyError: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2243 return None 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2244 raise 

2245 

2246 def encode_default(self, dft: Any) -> Any: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2248 

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

2250 

2251 Args: 

2252 dft: The default value to encode. 

2253 

2254 Returns: 

2255 The encoded default value. 

2256 """ 

2257 from .type_adapter import TypeAdapter, _type_has_config 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2258 

2259 config = self._config 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2260 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2261 default = ( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2262 dft 

2263 if _type_has_config(type(dft)) 

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

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

2266 ) 

2267 ) 

2268 except PydanticSchemaGenerationError: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2270 

2271 return pydantic_core.to_jsonable_python( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2273 ) 

2274 

2275 def update_with_validations( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2277 ) -> None: 

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

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

2280 

2281 Args: 

2282 json_schema: The JSON schema to update. 

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

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

2285 """ 

2286 for core_key, json_schema_key in mapping.items(): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2287 if core_key in core_schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2288 json_schema[json_schema_key] = core_schema[core_key] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2289 

2290 class ValidationsMapping: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

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

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

2294 GenerateJsonSchema.ValidationsMapping) to change these mappings. 

2295 """ 

2296 

2297 numeric = { 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2298 'multiple_of': 'multipleOf', 

2299 'le': 'maximum', 

2300 'ge': 'minimum', 

2301 'lt': 'exclusiveMaximum', 

2302 'gt': 'exclusiveMinimum', 

2303 } 

2304 bytes = { 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2305 'min_length': 'minLength', 

2306 'max_length': 'maxLength', 

2307 } 

2308 string = { 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2309 'min_length': 'minLength', 

2310 'max_length': 'maxLength', 

2311 'pattern': 'pattern', 

2312 } 

2313 array = { 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2314 'min_length': 'minItems', 

2315 'max_length': 'maxItems', 

2316 } 

2317 object = { 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2318 'min_length': 'minProperties', 

2319 'max_length': 'maxProperties', 

2320 } 

2321 

2322 def get_flattened_anyof(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2323 members = [] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2324 for schema in schemas: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2325 if len(schema) == 1 and 'anyOf' in schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2326 members.extend(schema['anyOf']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2327 else: 

2328 members.append(schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2329 members = _deduplicate_schemas(members) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2330 if len(members) == 1: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2331 return members[0] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2332 return {'anyOf': members} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2333 

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

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

2336 json_refs: dict[JsonRef, int] = Counter() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2337 

2338 def _add_json_refs(schema: Any) -> None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2339 if isinstance(schema, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2340 if '$ref' in schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2341 json_ref = JsonRef(schema['$ref']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2342 if not isinstance(json_ref, str): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2344 already_visited = json_ref in json_refs 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2345 json_refs[json_ref] += 1 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2346 if already_visited: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2347 return # prevent recursion on a definition that was already visited 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2348 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2349 defs_ref = self.json_to_defs_refs[json_ref] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2350 if defs_ref in self._core_defs_invalid_for_json_schema: 2350 ↛ 2351line 2350 didn't jump to line 2351 because the condition on line 2350 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2351 raise self._core_defs_invalid_for_json_schema[defs_ref] 

2352 _add_json_refs(self.definitions[defs_ref]) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2353 except KeyError: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

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

2355 raise 

2356 

2357 for k, v in schema.items(): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2358 if k == 'examples' and isinstance(v, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2359 # Skip examples that may contain arbitrary values and references 

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

2361 continue 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2362 _add_json_refs(v) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2363 elif isinstance(schema, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2364 for v in schema: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2365 _add_json_refs(v) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2366 

2367 _add_json_refs(json_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2368 return json_refs 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2369 

2370 def handle_invalid_for_json_schema(self, schema: CoreSchemaOrField, error_info: str) -> JsonSchemaValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2371 raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2372 

2373 def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

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

2375 message = self.render_warning_message(kind, detail) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2376 if message is not None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2377 warnings.warn(message, PydanticJsonSchemaWarning) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2378 

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

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

2381 

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

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

2384 just return None in situations where you don't want warnings to be emitted. 

2385 

2386 Args: 

2387 kind: The kind of warning to render. It can be one of the following: 

2388 

2389 - 'skipped-choice': A choice field was skipped because it had no valid choices. 

2390 - 'non-serializable-default': A default value was skipped because it was not JSON-serializable. 

2391 detail: A string with additional details about the warning. 

2392 

2393 Returns: 

2394 The formatted warning message, or `None` if no warning should be emitted. 

2395 """ 

2396 if kind in self.ignored_warning_kinds: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2397 return None 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2398 return f'{detail} [{kind}]' 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2399 

2400 def _build_definitions_remapping(self) -> _DefinitionsRemapping: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2401 defs_to_json: dict[DefsRef, JsonRef] = {} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2402 for defs_refs in self._prioritized_defsref_choices.values(): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2403 for defs_ref in defs_refs: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2404 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2405 defs_to_json[defs_ref] = json_ref 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2406 

2407 return _DefinitionsRemapping.from_prioritized_choices( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2408 self._prioritized_defsref_choices, defs_to_json, self.definitions 

2409 ) 

2410 

2411 def _garbage_collect_definitions(self, schema: JsonSchemaValue) -> None: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2412 visited_defs_refs: set[DefsRef] = set() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2413 unvisited_json_refs = _get_all_json_refs(schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2414 while unvisited_json_refs: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2415 next_json_ref = unvisited_json_refs.pop() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2416 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2417 next_defs_ref = self.json_to_defs_refs[next_json_ref] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2418 if next_defs_ref in visited_defs_refs: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2419 continue 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2420 visited_defs_refs.add(next_defs_ref) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2421 unvisited_json_refs.update(_get_all_json_refs(self.definitions[next_defs_ref])) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2422 except KeyError: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2423 if not next_json_ref.startswith(('http://', 'https://')): 2423 ↛ 2424line 2423 didn't jump to line 2424 because the condition on line 2423 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2424 raise 

2425 

2426 self.definitions = {k: v for k, v in self.definitions.items() if k in visited_defs_refs} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2427 

2428 

2429# ##### Start JSON Schema Generation Functions ##### 

2430 

2431 

2432def model_json_schema( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2433 cls: type[BaseModel] | type[PydanticDataclass], 

2434 by_alias: bool = True, 

2435 ref_template: str = DEFAULT_REF_TEMPLATE, 

2436 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2437 mode: JsonSchemaMode = 'validation', 

2438) -> dict[str, Any]: 

2439 """Utility function to generate a JSON Schema for a model. 

2440 

2441 Args: 

2442 cls: The model class to generate a JSON Schema for. 

2443 by_alias: If `True` (the default), fields will be serialized according to their alias. 

2444 If `False`, fields will be serialized according to their attribute name. 

2445 ref_template: The template to use for generating JSON Schema references. 

2446 schema_generator: The class to use for generating the JSON Schema. 

2447 mode: The mode to use for generating the JSON Schema. It can be one of the following: 

2448 

2449 - 'validation': Generate a JSON Schema for validating data. 

2450 - 'serialization': Generate a JSON Schema for serializing data. 

2451 

2452 Returns: 

2453 The generated JSON Schema. 

2454 """ 

2455 from .main import BaseModel 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2456 

2457 schema_generator_instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2458 

2459 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2460 cls.__pydantic_core_schema__.rebuild() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2461 

2462 if cls is BaseModel: 2462 ↛ 2463line 2462 didn't jump to line 2463 because the condition on line 2462 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2463 raise AttributeError('model_json_schema() must be called on a subclass of BaseModel, not BaseModel itself.') 

2464 

2465 assert not isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2466 return schema_generator_instance.generate(cls.__pydantic_core_schema__, mode=mode) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2467 

2468 

2469def models_json_schema( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2470 models: Sequence[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode]], 

2471 *, 

2472 by_alias: bool = True, 

2473 title: str | None = None, 

2474 description: str | None = None, 

2475 ref_template: str = DEFAULT_REF_TEMPLATE, 

2476 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2477) -> tuple[dict[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: 

2478 """Utility function to generate a JSON Schema for multiple models. 

2479 

2480 Args: 

2481 models: A sequence of tuples of the form (model, mode). 

2482 by_alias: Whether field aliases should be used as keys in the generated JSON Schema. 

2483 title: The title of the generated JSON Schema. 

2484 description: The description of the generated JSON Schema. 

2485 ref_template: The reference template to use for generating JSON Schema references. 

2486 schema_generator: The schema generator to use for generating the JSON Schema. 

2487 

2488 Returns: 

2489 A tuple where: 

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

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

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

2493 - The second element is a JSON schema containing all definitions referenced in the first returned 

2494 element, along with the optional title and description keys. 

2495 """ 

2496 for cls, _ in models: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2497 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 2497 ↛ 2498line 2497 didn't jump to line 2498 because the condition on line 2497 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2498 cls.__pydantic_core_schema__.rebuild() 

2499 

2500 instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2501 inputs: list[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode, CoreSchema]] = [ 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2502 (m, mode, m.__pydantic_core_schema__) for m, mode in models 

2503 ] 

2504 json_schemas_map, definitions = instance.generate_definitions(inputs) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2505 

2506 json_schema: dict[str, Any] = {} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2507 if definitions: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2508 json_schema['$defs'] = definitions 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2509 if title: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2510 json_schema['title'] = title 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2511 if description: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2512 json_schema['description'] = description 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2513 

2514 return json_schemas_map, json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2515 

2516 

2517# ##### End JSON Schema Generation Functions ##### 

2518 

2519 

2520_HashableJsonValue: TypeAlias = Union[ 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2521 int, float, str, bool, None, tuple['_HashableJsonValue', ...], tuple[tuple[str, '_HashableJsonValue'], ...] 

2522] 

2523 

2524 

2525def _deduplicate_schemas(schemas: Iterable[JsonDict]) -> list[JsonDict]: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2526 return list({_make_json_hashable(schema): schema for schema in schemas}.values()) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2527 

2528 

2529def _make_json_hashable(value: JsonValue) -> _HashableJsonValue: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2530 if isinstance(value, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2531 return tuple(sorted((k, _make_json_hashable(v)) for k, v in value.items())) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2532 elif isinstance(value, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2533 return tuple(_make_json_hashable(v) for v in value) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2534 else: 

2535 return value 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2536 

2537 

2538@dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2539class WithJsonSchema: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2540 """!!! abstract "Usage Documentation" 

2541 [`WithJsonSchema` Annotation](../concepts/json_schema.md#withjsonschema-annotation) 

2542 

2543 Add this as an annotation on a field to override the (base) JSON schema that would be generated for that field. 

2544 This provides a way to set a JSON schema for types that would otherwise raise errors when producing a JSON schema, 

2545 such as Callable, or types that have an is-instance core schema, without needing to go so far as creating a 

2546 custom subclass of pydantic.json_schema.GenerateJsonSchema. 

2547 Note that any _modifications_ to the schema that would normally be made (such as setting the title for model fields) 

2548 will still be performed. 

2549 

2550 If `mode` is set this will only apply to that schema generation mode, allowing you 

2551 to set different json schemas for validation and serialization. 

2552 """ 

2553 

2554 json_schema: JsonSchemaValue | None 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2555 mode: Literal['validation', 'serialization'] | None = None 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2556 

2557 def __get_pydantic_json_schema__( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2558 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2559 ) -> JsonSchemaValue: 

2560 mode = self.mode or handler.mode 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2561 if mode != handler.mode: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2562 return handler(core_schema) 1zbefgALcklmB

2563 if self.json_schema is None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2564 # This exception is handled in pydantic.json_schema.GenerateJsonSchema._named_required_fields_schema 

2565 raise PydanticOmit 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2566 else: 

2567 return self.json_schema.copy() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2568 

2569 def __hash__(self) -> int: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2570 return hash(type(self.mode)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2571 

2572 

2573class Examples: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2574 """Add examples to a JSON schema. 

2575 

2576 If the JSON Schema already contains examples, the provided examples 

2577 will be appended. 

2578 

2579 If `mode` is set this will only apply to that schema generation mode, 

2580 allowing you to add different examples for validation and serialization. 

2581 """ 

2582 

2583 @overload 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2584 @deprecated('Using a dict for `examples` is deprecated since v2.9 and will be removed in v3.0. Use a list instead.') 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2585 def __init__( 1zCbdenfogpADEMNhiqrstuvGHIPLOcjkwlxmyBJK

2586 self, examples: dict[str, Any], mode: Literal['validation', 'serialization'] | None = None 1bdenfogpFahiqrstuvPcjkwlxmy

2587 ) -> None: ... 1fogpFastuvPlxmy

2588 

2589 @overload 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2590 def __init__(self, examples: list[Any], mode: Literal['validation', 'serialization'] | None = None) -> None: ... 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2591 

2592 def __init__( 1zCbdenfogpADEMNhiqrstuvGHIPLOcjkwlxmyBJK

2593 self, examples: dict[str, Any] | list[Any], mode: Literal['validation', 'serialization'] | None = None 

2594 ) -> None: 

2595 if isinstance(examples, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2596 warnings.warn( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2597 'Using a dict for `examples` is deprecated, use a list instead.', 

2598 PydanticDeprecatedSince29, 

2599 stacklevel=2, 

2600 ) 

2601 self.examples = examples 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2602 self.mode = mode 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2603 

2604 def __get_pydantic_json_schema__( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2605 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2606 ) -> JsonSchemaValue: 

2607 mode = self.mode or handler.mode 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2608 json_schema = handler(core_schema) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2609 if mode != handler.mode: 2609 ↛ 2610line 2609 didn't jump to line 2610 because the condition on line 2609 was never true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2610 return json_schema 

2611 examples = json_schema.get('examples') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2612 if examples is None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2613 json_schema['examples'] = to_jsonable_python(self.examples) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2614 if isinstance(examples, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2615 if isinstance(self.examples, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2616 warnings.warn( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2617 'Updating existing JSON Schema examples of type dict with examples of type list. ' 

2618 'Only the existing examples values will be retained. Note that dict support for ' 

2619 'examples is deprecated and will be removed in v3.0.', 

2620 UserWarning, 

2621 ) 

2622 json_schema['examples'] = to_jsonable_python( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2623 [ex for value in examples.values() for ex in value] + self.examples 

2624 ) 

2625 else: 

2626 json_schema['examples'] = to_jsonable_python({**examples, **self.examples}) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2627 if isinstance(examples, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2628 if isinstance(self.examples, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2629 json_schema['examples'] = to_jsonable_python(examples + self.examples) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2630 elif isinstance(self.examples, dict): 2630 ↛ 2641line 2630 didn't jump to line 2641 because the condition on line 2630 was always true1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2631 warnings.warn( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2632 'Updating existing JSON Schema examples of type list with examples of type dict. ' 

2633 'Only the examples values will be retained. Note that dict support for ' 

2634 'examples is deprecated and will be removed in v3.0.', 

2635 UserWarning, 

2636 ) 

2637 json_schema['examples'] = to_jsonable_python( 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2638 examples + [ex for value in self.examples.values() for ex in value] 

2639 ) 

2640 

2641 return json_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2642 

2643 def __hash__(self) -> int: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2644 return hash(type(self.mode)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2645 

2646 

2647def _get_all_json_refs(item: Any) -> set[JsonRef]: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2648 """Get all the definitions references from a JSON schema.""" 

2649 refs: set[JsonRef] = set() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2650 stack = [item] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2651 

2652 while stack: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2653 current = stack.pop() 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2654 if isinstance(current, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2655 for key, value in current.items(): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2656 if key == 'examples' and isinstance(value, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2657 # Skip examples that may contain arbitrary values and references 

2658 # (e.g. `{"examples": [{"$ref": "..."}]}`). Note: checking for value 

2659 # of type list is necessary to avoid skipping valid portions of the schema, 

2660 # for instance when "examples" is used as a property key. A more robust solution 

2661 # could be found, but would require more advanced JSON Schema parsing logic. 

2662 continue 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2663 if key == '$ref' and isinstance(value, str): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2664 refs.add(JsonRef(value)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2665 elif isinstance(value, dict): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2666 stack.append(value) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2667 elif isinstance(value, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2668 stack.extend(value) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2669 elif isinstance(current, list): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2670 stack.extend(current) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2671 

2672 return refs 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2673 

2674 

2675AnyType = TypeVar('AnyType') 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2676 

2677if TYPE_CHECKING: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2678 SkipJsonSchema = Annotated[AnyType, ...] 

2679else: 

2680 

2681 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2682 class SkipJsonSchema: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2683 """!!! abstract "Usage Documentation" 

2684 [`SkipJsonSchema` Annotation](../concepts/json_schema.md#skipjsonschema-annotation) 

2685 

2686 Add this as an annotation on a field to skip generating a JSON schema for that field. 

2687 

2688 Example: 

2689 ```python 

2690 from pprint import pprint 

2691 from typing import Union 

2692 

2693 from pydantic import BaseModel 

2694 from pydantic.json_schema import SkipJsonSchema 

2695 

2696 class Model(BaseModel): 

2697 a: Union[int, None] = None # (1)! 

2698 b: Union[int, SkipJsonSchema[None]] = None # (2)! 

2699 c: SkipJsonSchema[Union[int, None]] = None # (3)! 

2700 

2701 pprint(Model.model_json_schema()) 

2702 ''' 

2703 { 

2704 'properties': { 

2705 'a': { 

2706 'anyOf': [ 

2707 {'type': 'integer'}, 

2708 {'type': 'null'} 

2709 ], 

2710 'default': None, 

2711 'title': 'A' 

2712 }, 

2713 'b': { 

2714 'default': None, 

2715 'title': 'B', 

2716 'type': 'integer' 

2717 } 

2718 }, 

2719 'title': 'Model', 

2720 'type': 'object' 

2721 } 

2722 ''' 

2723 ``` 

2724 

2725 1. The integer and null types are both included in the schema for `a`. 

2726 2. The integer type is the only type included in the schema for `b`. 

2727 3. The entirety of the `c` field is omitted from the schema. 

2728 """ 

2729 

2730 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2731 return Annotated[item, cls()] 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2732 

2733 def __get_pydantic_json_schema__( 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2734 self, core_schema: CoreSchema, handler: GetJsonSchemaHandler 

2735 ) -> JsonSchemaValue: 

2736 raise PydanticOmit 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2737 

2738 def __hash__(self) -> int: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2739 return hash(type(self)) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2740 

2741 

2742def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2743 if cls is not None: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2744 try: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2745 return _decorators.get_attribute_from_bases(cls, '__pydantic_config__') 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2746 except AttributeError: 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2747 pass 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2748 return {} 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2749 

2750 

2751def _get_ser_schema_for_default_value(schema: CoreSchema) -> core_schema.PlainSerializerFunctionSerSchema | None: 1zCbdenfogpADEFaMNhiqrstuvGHIPLOcjkwlxmyBJK

2752 """Get a `'function-plain'` serialization schema that can be used to serialize a default value. 

2753 

2754 This takes into account having the serialization schema nested under validation schema(s). 

2755 """ 

2756 if ( 1zCbdenFaMNhiqrLOcjkw

2757 (ser_schema := schema.get('serialization')) 

2758 and ser_schema['type'] == 'function-plain' 

2759 and not ser_schema.get('info_arg') 

2760 ): 

2761 return ser_schema 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2762 if _core_utils.is_function_with_inner_schema(schema): 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK

2763 return _get_ser_schema_for_default_value(schema['schema']) 1zCbdenfogpADEFaMNhiqrstuvGHILOcjkwlxmyBJK