Coverage for pydantic/json_schema.py: 94.65%

1105 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-20 16: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 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

13 

14import dataclasses 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

15import inspect 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

16import math 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

17import os 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

18import re 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

19import warnings 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

20from collections import Counter, defaultdict 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

22from copy import deepcopy 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

23from enum import Enum 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

24from re import Pattern 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

25from typing import ( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

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

40from pydantic_core.core_schema import ComputedField 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

42from typing_inspection.introspection import get_literal_values 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

43 

44from pydantic.warnings import PydanticDeprecatedSince26, PydanticDeprecatedSince29 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

45 

46from ._internal import ( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

56from .config import JsonDict, JsonValue 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

58 

59if TYPE_CHECKING: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

68""" 1bdenfogpADMahiqrstuvFGOPcjkwlxmyBHN

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

75""" 1bdenfogpADMahiqrstuvFGOPcjkwlxmyBHN

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

80""" 1bdenfogpADMahiqrstuvFGOPcjkwlxmyBHN

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

90 

91 

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

93""" 1bdenfogpADMahiqrstuvFGOPcjkwlxmyBHN

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

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

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

111for a core schema with a default value. 

112""" 

113 

114 

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

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

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

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

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

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

130 

131CoreModeRef = tuple[CoreRef, JsonSchemaMode] 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

133 

134 

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

136class _DefinitionsRemapping: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

137 defs_remapping: dict[DefsRef, DefsRef] 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

138 json_remapping: dict[JsonRef, JsonRef] 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

139 

140 @staticmethod 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

141 def from_prioritized_choices( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

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

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 complete1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

159 for defs_ref in copied_definitions: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

160 alternatives = prioritized_choices[defs_ref] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

161 for alternative in alternatives: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

168 

169 # Build the remapping 

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

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

172 for original_defs_ref in definitions: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

173 alternatives = prioritized_choices[original_defs_ref] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

176 defs_remapping[original_defs_ref] = remapped_defs_ref 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

178 remapping = _DefinitionsRemapping(defs_remapping, json_remapping) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

180 if definitions_schema == new_definitions_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

181 # We've reached the fixed point 

182 return remapping 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

183 definitions_schema = new_definitions_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

184 

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

186 

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

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

189 

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

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

192 

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

194 """ 

195 Recursively update the JSON schema replacing all $refs 

196 """ 

197 if isinstance(schema, str): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

200 elif isinstance(schema, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

202 elif isinstance(schema, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

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

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

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

213 return schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

214 

215 

216class GenerateJsonSchema: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

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

255 

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

257 self.by_alias = by_alias 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

258 self.ref_template = ref_template 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

259 

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

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

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

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

264 

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

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

267 

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

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

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

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

277 

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

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

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

291 

292 @property 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

294 return self._config_wrapper_stack.tail 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

295 

296 @property 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

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

299 return self._config.json_schema_mode_override 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

300 else: 

301 return self._mode 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

302 

303 def build_schema_type_to_method( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

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

316 for key in core_schema_types: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

318 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

328 

329 def generate_definitions( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

355 raise PydanticUserError( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

362 self._mode = mode 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

363 self.generate_inner(schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

364 

365 definitions_remapping = self._build_definitions_remapping() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

366 

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

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

369 self._mode = mode 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

370 json_schema = self.generate_inner(schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

372 

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

374 json_schema = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

375 self._used = True 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

377 

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

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

392 if self._used: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

393 raise PydanticUserError( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

400 json_ref_counts = self.get_json_ref_counts(json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

401 

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

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

404 ref_json_schema = self.get_schema_from_definitions(ref) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

408 json_ref_counts[ref] -= 1 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

410 ref = None 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

411 

412 self._garbage_collect_definitions(json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

413 definitions_remapping = self._build_definitions_remapping() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

414 

415 if self.definitions: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

417 

418 json_schema = definitions_remapping.remap_json_schema(json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

425 return self.sort(json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

426 

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

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

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

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

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

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

448 

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

450 if 'ref' in core_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

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 true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

458 self.definitions[defs_ref] = json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

460 json_schema = ref_json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

461 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

462 

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

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

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

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

482 json_schema = self.ser_schema(ser_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

483 

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

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

486 if ( 1zCEa

487 json_schema is not None 

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

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

490 ): 

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

492 if json_schema is None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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 true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

495 json_schema = generate_for_schema_type(schema_or_field) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

496 else: 

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

498 

499 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

500 

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

502 

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

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

508 

509 def js_updates_handler_func( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

510 schema_or_field: CoreSchemaOrField, 

511 current_handler: GetJsonSchemaHandler = current_handler, 

512 ) -> JsonSchemaValue: 

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

514 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

515 

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

517 

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

519 

520 def js_extra_handler_func( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

521 schema_or_field: CoreSchemaOrField, 

522 current_handler: GetJsonSchemaHandler = current_handler, 

523 ) -> JsonSchemaValue: 

524 json_schema = current_handler(schema_or_field) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

525 if isinstance(js_extra, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

529 js_extra(json_schema) # type: ignore 1zCbdenfogpADMEaJKhiqrstuvFGILcjkwlxmyBH

530 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

531 

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

533 

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

535 

536 def new_handler_func( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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 true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

543 json_schema = populate_defs(schema_or_field, json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

544 original_schema = current_handler.resolve_ref_schema(json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

547 original_schema.update(json_schema) 

548 return original_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

549 

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

551 

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

553 

554 def new_handler_func( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

560 

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

562 

563 json_schema = current_handler(schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

564 if _core_utils.is_core_schema(schema): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

565 json_schema = populate_defs(schema, json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

566 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

567 

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

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

575 keys = value.keys() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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 true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

577 keys = sorted(keys) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

578 for key in keys: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

580 return sorted_dict 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

581 

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

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

584 if isinstance(value, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

586 keys = value.keys() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

588 keys = sorted(keys) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

589 for key in keys: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

591 return sorted_dict 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

592 elif isinstance(value, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

594 for item in value: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

596 return sorted_list 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

597 else: 

598 return value 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

599 

600 # ### Schema generation methods 

601 

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

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

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

617 

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

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

628 

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

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

639 

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

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

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

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

652 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

653 

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

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

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

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

666 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

667 

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

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

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

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

681 

682 pattern = ( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

689 pattern += ( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

700 pattern += ( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

712 

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

714 else: 

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

716 

717 return pattern 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

718 

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

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

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

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

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

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

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

726 json_schema = { 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

742 

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

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

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

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

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

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

757 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

758 

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

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

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

770 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

771 

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

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

782 

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

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

793 

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

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

804 

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

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

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

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

817 

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

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

828 

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

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

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

832 else: 

833 result['enum'] = expected 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

834 

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

836 if types == {str}: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

838 elif types == {int}: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

840 elif types == {float}: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

842 elif types == {bool}: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

844 elif types == {list}: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

848 return result 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

849 

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

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

852 

853 Args: 

854 schema: The core schema. 

855 

856 Returns: 

857 The generated JSON schema. 

858 """ 

859 enum_type = schema['cls'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

861 if ( 1zCEa

862 description == 'An enumeration.' 

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

864 description = None 1zCbdEaJKhiILcj

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

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

867 

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

869 

870 result['enum'] = expected 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

871 

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

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

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

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

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

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

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

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

880 result['type'] = 'boolean' 

881 elif types == {list}: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

883 

884 return result 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

885 

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

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

888 

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

890 

891 Args: 

892 schema: The core schema. 

893 

894 Returns: 

895 The generated JSON schema. 

896 """ 

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

898 

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

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

901 

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

903 

904 Args: 

905 schema: The core schema. 

906 

907 Returns: 

908 The generated JSON schema. 

909 """ 

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

911 return {} 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

912 

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

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

915 

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

917 

918 Args: 

919 schema: The core schema. 

920 

921 Returns: 

922 The generated JSON schema. 

923 """ 

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

925 

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

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

928 

929 Args: 

930 schema: The core schema. 

931 

932 Returns: 

933 The generated JSON schema. 

934 """ 

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

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

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

938 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

939 

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

941 @final 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

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

944 warnings.warn( 

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

946 PydanticDeprecatedSince26, 

947 stacklevel=2, 

948 ) 

949 return self.tuple_schema(schema) 

950 

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

952 @final 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

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

955 warnings.warn( 

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

957 PydanticDeprecatedSince26, 

958 stacklevel=2, 

959 ) 

960 return self.tuple_schema(schema) 

961 

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

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

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

965 

966 Args: 

967 schema: The core schema. 

968 

969 Returns: 

970 The generated JSON schema. 

971 """ 

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

973 if 'variadic_item_index' in schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

974 variadic_item_index = schema['variadic_item_index'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

975 if variadic_item_index > 0: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

976 json_schema['minItems'] = variadic_item_index 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

977 json_schema['prefixItems'] = [ 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

979 ] 

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

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

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

983 else: 

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

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

986 # for now 

987 json_schema['items'] = True 

988 else: 

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

990 if prefixItems: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

991 json_schema['prefixItems'] = prefixItems 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

995 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

996 

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

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

999 

1000 Args: 

1001 schema: The core schema. 

1002 

1003 Returns: 

1004 The generated JSON schema. 

1005 """ 

1006 return self._common_set_schema(schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1007 

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

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

1010 

1011 Args: 

1012 schema: The core schema. 

1013 

1014 Returns: 

1015 The generated JSON schema. 

1016 """ 

1017 return self._common_set_schema(schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1018 

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

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

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

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

1023 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1024 

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

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

1027 

1028 Args: 

1029 schema: The schema. 

1030 

1031 Returns: 

1032 The generated JSON schema. 

1033 """ 

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

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

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

1037 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1038 

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

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

1041 

1042 Args: 

1043 schema: The core schema. 

1044 

1045 Returns: 

1046 The generated JSON schema. 

1047 """ 

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

1049 

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

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

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

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

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

1055 else: 

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

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

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

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

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

1061 keys_pattern = None 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1062 

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

1064 # don't give a title to additionalProperties: 

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

1066 

1067 if values_schema or keys_pattern is not None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1068 if keys_pattern is None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1069 json_schema['additionalProperties'] = values_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1070 else: 

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

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

1073 json_schema['additionalProperties'] = True 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1074 

1075 if ( 1zCEa

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

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

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

1079 or '$ref' in keys_schema 

1080 ): 

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

1082 json_schema['propertyNames'] = keys_schema 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1083 

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

1085 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1086 

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

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

1089 

1090 Args: 

1091 schema: The core schema. 

1092 

1093 Returns: 

1094 The generated JSON schema. 

1095 """ 

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

1097 return self.generate_inner(input_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1098 

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

1100 

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

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

1103 

1104 Args: 

1105 schema: The core schema. 

1106 

1107 Returns: 

1108 The generated JSON schema. 

1109 """ 

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

1111 

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

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

1114 

1115 Args: 

1116 schema: The core schema. 

1117 

1118 Returns: 

1119 The generated JSON schema. 

1120 """ 

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

1122 return self.generate_inner(input_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1123 

1124 return self.handle_invalid_for_json_schema( 

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

1126 ) 

1127 

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

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

1130 

1131 Args: 

1132 schema: The core schema. 

1133 

1134 Returns: 

1135 The generated JSON schema. 

1136 """ 

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

1138 return self.generate_inner(input_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1139 

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

1141 

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

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

1144 

1145 Args: 

1146 schema: The core schema. 

1147 

1148 Returns: 

1149 The generated JSON schema. 

1150 """ 

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

1152 

1153 default = self.get_default_value(schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1154 if default is NoDefault: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1155 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1156 

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

1158 # JSON Schemas viewed in serialization mode: 

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

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

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

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

1163 if ( 1zCEaJKIL

1164 ser_schema is not None 

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

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

1167 ): 

1168 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1170 except Exception: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

1174 # this pattern for now. 

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

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

1177 self.emit_warning( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1178 'non-serializable-default', 

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

1180 ) 

1181 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1182 

1183 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1184 encoded_default = self.encode_default(default) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1185 except pydantic_core.PydanticSerializationError: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1186 self.emit_warning( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1187 'non-serializable-default', 

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

1189 ) 

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

1191 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1192 

1193 json_schema['default'] = encoded_default 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1194 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1195 

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

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

1198 

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

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

1201 

1202 Args: 

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

1204 

1205 Returns: 

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

1207 value is available. 

1208 """ 

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

1210 

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

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

1213 

1214 Args: 

1215 schema: The core schema. 

1216 

1217 Returns: 

1218 The generated JSON schema. 

1219 """ 

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

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

1222 

1223 if inner_json_schema == null_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1224 return null_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1225 else: 

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

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

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

1229 

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

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

1232 

1233 Args: 

1234 schema: The core schema. 

1235 

1236 Returns: 

1237 The generated JSON schema. 

1238 """ 

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

1240 

1241 choices = schema['choices'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1242 for choice in choices: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

1245 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1247 except PydanticOmit: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1248 continue 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1249 except PydanticInvalidForJsonSchema as exc: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

1252 return generated[0] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1253 return self.get_flattened_anyof(generated) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1254 

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

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

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

1258 the value. 

1259 

1260 Args: 

1261 schema: The core schema. 

1262 

1263 Returns: 

1264 The generated JSON schema. 

1265 """ 

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

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

1268 if isinstance(k, Enum): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1269 k = k.value 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1270 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

1274 except PydanticOmit: 

1275 continue 

1276 except PydanticInvalidForJsonSchema as exc: 

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

1278 

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

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

1281 

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

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

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

1285 json_schema['discriminator'] = { 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1286 'propertyName': openapi_discriminator, 

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

1288 } 

1289 

1290 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1291 

1292 def _extract_discriminator( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

1294 ) -> str | None: 

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

1296 schema.""" 

1297 openapi_discriminator: str | None = None 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1298 

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

1300 return schema['discriminator'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1301 

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

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

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

1305 return schema['discriminator'][0] 

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

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

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

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

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

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

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

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

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

1315 alias = alias_path[0] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

1318 alias_is_present_on_all_choices = True 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1319 for choice in one_of_choices: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1320 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1321 choice = self.resolve_ref_schema(choice) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1322 except RuntimeError as exc: 

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

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

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

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

1327 choice = {} 

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

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

1330 alias_is_present_on_all_choices = False 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1331 break 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1332 if alias_is_present_on_all_choices: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1333 openapi_discriminator = alias 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1334 break 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1335 return openapi_discriminator 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1336 

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

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

1339 

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

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

1342 

1343 Args: 

1344 schema: The core schema. 

1345 

1346 Returns: 

1347 The generated JSON schema. 

1348 """ 

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

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

1351 

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

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

1354 strict schema. 

1355 

1356 Args: 

1357 schema: The core schema. 

1358 

1359 Returns: 

1360 The generated JSON schema. 

1361 """ 

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

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

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

1365 # because one of the following two branches failed. 

1366 if use_strict: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1368 else: 

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

1370 

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

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

1373 Python schema. 

1374 

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

1376 this method. 

1377 

1378 Args: 

1379 schema: The core schema. 

1380 

1381 Returns: 

1382 The generated JSON schema. 

1383 """ 

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

1385 

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

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

1388 

1389 Args: 

1390 schema: The core schema. 

1391 

1392 Returns: 

1393 The generated JSON schema. 

1394 """ 

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

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

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

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

1399 if self.field_is_present(field) 

1400 ] 

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

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

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

1404 config = _get_typed_dict_config(cls) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1406 json_schema = self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1407 

1408 if cls is not None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1410 else: 

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

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

1413 json_schema['additionalProperties'] = False 

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

1415 json_schema['additionalProperties'] = True 

1416 

1417 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1418 

1419 @staticmethod 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

1420 def _name_required_computed_fields( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

1421 computed_fields: list[ComputedField], 

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

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

1424 

1425 def _named_required_fields_schema( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

1427 ) -> JsonSchemaValue: 

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

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

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

1431 if self.by_alias: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1433 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1435 except PydanticOmit: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1436 continue 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1438 title = self.get_title_from_name(name) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1439 field_json_schema['title'] = title 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1440 field_json_schema = self.handle_ref_overrides(field_json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1441 properties[name] = field_json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1442 if required: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1443 required_fields.append(name) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1444 

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

1446 if required_fields: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1447 json_schema['required'] = required_fields 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1448 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1449 

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

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

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

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

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

1455 else: 

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

1457 if isinstance(alias, str): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1458 name = alias 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1459 elif isinstance(alias, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

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

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

1465 name = path[0] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1466 break 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1467 else: 

1468 assert_never(alias) 

1469 return name 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1470 

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

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

1473 

1474 Args: 

1475 schema: The core schema. 

1476 

1477 Returns: 

1478 The generated JSON schema. 

1479 """ 

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

1481 

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

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

1484 

1485 Args: 

1486 schema: The core schema. 

1487 

1488 Returns: 

1489 The generated JSON schema. 

1490 """ 

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

1492 

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

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

1495 

1496 Args: 

1497 schema: The core schema. 

1498 

1499 Returns: 

1500 The generated JSON schema. 

1501 """ 

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

1503 

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

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

1506 

1507 Args: 

1508 schema: The core schema. 

1509 

1510 Returns: 

1511 The generated JSON schema. 

1512 """ 

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

1514 

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

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

1517 

1518 Args: 

1519 schema: The core schema. 

1520 

1521 Returns: 

1522 The generated JSON schema. 

1523 """ 

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

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

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

1527 config = cls.model_config 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1528 

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

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

1531 

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

1533 

1534 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1535 

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

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

1538 

1539 * title 

1540 * description 

1541 * additional properties 

1542 * json_schema_extra 

1543 * deprecated 

1544 

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

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

1547 """ 

1548 from .main import BaseModel 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1549 from .root_model import RootModel 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1550 

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

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

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

1554 title = model_title_generator(cls) 1zCbdenfogpADMEaJKhiqrstuvFGILcjkwlxmyBHN

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

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

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

1558 if 'title' not in json_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1560 

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

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

1563 

1564 if docstring: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

1568 

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

1570 if 'additionalProperties' not in json_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1571 if extra == 'allow': 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1572 json_schema['additionalProperties'] = True 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBHN

1573 elif extra == 'forbid': 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1574 json_schema['additionalProperties'] = False 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1575 

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

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

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

1579 if json_schema_extra and root_json_schema_extra: 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1580 raise ValueError( 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

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

1582 ' field must not be set simultaneously' 

1583 ) 

1584 if root_json_schema_extra: 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1585 json_schema_extra = root_json_schema_extra 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1586 

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

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

1589 json_schema_extra = json_schema_extra.__get__(cls) 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1590 

1591 if isinstance(json_schema_extra, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1592 json_schema.update(json_schema_extra) 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

1593 elif callable(json_schema_extra): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

1597 else: 

1598 json_schema_extra(json_schema) # type: ignore 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1599 elif json_schema_extra is not None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1600 raise ValueError( 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

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

1602 ) 

1603 

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

1605 json_schema['deprecated'] = True 1zCbdenfogpADMEaJKhiqrstuvFGILcjkwlxmyBHN

1606 

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

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

1609 

1610 Args: 

1611 json_schema: The schema to resolve. 

1612 

1613 Returns: 

1614 The resolved schema. 

1615 

1616 Raises: 

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

1618 """ 

1619 while '$ref' in json_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

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

1624 json_schema = schema_to_update 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1625 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1626 

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

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

1629 

1630 Args: 

1631 schema: The core schema. 

1632 

1633 Returns: 

1634 The generated JSON schema. 

1635 """ 

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

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

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

1639 if self.field_is_present(field) 

1640 ] 

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

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

1643 json_schema = self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1645 if extras_schema is not None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1646 schema_to_update = self.resolve_ref_schema(json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1648 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1649 

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

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

1652 

1653 Args: 

1654 field: The schema for the field itself. 

1655 

1656 Returns: 

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

1658 """ 

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

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

1661 # override this method and return True 

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

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

1664 return True 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1665 else: 

1666 assert_never(self.mode) 

1667 

1668 def field_is_required( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

1669 self, 

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

1671 total: bool, 

1672 ) -> bool: 

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

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

1675 

1676 Args: 

1677 field: The schema for the field itself. 

1678 total: Only applies to `TypedDictField`s. 

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

1680 explicitly specify `required=False` are required. 

1681 

1682 Returns: 

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

1684 """ 

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

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

1687 else: 

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

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

1690 else: 

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

1692 

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

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

1695 

1696 Args: 

1697 schema: The core schema. 

1698 

1699 Returns: 

1700 The generated JSON schema. 

1701 """ 

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

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

1704 for field in schema['fields'] 

1705 if self.field_is_present(field) 

1706 ] 

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

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

1709 return self._named_required_fields_schema(named_required_fields) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1710 

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

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

1713 

1714 Args: 

1715 schema: The core schema. 

1716 

1717 Returns: 

1718 The generated JSON schema. 

1719 """ 

1720 from ._internal._dataclasses import is_stdlib_dataclass 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1721 

1722 cls = schema['cls'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1724 

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

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

1727 

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

1729 

1730 # Dataclass-specific handling of description 

1731 if is_stdlib_dataclass(cls): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1733 description = None 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1734 else: 

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

1736 if description: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1737 json_schema['description'] = description 1zCbdenfogpADEaJKhiqrstuvFGOILcjkwlxmyBH

1738 

1739 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1740 

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

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

1743 

1744 Args: 

1745 schema: The core schema. 

1746 

1747 Returns: 

1748 The generated JSON schema. 

1749 """ 

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

1751 

1752 arguments = schema['arguments_schema'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

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

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

1758 

1759 if prefer_positional: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1760 positional_possible = not kw_only_arguments and not var_kwargs_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

1763 

1764 keyword_possible = not p_only_arguments and not var_args_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1765 if keyword_possible: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1767 

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

1769 positional_possible = not kw_only_arguments and not var_kwargs_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1770 if positional_possible: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1772 

1773 raise PydanticInvalidForJsonSchema( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1775 ) 

1776 

1777 def kw_arguments_schema( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

1779 ) -> JsonSchemaValue: 

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

1781 

1782 Args: 

1783 arguments: The core schema. 

1784 

1785 Returns: 

1786 The generated JSON schema. 

1787 """ 

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

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

1790 for argument in arguments: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1791 name = self.get_argument_name(argument) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

1794 properties[name] = argument_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1795 

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

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

1798 # the inner schema must be of type WithDefaultSchema. 

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

1800 required.append(name) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1801 

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

1803 if required: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1804 json_schema['required'] = required 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1805 

1806 if var_kwargs_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1807 additional_properties_schema = self.generate_inner(var_kwargs_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1809 json_schema['additionalProperties'] = additional_properties_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1810 else: 

1811 json_schema['additionalProperties'] = False 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1812 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1813 

1814 def p_arguments_schema( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

1816 ) -> JsonSchemaValue: 

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

1818 

1819 Args: 

1820 arguments: The core schema. 

1821 

1822 Returns: 

1823 The generated JSON schema. 

1824 """ 

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

1826 min_items = 0 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1827 

1828 for argument in arguments: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1829 name = self.get_argument_name(argument) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1830 

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

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

1833 prefix_items.append(argument_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1834 

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

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

1837 # the inner schema must be of type WithDefaultSchema. 

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

1839 min_items += 1 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1840 

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

1842 if prefix_items: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1843 json_schema['prefixItems'] = prefix_items 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1844 if min_items: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1845 json_schema['minItems'] = min_items 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1846 

1847 if var_args_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1848 items_schema = self.generate_inner(var_args_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1850 json_schema['items'] = items_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1851 else: 

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

1853 

1854 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1855 

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

1857 """Retrieves the name of an argument. 

1858 

1859 Args: 

1860 argument: The core schema. 

1861 

1862 Returns: 

1863 The name of the argument. 

1864 """ 

1865 name = argument['name'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

1868 if isinstance(alias, str): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1869 name = alias 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1870 else: 

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

1872 return name 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1873 

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

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

1876 

1877 Args: 

1878 schema: The core schema. 

1879 

1880 Returns: 

1881 The generated JSON schema. 

1882 """ 

1883 arguments = schema['arguments_schema'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

1886 for argument in arguments: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1888 name = self.get_argument_name(argument) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1890 if mode == 'var_args': 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1892 elif mode == 'var_kwargs_uniform': 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

1894 

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

1896 properties[name] = argument_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1897 

1898 if ( 1zCEa

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

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

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

1902 ): 

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

1904 # the inner schema must be of type WithDefaultSchema. 

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

1906 required.append(name) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1907 

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

1909 if required: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1910 json_schema['required'] = required 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1911 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1912 

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

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

1915 

1916 Args: 

1917 schema: The core schema. 

1918 

1919 Returns: 

1920 The generated JSON schema. 

1921 """ 

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

1923 

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

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

1926 

1927 Args: 

1928 schema: The core schema. 

1929 

1930 Returns: 

1931 The generated JSON schema. 

1932 """ 

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

1934 

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

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

1937 

1938 Args: 

1939 schema: The core schema. 

1940 

1941 Returns: 

1942 The generated JSON schema. 

1943 """ 

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

1945 content_json_schema = self.generate_inner(content_core_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

1948 else: 

1949 # self.mode == 'serialization' 

1950 return content_json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1951 

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

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

1954 

1955 Args: 

1956 schema: The core schema. 

1957 

1958 Returns: 

1959 The generated JSON schema. 

1960 """ 

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

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

1963 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1964 

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

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

1967 

1968 Args: 

1969 schema: The core schema. 

1970 

1971 Returns: 

1972 The generated JSON schema. 

1973 """ 

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

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

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

1977 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

1978 

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

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

1981 

1982 Args: 

1983 schema: The core schema. 

1984 

1985 Returns: 

1986 The generated JSON schema. 

1987 """ 

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

1989 

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

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

1992 

1993 Args: 

1994 schema: The core schema. 

1995 

1996 Returns: 

1997 The generated JSON schema. 

1998 """ 

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

2000 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2001 self.generate_inner(definition) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2002 except PydanticInvalidForJsonSchema as e: 

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

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

2005 continue 

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

2007 

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

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

2010 

2011 Args: 

2012 schema: The core schema. 

2013 

2014 Returns: 

2015 The generated JSON schema. 

2016 """ 

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

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

2019 return ref_json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2020 

2021 def ser_schema( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

2023 ) -> JsonSchemaValue | None: 

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

2025 

2026 Args: 

2027 schema: The core schema. 

2028 

2029 Returns: 

2030 The generated JSON schema. 

2031 """ 

2032 schema_type = schema['type'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2034 # PlainSerializerFunctionSerSchema or WrapSerializerFunctionSerSchema 

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

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

2037 return self.generate_inner(return_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2039 # FormatSerSchema or ToStringSerSchema 

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

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

2042 # ModelSerSchema 

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

2044 return None 

2045 

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

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

2048 

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

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

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

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

2053 

2054 Args: 

2055 schema: The core schema. 

2056 

2057 Returns: 

2058 The generated JSON schema. 

2059 """ 

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

2061 

2062 # ### Utility methods 

2063 

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

2065 """Retrieves a title from a name. 

2066 

2067 Args: 

2068 name: The name to retrieve a title from. 

2069 

2070 Returns: 

2071 The title. 

2072 """ 

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

2074 

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

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

2077 

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

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

2080 

2081 Args: 

2082 schema: The schema to check. 

2083 

2084 Returns: 

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

2086 """ 

2087 if _core_utils.is_core_schema_field(schema): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2089 field_schema = schema['return_schema'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2090 else: 

2091 field_schema = schema['schema'] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2092 return self.field_title_should_be_set(field_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2093 

2094 elif _core_utils.is_core_schema(schema): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2096 return False 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

2099 if _core_utils.is_function_with_inner_schema(schema): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

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

2103 # schemas with refs should not 

2104 return False 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2106 

2107 else: 

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

2109 

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

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

2112 

2113 Args: 

2114 name: The name to normalize. 

2115 

2116 Returns: 

2117 The normalized name. 

2118 """ 

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

2120 

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

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

2123 

2124 Args: 

2125 core_mode_ref: The core reference. 

2126 

2127 Returns: 

2128 The definitions key. 

2129 """ 

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

2131 core_ref, mode = core_mode_ref 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2132 components = re.split(r'([\][,])', core_ref) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2133 # Remove IDs from each component 

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

2135 core_ref_no_id = ''.join(components) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

2138 short_ref = ''.join(components) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2139 

2140 mode_title = _MODE_TITLE_MAPPING[mode] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2141 

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

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

2144 # the id of the source type in the core_ref 

2145 name = DefsRef(self.normalize_name(short_ref)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2147 module_qualname = DefsRef(self.normalize_name(core_ref_no_id)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2148 module_qualname_mode = DefsRef(f'{module_qualname}-{mode_title}') 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2149 module_qualname_id = DefsRef(self.normalize_name(core_ref)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2150 occurrence_index = self._collision_index.get(module_qualname_id) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2151 if occurrence_index is None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2152 self._collision_counter[module_qualname] += 1 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2153 occurrence_index = self._collision_index[module_qualname_id] = self._collision_counter[module_qualname] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2154 

2155 module_qualname_occurrence = DefsRef(f'{module_qualname}__{occurrence_index}') 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2156 module_qualname_occurrence_mode = DefsRef(f'{module_qualname_mode}__{occurrence_index}') 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2157 

2158 self._prioritized_defsref_choices[module_qualname_occurrence_mode] = [ 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2159 name, 

2160 name_mode, 

2161 module_qualname, 

2162 module_qualname_mode, 

2163 module_qualname_occurrence, 

2164 module_qualname_occurrence_mode, 

2165 ] 

2166 

2167 return module_qualname_occurrence_mode 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2168 

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

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

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

2172 

2173 Args: 

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

2175 

2176 Returns: 

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

2178 """ 

2179 core_mode_ref = (core_ref, self.mode) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2180 maybe_defs_ref = self.core_to_defs_refs.get(core_mode_ref) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2181 if maybe_defs_ref is not None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2182 json_ref = self.core_to_json_refs[core_mode_ref] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2183 return maybe_defs_ref, {'$ref': json_ref} 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2184 

2185 defs_ref = self.get_defs_ref(core_mode_ref) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2186 

2187 # populate the ref translation mappings 

2188 self.core_to_defs_refs[core_mode_ref] = defs_ref 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2189 self.defs_to_core_refs[defs_ref] = core_mode_ref 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2190 

2191 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2192 self.core_to_json_refs[core_mode_ref] = json_ref 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2193 self.json_to_defs_refs[json_ref] = defs_ref 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2194 ref_json_schema = {'$ref': json_ref} 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2195 return defs_ref, ref_json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2196 

2197 def handle_ref_overrides(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

2199 

2200 Args: 

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

2202 

2203 Returns: 

2204 The schema with redundant sibling keys removed. 

2205 """ 

2206 if '$ref' in json_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2208 json_schema = json_schema.copy() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2209 

2210 referenced_json_schema = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2211 if referenced_json_schema is None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

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

2214 # any redundant override keys. 

2215 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2216 for k, v in list(json_schema.items()): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2217 if k == '$ref': 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2218 continue 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2219 if k in referenced_json_schema and referenced_json_schema[k] == v: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2220 del json_schema[k] # redundant key 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2221 

2222 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2223 

2224 def get_schema_from_definitions(self, json_ref: JsonRef) -> JsonSchemaValue | None: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2225 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2226 def_ref = self.json_to_defs_refs[json_ref] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2227 if def_ref in self._core_defs_invalid_for_json_schema: 2227 ↛ 2228line 2227 didn't jump to line 2228 because the condition on line 2227 was never true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2228 raise self._core_defs_invalid_for_json_schema[def_ref] 

2229 return self.definitions.get(def_ref, None) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2230 except KeyError: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2232 return None 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2233 raise 

2234 

2235 def encode_default(self, dft: Any) -> Any: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

2237 

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

2239 

2240 Args: 

2241 dft: The default value to encode. 

2242 

2243 Returns: 

2244 The encoded default value. 

2245 """ 

2246 from .type_adapter import TypeAdapter, _type_has_config 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2247 

2248 config = self._config 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2249 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2250 default = ( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2251 dft 

2252 if _type_has_config(type(dft)) 

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

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

2255 ) 

2256 ) 

2257 except PydanticSchemaGenerationError: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2259 

2260 return pydantic_core.to_jsonable_python( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2262 ) 

2263 

2264 def update_with_validations( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

2266 ) -> None: 

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

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

2269 

2270 Args: 

2271 json_schema: The JSON schema to update. 

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

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

2274 """ 

2275 for core_key, json_schema_key in mapping.items(): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2276 if core_key in core_schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2277 json_schema[json_schema_key] = core_schema[core_key] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2278 

2279 class ValidationsMapping: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

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

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

2283 GenerateJsonSchema.ValidationsMapping) to change these mappings. 

2284 """ 

2285 

2286 numeric = { 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2287 'multiple_of': 'multipleOf', 

2288 'le': 'maximum', 

2289 'ge': 'minimum', 

2290 'lt': 'exclusiveMaximum', 

2291 'gt': 'exclusiveMinimum', 

2292 } 

2293 bytes = { 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2294 'min_length': 'minLength', 

2295 'max_length': 'maxLength', 

2296 } 

2297 string = { 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2298 'min_length': 'minLength', 

2299 'max_length': 'maxLength', 

2300 'pattern': 'pattern', 

2301 } 

2302 array = { 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2303 'min_length': 'minItems', 

2304 'max_length': 'maxItems', 

2305 } 

2306 object = { 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2307 'min_length': 'minProperties', 

2308 'max_length': 'maxProperties', 

2309 } 

2310 

2311 def get_flattened_anyof(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2312 members = [] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2313 for schema in schemas: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2314 if len(schema) == 1 and 'anyOf' in schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2315 members.extend(schema['anyOf']) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2316 else: 

2317 members.append(schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2318 members = _deduplicate_schemas(members) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2319 if len(members) == 1: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2320 return members[0] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2321 return {'anyOf': members} 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2322 

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

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

2325 json_refs: dict[JsonRef, int] = Counter() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2326 

2327 def _add_json_refs(schema: Any) -> None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2328 if isinstance(schema, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2329 if '$ref' in schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2330 json_ref = JsonRef(schema['$ref']) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2331 if not isinstance(json_ref, str): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2333 already_visited = json_ref in json_refs 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2334 json_refs[json_ref] += 1 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2335 if already_visited: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2336 return # prevent recursion on a definition that was already visited 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2337 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2338 defs_ref = self.json_to_defs_refs[json_ref] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2339 if defs_ref in self._core_defs_invalid_for_json_schema: 2339 ↛ 2340line 2339 didn't jump to line 2340 because the condition on line 2339 was never true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2340 raise self._core_defs_invalid_for_json_schema[defs_ref] 

2341 _add_json_refs(self.definitions[defs_ref]) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2342 except KeyError: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2344 raise 

2345 

2346 for k, v in schema.items(): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2347 if k == 'examples' and isinstance(v, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2348 # Skip examples that may contain arbitrary values and references 

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

2350 continue 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2351 _add_json_refs(v) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2352 elif isinstance(schema, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2353 for v in schema: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2354 _add_json_refs(v) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2355 

2356 _add_json_refs(json_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2357 return json_refs 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2358 

2359 def handle_invalid_for_json_schema(self, schema: CoreSchemaOrField, error_info: str) -> JsonSchemaValue: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2360 raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}') 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2361 

2362 def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

2364 message = self.render_warning_message(kind, detail) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2365 if message is not None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2366 warnings.warn(message, PydanticJsonSchemaWarning) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2367 

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

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

2370 

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

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

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

2374 

2375 Args: 

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

2377 

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

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

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

2381 

2382 Returns: 

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

2384 """ 

2385 if kind in self.ignored_warning_kinds: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2386 return None 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2387 return f'{detail} [{kind}]' 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2388 

2389 def _build_definitions_remapping(self) -> _DefinitionsRemapping: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2390 defs_to_json: dict[DefsRef, JsonRef] = {} 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2391 for defs_refs in self._prioritized_defsref_choices.values(): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2392 for defs_ref in defs_refs: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2393 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2394 defs_to_json[defs_ref] = json_ref 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2395 

2396 return _DefinitionsRemapping.from_prioritized_choices( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2397 self._prioritized_defsref_choices, defs_to_json, self.definitions 

2398 ) 

2399 

2400 def _garbage_collect_definitions(self, schema: JsonSchemaValue) -> None: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2401 visited_defs_refs: set[DefsRef] = set() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2402 unvisited_json_refs = _get_all_json_refs(schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2403 while unvisited_json_refs: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2404 next_json_ref = unvisited_json_refs.pop() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2405 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2406 next_defs_ref = self.json_to_defs_refs[next_json_ref] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2407 if next_defs_ref in visited_defs_refs: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2408 continue 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2409 visited_defs_refs.add(next_defs_ref) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2410 unvisited_json_refs.update(_get_all_json_refs(self.definitions[next_defs_ref])) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2411 except KeyError: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2413 raise 

2414 

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

2416 

2417 

2418# ##### Start JSON Schema Generation Functions ##### 

2419 

2420 

2421def model_json_schema( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

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

2423 by_alias: bool = True, 

2424 ref_template: str = DEFAULT_REF_TEMPLATE, 

2425 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2426 mode: JsonSchemaMode = 'validation', 

2427) -> dict[str, Any]: 

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

2429 

2430 Args: 

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

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

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

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

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

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

2437 

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

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

2440 

2441 Returns: 

2442 The generated JSON Schema. 

2443 """ 

2444 from .main import BaseModel 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2445 

2446 schema_generator_instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2447 

2448 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2449 cls.__pydantic_core_schema__.rebuild() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2450 

2451 if cls is BaseModel: 2451 ↛ 2452line 2451 didn't jump to line 2452 because the condition on line 2451 was never true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

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

2453 

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

2455 return schema_generator_instance.generate(cls.__pydantic_core_schema__, mode=mode) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2456 

2457 

2458def models_json_schema( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2459 models: Sequence[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode]], 

2460 *, 

2461 by_alias: bool = True, 

2462 title: str | None = None, 

2463 description: str | None = None, 

2464 ref_template: str = DEFAULT_REF_TEMPLATE, 

2465 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, 

2466) -> tuple[dict[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: 

2467 """Utility function to generate a JSON Schema for multiple models. 

2468 

2469 Args: 

2470 models: A sequence of tuples of the form (model, mode). 

2471 by_alias: Whether field aliases should be used as keys in the generated JSON Schema. 

2472 title: The title of the generated JSON Schema. 

2473 description: The description of the generated JSON Schema. 

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

2475 schema_generator: The schema generator to use for generating the JSON Schema. 

2476 

2477 Returns: 

2478 A tuple where: 

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

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

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

2482 - The second element is a JSON schema containing all definitions referenced in the first returned 

2483 element, along with the optional title and description keys. 

2484 """ 

2485 for cls, _ in models: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2486 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 2486 ↛ 2487line 2486 didn't jump to line 2487 because the condition on line 2486 was never true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2487 cls.__pydantic_core_schema__.rebuild() 

2488 

2489 instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2490 inputs: list[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode, CoreSchema]] = [ 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2491 (m, mode, m.__pydantic_core_schema__) for m, mode in models 

2492 ] 

2493 json_schemas_map, definitions = instance.generate_definitions(inputs) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2494 

2495 json_schema: dict[str, Any] = {} 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2496 if definitions: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2497 json_schema['$defs'] = definitions 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2498 if title: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2499 json_schema['title'] = title 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2500 if description: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2501 json_schema['description'] = description 1zCbdenfogpADEaJKhiqrstuvFGILcjkwlxmyBH

2502 

2503 return json_schemas_map, json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2504 

2505 

2506# ##### End JSON Schema Generation Functions ##### 

2507 

2508 

2509_HashableJsonValue: TypeAlias = Union[ 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2510 int, float, str, bool, None, tuple['_HashableJsonValue', ...], tuple[tuple[str, '_HashableJsonValue'], ...] 

2511] 

2512 

2513 

2514def _deduplicate_schemas(schemas: Iterable[JsonDict]) -> list[JsonDict]: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2515 return list({_make_json_hashable(schema): schema for schema in schemas}.values()) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2516 

2517 

2518def _make_json_hashable(value: JsonValue) -> _HashableJsonValue: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2519 if isinstance(value, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2520 return tuple(sorted((k, _make_json_hashable(v)) for k, v in value.items())) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2521 elif isinstance(value, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2522 return tuple(_make_json_hashable(v) for v in value) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2523 else: 

2524 return value 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2525 

2526 

2527@dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2528class WithJsonSchema: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2529 """!!! abstract "Usage Documentation" 

2530 [`WithJsonSchema` Annotation](../concepts/json_schema.md#withjsonschema-annotation) 

2531 

2532 Add this as an annotation on a field to override the (base) JSON schema that would be generated for that field. 

2533 This provides a way to set a JSON schema for types that would otherwise raise errors when producing a JSON schema, 

2534 such as Callable, or types that have an is-instance core schema, without needing to go so far as creating a 

2535 custom subclass of pydantic.json_schema.GenerateJsonSchema. 

2536 Note that any _modifications_ to the schema that would normally be made (such as setting the title for model fields) 

2537 will still be performed. 

2538 

2539 If `mode` is set this will only apply to that schema generation mode, allowing you 

2540 to set different json schemas for validation and serialization. 

2541 """ 

2542 

2543 json_schema: JsonSchemaValue | None 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2544 mode: Literal['validation', 'serialization'] | None = None 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2545 

2546 def __get_pydantic_json_schema__( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2547 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2548 ) -> JsonSchemaValue: 

2549 mode = self.mode or handler.mode 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2550 if mode != handler.mode: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2551 return handler(core_schema) 1zbefgAIcklmB

2552 if self.json_schema is None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2553 # This exception is handled in pydantic.json_schema.GenerateJsonSchema._named_required_fields_schema 

2554 raise PydanticOmit 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2555 else: 

2556 return self.json_schema.copy() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2557 

2558 def __hash__(self) -> int: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2559 return hash(type(self.mode)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2560 

2561 

2562class Examples: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2563 """Add examples to a JSON schema. 

2564 

2565 If the JSON Schema already contains examples, the provided examples 

2566 will be appended. 

2567 

2568 If `mode` is set this will only apply to that schema generation mode, 

2569 allowing you to add different examples for validation and serialization. 

2570 """ 

2571 

2572 @overload 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2573 @deprecated('Using a dict for `examples` is deprecated since v2.9 and will be removed in v3.0. Use a list instead.') 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2574 def __init__( 1zCbdenfogpADMJKhiqrstuvFGOPILcjkwlxmyBHN

2575 self, examples: dict[str, Any], mode: Literal['validation', 'serialization'] | None = None 1bdenfogpEahiqrstuvPcjkwlxmy

2576 ) -> None: ... 1fogpEastuvPlxmy

2577 

2578 @overload 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2579 def __init__(self, examples: list[Any], mode: Literal['validation', 'serialization'] | None = None) -> None: ... 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2580 

2581 def __init__( 1zCbdenfogpADMJKhiqrstuvFGOPILcjkwlxmyBHN

2582 self, examples: dict[str, Any] | list[Any], mode: Literal['validation', 'serialization'] | None = None 

2583 ) -> None: 

2584 if isinstance(examples, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2585 warnings.warn( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2586 'Using a dict for `examples` is deprecated, use a list instead.', 

2587 PydanticDeprecatedSince29, 

2588 stacklevel=2, 

2589 ) 

2590 self.examples = examples 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2591 self.mode = mode 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2592 

2593 def __get_pydantic_json_schema__( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2594 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler 

2595 ) -> JsonSchemaValue: 

2596 mode = self.mode or handler.mode 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2597 json_schema = handler(core_schema) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2598 if mode != handler.mode: 2598 ↛ 2599line 2598 didn't jump to line 2599 because the condition on line 2598 was never true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2599 return json_schema 

2600 examples = json_schema.get('examples') 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2601 if examples is None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2602 json_schema['examples'] = to_jsonable_python(self.examples) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2603 if isinstance(examples, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2604 if isinstance(self.examples, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2605 warnings.warn( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2606 'Updating existing JSON Schema examples of type dict with examples of type list. ' 

2607 'Only the existing examples values will be retained. Note that dict support for ' 

2608 'examples is deprecated and will be removed in v3.0.', 

2609 UserWarning, 

2610 ) 

2611 json_schema['examples'] = to_jsonable_python( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2612 [ex for value in examples.values() for ex in value] + self.examples 

2613 ) 

2614 else: 

2615 json_schema['examples'] = to_jsonable_python({**examples, **self.examples}) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2616 if isinstance(examples, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2617 if isinstance(self.examples, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2618 json_schema['examples'] = to_jsonable_python(examples + self.examples) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2619 elif isinstance(self.examples, dict): 2619 ↛ 2630line 2619 didn't jump to line 2630 because the condition on line 2619 was always true1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2620 warnings.warn( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2621 'Updating existing JSON Schema examples of type list with examples of type dict. ' 

2622 'Only the examples values will be retained. Note that dict support for ' 

2623 'examples is deprecated and will be removed in v3.0.', 

2624 UserWarning, 

2625 ) 

2626 json_schema['examples'] = to_jsonable_python( 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2627 examples + [ex for value in self.examples.values() for ex in value] 

2628 ) 

2629 

2630 return json_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2631 

2632 def __hash__(self) -> int: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2633 return hash(type(self.mode)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2634 

2635 

2636def _get_all_json_refs(item: Any) -> set[JsonRef]: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2637 """Get all the definitions references from a JSON schema.""" 

2638 refs: set[JsonRef] = set() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2639 stack = [item] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2640 

2641 while stack: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2642 current = stack.pop() 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2643 if isinstance(current, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2644 for key, value in current.items(): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2645 if key == 'examples' and isinstance(value, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2646 # Skip examples that may contain arbitrary values and references 

2647 # (e.g. `{"examples": [{"$ref": "..."}]}`). Note: checking for value 

2648 # of type list is necessary to avoid skipping valid portions of the schema, 

2649 # for instance when "examples" is used as a property key. A more robust solution 

2650 # could be found, but would require more advanced JSON Schema parsing logic. 

2651 continue 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2652 if key == '$ref' and isinstance(value, str): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2653 refs.add(JsonRef(value)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2654 elif isinstance(value, dict): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2655 stack.append(value) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2656 elif isinstance(value, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2657 stack.extend(value) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2658 elif isinstance(current, list): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2659 stack.extend(current) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2660 

2661 return refs 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2662 

2663 

2664AnyType = TypeVar('AnyType') 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2665 

2666if TYPE_CHECKING: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2667 SkipJsonSchema = Annotated[AnyType, ...] 

2668else: 

2669 

2670 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2671 class SkipJsonSchema: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2672 """!!! abstract "Usage Documentation" 

2673 [`SkipJsonSchema` Annotation](../concepts/json_schema.md#skipjsonschema-annotation) 

2674 

2675 Add this as an annotation on a field to skip generating a JSON schema for that field. 

2676 

2677 Example: 

2678 ```python 

2679 from pprint import pprint 

2680 from typing import Union 

2681 

2682 from pydantic import BaseModel 

2683 from pydantic.json_schema import SkipJsonSchema 

2684 

2685 class Model(BaseModel): 

2686 a: Union[int, None] = None # (1)! 

2687 b: Union[int, SkipJsonSchema[None]] = None # (2)! 

2688 c: SkipJsonSchema[Union[int, None]] = None # (3)! 

2689 

2690 pprint(Model.model_json_schema()) 

2691 ''' 

2692 { 

2693 'properties': { 

2694 'a': { 

2695 'anyOf': [ 

2696 {'type': 'integer'}, 

2697 {'type': 'null'} 

2698 ], 

2699 'default': None, 

2700 'title': 'A' 

2701 }, 

2702 'b': { 

2703 'default': None, 

2704 'title': 'B', 

2705 'type': 'integer' 

2706 } 

2707 }, 

2708 'title': 'Model', 

2709 'type': 'object' 

2710 } 

2711 ''' 

2712 ``` 

2713 

2714 1. The integer and null types are both included in the schema for `a`. 

2715 2. The integer type is the only type included in the schema for `b`. 

2716 3. The entirety of the `c` field is omitted from the schema. 

2717 """ 

2718 

2719 def __class_getitem__(cls, item: AnyType) -> AnyType: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2720 return Annotated[item, cls()] 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2721 

2722 def __get_pydantic_json_schema__( 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2723 self, core_schema: CoreSchema, handler: GetJsonSchemaHandler 

2724 ) -> JsonSchemaValue: 

2725 raise PydanticOmit 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2726 

2727 def __hash__(self) -> int: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2728 return hash(type(self)) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2729 

2730 

2731def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2732 if cls is not None: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2733 try: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2734 return _decorators.get_attribute_from_bases(cls, '__pydantic_config__') 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2735 except AttributeError: 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBH

2736 pass 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBH

2737 return {} 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2738 

2739 

2740def _get_ser_schema_for_default_value(schema: CoreSchema) -> core_schema.PlainSerializerFunctionSerSchema | None: 1zCbdenfogpADMEaJKhiqrstuvFGOPILcjkwlxmyBHN

2741 """Get a `'function-plain'` serialization schema that can be used to serialize a default value. 

2742 

2743 This takes into account having the serialization schema nested under validation schema(s). 

2744 """ 

2745 if ( 1zCbdenEaJKhiqrILcjkw

2746 (ser_schema := schema.get('serialization')) 

2747 and ser_schema['type'] == 'function-plain' 

2748 and not ser_schema.get('info_arg') 

2749 ): 

2750 return ser_schema 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2751 if _core_utils.is_function_with_inner_schema(schema): 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN

2752 return _get_ser_schema_for_default_value(schema['schema']) 1zCbdenfogpADMEaJKhiqrstuvFGOILcjkwlxmyBHN