Coverage for pydantic/json_schema.py: 94.57%
1020 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-03 19:29 +0000
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-03 19:29 +0000
1"""
2Usage docs: https://docs.pydantic.dev/2.5/concepts/json_schema/
4The `json_schema` module contains classes and functions to allow the way [JSON Schema](https://json-schema.org/)
5is generated to be customized.
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"""
12from __future__ import annotations as _annotations 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
14import dataclasses 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
15import inspect 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
16import math 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
17import re 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
18import warnings 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
19from collections import defaultdict 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
20from copy import deepcopy 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
21from dataclasses import is_dataclass 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
22from enum import Enum 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
23from typing import ( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
24 TYPE_CHECKING,
25 Any,
26 Callable,
27 Counter,
28 Dict,
29 Hashable,
30 Iterable,
31 NewType,
32 Pattern,
33 Sequence,
34 Tuple,
35 TypeVar,
36 Union,
37 cast,
38)
40import pydantic_core 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
41from pydantic_core import CoreSchema, PydanticOmit, core_schema, to_jsonable_python 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
42from pydantic_core.core_schema import ComputedField 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
43from typing_extensions import Annotated, Literal, TypeAlias, assert_never, deprecated, final 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
45from pydantic.warnings import PydanticDeprecatedSince26 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
47from ._internal import ( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
48 _config,
49 _core_metadata,
50 _core_utils,
51 _decorators,
52 _internal_dataclass,
53 _mock_val_ser,
54 _schema_generation_shared,
55 _typing_extra,
56)
57from .annotated_handlers import GetJsonSchemaHandler 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
58from .config import JsonDict, JsonSchemaExtraCallable, JsonValue 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
59from .errors import PydanticInvalidForJsonSchema, PydanticSchemaGenerationError, PydanticUserError 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
61if TYPE_CHECKING: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
62 from . import ConfigDict
63 from ._internal._core_utils import CoreSchemaField, CoreSchemaOrField
64 from ._internal._dataclasses import PydanticDataclass
65 from ._internal._schema_generation_shared import GetJsonSchemaFunction
66 from .main import BaseModel
69CoreSchemaOrFieldType = Literal[core_schema.CoreSchemaType, core_schema.CoreSchemaFieldType] 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
70""" 1adejkpqrbfglmstuvMNOPQRSTchinowxy
71A type alias for defined schema types that represents a union of
72`core_schema.CoreSchemaType` and
73`core_schema.CoreSchemaFieldType`.
74"""
76JsonSchemaValue = Dict[str, Any] 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
77""" 1adejkpqrbfglmstuvMNOPQRSTchinowxy
78A type alias for a JSON schema value. This is a dictionary of string keys to arbitrary JSON values.
79"""
81JsonSchemaMode = Literal['validation', 'serialization'] 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
82""" 1adejkpqrbfglmstuvMNOPQRSTchinowxy
83A type alias that represents the mode of a JSON schema; either 'validation' or 'serialization'.
85For some types, the inputs to validation differ from the outputs of serialization. For example,
86computed fields will only be present when serializing, and should not be provided when
87validating. This flag provides a way to indicate whether you want the JSON schema required
88for validation inputs, or that will be matched by serialization outputs.
89"""
91_MODE_TITLE_MAPPING: dict[JsonSchemaMode, str] = {'validation': 'Input', 'serialization': 'Output'} 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
94@deprecated( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
95 '`update_json_schema` is deprecated, use a simple `my_dict.update(update_dict)` call instead.',
96 category=None,
97)
98def update_json_schema(schema: JsonSchemaValue, updates: dict[str, Any]) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
99 """Update a JSON schema in-place by providing a dictionary of updates.
101 This function sets the provided key-value pairs in the schema and returns the updated schema.
103 Args:
104 schema: The JSON schema to update.
105 updates: A dictionary of key-value pairs to set in the schema.
107 Returns:
108 The updated JSON schema.
109 """
110 schema.update(updates)
111 return schema
114JsonSchemaWarningKind = Literal['skipped-choice', 'non-serializable-default'] 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
115""" 1adejkpqrbfglmstuvMNOPQRSTchinowxy
116A type alias representing the kinds of warnings that can be emitted during JSON schema generation.
118See [`GenerateJsonSchema.render_warning_message`][pydantic.json_schema.GenerateJsonSchema.render_warning_message]
119for more details.
120"""
123class PydanticJsonSchemaWarning(UserWarning): 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
124 """This class is used to emit warnings produced during JSON schema generation.
125 See the [`GenerateJsonSchema.emit_warning`][pydantic.json_schema.GenerateJsonSchema.emit_warning] and
126 [`GenerateJsonSchema.render_warning_message`][pydantic.json_schema.GenerateJsonSchema.render_warning_message]
127 methods for more details; these can be overridden to control warning behavior.
128 """
131# ##### JSON Schema Generation #####
132DEFAULT_REF_TEMPLATE = '#/$defs/{model}' 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
133"""The default format string used to generate reference names.""" 1adejkpqrbfglmstuvMNOPQRSTchinowxy
135# There are three types of references relevant to building JSON schemas:
136# 1. core_schema "ref" values; these are not exposed as part of the JSON schema
137# * these might look like the fully qualified path of a model, its id, or something similar
138CoreRef = NewType('CoreRef', str) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
139# 2. keys of the "definitions" object that will eventually go into the JSON schema
140# * by default, these look like "MyModel", though may change in the presence of collisions
141# * eventually, we may want to make it easier to modify the way these names are generated
142DefsRef = NewType('DefsRef', str) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
143# 3. the values corresponding to the "$ref" key in the schema
144# * By default, these look like "#/$defs/MyModel", as in {"$ref": "#/$defs/MyModel"}
145JsonRef = NewType('JsonRef', str) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
147CoreModeRef = Tuple[CoreRef, JsonSchemaMode] 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
148JsonSchemaKeyT = TypeVar('JsonSchemaKeyT', bound=Hashable) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
151@dataclasses.dataclass(**_internal_dataclass.slots_true) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
152class _DefinitionsRemapping: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
153 defs_remapping: dict[DefsRef, DefsRef] 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
154 json_remapping: dict[JsonRef, JsonRef] 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
156 @staticmethod 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
157 def from_prioritized_choices( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
158 prioritized_choices: dict[DefsRef, list[DefsRef]],
159 defs_to_json: dict[DefsRef, JsonRef],
160 definitions: dict[DefsRef, JsonSchemaValue],
161 ) -> _DefinitionsRemapping:
162 """
163 This function should produce a remapping that replaces complex DefsRef with the simpler ones from the
164 prioritized_choices such that applying the name remapping would result in an equivalent JSON schema.
165 """
166 # We need to iteratively simplify the definitions until we reach a fixed point.
167 # The reason for this is that outer definitions may reference inner definitions that get simplified
168 # into an equivalent reference, and the outer definitions won't be equivalent until we've simplified
169 # the inner definitions.
170 copied_definitions = deepcopy(definitions) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
171 definitions_schema = {'$defs': copied_definitions} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
172 for _iter in range(100): # prevent an infinite loop in the case of a bug, 100 iterations should be enough 172 ↛ 201line 172 didn't jump to line 201 because the loop on line 172 didn't complete1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
173 # For every possible remapped DefsRef, collect all schemas that that DefsRef might be used for:
174 schemas_for_alternatives: dict[DefsRef, list[JsonSchemaValue]] = defaultdict(list) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
175 for defs_ref in copied_definitions: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
176 alternatives = prioritized_choices[defs_ref] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
177 for alternative in alternatives: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
178 schemas_for_alternatives[alternative].append(copied_definitions[defs_ref]) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
180 # Deduplicate the schemas for each alternative; the idea is that we only want to remap to a new DefsRef
181 # if it introduces no ambiguity, i.e., there is only one distinct schema for that DefsRef.
182 for defs_ref, schemas in schemas_for_alternatives.items(): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
183 schemas_for_alternatives[defs_ref] = _deduplicate_schemas(schemas_for_alternatives[defs_ref]) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
185 # Build the remapping
186 defs_remapping: dict[DefsRef, DefsRef] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
187 json_remapping: dict[JsonRef, JsonRef] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
188 for original_defs_ref in definitions: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
189 alternatives = prioritized_choices[original_defs_ref] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
190 # Pick the first alternative that has only one schema, since that means there is no collision
191 remapped_defs_ref = next(x for x in alternatives if len(schemas_for_alternatives[x]) == 1) 191 ↛ exitline 191 didn't finish the generator expression on line 1911EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
192 defs_remapping[original_defs_ref] = remapped_defs_ref 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
193 json_remapping[defs_to_json[original_defs_ref]] = defs_to_json[remapped_defs_ref] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
194 remapping = _DefinitionsRemapping(defs_remapping, json_remapping) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
195 new_definitions_schema = remapping.remap_json_schema({'$defs': copied_definitions}) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
196 if definitions_schema == new_definitions_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
197 # We've reached the fixed point
198 return remapping 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
199 definitions_schema = new_definitions_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
201 raise PydanticInvalidForJsonSchema('Failed to simplify the JSON schema definitions')
203 def remap_defs_ref(self, ref: DefsRef) -> DefsRef: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
204 return self.defs_remapping.get(ref, ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
206 def remap_json_ref(self, ref: JsonRef) -> JsonRef: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
207 return self.json_remapping.get(ref, ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
209 def remap_json_schema(self, schema: Any) -> Any: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
210 """
211 Recursively update the JSON schema replacing all $refs
212 """
213 if isinstance(schema, str): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
214 # Note: this may not really be a JsonRef; we rely on having no collisions between JsonRefs and other strings
215 return self.remap_json_ref(JsonRef(schema)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
216 elif isinstance(schema, list): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
217 return [self.remap_json_schema(item) for item in schema] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
218 elif isinstance(schema, dict): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
219 for key, value in schema.items(): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
220 if key == '$ref' and isinstance(value, str): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
221 schema['$ref'] = self.remap_json_ref(JsonRef(value)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
222 elif key == '$defs': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
223 schema['$defs'] = { 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
224 self.remap_defs_ref(DefsRef(key)): self.remap_json_schema(value)
225 for key, value in schema['$defs'].items()
226 }
227 else:
228 schema[key] = self.remap_json_schema(value) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
229 return schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
232class GenerateJsonSchema: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
233 """Usage docs: https://docs.pydantic.dev/2.8/concepts/json_schema/#customizing-the-json-schema-generation-process
235 A class for generating JSON schemas.
237 This class generates JSON schemas based on configured parameters. The default schema dialect
238 is [https://json-schema.org/draft/2020-12/schema](https://json-schema.org/draft/2020-12/schema).
239 The class uses `by_alias` to configure how fields with
240 multiple names are handled and `ref_template` to format reference names.
242 Attributes:
243 schema_dialect: The JSON schema dialect used to generate the schema. See
244 [Declaring a Dialect](https://json-schema.org/understanding-json-schema/reference/schema.html#id4)
245 in the JSON Schema documentation for more information about dialects.
246 ignored_warning_kinds: Warnings to ignore when generating the schema. `self.render_warning_message` will
247 do nothing if its argument `kind` is in `ignored_warning_kinds`;
248 this value can be modified on subclasses to easily control which warnings are emitted.
249 by_alias: Whether to use field aliases when generating the schema.
250 ref_template: The format string used when generating reference names.
251 core_to_json_refs: A mapping of core refs to JSON refs.
252 core_to_defs_refs: A mapping of core refs to definition refs.
253 defs_to_core_refs: A mapping of definition refs to core refs.
254 json_to_defs_refs: A mapping of JSON refs to definition refs.
255 definitions: Definitions in the schema.
257 Args:
258 by_alias: Whether to use field aliases in the generated schemas.
259 ref_template: The format string to use when generating reference names.
261 Raises:
262 JsonSchemaError: If the instance of the class is inadvertently re-used after generating a schema.
263 """
265 schema_dialect = 'https://json-schema.org/draft/2020-12/schema' 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
267 # `self.render_warning_message` will do nothing if its argument `kind` is in `ignored_warning_kinds`;
268 # this value can be modified on subclasses to easily control which warnings are emitted
269 ignored_warning_kinds: set[JsonSchemaWarningKind] = {'skipped-choice'} 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
271 def __init__(self, by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE): 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
272 self.by_alias = by_alias 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
273 self.ref_template = ref_template 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
275 self.core_to_json_refs: dict[CoreModeRef, JsonRef] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
276 self.core_to_defs_refs: dict[CoreModeRef, DefsRef] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
277 self.defs_to_core_refs: dict[DefsRef, CoreModeRef] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
278 self.json_to_defs_refs: dict[JsonRef, DefsRef] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
280 self.definitions: dict[DefsRef, JsonSchemaValue] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
281 self._config_wrapper_stack = _config.ConfigWrapperStack(_config.ConfigWrapper({})) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
283 self._mode: JsonSchemaMode = 'validation' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
285 # The following includes a mapping of a fully-unique defs ref choice to a list of preferred
286 # alternatives, which are generally simpler, such as only including the class name.
287 # At the end of schema generation, we use these to produce a JSON schema with more human-readable
288 # definitions, which would also work better in a generated OpenAPI client, etc.
289 self._prioritized_defsref_choices: dict[DefsRef, list[DefsRef]] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
290 self._collision_counter: dict[str, int] = defaultdict(int) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
291 self._collision_index: dict[str, int] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
293 self._schema_type_to_method = self.build_schema_type_to_method() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
295 # When we encounter definitions we need to try to build them immediately
296 # so that they are available schemas that reference them
297 # But it's possible that CoreSchema was never going to be used
298 # (e.g. because the CoreSchema that references short circuits is JSON schema generation without needing
299 # the reference) so instead of failing altogether if we can't build a definition we
300 # store the error raised and re-throw it if we end up needing that def
301 self._core_defs_invalid_for_json_schema: dict[DefsRef, PydanticInvalidForJsonSchema] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
303 # This changes to True after generating a schema, to prevent issues caused by accidental re-use
304 # of a single instance of a schema generator
305 self._used = False 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
307 @property 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
308 def _config(self) -> _config.ConfigWrapper: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
309 return self._config_wrapper_stack.tail 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
311 @property 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
312 def mode(self) -> JsonSchemaMode: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
313 if self._config.json_schema_mode_override is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
314 return self._config.json_schema_mode_override 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
315 else:
316 return self._mode 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
318 def build_schema_type_to_method( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
319 self,
320 ) -> dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]]:
321 """Builds a dictionary mapping fields to methods for generating JSON schemas.
323 Returns:
324 A dictionary containing the mapping of `CoreSchemaOrFieldType` to a handler method.
326 Raises:
327 TypeError: If no method has been defined for generating a JSON schema for a given pydantic core schema type.
328 """
329 mapping: dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
330 core_schema_types: list[CoreSchemaOrFieldType] = _typing_extra.all_literal_values( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
331 CoreSchemaOrFieldType # type: ignore
332 )
333 for key in core_schema_types: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
334 method_name = f"{key.replace('-', '_')}_schema" 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
335 try: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
336 mapping[key] = getattr(self, method_name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
337 except AttributeError as e: # pragma: no cover
338 raise TypeError(
339 f'No method for generating JsonSchema for core_schema.type={key!r} '
340 f'(expected: {type(self).__name__}.{method_name})'
341 ) from e
342 return mapping 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
344 def generate_definitions( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
345 self, inputs: Sequence[tuple[JsonSchemaKeyT, JsonSchemaMode, core_schema.CoreSchema]]
346 ) -> tuple[dict[tuple[JsonSchemaKeyT, JsonSchemaMode], JsonSchemaValue], dict[DefsRef, JsonSchemaValue]]:
347 """Generates JSON schema definitions from a list of core schemas, pairing the generated definitions with a
348 mapping that links the input keys to the definition references.
350 Args:
351 inputs: A sequence of tuples, where:
353 - The first element is a JSON schema key type.
354 - The second element is the JSON mode: either 'validation' or 'serialization'.
355 - The third element is a core schema.
357 Returns:
358 A tuple where:
360 - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and
361 whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have
362 JsonRef references to definitions that are defined in the second returned element.)
363 - The second element is a dictionary whose keys are definition references for the JSON schemas
364 from the first returned element, and whose values are the actual JSON schema definitions.
366 Raises:
367 PydanticUserError: Raised if the JSON schema generator has already been used to generate a JSON schema.
368 """
369 if self._used: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
370 raise PydanticUserError( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
371 'This JSON schema generator has already been used to generate a JSON schema. '
372 f'You must create a new instance of {type(self).__name__} to generate a new JSON schema.',
373 code='json-schema-already-used',
374 )
376 for key, mode, schema in inputs: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
377 self._mode = mode 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
378 self.generate_inner(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
380 definitions_remapping = self._build_definitions_remapping() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
382 json_schemas_map: dict[tuple[JsonSchemaKeyT, JsonSchemaMode], DefsRef] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
383 for key, mode, schema in inputs: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
384 self._mode = mode 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
385 json_schema = self.generate_inner(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
386 json_schemas_map[(key, mode)] = definitions_remapping.remap_json_schema(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
388 json_schema = {'$defs': self.definitions} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
389 json_schema = definitions_remapping.remap_json_schema(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
390 self._used = True 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
391 return json_schemas_map, _sort_json_schema(json_schema['$defs']) # type: ignore 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
393 def generate(self, schema: CoreSchema, mode: JsonSchemaMode = 'validation') -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
394 """Generates a JSON schema for a specified schema in a specified mode.
396 Args:
397 schema: A Pydantic model.
398 mode: The mode in which to generate the schema. Defaults to 'validation'.
400 Returns:
401 A JSON schema representing the specified schema.
403 Raises:
404 PydanticUserError: If the JSON schema generator has already been used to generate a JSON schema.
405 """
406 self._mode = mode 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
407 if self._used: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
408 raise PydanticUserError( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
409 'This JSON schema generator has already been used to generate a JSON schema. '
410 f'You must create a new instance of {type(self).__name__} to generate a new JSON schema.',
411 code='json-schema-already-used',
412 )
414 json_schema: JsonSchemaValue = self.generate_inner(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
415 json_ref_counts = self.get_json_ref_counts(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
417 # Remove the top-level $ref if present; note that the _generate method already ensures there are no sibling keys
418 ref = cast(JsonRef, json_schema.get('$ref')) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
419 while ref is not None: # may need to unpack multiple levels 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
420 ref_json_schema = self.get_schema_from_definitions(ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
421 if json_ref_counts[ref] > 1 or ref_json_schema is None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
422 # Keep the ref, but use an allOf to remove the top level $ref
423 json_schema = {'allOf': [{'$ref': ref}]} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
424 else:
425 # "Unpack" the ref since this is the only reference
426 json_schema = ref_json_schema.copy() # copy to prevent recursive dict reference 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
427 json_ref_counts[ref] -= 1 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
428 ref = cast(JsonRef, json_schema.get('$ref')) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
430 self._garbage_collect_definitions(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
431 definitions_remapping = self._build_definitions_remapping() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
433 if self.definitions: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
434 json_schema['$defs'] = self.definitions 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
436 json_schema = definitions_remapping.remap_json_schema(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
438 # For now, we will not set the $schema key. However, if desired, this can be easily added by overriding
439 # this method and adding the following line after a call to super().generate(schema):
440 # json_schema['$schema'] = self.schema_dialect
442 self._used = True 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
443 return _sort_json_schema(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
445 def generate_inner(self, schema: CoreSchemaOrField) -> JsonSchemaValue: # noqa: C901 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
446 """Generates a JSON schema for a given core schema.
448 Args:
449 schema: The given core schema.
451 Returns:
452 The generated JSON schema.
453 """
454 # If a schema with the same CoreRef has been handled, just return a reference to it
455 # Note that this assumes that it will _never_ be the case that the same CoreRef is used
456 # on types that should have different JSON schemas
457 if 'ref' in schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
458 core_ref = CoreRef(schema['ref']) # type: ignore[typeddict-item] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
459 core_mode_ref = (core_ref, self.mode) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
460 if core_mode_ref in self.core_to_defs_refs and self.core_to_defs_refs[core_mode_ref] in self.definitions: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
461 return {'$ref': self.core_to_json_refs[core_mode_ref]} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
463 # Generate the JSON schema, accounting for the json_schema_override and core_schema_override
464 metadata_handler = _core_metadata.CoreMetadataHandler(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
466 def populate_defs(core_schema: CoreSchema, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
467 if 'ref' in core_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
468 core_ref = CoreRef(core_schema['ref']) # type: ignore[typeddict-item] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
469 defs_ref, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
470 json_ref = JsonRef(ref_json_schema['$ref']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
471 self.json_to_defs_refs[json_ref] = defs_ref 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
472 # Replace the schema if it's not a reference to itself
473 # What we want to avoid is having the def be just a ref to itself
474 # which is what would happen if we blindly assigned any
475 if json_schema.get('$ref', None) != json_ref: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
476 self.definitions[defs_ref] = json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
477 self._core_defs_invalid_for_json_schema.pop(defs_ref, None) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
478 json_schema = ref_json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
479 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
481 def convert_to_all_of(json_schema: JsonSchemaValue) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
482 if '$ref' in json_schema and len(json_schema.keys()) > 1: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
483 # technically you can't have any other keys next to a "$ref"
484 # but it's an easy mistake to make and not hard to correct automatically here
485 json_schema = json_schema.copy() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
486 ref = json_schema.pop('$ref') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
487 json_schema = {'allOf': [{'$ref': ref}], **json_schema} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
488 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
490 def handler_func(schema_or_field: CoreSchemaOrField) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
491 """Generate a JSON schema based on the input schema.
493 Args:
494 schema_or_field: The core schema to generate a JSON schema from.
496 Returns:
497 The generated JSON schema.
499 Raises:
500 TypeError: If an unexpected schema type is encountered.
501 """
502 # Generate the core-schema-type-specific bits of the schema generation:
503 json_schema: JsonSchemaValue | None = None 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
504 if self.mode == 'serialization' and 'serialization' in schema_or_field: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
505 ser_schema = schema_or_field['serialization'] # type: ignore 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
506 json_schema = self.ser_schema(ser_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
507 if json_schema is None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
508 if _core_utils.is_core_schema(schema_or_field) or _core_utils.is_core_schema_field(schema_or_field): 508 ↛ 512line 508 didn't jump to line 512 because the condition on line 508 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
509 generate_for_schema_type = self._schema_type_to_method[schema_or_field['type']] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
510 json_schema = generate_for_schema_type(schema_or_field) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
511 else:
512 raise TypeError(f'Unexpected schema type: schema={schema_or_field}')
513 if _core_utils.is_core_schema(schema_or_field): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
514 json_schema = populate_defs(schema_or_field, json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
515 json_schema = convert_to_all_of(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
516 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
518 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, handler_func) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
520 for js_modify_function in metadata_handler.metadata.get('pydantic_js_functions', ()): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
522 def new_handler_func( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
523 schema_or_field: CoreSchemaOrField,
524 current_handler: GetJsonSchemaHandler = current_handler,
525 js_modify_function: GetJsonSchemaFunction = js_modify_function,
526 ) -> JsonSchemaValue:
527 json_schema = js_modify_function(schema_or_field, current_handler) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
528 if _core_utils.is_core_schema(schema_or_field): 528 ↛ 530line 528 didn't jump to line 530 because the condition on line 528 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
529 json_schema = populate_defs(schema_or_field, json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
530 original_schema = current_handler.resolve_ref_schema(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
531 ref = json_schema.pop('$ref', None) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
532 if ref and json_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
533 original_schema.update(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
534 return original_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
536 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
538 for js_modify_function in metadata_handler.metadata.get('pydantic_js_annotation_functions', ()): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
540 def new_handler_func( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
541 schema_or_field: CoreSchemaOrField,
542 current_handler: GetJsonSchemaHandler = current_handler,
543 js_modify_function: GetJsonSchemaFunction = js_modify_function,
544 ) -> JsonSchemaValue:
545 json_schema = js_modify_function(schema_or_field, current_handler) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
546 if _core_utils.is_core_schema(schema_or_field): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
547 json_schema = populate_defs(schema_or_field, json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
548 json_schema = convert_to_all_of(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
549 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
551 current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
553 json_schema = current_handler(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
554 if _core_utils.is_core_schema(schema): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
555 json_schema = populate_defs(schema, json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
556 json_schema = convert_to_all_of(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
557 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
559 # ### Schema generation methods
560 def any_schema(self, schema: core_schema.AnySchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
561 """Generates a JSON schema that matches any value.
563 Args:
564 schema: The core schema.
566 Returns:
567 The generated JSON schema.
568 """
569 return {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
571 def none_schema(self, schema: core_schema.NoneSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
572 """Generates a JSON schema that matches `None`.
574 Args:
575 schema: The core schema.
577 Returns:
578 The generated JSON schema.
579 """
580 return {'type': 'null'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
582 def bool_schema(self, schema: core_schema.BoolSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
583 """Generates a JSON schema that matches a bool value.
585 Args:
586 schema: The core schema.
588 Returns:
589 The generated JSON schema.
590 """
591 return {'type': 'boolean'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
593 def int_schema(self, schema: core_schema.IntSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
594 """Generates a JSON schema that matches an int value.
596 Args:
597 schema: The core schema.
599 Returns:
600 The generated JSON schema.
601 """
602 json_schema: dict[str, Any] = {'type': 'integer'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
603 self.update_with_validations(json_schema, schema, self.ValidationsMapping.numeric) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
604 json_schema = {k: v for k, v in json_schema.items() if v not in {math.inf, -math.inf}} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
605 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
607 def float_schema(self, schema: core_schema.FloatSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
608 """Generates a JSON schema that matches a float value.
610 Args:
611 schema: The core schema.
613 Returns:
614 The generated JSON schema.
615 """
616 json_schema: dict[str, Any] = {'type': 'number'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
617 self.update_with_validations(json_schema, schema, self.ValidationsMapping.numeric) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
618 json_schema = {k: v for k, v in json_schema.items() if v not in {math.inf, -math.inf}} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
619 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
621 def decimal_schema(self, schema: core_schema.DecimalSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
622 """Generates a JSON schema that matches a decimal value.
624 Args:
625 schema: The core schema.
627 Returns:
628 The generated JSON schema.
629 """
630 json_schema = self.str_schema(core_schema.str_schema()) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
631 if self.mode == 'validation': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
632 multiple_of = schema.get('multiple_of') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
633 le = schema.get('le') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
634 ge = schema.get('ge') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
635 lt = schema.get('lt') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
636 gt = schema.get('gt') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
637 json_schema = { 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
638 'anyOf': [
639 self.float_schema(
640 core_schema.float_schema(
641 allow_inf_nan=schema.get('allow_inf_nan'),
642 multiple_of=None if multiple_of is None else float(multiple_of),
643 le=None if le is None else float(le),
644 ge=None if ge is None else float(ge),
645 lt=None if lt is None else float(lt),
646 gt=None if gt is None else float(gt),
647 )
648 ),
649 json_schema,
650 ],
651 }
652 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
654 def str_schema(self, schema: core_schema.StringSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
655 """Generates a JSON schema that matches a string value.
657 Args:
658 schema: The core schema.
660 Returns:
661 The generated JSON schema.
662 """
663 json_schema = {'type': 'string'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
664 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
665 if isinstance(json_schema.get('pattern'), Pattern): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
666 # TODO: should we add regex flags to the pattern?
667 json_schema['pattern'] = json_schema.get('pattern').pattern # type: ignore 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
668 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
670 def bytes_schema(self, schema: core_schema.BytesSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
671 """Generates a JSON schema that matches a bytes value.
673 Args:
674 schema: The core schema.
676 Returns:
677 The generated JSON schema.
678 """
679 json_schema = {'type': 'string', 'format': 'base64url' if self._config.ser_json_bytes == 'base64' else 'binary'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
680 self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
681 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
683 def date_schema(self, schema: core_schema.DateSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
684 """Generates a JSON schema that matches a date value.
686 Args:
687 schema: The core schema.
689 Returns:
690 The generated JSON schema.
691 """
692 json_schema = {'type': 'string', 'format': 'date'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
693 self.update_with_validations(json_schema, schema, self.ValidationsMapping.date) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
694 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
696 def time_schema(self, schema: core_schema.TimeSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
697 """Generates a JSON schema that matches a time value.
699 Args:
700 schema: The core schema.
702 Returns:
703 The generated JSON schema.
704 """
705 return {'type': 'string', 'format': 'time'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
707 def datetime_schema(self, schema: core_schema.DatetimeSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
708 """Generates a JSON schema that matches a datetime value.
710 Args:
711 schema: The core schema.
713 Returns:
714 The generated JSON schema.
715 """
716 return {'type': 'string', 'format': 'date-time'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
718 def timedelta_schema(self, schema: core_schema.TimedeltaSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
719 """Generates a JSON schema that matches a timedelta value.
721 Args:
722 schema: The core schema.
724 Returns:
725 The generated JSON schema.
726 """
727 if self._config.ser_json_timedelta == 'float': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
728 return {'type': 'number'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
729 return {'type': 'string', 'format': 'duration'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
731 def literal_schema(self, schema: core_schema.LiteralSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
732 """Generates a JSON schema that matches a literal value.
734 Args:
735 schema: The core schema.
737 Returns:
738 The generated JSON schema.
739 """
740 expected = [v.value if isinstance(v, Enum) else v for v in schema['expected']] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
741 # jsonify the expected values
742 expected = [to_jsonable_python(v) for v in expected] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
744 result: dict[str, Any] = {'enum': expected} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
745 if len(expected) == 1: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
746 result['const'] = expected[0] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
748 types = {type(e) for e in expected} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
749 if types == {str}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
750 result['type'] = 'string' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
751 elif types == {int}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
752 result['type'] = 'integer' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
753 elif types == {float}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
754 result['type'] = 'numeric' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
755 elif types == {bool}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
756 result['type'] = 'boolean' 1zBadejkpqrCbFGfglmstuvADchinowxy
757 elif types == {list}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
758 result['type'] = 'array' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
759 elif types == {type(None)}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
760 result['type'] = 'null' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
761 return result 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
763 def enum_schema(self, schema: core_schema.EnumSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
764 """Generates a JSON schema that matches an Enum value.
766 Args:
767 schema: The core schema.
769 Returns:
770 The generated JSON schema.
771 """
772 enum_type = schema['cls'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
773 description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
774 if ( 1EIzBCbHJAD
775 description == 'An enumeration.'
776 ): # This is the default value provided by enum.EnumMeta.__new__; don't use it
777 description = None 1EIzBadCbKLFGfgHJADch
778 result: dict[str, Any] = {'title': enum_type.__name__, 'description': description} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
779 result = {k: v for k, v in result.items() if v is not None} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
781 expected = [to_jsonable_python(v.value) for v in schema['members']] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
783 result['enum'] = expected 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
784 if len(expected) == 1: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
785 result['const'] = expected[0] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
787 types = {type(e) for e in expected} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
788 if isinstance(enum_type, str) or types == {str}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
789 result['type'] = 'string' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
790 elif isinstance(enum_type, int) or types == {int}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
791 result['type'] = 'integer' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
792 elif isinstance(enum_type, float) or types == {float}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
793 result['type'] = 'numeric' 1zBadejkpqrCbFGfglmstuvADchinowxy
794 elif types == {bool}: 794 ↛ 795line 794 didn't jump to line 795 because the condition on line 794 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
795 result['type'] = 'boolean'
796 elif types == {list}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
797 result['type'] = 'array' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
799 return result 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
801 def is_instance_schema(self, schema: core_schema.IsInstanceSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
802 """Handles JSON schema generation for a core schema that checks if a value is an instance of a class.
804 Unless overridden in a subclass, this raises an error.
806 Args:
807 schema: The core schema.
809 Returns:
810 The generated JSON schema.
811 """
812 return self.handle_invalid_for_json_schema(schema, f'core_schema.IsInstanceSchema ({schema["cls"]})') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
814 def is_subclass_schema(self, schema: core_schema.IsSubclassSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
815 """Handles JSON schema generation for a core schema that checks if a value is a subclass of a class.
817 For backwards compatibility with v1, this does not raise an error, but can be overridden to change this.
819 Args:
820 schema: The core schema.
822 Returns:
823 The generated JSON schema.
824 """
825 # Note: This is for compatibility with V1; you can override if you want different behavior.
826 return {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
828 def callable_schema(self, schema: core_schema.CallableSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
829 """Generates a JSON schema that matches a callable value.
831 Unless overridden in a subclass, this raises an error.
833 Args:
834 schema: The core schema.
836 Returns:
837 The generated JSON schema.
838 """
839 return self.handle_invalid_for_json_schema(schema, 'core_schema.CallableSchema') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
841 def list_schema(self, schema: core_schema.ListSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
842 """Returns a schema that matches a list schema.
844 Args:
845 schema: The core schema.
847 Returns:
848 The generated JSON schema.
849 """
850 items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
851 json_schema = {'type': 'array', 'items': items_schema} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
852 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
853 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
855 @deprecated('`tuple_positional_schema` is deprecated. Use `tuple_schema` instead.', category=None) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
856 @final 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
857 def tuple_positional_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
858 """Replaced by `tuple_schema`."""
859 warnings.warn(
860 '`tuple_positional_schema` is deprecated. Use `tuple_schema` instead.',
861 PydanticDeprecatedSince26,
862 stacklevel=2,
863 )
864 return self.tuple_schema(schema)
866 @deprecated('`tuple_variable_schema` is deprecated. Use `tuple_schema` instead.', category=None) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
867 @final 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
868 def tuple_variable_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
869 """Replaced by `tuple_schema`."""
870 warnings.warn(
871 '`tuple_variable_schema` is deprecated. Use `tuple_schema` instead.',
872 PydanticDeprecatedSince26,
873 stacklevel=2,
874 )
875 return self.tuple_schema(schema)
877 def tuple_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
878 """Generates a JSON schema that matches a tuple schema e.g. `Tuple[int,
879 str, bool]` or `Tuple[int, ...]`.
881 Args:
882 schema: The core schema.
884 Returns:
885 The generated JSON schema.
886 """
887 json_schema: JsonSchemaValue = {'type': 'array'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
888 if 'variadic_item_index' in schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
889 variadic_item_index = schema['variadic_item_index'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
890 if variadic_item_index > 0: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
891 json_schema['minItems'] = variadic_item_index 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
892 json_schema['prefixItems'] = [ 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
893 self.generate_inner(item) for item in schema['items_schema'][:variadic_item_index]
894 ]
895 if variadic_item_index + 1 == len(schema['items_schema']): 895 ↛ 902line 895 didn't jump to line 902 because the condition on line 895 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
896 # if the variadic item is the last item, then represent it faithfully
897 json_schema['items'] = self.generate_inner(schema['items_schema'][variadic_item_index]) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
898 else:
899 # otherwise, 'items' represents the schema for the variadic
900 # item plus the suffix, so just allow anything for simplicity
901 # for now
902 json_schema['items'] = True
903 else:
904 prefixItems = [self.generate_inner(item) for item in schema['items_schema']] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
905 if prefixItems: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
906 json_schema['prefixItems'] = prefixItems 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
907 json_schema['minItems'] = len(prefixItems) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
908 json_schema['maxItems'] = len(prefixItems) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
909 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
910 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
912 def set_schema(self, schema: core_schema.SetSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
913 """Generates a JSON schema that matches a set schema.
915 Args:
916 schema: The core schema.
918 Returns:
919 The generated JSON schema.
920 """
921 return self._common_set_schema(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
923 def frozenset_schema(self, schema: core_schema.FrozenSetSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
924 """Generates a JSON schema that matches a frozenset schema.
926 Args:
927 schema: The core schema.
929 Returns:
930 The generated JSON schema.
931 """
932 return self._common_set_schema(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
934 def _common_set_schema(self, schema: core_schema.SetSchema | core_schema.FrozenSetSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
935 items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
936 json_schema = {'type': 'array', 'uniqueItems': True, 'items': items_schema} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
937 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
938 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
940 def generator_schema(self, schema: core_schema.GeneratorSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
941 """Returns a JSON schema that represents the provided GeneratorSchema.
943 Args:
944 schema: The schema.
946 Returns:
947 The generated JSON schema.
948 """
949 items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
950 json_schema = {'type': 'array', 'items': items_schema} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
951 self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
952 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
954 def dict_schema(self, schema: core_schema.DictSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
955 """Generates a JSON schema that matches a dict schema.
957 Args:
958 schema: The core schema.
960 Returns:
961 The generated JSON schema.
962 """
963 json_schema: JsonSchemaValue = {'type': 'object'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
965 keys_schema = self.generate_inner(schema['keys_schema']).copy() if 'keys_schema' in schema else {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
966 keys_pattern = keys_schema.pop('pattern', None) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
968 values_schema = self.generate_inner(schema['values_schema']).copy() if 'values_schema' in schema else {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
969 values_schema.pop('title', None) # don't give a title to the additionalProperties 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
970 if values_schema or keys_pattern is not None: # don't add additionalProperties if it's empty 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
971 if keys_pattern is None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
972 json_schema['additionalProperties'] = values_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
973 else:
974 json_schema['patternProperties'] = {keys_pattern: values_schema} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
976 self.update_with_validations(json_schema, schema, self.ValidationsMapping.object) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
977 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
979 def _function_schema( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
980 self,
981 schema: _core_utils.AnyFunctionSchema,
982 ) -> JsonSchemaValue:
983 if _core_utils.is_function_with_inner_schema(schema): 983 ↛ 989line 983 didn't jump to line 989 because the condition on line 983 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
984 # This could be wrong if the function's mode is 'before', but in practice will often be right, and when it
985 # isn't, I think it would be hard to automatically infer what the desired schema should be.
986 return self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
988 # function-plain
989 return self.handle_invalid_for_json_schema(
990 schema, f'core_schema.PlainValidatorFunctionSchema ({schema["function"]})'
991 )
993 def function_before_schema(self, schema: core_schema.BeforeValidatorFunctionSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
994 """Generates a JSON schema that matches a function-before schema.
996 Args:
997 schema: The core schema.
999 Returns:
1000 The generated JSON schema.
1001 """
1002 return self._function_schema(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1004 def function_after_schema(self, schema: core_schema.AfterValidatorFunctionSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1005 """Generates a JSON schema that matches a function-after schema.
1007 Args:
1008 schema: The core schema.
1010 Returns:
1011 The generated JSON schema.
1012 """
1013 return self._function_schema(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1015 def function_plain_schema(self, schema: core_schema.PlainValidatorFunctionSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1016 """Generates a JSON schema that matches a function-plain schema.
1018 Args:
1019 schema: The core schema.
1021 Returns:
1022 The generated JSON schema.
1023 """
1024 return self._function_schema(schema)
1026 def function_wrap_schema(self, schema: core_schema.WrapValidatorFunctionSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1027 """Generates a JSON schema that matches a function-wrap schema.
1029 Args:
1030 schema: The core schema.
1032 Returns:
1033 The generated JSON schema.
1034 """
1035 return self._function_schema(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1037 def default_schema(self, schema: core_schema.WithDefaultSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1038 """Generates a JSON schema that matches a schema with a default value.
1040 Args:
1041 schema: The core schema.
1043 Returns:
1044 The generated JSON schema.
1045 """
1046 json_schema = self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1048 if 'default' not in schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1049 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1050 default = schema['default'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1051 # Note: if you want to include the value returned by the default_factory,
1052 # override this method and replace the code above with:
1053 # if 'default' in schema:
1054 # default = schema['default']
1055 # elif 'default_factory' in schema:
1056 # default = schema['default_factory']()
1057 # else:
1058 # return json_schema
1060 # we reflect the application of custom plain, no-info serializers to defaults for
1061 # json schemas viewed in serialization mode
1062 # TODO: improvements along with https://github.com/pydantic/pydantic/issues/8208
1063 # TODO: improve type safety here
1064 if self.mode == 'serialization': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1065 if ( 1EIzBadejCbKLFGfglmHJADchin
1066 (ser_schema := schema['schema'].get('serialization', {}))
1067 and (ser_func := ser_schema.get('function'))
1068 and ser_schema.get('type') == 'function-plain' # type: ignore
1069 and ser_schema.get('info_arg') is False # type: ignore
1070 ):
1071 default = ser_func(default) # type: ignore 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1073 try: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1074 encoded_default = self.encode_default(default) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1075 except pydantic_core.PydanticSerializationError: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1076 self.emit_warning( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1077 'non-serializable-default',
1078 f'Default value {default} is not JSON serializable; excluding default from JSON schema',
1079 )
1080 # Return the inner schema, as though there was no default
1081 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1083 if '$ref' in json_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1084 # Since reference schemas do not support child keys, we wrap the reference schema in a single-case allOf:
1085 return {'allOf': [json_schema], 'default': encoded_default} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1086 else:
1087 json_schema['default'] = encoded_default 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1088 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1090 def nullable_schema(self, schema: core_schema.NullableSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1091 """Generates a JSON schema that matches a schema that allows null values.
1093 Args:
1094 schema: The core schema.
1096 Returns:
1097 The generated JSON schema.
1098 """
1099 null_schema = {'type': 'null'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1100 inner_json_schema = self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1102 if inner_json_schema == null_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1103 return null_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1104 else:
1105 # Thanks to the equality check against `null_schema` above, I think 'oneOf' would also be valid here;
1106 # I'll use 'anyOf' for now, but it could be changed it if it would work better with some external tooling
1107 return self.get_flattened_anyof([inner_json_schema, null_schema]) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1109 def union_schema(self, schema: core_schema.UnionSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1110 """Generates a JSON schema that matches a schema that allows values matching any of the given schemas.
1112 Args:
1113 schema: The core schema.
1115 Returns:
1116 The generated JSON schema.
1117 """
1118 generated: list[JsonSchemaValue] = [] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1120 choices = schema['choices'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1121 for choice in choices: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1122 # choice will be a tuple if an explicit label was provided
1123 choice_schema = choice[0] if isinstance(choice, tuple) else choice 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1124 try: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1125 generated.append(self.generate_inner(choice_schema)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1126 except PydanticOmit: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1127 continue 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1128 except PydanticInvalidForJsonSchema as exc: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1129 self.emit_warning('skipped-choice', exc.message) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1130 if len(generated) == 1: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1131 return generated[0] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1132 return self.get_flattened_anyof(generated) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1134 def tagged_union_schema(self, schema: core_schema.TaggedUnionSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1135 """Generates a JSON schema that matches a schema that allows values matching any of the given schemas, where
1136 the schemas are tagged with a discriminator field that indicates which schema should be used to validate
1137 the value.
1139 Args:
1140 schema: The core schema.
1142 Returns:
1143 The generated JSON schema.
1144 """
1145 generated: dict[str, JsonSchemaValue] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1146 for k, v in schema['choices'].items(): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1147 if isinstance(k, Enum): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1148 k = k.value 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1149 try: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1150 # Use str(k) since keys must be strings for json; while not technically correct,
1151 # it's the closest that can be represented in valid JSON
1152 generated[str(k)] = self.generate_inner(v).copy() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1153 except PydanticOmit:
1154 continue
1155 except PydanticInvalidForJsonSchema as exc:
1156 self.emit_warning('skipped-choice', exc.message)
1158 one_of_choices = _deduplicate_schemas(generated.values()) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1159 json_schema: JsonSchemaValue = {'oneOf': one_of_choices} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1161 # This reflects the v1 behavior; TODO: we should make it possible to exclude OpenAPI stuff from the JSON schema
1162 openapi_discriminator = self._extract_discriminator(schema, one_of_choices) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1163 if openapi_discriminator is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1164 json_schema['discriminator'] = { 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1165 'propertyName': openapi_discriminator,
1166 'mapping': {k: v.get('$ref', v) for k, v in generated.items()},
1167 }
1169 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1171 def _extract_discriminator( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1172 self, schema: core_schema.TaggedUnionSchema, one_of_choices: list[JsonDict]
1173 ) -> str | None:
1174 """Extract a compatible OpenAPI discriminator from the schema and one_of choices that end up in the final
1175 schema."""
1176 openapi_discriminator: str | None = None 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1178 if isinstance(schema['discriminator'], str): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1179 return schema['discriminator'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1181 if isinstance(schema['discriminator'], list): 1181 ↛ 1209line 1181 didn't jump to line 1209 because the condition on line 1181 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1182 # If the discriminator is a single item list containing a string, that is equivalent to the string case
1183 if len(schema['discriminator']) == 1 and isinstance(schema['discriminator'][0], str): 1183 ↛ 1184line 1183 didn't jump to line 1184 because the condition on line 1183 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1184 return schema['discriminator'][0]
1185 # When an alias is used that is different from the field name, the discriminator will be a list of single
1186 # str lists, one for the attribute and one for the actual alias. The logic here will work even if there is
1187 # more than one possible attribute, and looks for whether a single alias choice is present as a documented
1188 # property on all choices. If so, that property will be used as the OpenAPI discriminator.
1189 for alias_path in schema['discriminator']: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1190 if not isinstance(alias_path, list): 1190 ↛ 1191line 1190 didn't jump to line 1191 because the condition on line 1190 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1191 break # this means that the discriminator is not a list of alias paths
1192 if len(alias_path) != 1: 1192 ↛ 1193line 1192 didn't jump to line 1193 because the condition on line 1192 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1193 continue # this means that the "alias" does not represent a single field
1194 alias = alias_path[0] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1195 if not isinstance(alias, str): 1195 ↛ 1196line 1195 didn't jump to line 1196 because the condition on line 1195 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1196 continue # this means that the "alias" does not represent a field
1197 alias_is_present_on_all_choices = True 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1198 for choice in one_of_choices: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1199 while '$ref' in choice: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1200 assert isinstance(choice['$ref'], str) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1201 choice = self.get_schema_from_definitions(JsonRef(choice['$ref'])) or {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1202 properties = choice.get('properties', {}) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1203 if not isinstance(properties, dict) or alias not in properties: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1204 alias_is_present_on_all_choices = False 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1205 break 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1206 if alias_is_present_on_all_choices: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1207 openapi_discriminator = alias 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1208 break 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1209 return openapi_discriminator 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1211 def chain_schema(self, schema: core_schema.ChainSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1212 """Generates a JSON schema that matches a core_schema.ChainSchema.
1214 When generating a schema for validation, we return the validation JSON schema for the first step in the chain.
1215 For serialization, we return the serialization JSON schema for the last step in the chain.
1217 Args:
1218 schema: The core schema.
1220 Returns:
1221 The generated JSON schema.
1222 """
1223 step_index = 0 if self.mode == 'validation' else -1 # use first step for validation, last for serialization 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1224 return self.generate_inner(schema['steps'][step_index]) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1226 def lax_or_strict_schema(self, schema: core_schema.LaxOrStrictSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1227 """Generates a JSON schema that matches a schema that allows values matching either the lax schema or the
1228 strict schema.
1230 Args:
1231 schema: The core schema.
1233 Returns:
1234 The generated JSON schema.
1235 """
1236 # TODO: Need to read the default value off of model config or whatever
1237 use_strict = schema.get('strict', False) # TODO: replace this default False 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1238 # If your JSON schema fails to generate it is probably
1239 # because one of the following two branches failed.
1240 if use_strict: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1241 return self.generate_inner(schema['strict_schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1242 else:
1243 return self.generate_inner(schema['lax_schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1245 def json_or_python_schema(self, schema: core_schema.JsonOrPythonSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1246 """Generates a JSON schema that matches a schema that allows values matching either the JSON schema or the
1247 Python schema.
1249 The JSON schema is used instead of the Python schema. If you want to use the Python schema, you should override
1250 this method.
1252 Args:
1253 schema: The core schema.
1255 Returns:
1256 The generated JSON schema.
1257 """
1258 return self.generate_inner(schema['json_schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1260 def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1261 """Generates a JSON schema that matches a schema that defines a typed dict.
1263 Args:
1264 schema: The core schema.
1266 Returns:
1267 The generated JSON schema.
1268 """
1269 total = schema.get('total', True) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1270 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1271 (name, self.field_is_required(field, total), field)
1272 for name, field in schema['fields'].items()
1273 if self.field_is_present(field)
1274 ]
1275 if self.mode == 'serialization': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1276 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1277 cls = _get_typed_dict_cls(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1278 config = _get_typed_dict_config(cls) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1279 with self._config_wrapper_stack.push(config): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1280 json_schema = self._named_required_fields_schema(named_required_fields) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1282 json_schema_extra = config.get('json_schema_extra') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1283 extra = schema.get('extra_behavior') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1284 if extra is None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1285 extra = config.get('extra', 'ignore') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1287 if cls is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1288 title = config.get('title') or cls.__name__ 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1289 json_schema = self._update_class_schema(json_schema, title, extra, cls, json_schema_extra) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1290 else:
1291 if extra == 'forbid': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1292 json_schema['additionalProperties'] = False 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1293 elif extra == 'allow': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1294 json_schema['additionalProperties'] = True 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1296 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1298 @staticmethod 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1299 def _name_required_computed_fields( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1300 computed_fields: list[ComputedField],
1301 ) -> list[tuple[str, bool, core_schema.ComputedField]]:
1302 return [(field['property_name'], True, field) for field in computed_fields] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1304 def _named_required_fields_schema( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1305 self, named_required_fields: Sequence[tuple[str, bool, CoreSchemaField]]
1306 ) -> JsonSchemaValue:
1307 properties: dict[str, JsonSchemaValue] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1308 required_fields: list[str] = [] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1309 for name, required, field in named_required_fields: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1310 if self.by_alias: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1311 name = self._get_alias_name(field, name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1312 try: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1313 field_json_schema = self.generate_inner(field).copy() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1314 except PydanticOmit: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1315 continue 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1316 if 'title' not in field_json_schema and self.field_title_should_be_set(field): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1317 title = self.get_title_from_name(name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1318 field_json_schema['title'] = title 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1319 field_json_schema = self.handle_ref_overrides(field_json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1320 properties[name] = field_json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1321 if required: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1322 required_fields.append(name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1324 json_schema = {'type': 'object', 'properties': properties} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1325 if required_fields: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1326 json_schema['required'] = required_fields 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1327 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1329 def _get_alias_name(self, field: CoreSchemaField, name: str) -> str: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1330 if field['type'] == 'computed-field': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1331 alias: Any = field.get('alias', name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1332 elif self.mode == 'validation': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1333 alias = field.get('validation_alias', name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1334 else:
1335 alias = field.get('serialization_alias', name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1336 if isinstance(alias, str): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1337 name = alias 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1338 elif isinstance(alias, list): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1339 alias = cast('list[str] | str', alias) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1340 for path in alias: 1340 ↛ 1348line 1340 didn't jump to line 1348 because the loop on line 1340 didn't complete1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1341 if isinstance(path, list) and len(path) == 1 and isinstance(path[0], str): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1342 # Use the first valid single-item string path; the code that constructs the alias array
1343 # should ensure the first such item is what belongs in the JSON schema
1344 name = path[0] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1345 break 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1346 else:
1347 assert_never(alias)
1348 return name 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1350 def typed_dict_field_schema(self, schema: core_schema.TypedDictField) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1351 """Generates a JSON schema that matches a schema that defines a typed dict field.
1353 Args:
1354 schema: The core schema.
1356 Returns:
1357 The generated JSON schema.
1358 """
1359 return self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1361 def dataclass_field_schema(self, schema: core_schema.DataclassField) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1362 """Generates a JSON schema that matches a schema that defines a dataclass field.
1364 Args:
1365 schema: The core schema.
1367 Returns:
1368 The generated JSON schema.
1369 """
1370 return self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1372 def model_field_schema(self, schema: core_schema.ModelField) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1373 """Generates a JSON schema that matches a schema that defines a model field.
1375 Args:
1376 schema: The core schema.
1378 Returns:
1379 The generated JSON schema.
1380 """
1381 return self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1383 def computed_field_schema(self, schema: core_schema.ComputedField) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1384 """Generates a JSON schema that matches a schema that defines a computed field.
1386 Args:
1387 schema: The core schema.
1389 Returns:
1390 The generated JSON schema.
1391 """
1392 return self.generate_inner(schema['return_schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1394 def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1395 """Generates a JSON schema that matches a schema that defines a model.
1397 Args:
1398 schema: The core schema.
1400 Returns:
1401 The generated JSON schema.
1402 """
1403 # We do not use schema['model'].model_json_schema() here
1404 # because it could lead to inconsistent refs handling, etc.
1405 cls = cast('type[BaseModel]', schema['cls']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1406 config = cls.model_config 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1407 title = config.get('title') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1409 with self._config_wrapper_stack.push(config): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1410 json_schema = self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1412 json_schema_extra = config.get('json_schema_extra') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1413 if cls.__pydantic_root_model__: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1414 root_json_schema_extra = cls.model_fields['root'].json_schema_extra 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1415 if json_schema_extra and root_json_schema_extra: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1416 raise ValueError( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1417 '"model_config[\'json_schema_extra\']" and "Field.json_schema_extra" on "RootModel.root"'
1418 ' field must not be set simultaneously'
1419 )
1420 if root_json_schema_extra: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1421 json_schema_extra = root_json_schema_extra 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1423 json_schema = self._update_class_schema(json_schema, title, config.get('extra', None), cls, json_schema_extra) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1425 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1427 def _update_class_schema( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1428 self,
1429 json_schema: JsonSchemaValue,
1430 title: str | None,
1431 extra: Literal['allow', 'ignore', 'forbid'] | None,
1432 cls: type[Any],
1433 json_schema_extra: JsonDict | JsonSchemaExtraCallable | None,
1434 ) -> JsonSchemaValue:
1435 if '$ref' in json_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1436 schema_to_update = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) or json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1437 else:
1438 schema_to_update = json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1440 if title is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1441 # referenced_schema['title'] = title
1442 schema_to_update.setdefault('title', title) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1444 if 'additionalProperties' not in schema_to_update: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1445 if extra == 'allow': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1446 schema_to_update['additionalProperties'] = True 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1447 elif extra == 'forbid': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1448 schema_to_update['additionalProperties'] = False 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1450 if isinstance(json_schema_extra, (staticmethod, classmethod)): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1451 # In older versions of python, this is necessary to ensure staticmethod/classmethods are callable
1452 json_schema_extra = json_schema_extra.__get__(cls) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1454 if isinstance(json_schema_extra, dict): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1455 schema_to_update.update(json_schema_extra) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1456 elif callable(json_schema_extra): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1457 if len(inspect.signature(json_schema_extra).parameters) > 1: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1458 json_schema_extra(schema_to_update, cls) # type: ignore 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1459 else:
1460 json_schema_extra(schema_to_update) # type: ignore 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1461 elif json_schema_extra is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1462 raise ValueError( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1463 f"model_config['json_schema_extra']={json_schema_extra} should be a dict, callable, or None"
1464 )
1466 if hasattr(cls, '__deprecated__'): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1467 json_schema['deprecated'] = True 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1469 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1471 def resolve_schema_to_update(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1472 """Resolve a JsonSchemaValue to the non-ref schema if it is a $ref schema.
1474 Args:
1475 json_schema: The schema to resolve.
1477 Returns:
1478 The resolved schema.
1479 """
1480 if '$ref' in json_schema: 1480 ↛ 1481line 1480 didn't jump to line 1481 because the condition on line 1480 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1481 schema_to_update = self.get_schema_from_definitions(JsonRef(json_schema['$ref']))
1482 if schema_to_update is None:
1483 raise RuntimeError(f'Cannot update undefined schema for $ref={json_schema["$ref"]}')
1484 return self.resolve_schema_to_update(schema_to_update)
1485 else:
1486 schema_to_update = json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1487 return schema_to_update 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1489 def model_fields_schema(self, schema: core_schema.ModelFieldsSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1490 """Generates a JSON schema that matches a schema that defines a model's fields.
1492 Args:
1493 schema: The core schema.
1495 Returns:
1496 The generated JSON schema.
1497 """
1498 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1499 (name, self.field_is_required(field, total=True), field)
1500 for name, field in schema['fields'].items()
1501 if self.field_is_present(field)
1502 ]
1503 if self.mode == 'serialization': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1504 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1505 json_schema = self._named_required_fields_schema(named_required_fields) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1506 extras_schema = schema.get('extras_schema', None) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1507 if extras_schema is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1508 schema_to_update = self.resolve_schema_to_update(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1509 schema_to_update['additionalProperties'] = self.generate_inner(extras_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1510 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1512 def field_is_present(self, field: CoreSchemaField) -> bool: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1513 """Whether the field should be included in the generated JSON schema.
1515 Args:
1516 field: The schema for the field itself.
1518 Returns:
1519 `True` if the field should be included in the generated JSON schema, `False` otherwise.
1520 """
1521 if self.mode == 'serialization': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1522 # If you still want to include the field in the generated JSON schema,
1523 # override this method and return True
1524 return not field.get('serialization_exclude') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1525 elif self.mode == 'validation': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1526 return True 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1527 else:
1528 assert_never(self.mode)
1530 def field_is_required( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1531 self,
1532 field: core_schema.ModelField | core_schema.DataclassField | core_schema.TypedDictField,
1533 total: bool,
1534 ) -> bool:
1535 """Whether the field should be marked as required in the generated JSON schema.
1536 (Note that this is irrelevant if the field is not present in the JSON schema.).
1538 Args:
1539 field: The schema for the field itself.
1540 total: Only applies to `TypedDictField`s.
1541 Indicates if the `TypedDict` this field belongs to is total, in which case any fields that don't
1542 explicitly specify `required=False` are required.
1544 Returns:
1545 `True` if the field should be marked as required in the generated JSON schema, `False` otherwise.
1546 """
1547 if self.mode == 'serialization' and self._config.json_schema_serialization_defaults_required: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1548 return not field.get('serialization_exclude') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1549 else:
1550 if field['type'] == 'typed-dict-field': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1551 return field.get('required', total) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1552 else:
1553 return field['schema']['type'] != 'default' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1555 def dataclass_args_schema(self, schema: core_schema.DataclassArgsSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1556 """Generates a JSON schema that matches a schema that defines a dataclass's constructor arguments.
1558 Args:
1559 schema: The core schema.
1561 Returns:
1562 The generated JSON schema.
1563 """
1564 named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1565 (field['name'], self.field_is_required(field, total=True), field)
1566 for field in schema['fields']
1567 if self.field_is_present(field)
1568 ]
1569 if self.mode == 'serialization': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1570 named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1571 return self._named_required_fields_schema(named_required_fields) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1573 def dataclass_schema(self, schema: core_schema.DataclassSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1574 """Generates a JSON schema that matches a schema that defines a dataclass.
1576 Args:
1577 schema: The core schema.
1579 Returns:
1580 The generated JSON schema.
1581 """
1582 cls = schema['cls'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1583 config: ConfigDict = getattr(cls, '__pydantic_config__', cast('ConfigDict', {})) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1584 title = config.get('title') or cls.__name__ 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1586 with self._config_wrapper_stack.push(config): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1587 json_schema = self.generate_inner(schema['schema']).copy() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1589 json_schema_extra = config.get('json_schema_extra') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1590 json_schema = self._update_class_schema(json_schema, title, config.get('extra', None), cls, json_schema_extra) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1592 # Dataclass-specific handling of description
1593 if is_dataclass(cls) and not hasattr(cls, '__pydantic_validator__'): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1594 # vanilla dataclass; don't use cls.__doc__ as it will contain the class signature by default
1595 description = None 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1596 else:
1597 description = None if cls.__doc__ is None else inspect.cleandoc(cls.__doc__) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1598 if description: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1599 json_schema['description'] = description 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1601 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1603 def arguments_schema(self, schema: core_schema.ArgumentsSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1604 """Generates a JSON schema that matches a schema that defines a function's arguments.
1606 Args:
1607 schema: The core schema.
1609 Returns:
1610 The generated JSON schema.
1611 """
1612 metadata = _core_metadata.CoreMetadataHandler(schema).metadata 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1613 prefer_positional = metadata.get('pydantic_js_prefer_positional_arguments') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1615 arguments = schema['arguments_schema'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1616 kw_only_arguments = [a for a in arguments if a.get('mode') == 'keyword_only'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1617 kw_or_p_arguments = [a for a in arguments if a.get('mode') in {'positional_or_keyword', None}] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1618 p_only_arguments = [a for a in arguments if a.get('mode') == 'positional_only'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1619 var_args_schema = schema.get('var_args_schema') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1620 var_kwargs_schema = schema.get('var_kwargs_schema') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1622 if prefer_positional: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1623 positional_possible = not kw_only_arguments and not var_kwargs_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1624 if positional_possible: 1624 ↛ 1627line 1624 didn't jump to line 1627 because the condition on line 1624 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1625 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1627 keyword_possible = not p_only_arguments and not var_args_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1628 if keyword_possible: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1629 return self.kw_arguments_schema(kw_or_p_arguments + kw_only_arguments, var_kwargs_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1631 if not prefer_positional: 1631 ↛ 1636line 1631 didn't jump to line 1636 because the condition on line 1631 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1632 positional_possible = not kw_only_arguments and not var_kwargs_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1633 if positional_possible: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1634 return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1636 raise PydanticInvalidForJsonSchema( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1637 'Unable to generate JSON schema for arguments validator with positional-only and keyword-only arguments'
1638 )
1640 def kw_arguments_schema( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1641 self, arguments: list[core_schema.ArgumentsParameter], var_kwargs_schema: CoreSchema | None
1642 ) -> JsonSchemaValue:
1643 """Generates a JSON schema that matches a schema that defines a function's keyword arguments.
1645 Args:
1646 arguments: The core schema.
1648 Returns:
1649 The generated JSON schema.
1650 """
1651 properties: dict[str, JsonSchemaValue] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1652 required: list[str] = [] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1653 for argument in arguments: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1654 name = self.get_argument_name(argument) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1655 argument_schema = self.generate_inner(argument['schema']).copy() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1656 argument_schema['title'] = self.get_title_from_name(name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1657 properties[name] = argument_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1659 if argument['schema']['type'] != 'default': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1660 # This assumes that if the argument has a default value,
1661 # the inner schema must be of type WithDefaultSchema.
1662 # I believe this is true, but I am not 100% sure
1663 required.append(name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1665 json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1666 if required: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1667 json_schema['required'] = required 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1669 if var_kwargs_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1670 additional_properties_schema = self.generate_inner(var_kwargs_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1671 if additional_properties_schema: 1671 ↛ 1675line 1671 didn't jump to line 1675 because the condition on line 1671 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1672 json_schema['additionalProperties'] = additional_properties_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1673 else:
1674 json_schema['additionalProperties'] = False 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1675 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1677 def p_arguments_schema( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1678 self, arguments: list[core_schema.ArgumentsParameter], var_args_schema: CoreSchema | None
1679 ) -> JsonSchemaValue:
1680 """Generates a JSON schema that matches a schema that defines a function's positional arguments.
1682 Args:
1683 arguments: The core schema.
1685 Returns:
1686 The generated JSON schema.
1687 """
1688 prefix_items: list[JsonSchemaValue] = [] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1689 min_items = 0 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1691 for argument in arguments: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1692 name = self.get_argument_name(argument) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1694 argument_schema = self.generate_inner(argument['schema']).copy() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1695 argument_schema['title'] = self.get_title_from_name(name) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1696 prefix_items.append(argument_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1698 if argument['schema']['type'] != 'default': 1698 ↛ 1691line 1698 didn't jump to line 1691 because the condition on line 1698 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1699 # This assumes that if the argument has a default value,
1700 # the inner schema must be of type WithDefaultSchema.
1701 # I believe this is true, but I am not 100% sure
1702 min_items += 1 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1704 json_schema: JsonSchemaValue = {'type': 'array', 'prefixItems': prefix_items} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1705 if min_items: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1706 json_schema['minItems'] = min_items 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1708 if var_args_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1709 items_schema = self.generate_inner(var_args_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1710 if items_schema: 1710 ↛ 1715line 1710 didn't jump to line 1715 because the condition on line 1710 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1711 json_schema['items'] = items_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1712 else:
1713 json_schema['maxItems'] = len(prefix_items) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1715 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1717 def get_argument_name(self, argument: core_schema.ArgumentsParameter) -> str: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1718 """Retrieves the name of an argument.
1720 Args:
1721 argument: The core schema.
1723 Returns:
1724 The name of the argument.
1725 """
1726 name = argument['name'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1727 if self.by_alias: 1727 ↛ 1733line 1727 didn't jump to line 1733 because the condition on line 1727 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1728 alias = argument.get('alias') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1729 if isinstance(alias, str): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1730 name = alias 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1731 else:
1732 pass # might want to do something else? 1adejkpqrbfglmstuvchinowxy
1733 return name 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1735 def call_schema(self, schema: core_schema.CallSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1736 """Generates a JSON schema that matches a schema that defines a function call.
1738 Args:
1739 schema: The core schema.
1741 Returns:
1742 The generated JSON schema.
1743 """
1744 return self.generate_inner(schema['arguments_schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1746 def custom_error_schema(self, schema: core_schema.CustomErrorSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1747 """Generates a JSON schema that matches a schema that defines a custom error.
1749 Args:
1750 schema: The core schema.
1752 Returns:
1753 The generated JSON schema.
1754 """
1755 return self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1757 def json_schema(self, schema: core_schema.JsonSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1758 """Generates a JSON schema that matches a schema that defines a JSON object.
1760 Args:
1761 schema: The core schema.
1763 Returns:
1764 The generated JSON schema.
1765 """
1766 content_core_schema = schema.get('schema') or core_schema.any_schema() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1767 content_json_schema = self.generate_inner(content_core_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1768 if self.mode == 'validation': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1769 return {'type': 'string', 'contentMediaType': 'application/json', 'contentSchema': content_json_schema} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1770 else:
1771 # self.mode == 'serialization'
1772 return content_json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1774 def url_schema(self, schema: core_schema.UrlSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1775 """Generates a JSON schema that matches a schema that defines a URL.
1777 Args:
1778 schema: The core schema.
1780 Returns:
1781 The generated JSON schema.
1782 """
1783 json_schema = {'type': 'string', 'format': 'uri', 'minLength': 1} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1784 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1785 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1787 def multi_host_url_schema(self, schema: core_schema.MultiHostUrlSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1788 """Generates a JSON schema that matches a schema that defines a URL that can be used with multiple hosts.
1790 Args:
1791 schema: The core schema.
1793 Returns:
1794 The generated JSON schema.
1795 """
1796 # Note: 'multi-host-uri' is a custom/pydantic-specific format, not part of the JSON Schema spec
1797 json_schema = {'type': 'string', 'format': 'multi-host-uri', 'minLength': 1} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1798 self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1799 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1801 def uuid_schema(self, schema: core_schema.UuidSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1802 """Generates a JSON schema that matches a UUID.
1804 Args:
1805 schema: The core schema.
1807 Returns:
1808 The generated JSON schema.
1809 """
1810 return {'type': 'string', 'format': 'uuid'} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1812 def definitions_schema(self, schema: core_schema.DefinitionsSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1813 """Generates a JSON schema that matches a schema that defines a JSON object with definitions.
1815 Args:
1816 schema: The core schema.
1818 Returns:
1819 The generated JSON schema.
1820 """
1821 for definition in schema['definitions']: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1822 try: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1823 self.generate_inner(definition) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1824 except PydanticInvalidForJsonSchema as e:
1825 core_ref: CoreRef = CoreRef(definition['ref']) # type: ignore
1826 self._core_defs_invalid_for_json_schema[self.get_defs_ref((core_ref, self.mode))] = e
1827 continue
1828 return self.generate_inner(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1830 def definition_ref_schema(self, schema: core_schema.DefinitionReferenceSchema) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1831 """Generates a JSON schema that matches a schema that references a definition.
1833 Args:
1834 schema: The core schema.
1836 Returns:
1837 The generated JSON schema.
1838 """
1839 core_ref = CoreRef(schema['schema_ref']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1840 _, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1841 return ref_json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1843 def ser_schema( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1844 self, schema: core_schema.SerSchema | core_schema.IncExSeqSerSchema | core_schema.IncExDictSerSchema
1845 ) -> JsonSchemaValue | None:
1846 """Generates a JSON schema that matches a schema that defines a serialized object.
1848 Args:
1849 schema: The core schema.
1851 Returns:
1852 The generated JSON schema.
1853 """
1854 schema_type = schema['type'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1855 if schema_type == 'function-plain' or schema_type == 'function-wrap': 1855 ↛ 1860line 1855 didn't jump to line 1860 because the condition on line 1855 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1856 # PlainSerializerFunctionSerSchema or WrapSerializerFunctionSerSchema
1857 return_schema = schema.get('return_schema') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1858 if return_schema is not None: 1858 ↛ 1866line 1858 didn't jump to line 1866 because the condition on line 1858 was always true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1859 return self.generate_inner(return_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1860 elif schema_type == 'format' or schema_type == 'to-string':
1861 # FormatSerSchema or ToStringSerSchema
1862 return self.str_schema(core_schema.str_schema())
1863 elif schema['type'] == 'model':
1864 # ModelSerSchema
1865 return self.generate_inner(schema['schema'])
1866 return None
1868 # ### Utility methods
1870 def get_title_from_name(self, name: str) -> str: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1871 """Retrieves a title from a name.
1873 Args:
1874 name: The name to retrieve a title from.
1876 Returns:
1877 The title.
1878 """
1879 return name.title().replace('_', ' ') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1881 def field_title_should_be_set(self, schema: CoreSchemaOrField) -> bool: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1882 """Returns true if a field with the given schema should have a title set based on the field name.
1884 Intuitively, we want this to return true for schemas that wouldn't otherwise provide their own title
1885 (e.g., int, float, str), and false for those that would (e.g., BaseModel subclasses).
1887 Args:
1888 schema: The schema to check.
1890 Returns:
1891 `True` if the field should have a title set, `False` otherwise.
1892 """
1893 if _core_utils.is_core_schema_field(schema): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1894 if schema['type'] == 'computed-field': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1895 field_schema = schema['return_schema'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1896 else:
1897 field_schema = schema['schema'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1898 return self.field_title_should_be_set(field_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1900 elif _core_utils.is_core_schema(schema): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1901 if schema.get('ref'): # things with refs, such as models and enums, should not have titles set 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1902 return False 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1903 if schema['type'] in {'default', 'nullable', 'definitions'}: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1904 return self.field_title_should_be_set(schema['schema']) # type: ignore[typeddict-item] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1905 if _core_utils.is_function_with_inner_schema(schema): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1906 return self.field_title_should_be_set(schema['schema']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1907 if schema['type'] == 'definition-ref': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1908 # Referenced schemas should not have titles set for the same reason
1909 # schemas with refs should not
1910 return False 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1911 return True # anything else should have title set 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1913 else:
1914 raise PydanticInvalidForJsonSchema(f'Unexpected schema type: schema={schema}') # pragma: no cover
1916 def normalize_name(self, name: str) -> str: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1917 """Normalizes a name to be used as a key in a dictionary.
1919 Args:
1920 name: The name to normalize.
1922 Returns:
1923 The normalized name.
1924 """
1925 return re.sub(r'[^a-zA-Z0-9.\-_]', '_', name).replace('.', '__') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1927 def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1928 """Override this method to change the way that definitions keys are generated from a core reference.
1930 Args:
1931 core_mode_ref: The core reference.
1933 Returns:
1934 The definitions key.
1935 """
1936 # Split the core ref into "components"; generic origins and arguments are each separate components
1937 core_ref, mode = core_mode_ref 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1938 components = re.split(r'([\][,])', core_ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1939 # Remove IDs from each component
1940 components = [x.rsplit(':', 1)[0] for x in components] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1941 core_ref_no_id = ''.join(components) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1942 # Remove everything before the last period from each "component"
1943 components = [re.sub(r'(?:[^.[\]]+\.)+((?:[^.[\]]+))', r'\1', x) for x in components] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1944 short_ref = ''.join(components) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1946 mode_title = _MODE_TITLE_MAPPING[mode] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1948 # It is important that the generated defs_ref values be such that at least one choice will not
1949 # be generated for any other core_ref. Currently, this should be the case because we include
1950 # the id of the source type in the core_ref
1951 name = DefsRef(self.normalize_name(short_ref)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1952 name_mode = DefsRef(self.normalize_name(short_ref) + f'-{mode_title}') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1953 module_qualname = DefsRef(self.normalize_name(core_ref_no_id)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1954 module_qualname_mode = DefsRef(f'{module_qualname}-{mode_title}') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1955 module_qualname_id = DefsRef(self.normalize_name(core_ref)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1956 occurrence_index = self._collision_index.get(module_qualname_id) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1957 if occurrence_index is None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1958 self._collision_counter[module_qualname] += 1 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1959 occurrence_index = self._collision_index[module_qualname_id] = self._collision_counter[module_qualname] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1961 module_qualname_occurrence = DefsRef(f'{module_qualname}__{occurrence_index}') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1962 module_qualname_occurrence_mode = DefsRef(f'{module_qualname_mode}__{occurrence_index}') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1964 self._prioritized_defsref_choices[module_qualname_occurrence_mode] = [ 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1965 name,
1966 name_mode,
1967 module_qualname,
1968 module_qualname_mode,
1969 module_qualname_occurrence,
1970 module_qualname_occurrence_mode,
1971 ]
1973 return module_qualname_occurrence_mode 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1975 def get_cache_defs_ref_schema(self, core_ref: CoreRef) -> tuple[DefsRef, JsonSchemaValue]: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
1976 """This method wraps the get_defs_ref method with some cache-lookup/population logic,
1977 and returns both the produced defs_ref and the JSON schema that will refer to the right definition.
1979 Args:
1980 core_ref: The core reference to get the definitions reference for.
1982 Returns:
1983 A tuple of the definitions reference and the JSON schema that will refer to it.
1984 """
1985 core_mode_ref = (core_ref, self.mode) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1986 maybe_defs_ref = self.core_to_defs_refs.get(core_mode_ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1987 if maybe_defs_ref is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1988 json_ref = self.core_to_json_refs[core_mode_ref] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1989 return maybe_defs_ref, {'$ref': json_ref} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1991 defs_ref = self.get_defs_ref(core_mode_ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1993 # populate the ref translation mappings
1994 self.core_to_defs_refs[core_mode_ref] = defs_ref 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1995 self.defs_to_core_refs[defs_ref] = core_mode_ref 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1997 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1998 self.core_to_json_refs[core_mode_ref] = json_ref 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
1999 self.json_to_defs_refs[json_ref] = defs_ref 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2000 ref_json_schema = {'$ref': json_ref} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2001 return defs_ref, ref_json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2003 def handle_ref_overrides(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2004 """It is not valid for a schema with a top-level $ref to have sibling keys.
2006 During our own schema generation, we treat sibling keys as overrides to the referenced schema,
2007 but this is not how the official JSON schema spec works.
2009 Because of this, we first remove any sibling keys that are redundant with the referenced schema, then if
2010 any remain, we transform the schema from a top-level '$ref' to use allOf to move the $ref out of the top level.
2011 (See bottom of https://swagger.io/docs/specification/using-ref/ for a reference about this behavior)
2012 """
2013 if '$ref' in json_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2014 # prevent modifications to the input; this copy may be safe to drop if there is significant overhead
2015 json_schema = json_schema.copy() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2017 referenced_json_schema = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2018 if referenced_json_schema is None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2019 # This can happen when building schemas for models with not-yet-defined references.
2020 # It may be a good idea to do a recursive pass at the end of the generation to remove
2021 # any redundant override keys.
2022 if len(json_schema) > 1: 2022 ↛ 2024line 2022 didn't jump to line 2024 because the condition on line 2022 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2023 # Make it an allOf to at least resolve the sibling keys issue
2024 json_schema = json_schema.copy()
2025 json_schema.setdefault('allOf', [])
2026 json_schema['allOf'].append({'$ref': json_schema['$ref']})
2027 del json_schema['$ref']
2029 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2030 for k, v in list(json_schema.items()): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2031 if k == '$ref': 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2032 continue 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2033 if k in referenced_json_schema and referenced_json_schema[k] == v: 2033 ↛ 2034line 2033 didn't jump to line 2034 because the condition on line 2033 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2034 del json_schema[k] # redundant key
2035 if len(json_schema) > 1: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2036 # There is a remaining "override" key, so we need to move $ref out of the top level
2037 json_ref = JsonRef(json_schema['$ref']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2038 del json_schema['$ref'] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2039 assert 'allOf' not in json_schema # this should never happen, but just in case 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2040 json_schema['allOf'] = [{'$ref': json_ref}] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2042 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2044 def get_schema_from_definitions(self, json_ref: JsonRef) -> JsonSchemaValue | None: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2045 def_ref = self.json_to_defs_refs[json_ref] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2046 if def_ref in self._core_defs_invalid_for_json_schema: 2046 ↛ 2047line 2046 didn't jump to line 2047 because the condition on line 2046 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2047 raise self._core_defs_invalid_for_json_schema[def_ref]
2048 return self.definitions.get(def_ref, None) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2050 def encode_default(self, dft: Any) -> Any: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2051 """Encode a default value to a JSON-serializable value.
2053 This is used to encode default values for fields in the generated JSON schema.
2055 Args:
2056 dft: The default value to encode.
2058 Returns:
2059 The encoded default value.
2060 """
2061 from .type_adapter import TypeAdapter, _type_has_config 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2063 config = self._config 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2064 try: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2065 default = ( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2066 dft
2067 if _type_has_config(type(dft))
2068 else TypeAdapter(type(dft), config=config.config_dict).dump_python(dft, mode='json')
2069 )
2070 except PydanticSchemaGenerationError: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2071 raise pydantic_core.PydanticSerializationError(f'Unable to encode default value {dft}') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2073 return pydantic_core.to_jsonable_python( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2074 default,
2075 timedelta_mode=config.ser_json_timedelta,
2076 bytes_mode=config.ser_json_bytes,
2077 )
2079 def update_with_validations( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2080 self, json_schema: JsonSchemaValue, core_schema: CoreSchema, mapping: dict[str, str]
2081 ) -> None:
2082 """Update the json_schema with the corresponding validations specified in the core_schema,
2083 using the provided mapping to translate keys in core_schema to the appropriate keys for a JSON schema.
2085 Args:
2086 json_schema: The JSON schema to update.
2087 core_schema: The core schema to get the validations from.
2088 mapping: A mapping from core_schema attribute names to the corresponding JSON schema attribute names.
2089 """
2090 for core_key, json_schema_key in mapping.items(): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2091 if core_key in core_schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2092 json_schema[json_schema_key] = core_schema[core_key] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2094 class ValidationsMapping: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2095 """This class just contains mappings from core_schema attribute names to the corresponding
2096 JSON schema attribute names. While I suspect it is unlikely to be necessary, you can in
2097 principle override this class in a subclass of GenerateJsonSchema (by inheriting from
2098 GenerateJsonSchema.ValidationsMapping) to change these mappings.
2099 """
2101 numeric = { 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2102 'multiple_of': 'multipleOf',
2103 'le': 'maximum',
2104 'ge': 'minimum',
2105 'lt': 'exclusiveMaximum',
2106 'gt': 'exclusiveMinimum',
2107 }
2108 bytes = { 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2109 'min_length': 'minLength',
2110 'max_length': 'maxLength',
2111 }
2112 string = { 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2113 'min_length': 'minLength',
2114 'max_length': 'maxLength',
2115 'pattern': 'pattern',
2116 }
2117 array = { 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2118 'min_length': 'minItems',
2119 'max_length': 'maxItems',
2120 }
2121 object = { 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2122 'min_length': 'minProperties',
2123 'max_length': 'maxProperties',
2124 }
2125 date = { 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2126 'le': 'maximum',
2127 'ge': 'minimum',
2128 'lt': 'exclusiveMaximum',
2129 'gt': 'exclusiveMinimum',
2130 }
2132 def get_flattened_anyof(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2133 members = [] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2134 for schema in schemas: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2135 if len(schema) == 1 and 'anyOf' in schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2136 members.extend(schema['anyOf']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2137 else:
2138 members.append(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2139 members = _deduplicate_schemas(members) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2140 if len(members) == 1: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2141 return members[0] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2142 return {'anyOf': members} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2144 def get_json_ref_counts(self, json_schema: JsonSchemaValue) -> dict[JsonRef, int]: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2145 """Get all values corresponding to the key '$ref' anywhere in the json_schema."""
2146 json_refs: dict[JsonRef, int] = Counter() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2148 def _add_json_refs(schema: Any) -> None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2149 if isinstance(schema, dict): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2150 if '$ref' in schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2151 json_ref = JsonRef(schema['$ref']) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2152 if not isinstance(json_ref, str): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2153 return # in this case, '$ref' might have been the name of a property 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2154 already_visited = json_ref in json_refs 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2155 json_refs[json_ref] += 1 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2156 if already_visited: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2157 return # prevent recursion on a definition that was already visited 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2158 defs_ref = self.json_to_defs_refs[json_ref] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2159 if defs_ref in self._core_defs_invalid_for_json_schema: 2159 ↛ 2160line 2159 didn't jump to line 2160 because the condition on line 2159 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2160 raise self._core_defs_invalid_for_json_schema[defs_ref]
2161 _add_json_refs(self.definitions[defs_ref]) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2163 for v in schema.values(): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2164 _add_json_refs(v) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2165 elif isinstance(schema, list): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2166 for v in schema: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2167 _add_json_refs(v) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2169 _add_json_refs(json_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2170 return json_refs 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2172 def handle_invalid_for_json_schema(self, schema: CoreSchemaOrField, error_info: str) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2173 raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2175 def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2176 """This method simply emits PydanticJsonSchemaWarnings based on handling in the `warning_message` method."""
2177 message = self.render_warning_message(kind, detail) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2178 if message is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2179 warnings.warn(message, PydanticJsonSchemaWarning) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2181 def render_warning_message(self, kind: JsonSchemaWarningKind, detail: str) -> str | None: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2182 """This method is responsible for ignoring warnings as desired, and for formatting the warning messages.
2184 You can override the value of `ignored_warning_kinds` in a subclass of GenerateJsonSchema
2185 to modify what warnings are generated. If you want more control, you can override this method;
2186 just return None in situations where you don't want warnings to be emitted.
2188 Args:
2189 kind: The kind of warning to render. It can be one of the following:
2191 - 'skipped-choice': A choice field was skipped because it had no valid choices.
2192 - 'non-serializable-default': A default value was skipped because it was not JSON-serializable.
2193 detail: A string with additional details about the warning.
2195 Returns:
2196 The formatted warning message, or `None` if no warning should be emitted.
2197 """
2198 if kind in self.ignored_warning_kinds: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2199 return None 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2200 return f'{detail} [{kind}]' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2202 def _build_definitions_remapping(self) -> _DefinitionsRemapping: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2203 defs_to_json: dict[DefsRef, JsonRef] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2204 for defs_refs in self._prioritized_defsref_choices.values(): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2205 for defs_ref in defs_refs: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2206 json_ref = JsonRef(self.ref_template.format(model=defs_ref)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2207 defs_to_json[defs_ref] = json_ref 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2209 return _DefinitionsRemapping.from_prioritized_choices( 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2210 self._prioritized_defsref_choices, defs_to_json, self.definitions
2211 )
2213 def _garbage_collect_definitions(self, schema: JsonSchemaValue) -> None: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2214 visited_defs_refs: set[DefsRef] = set() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2215 unvisited_json_refs = _get_all_json_refs(schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2216 while unvisited_json_refs: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2217 next_json_ref = unvisited_json_refs.pop() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2218 next_defs_ref = self.json_to_defs_refs[next_json_ref] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2219 if next_defs_ref in visited_defs_refs: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2220 continue 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2221 visited_defs_refs.add(next_defs_ref) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2222 unvisited_json_refs.update(_get_all_json_refs(self.definitions[next_defs_ref])) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2224 self.definitions = {k: v for k, v in self.definitions.items() if k in visited_defs_refs} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2227# ##### Start JSON Schema Generation Functions #####
2230def model_json_schema( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2231 cls: type[BaseModel] | type[PydanticDataclass],
2232 by_alias: bool = True,
2233 ref_template: str = DEFAULT_REF_TEMPLATE,
2234 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema,
2235 mode: JsonSchemaMode = 'validation',
2236) -> dict[str, Any]:
2237 """Utility function to generate a JSON Schema for a model.
2239 Args:
2240 cls: The model class to generate a JSON Schema for.
2241 by_alias: If `True` (the default), fields will be serialized according to their alias.
2242 If `False`, fields will be serialized according to their attribute name.
2243 ref_template: The template to use for generating JSON Schema references.
2244 schema_generator: The class to use for generating the JSON Schema.
2245 mode: The mode to use for generating the JSON Schema. It can be one of the following:
2247 - 'validation': Generate a JSON Schema for validating data.
2248 - 'serialization': Generate a JSON Schema for serializing data.
2250 Returns:
2251 The generated JSON Schema.
2252 """
2253 from .main import BaseModel 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2255 schema_generator_instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2257 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2258 cls.__pydantic_core_schema__.rebuild() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2260 if cls is BaseModel: 2260 ↛ 2261line 2260 didn't jump to line 2261 because the condition on line 2260 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2261 raise AttributeError('model_json_schema() must be called on a subclass of BaseModel, not BaseModel itself.')
2263 assert not isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2264 return schema_generator_instance.generate(cls.__pydantic_core_schema__, mode=mode) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2267def models_json_schema( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2268 models: Sequence[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode]],
2269 *,
2270 by_alias: bool = True,
2271 title: str | None = None,
2272 description: str | None = None,
2273 ref_template: str = DEFAULT_REF_TEMPLATE,
2274 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema,
2275) -> tuple[dict[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]:
2276 """Utility function to generate a JSON Schema for multiple models.
2278 Args:
2279 models: A sequence of tuples of the form (model, mode).
2280 by_alias: Whether field aliases should be used as keys in the generated JSON Schema.
2281 title: The title of the generated JSON Schema.
2282 description: The description of the generated JSON Schema.
2283 ref_template: The reference template to use for generating JSON Schema references.
2284 schema_generator: The schema generator to use for generating the JSON Schema.
2286 Returns:
2287 A tuple where:
2288 - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and
2289 whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have
2290 JsonRef references to definitions that are defined in the second returned element.)
2291 - The second element is a JSON schema containing all definitions referenced in the first returned
2292 element, along with the optional title and description keys.
2293 """
2294 for cls, _ in models: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2295 if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): 2295 ↛ 2296line 2295 didn't jump to line 2296 because the condition on line 2295 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2296 cls.__pydantic_core_schema__.rebuild()
2298 instance = schema_generator(by_alias=by_alias, ref_template=ref_template) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2299 inputs: list[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode, CoreSchema]] = [ 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2300 (m, mode, m.__pydantic_core_schema__) for m, mode in models
2301 ]
2302 json_schemas_map, definitions = instance.generate_definitions(inputs) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2304 json_schema: dict[str, Any] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2305 if definitions: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2306 json_schema['$defs'] = definitions 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2307 if title: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2308 json_schema['title'] = title 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2309 if description: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2310 json_schema['description'] = description 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2312 return json_schemas_map, json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2315# ##### End JSON Schema Generation Functions #####
2318_HashableJsonValue: TypeAlias = Union[ 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2319 int, float, str, bool, None, Tuple['_HashableJsonValue', ...], Tuple[Tuple[str, '_HashableJsonValue'], ...]
2320]
2323def _deduplicate_schemas(schemas: Iterable[JsonDict]) -> list[JsonDict]: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2324 return list({_make_json_hashable(schema): schema for schema in schemas}.values()) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2327def _make_json_hashable(value: JsonValue) -> _HashableJsonValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2328 if isinstance(value, dict): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2329 return tuple(sorted((k, _make_json_hashable(v)) for k, v in value.items())) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2330 elif isinstance(value, list): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2331 return tuple(_make_json_hashable(v) for v in value) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2332 else:
2333 return value 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2336def _sort_json_schema(value: JsonSchemaValue, parent_key: str | None = None) -> JsonSchemaValue: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2337 if isinstance(value, dict): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2338 sorted_dict: dict[str, JsonSchemaValue] = {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2339 keys = value.keys() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2340 if (parent_key != 'properties') and (parent_key != 'default'): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2341 keys = sorted(keys) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2342 for key in keys: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2343 sorted_dict[key] = _sort_json_schema(value[key], parent_key=key) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2344 return sorted_dict 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2345 elif isinstance(value, list): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2346 sorted_list: list[JsonSchemaValue] = [] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2347 for item in value: # type: ignore 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2348 sorted_list.append(_sort_json_schema(item, parent_key)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2349 return sorted_list # type: ignore 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2350 else:
2351 return value 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2354@dataclasses.dataclass(**_internal_dataclass.slots_true) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2355class WithJsonSchema: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2356 """Usage docs: https://docs.pydantic.dev/2.8/concepts/json_schema/#withjsonschema-annotation
2358 Add this as an annotation on a field to override the (base) JSON schema that would be generated for that field.
2359 This provides a way to set a JSON schema for types that would otherwise raise errors when producing a JSON schema,
2360 such as Callable, or types that have an is-instance core schema, without needing to go so far as creating a
2361 custom subclass of pydantic.json_schema.GenerateJsonSchema.
2362 Note that any _modifications_ to the schema that would normally be made (such as setting the title for model fields)
2363 will still be performed.
2365 If `mode` is set this will only apply to that schema generation mode, allowing you
2366 to set different json schemas for validation and serialization.
2367 """
2369 json_schema: JsonSchemaValue | None 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2370 mode: Literal['validation', 'serialization'] | None = None 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2372 def __get_pydantic_json_schema__( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2373 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2374 ) -> JsonSchemaValue:
2375 mode = self.mode or handler.mode 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2376 if mode != handler.mode: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2377 return handler(core_schema) 1EzaekHAcio
2378 if self.json_schema is None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2379 # This exception is handled in pydantic.json_schema.GenerateJsonSchema._named_required_fields_schema
2380 raise PydanticOmit 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2381 else:
2382 return self.json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2384 def __hash__(self) -> int: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2385 return hash(type(self.mode)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2388@dataclasses.dataclass(**_internal_dataclass.slots_true) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2389class Examples: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2390 """Add examples to a JSON schema.
2392 Examples should be a map of example names (strings)
2393 to example values (any valid JSON).
2395 If `mode` is set this will only apply to that schema generation mode,
2396 allowing you to add different examples for validation and serialization.
2397 """
2399 examples: dict[str, Any] 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2400 mode: Literal['validation', 'serialization'] | None = None 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2402 def __get_pydantic_json_schema__( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2403 self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
2404 ) -> JsonSchemaValue:
2405 mode = self.mode or handler.mode 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2406 json_schema = handler(core_schema) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2407 if mode != handler.mode: 2407 ↛ 2408line 2407 didn't jump to line 2408 because the condition on line 2407 was never true1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2408 return json_schema
2409 examples = json_schema.get('examples', {}) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2410 examples.update(to_jsonable_python(self.examples)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2411 json_schema['examples'] = examples 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2412 return json_schema 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2414 def __hash__(self) -> int: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2415 return hash(type(self.mode)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2418def _get_all_json_refs(item: Any) -> set[JsonRef]: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2419 """Get all the definitions references from a JSON schema."""
2420 refs: set[JsonRef] = set() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2421 stack = [item] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2423 while stack: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2424 current = stack.pop() 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2425 if isinstance(current, dict): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2426 for key, value in current.items(): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2427 if key == '$ref' and isinstance(value, str): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2428 refs.add(JsonRef(value)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2429 elif isinstance(value, dict): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2430 stack.append(value) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2431 elif isinstance(value, list): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2432 stack.extend(value) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2433 elif isinstance(current, list): 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2434 stack.extend(current) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2436 return refs 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2439AnyType = TypeVar('AnyType') 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2441if TYPE_CHECKING: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2442 SkipJsonSchema = Annotated[AnyType, ...]
2443else:
2445 @dataclasses.dataclass(**_internal_dataclass.slots_true) 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2446 class SkipJsonSchema: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2447 """Usage docs: https://docs.pydantic.dev/2.8/concepts/json_schema/#skipjsonschema-annotation
2449 Add this as an annotation on a field to skip generating a JSON schema for that field.
2451 Example:
2452 ```py
2453 from typing import Union
2455 from pydantic import BaseModel
2456 from pydantic.json_schema import SkipJsonSchema
2458 from pprint import pprint
2461 class Model(BaseModel):
2462 a: Union[int, None] = None # (1)!
2463 b: Union[int, SkipJsonSchema[None]] = None # (2)!
2464 c: SkipJsonSchema[Union[int, None]] = None # (3)!
2467 pprint(Model.model_json_schema())
2468 '''
2469 {
2470 'properties': {
2471 'a': {
2472 'anyOf': [
2473 {'type': 'integer'},
2474 {'type': 'null'}
2475 ],
2476 'default': None,
2477 'title': 'A'
2478 },
2479 'b': {
2480 'default': None,
2481 'title': 'B',
2482 'type': 'integer'
2483 }
2484 },
2485 'title': 'Model',
2486 'type': 'object'
2487 }
2488 '''
2489 ```
2491 1. The integer and null types are both included in the schema for `a`.
2492 2. The integer type is the only type included in the schema for `b`.
2493 3. The entirety of the `c` field is omitted from the schema.
2494 """
2496 def __class_getitem__(cls, item: AnyType) -> AnyType: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2497 return Annotated[item, cls()] 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2499 def __get_pydantic_json_schema__( 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2500 self, core_schema: CoreSchema, handler: GetJsonSchemaHandler
2501 ) -> JsonSchemaValue:
2502 raise PydanticOmit 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2504 def __hash__(self) -> int: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2505 return hash(type(self)) 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2508def _get_typed_dict_cls(schema: core_schema.TypedDictSchema) -> type[Any] | None: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2509 metadata = _core_metadata.CoreMetadataHandler(schema).metadata 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2510 cls = metadata.get('pydantic_typed_dict_cls') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2511 return cls 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2514def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict: 1EIzBadejkpqrCbKLFGfglmstuvUVMNOPQRSTHJADchinowxy
2515 if cls is not None: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2516 try: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2517 return _decorators.get_attribute_from_bases(cls, '__pydantic_config__') 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2518 except AttributeError: 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2519 pass 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy
2520 return {} 1EIzBadejkpqrCbKLFGfglmstuvHJADchinowxy