Coverage for fastapi / openapi / models.py: 100%
272 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
1from collections.abc import Callable, Iterable, Mapping 1abcd
2from enum import Enum 1abcd
3from typing import Annotated, Any, Literal, Optional, Union 1abcd
5from fastapi._compat import with_info_plain_validator_function 1abcd
6from fastapi.logger import logger 1abcd
7from pydantic import ( 1abcd
8 AnyUrl,
9 BaseModel,
10 Field,
11 GetJsonSchemaHandler,
12)
13from typing_extensions import TypedDict 1abcd
14from typing_extensions import deprecated as typing_deprecated 1abcd
16try: 1abcd
17 import email_validator 1abcd
19 assert email_validator # make autoflake ignore the unused import 1abcd
20 from pydantic import EmailStr 1abcd
21except ImportError: # pragma: no cover
23 class EmailStr(str): # type: ignore
24 @classmethod
25 def __get_validators__(cls) -> Iterable[Callable[..., Any]]:
26 yield cls.validate
28 @classmethod
29 def validate(cls, v: Any) -> str:
30 logger.warning(
31 "email-validator not installed, email fields will be treated as str.\n"
32 "To install, run: pip install email-validator"
33 )
34 return str(v)
36 @classmethod
37 def _validate(cls, __input_value: Any, _: Any) -> str:
38 logger.warning(
39 "email-validator not installed, email fields will be treated as str.\n"
40 "To install, run: pip install email-validator"
41 )
42 return str(__input_value)
44 @classmethod
45 def __get_pydantic_json_schema__(
46 cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler
47 ) -> dict[str, Any]:
48 return {"type": "string", "format": "email"}
50 @classmethod
51 def __get_pydantic_core_schema__(
52 cls, source: type[Any], handler: Callable[[Any], Mapping[str, Any]]
53 ) -> Mapping[str, Any]:
54 return with_info_plain_validator_function(cls._validate)
57class BaseModelWithConfig(BaseModel): 1abcd
58 model_config = {"extra": "allow"} 1abcd
61class Contact(BaseModelWithConfig): 1abcd
62 name: str | None = None 1abcd
63 url: AnyUrl | None = None 1abcd
64 email: EmailStr | None = None 1abcd
67class License(BaseModelWithConfig): 1abcd
68 name: str 1abcd
69 identifier: str | None = None 1abcd
70 url: AnyUrl | None = None 1abcd
73class Info(BaseModelWithConfig): 1abcd
74 title: str 1abcd
75 summary: str | None = None 1abcd
76 description: str | None = None 1abcd
77 termsOfService: str | None = None 1abcd
78 contact: Contact | None = None 1abcd
79 license: License | None = None 1abcd
80 version: str 1abcd
83class ServerVariable(BaseModelWithConfig): 1abcd
84 enum: Annotated[list[str] | None, Field(min_length=1)] = None 1abcd
85 default: str 1abcd
86 description: str | None = None 1abcd
89class Server(BaseModelWithConfig): 1abcd
90 url: AnyUrl | str 1abcd
91 description: str | None = None 1abcd
92 variables: dict[str, ServerVariable] | None = None 1abcd
95class Reference(BaseModel): 1abcd
96 ref: str = Field(alias="$ref") 1abcd
99class Discriminator(BaseModel): 1abcd
100 propertyName: str 1abcd
101 mapping: dict[str, str] | None = None 1abcd
104class XML(BaseModelWithConfig): 1abcd
105 name: str | None = None 1abcd
106 namespace: str | None = None 1abcd
107 prefix: str | None = None 1abcd
108 attribute: bool | None = None 1abcd
109 wrapped: bool | None = None 1abcd
112class ExternalDocumentation(BaseModelWithConfig): 1abcd
113 description: str | None = None 1abcd
114 url: AnyUrl 1abcd
117# Ref JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation#name-type
118SchemaType = Literal[ 1abcd
119 "array", "boolean", "integer", "null", "number", "object", "string"
120]
123class Schema(BaseModelWithConfig): 1abcd
124 # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
125 # Core Vocabulary
126 schema_: str | None = Field(default=None, alias="$schema") 1abcd
127 vocabulary: str | None = Field(default=None, alias="$vocabulary") 1abcd
128 id: str | None = Field(default=None, alias="$id") 1abcd
129 anchor: str | None = Field(default=None, alias="$anchor") 1abcd
130 dynamicAnchor: str | None = Field(default=None, alias="$dynamicAnchor") 1abcd
131 ref: str | None = Field(default=None, alias="$ref") 1abcd
132 dynamicRef: str | None = Field(default=None, alias="$dynamicRef") 1abcd
133 defs: dict[str, "SchemaOrBool"] | None = Field(default=None, alias="$defs") 1abcd
134 comment: str | None = Field(default=None, alias="$comment") 1abcd
135 # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s
136 # A Vocabulary for Applying Subschemas
137 allOf: list["SchemaOrBool"] | None = None 1abcd
138 anyOf: list["SchemaOrBool"] | None = None 1abcd
139 oneOf: list["SchemaOrBool"] | None = None 1abcd
140 not_: Optional["SchemaOrBool"] = Field(default=None, alias="not") 1abcd
141 if_: Optional["SchemaOrBool"] = Field(default=None, alias="if") 1abcd
142 then: Optional["SchemaOrBool"] = None 1abcd
143 else_: Optional["SchemaOrBool"] = Field(default=None, alias="else") 1abcd
144 dependentSchemas: dict[str, "SchemaOrBool"] | None = None 1abcd
145 prefixItems: list["SchemaOrBool"] | None = None 1abcd
146 items: Optional["SchemaOrBool"] = None 1abcd
147 contains: Optional["SchemaOrBool"] = None 1abcd
148 properties: dict[str, "SchemaOrBool"] | None = None 1abcd
149 patternProperties: dict[str, "SchemaOrBool"] | None = None 1abcd
150 additionalProperties: Optional["SchemaOrBool"] = None 1abcd
151 propertyNames: Optional["SchemaOrBool"] = None 1abcd
152 unevaluatedItems: Optional["SchemaOrBool"] = None 1abcd
153 unevaluatedProperties: Optional["SchemaOrBool"] = None 1abcd
154 # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural
155 # A Vocabulary for Structural Validation
156 type: SchemaType | list[SchemaType] | None = None 1abcd
157 enum: list[Any] | None = None 1abcd
158 const: Any | None = None 1abcd
159 multipleOf: float | None = Field(default=None, gt=0) 1abcd
160 maximum: float | None = None 1abcd
161 exclusiveMaximum: float | None = None 1abcd
162 minimum: float | None = None 1abcd
163 exclusiveMinimum: float | None = None 1abcd
164 maxLength: int | None = Field(default=None, ge=0) 1abcd
165 minLength: int | None = Field(default=None, ge=0) 1abcd
166 pattern: str | None = None 1abcd
167 maxItems: int | None = Field(default=None, ge=0) 1abcd
168 minItems: int | None = Field(default=None, ge=0) 1abcd
169 uniqueItems: bool | None = None 1abcd
170 maxContains: int | None = Field(default=None, ge=0) 1abcd
171 minContains: int | None = Field(default=None, ge=0) 1abcd
172 maxProperties: int | None = Field(default=None, ge=0) 1abcd
173 minProperties: int | None = Field(default=None, ge=0) 1abcd
174 required: list[str] | None = None 1abcd
175 dependentRequired: dict[str, set[str]] | None = None 1abcd
176 # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c
177 # Vocabularies for Semantic Content With "format"
178 format: str | None = None 1abcd
179 # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten
180 # A Vocabulary for the Contents of String-Encoded Data
181 contentEncoding: str | None = None 1abcd
182 contentMediaType: str | None = None 1abcd
183 contentSchema: Optional["SchemaOrBool"] = None 1abcd
184 # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta
185 # A Vocabulary for Basic Meta-Data Annotations
186 title: str | None = None 1abcd
187 description: str | None = None 1abcd
188 default: Any | None = None 1abcd
189 deprecated: bool | None = None 1abcd
190 readOnly: bool | None = None 1abcd
191 writeOnly: bool | None = None 1abcd
192 examples: list[Any] | None = None 1abcd
193 # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object
194 # Schema Object
195 discriminator: Discriminator | None = None 1abcd
196 xml: XML | None = None 1abcd
197 externalDocs: ExternalDocumentation | None = None 1abcd
198 example: Annotated[ 1abcd
199 Any | None,
200 typing_deprecated(
201 "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
202 "although still supported. Use examples instead."
203 ),
204 ] = None
207# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents
208# A JSON Schema MUST be an object or a boolean.
209SchemaOrBool = Schema | bool 1abcd
212class Example(TypedDict, total=False): 1abcd
213 summary: str | None 1abcd
214 description: str | None 1abcd
215 value: Any | None 1abcd
216 externalValue: AnyUrl | None 1abcd
218 __pydantic_config__ = {"extra": "allow"} # type: ignore[misc] 1abcd
221class ParameterInType(Enum): 1abcd
222 query = "query" 1abcd
223 header = "header" 1abcd
224 path = "path" 1abcd
225 cookie = "cookie" 1abcd
228class Encoding(BaseModelWithConfig): 1abcd
229 contentType: str | None = None 1abcd
230 headers: dict[str, Union["Header", Reference]] | None = None 1abcd
231 style: str | None = None 1abcd
232 explode: bool | None = None 1abcd
233 allowReserved: bool | None = None 1abcd
236class MediaType(BaseModelWithConfig): 1abcd
237 schema_: Schema | Reference | None = Field(default=None, alias="schema") 1abcd
238 example: Any | None = None 1abcd
239 examples: dict[str, Example | Reference] | None = None 1abcd
240 encoding: dict[str, Encoding] | None = None 1abcd
243class ParameterBase(BaseModelWithConfig): 1abcd
244 description: str | None = None 1abcd
245 required: bool | None = None 1abcd
246 deprecated: bool | None = None 1abcd
247 # Serialization rules for simple scenarios
248 style: str | None = None 1abcd
249 explode: bool | None = None 1abcd
250 allowReserved: bool | None = None 1abcd
251 schema_: Schema | Reference | None = Field(default=None, alias="schema") 1abcd
252 example: Any | None = None 1abcd
253 examples: dict[str, Example | Reference] | None = None 1abcd
254 # Serialization rules for more complex scenarios
255 content: dict[str, MediaType] | None = None 1abcd
258class Parameter(ParameterBase): 1abcd
259 name: str 1abcd
260 in_: ParameterInType = Field(alias="in") 1abcd
263class Header(ParameterBase): 1abcd
264 pass 1abcd
267class RequestBody(BaseModelWithConfig): 1abcd
268 description: str | None = None 1abcd
269 content: dict[str, MediaType] 1abcd
270 required: bool | None = None 1abcd
273class Link(BaseModelWithConfig): 1abcd
274 operationRef: str | None = None 1abcd
275 operationId: str | None = None 1abcd
276 parameters: dict[str, Any | str] | None = None 1abcd
277 requestBody: Any | str | None = None 1abcd
278 description: str | None = None 1abcd
279 server: Server | None = None 1abcd
282class Response(BaseModelWithConfig): 1abcd
283 description: str 1abcd
284 headers: dict[str, Header | Reference] | None = None 1abcd
285 content: dict[str, MediaType] | None = None 1abcd
286 links: dict[str, Link | Reference] | None = None 1abcd
289class Operation(BaseModelWithConfig): 1abcd
290 tags: list[str] | None = None 1abcd
291 summary: str | None = None 1abcd
292 description: str | None = None 1abcd
293 externalDocs: ExternalDocumentation | None = None 1abcd
294 operationId: str | None = None 1abcd
295 parameters: list[Parameter | Reference] | None = None 1abcd
296 requestBody: RequestBody | Reference | None = None 1abcd
297 # Using Any for Specification Extensions
298 responses: dict[str, Response | Any] | None = None 1abcd
299 callbacks: dict[str, dict[str, "PathItem"] | Reference] | None = None 1abcd
300 deprecated: bool | None = None 1abcd
301 security: list[dict[str, list[str]]] | None = None 1abcd
302 servers: list[Server] | None = None 1abcd
305class PathItem(BaseModelWithConfig): 1abcd
306 ref: str | None = Field(default=None, alias="$ref") 1abcd
307 summary: str | None = None 1abcd
308 description: str | None = None 1abcd
309 get: Operation | None = None 1abcd
310 put: Operation | None = None 1abcd
311 post: Operation | None = None 1abcd
312 delete: Operation | None = None 1abcd
313 options: Operation | None = None 1abcd
314 head: Operation | None = None 1abcd
315 patch: Operation | None = None 1abcd
316 trace: Operation | None = None 1abcd
317 servers: list[Server] | None = None 1abcd
318 parameters: list[Parameter | Reference] | None = None 1abcd
321class SecuritySchemeType(Enum): 1abcd
322 apiKey = "apiKey" 1abcd
323 http = "http" 1abcd
324 oauth2 = "oauth2" 1abcd
325 openIdConnect = "openIdConnect" 1abcd
328class SecurityBase(BaseModelWithConfig): 1abcd
329 type_: SecuritySchemeType = Field(alias="type") 1abcd
330 description: str | None = None 1abcd
333class APIKeyIn(Enum): 1abcd
334 query = "query" 1abcd
335 header = "header" 1abcd
336 cookie = "cookie" 1abcd
339class APIKey(SecurityBase): 1abcd
340 type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type") 1abcd
341 in_: APIKeyIn = Field(alias="in") 1abcd
342 name: str 1abcd
345class HTTPBase(SecurityBase): 1abcd
346 type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type") 1abcd
347 scheme: str 1abcd
350class HTTPBearer(HTTPBase): 1abcd
351 scheme: Literal["bearer"] = "bearer" 1abcd
352 bearerFormat: str | None = None 1abcd
355class OAuthFlow(BaseModelWithConfig): 1abcd
356 refreshUrl: str | None = None 1abcd
357 scopes: dict[str, str] = {} 1abcd
360class OAuthFlowImplicit(OAuthFlow): 1abcd
361 authorizationUrl: str 1abcd
364class OAuthFlowPassword(OAuthFlow): 1abcd
365 tokenUrl: str 1abcd
368class OAuthFlowClientCredentials(OAuthFlow): 1abcd
369 tokenUrl: str 1abcd
372class OAuthFlowAuthorizationCode(OAuthFlow): 1abcd
373 authorizationUrl: str 1abcd
374 tokenUrl: str 1abcd
377class OAuthFlows(BaseModelWithConfig): 1abcd
378 implicit: OAuthFlowImplicit | None = None 1abcd
379 password: OAuthFlowPassword | None = None 1abcd
380 clientCredentials: OAuthFlowClientCredentials | None = None 1abcd
381 authorizationCode: OAuthFlowAuthorizationCode | None = None 1abcd
384class OAuth2(SecurityBase): 1abcd
385 type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type") 1abcd
386 flows: OAuthFlows 1abcd
389class OpenIdConnect(SecurityBase): 1abcd
390 type_: SecuritySchemeType = Field( 1abcd
391 default=SecuritySchemeType.openIdConnect, alias="type"
392 )
393 openIdConnectUrl: str 1abcd
396SecurityScheme = APIKey | HTTPBase | OAuth2 | OpenIdConnect | HTTPBearer 1abcd
399class Components(BaseModelWithConfig): 1abcd
400 schemas: dict[str, Schema | Reference] | None = None 1abcd
401 responses: dict[str, Response | Reference] | None = None 1abcd
402 parameters: dict[str, Parameter | Reference] | None = None 1abcd
403 examples: dict[str, Example | Reference] | None = None 1abcd
404 requestBodies: dict[str, RequestBody | Reference] | None = None 1abcd
405 headers: dict[str, Header | Reference] | None = None 1abcd
406 securitySchemes: dict[str, SecurityScheme | Reference] | None = None 1abcd
407 links: dict[str, Link | Reference] | None = None 1abcd
408 # Using Any for Specification Extensions
409 callbacks: dict[str, dict[str, PathItem] | Reference | Any] | None = None 1abcd
410 pathItems: dict[str, PathItem | Reference] | None = None 1abcd
413class Tag(BaseModelWithConfig): 1abcd
414 name: str 1abcd
415 description: str | None = None 1abcd
416 externalDocs: ExternalDocumentation | None = None 1abcd
419class OpenAPI(BaseModelWithConfig): 1abcd
420 openapi: str 1abcd
421 info: Info 1abcd
422 jsonSchemaDialect: str | None = None 1abcd
423 servers: list[Server] | None = None 1abcd
424 # Using Any for Specification Extensions
425 paths: dict[str, PathItem | Any] | None = None 1abcd
426 webhooks: dict[str, PathItem | Reference] | None = None 1abcd
427 components: Components | None = None 1abcd
428 security: list[dict[str, list[str]]] | None = None 1abcd
429 tags: list[Tag] | None = None 1abcd
430 externalDocs: ExternalDocumentation | None = None 1abcd
433Schema.model_rebuild() 1abcd
434Operation.model_rebuild() 1abcd
435Encoding.model_rebuild() 1abcd