Coverage for fastapi/openapi/models.py: 100%

276 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-05-05 00:03 +0000

1from enum import Enum 1abcdef

2from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Type, Union 1abcdef

3 

4from fastapi._compat import ( 1abcdef

5 PYDANTIC_V2, 

6 CoreSchema, 

7 GetJsonSchemaHandler, 

8 JsonSchemaValue, 

9 _model_rebuild, 

10 with_info_plain_validator_function, 

11) 

12from fastapi.logger import logger 1abcdef

13from pydantic import AnyUrl, BaseModel, Field 1abcdef

14from typing_extensions import Annotated, Literal, TypedDict 1abcdef

15from typing_extensions import deprecated as typing_deprecated 1abcdef

16 

17try: 1abcdef

18 import email_validator 1abcdef

19 

20 assert email_validator # make autoflake ignore the unused import 1abcdef

21 from pydantic import EmailStr 1abcdef

22except ImportError: # pragma: no cover 

23 

24 class EmailStr(str): # type: ignore 

25 @classmethod 

26 def __get_validators__(cls) -> Iterable[Callable[..., Any]]: 

27 yield cls.validate 

28 

29 @classmethod 

30 def validate(cls, v: Any) -> str: 

31 logger.warning( 

32 "email-validator not installed, email fields will be treated as str.\n" 

33 "To install, run: pip install email-validator" 

34 ) 

35 return str(v) 

36 

37 @classmethod 

38 def _validate(cls, __input_value: Any, _: Any) -> str: 

39 logger.warning( 

40 "email-validator not installed, email fields will be treated as str.\n" 

41 "To install, run: pip install email-validator" 

42 ) 

43 return str(__input_value) 

44 

45 @classmethod 

46 def __get_pydantic_json_schema__( 

47 cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler 

48 ) -> JsonSchemaValue: 

49 return {"type": "string", "format": "email"} 

50 

51 @classmethod 

52 def __get_pydantic_core_schema__( 

53 cls, source: Type[Any], handler: Callable[[Any], CoreSchema] 

54 ) -> CoreSchema: 

55 return with_info_plain_validator_function(cls._validate) 

56 

57 

58class BaseModelWithConfig(BaseModel): 1abcdef

59 if PYDANTIC_V2: 1abcdef

60 model_config = {"extra": "allow"} 1abcdef

61 

62 else: 

63 

64 class Config: 1abcdef

65 extra = "allow" 1abcdef

66 

67 

68class Contact(BaseModelWithConfig): 1abcdef

69 name: Optional[str] = None 1abcdef

70 url: Optional[AnyUrl] = None 1abcdef

71 email: Optional[EmailStr] = None 1abcdef

72 

73 

74class License(BaseModelWithConfig): 1abcdef

75 name: str 1abcdef

76 identifier: Optional[str] = None 1abcdef

77 url: Optional[AnyUrl] = None 1abcdef

78 

79 

80class Info(BaseModelWithConfig): 1abcdef

81 title: str 1abcdef

82 summary: Optional[str] = None 1abcdef

83 description: Optional[str] = None 1abcdef

84 termsOfService: Optional[str] = None 1abcdef

85 contact: Optional[Contact] = None 1abcdef

86 license: Optional[License] = None 1abcdef

87 version: str 1abcdef

88 

89 

90class ServerVariable(BaseModelWithConfig): 1abcdef

91 enum: Annotated[Optional[List[str]], Field(min_length=1)] = None 1abcdef

92 default: str 1abcdef

93 description: Optional[str] = None 1abcdef

94 

95 

96class Server(BaseModelWithConfig): 1abcdef

97 url: Union[AnyUrl, str] 1abcdef

98 description: Optional[str] = None 1abcdef

99 variables: Optional[Dict[str, ServerVariable]] = None 1abcdef

100 

101 

102class Reference(BaseModel): 1abcdef

103 ref: str = Field(alias="$ref") 1abcdef

104 

105 

106class Discriminator(BaseModel): 1abcdef

107 propertyName: str 1abcdef

108 mapping: Optional[Dict[str, str]] = None 1abcdef

109 

110 

111class XML(BaseModelWithConfig): 1abcdef

112 name: Optional[str] = None 1abcdef

113 namespace: Optional[str] = None 1abcdef

114 prefix: Optional[str] = None 1abcdef

115 attribute: Optional[bool] = None 1abcdef

116 wrapped: Optional[bool] = None 1abcdef

117 

118 

119class ExternalDocumentation(BaseModelWithConfig): 1abcdef

120 description: Optional[str] = None 1abcdef

121 url: AnyUrl 1abcdef

122 

123 

124class Schema(BaseModelWithConfig): 1abcdef

125 # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu 

126 # Core Vocabulary 

127 schema_: Optional[str] = Field(default=None, alias="$schema") 1abcdef

128 vocabulary: Optional[str] = Field(default=None, alias="$vocabulary") 1abcdef

129 id: Optional[str] = Field(default=None, alias="$id") 1abcdef

130 anchor: Optional[str] = Field(default=None, alias="$anchor") 1abcdef

131 dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor") 1abcdef

132 ref: Optional[str] = Field(default=None, alias="$ref") 1abcdef

133 dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef") 1abcdef

134 defs: Optional[Dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs") 1abcdef

135 comment: Optional[str] = Field(default=None, alias="$comment") 1abcdef

136 # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s 

137 # A Vocabulary for Applying Subschemas 

138 allOf: Optional[List["SchemaOrBool"]] = None 1abcdef

139 anyOf: Optional[List["SchemaOrBool"]] = None 1abcdef

140 oneOf: Optional[List["SchemaOrBool"]] = None 1abcdef

141 not_: Optional["SchemaOrBool"] = Field(default=None, alias="not") 1abcdef

142 if_: Optional["SchemaOrBool"] = Field(default=None, alias="if") 1abcdef

143 then: Optional["SchemaOrBool"] = None 1abcdef

144 else_: Optional["SchemaOrBool"] = Field(default=None, alias="else") 1abcdef

145 dependentSchemas: Optional[Dict[str, "SchemaOrBool"]] = None 1abcdef

146 prefixItems: Optional[List["SchemaOrBool"]] = None 1abcdef

147 # TODO: uncomment and remove below when deprecating Pydantic v1 

148 # It generales a list of schemas for tuples, before prefixItems was available 

149 # items: Optional["SchemaOrBool"] = None 

150 items: Optional[Union["SchemaOrBool", List["SchemaOrBool"]]] = None 1abcdef

151 contains: Optional["SchemaOrBool"] = None 1abcdef

152 properties: Optional[Dict[str, "SchemaOrBool"]] = None 1abcdef

153 patternProperties: Optional[Dict[str, "SchemaOrBool"]] = None 1abcdef

154 additionalProperties: Optional["SchemaOrBool"] = None 1abcdef

155 propertyNames: Optional["SchemaOrBool"] = None 1abcdef

156 unevaluatedItems: Optional["SchemaOrBool"] = None 1abcdef

157 unevaluatedProperties: Optional["SchemaOrBool"] = None 1abcdef

158 # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural 

159 # A Vocabulary for Structural Validation 

160 type: Optional[str] = None 1abcdef

161 enum: Optional[List[Any]] = None 1abcdef

162 const: Optional[Any] = None 1abcdef

163 multipleOf: Optional[float] = Field(default=None, gt=0) 1abcdef

164 maximum: Optional[float] = None 1abcdef

165 exclusiveMaximum: Optional[float] = None 1abcdef

166 minimum: Optional[float] = None 1abcdef

167 exclusiveMinimum: Optional[float] = None 1abcdef

168 maxLength: Optional[int] = Field(default=None, ge=0) 1abcdef

169 minLength: Optional[int] = Field(default=None, ge=0) 1abcdef

170 pattern: Optional[str] = None 1abcdef

171 maxItems: Optional[int] = Field(default=None, ge=0) 1abcdef

172 minItems: Optional[int] = Field(default=None, ge=0) 1abcdef

173 uniqueItems: Optional[bool] = None 1abcdef

174 maxContains: Optional[int] = Field(default=None, ge=0) 1abcdef

175 minContains: Optional[int] = Field(default=None, ge=0) 1abcdef

176 maxProperties: Optional[int] = Field(default=None, ge=0) 1abcdef

177 minProperties: Optional[int] = Field(default=None, ge=0) 1abcdef

178 required: Optional[List[str]] = None 1abcdef

179 dependentRequired: Optional[Dict[str, Set[str]]] = None 1abcdef

180 # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c 

181 # Vocabularies for Semantic Content With "format" 

182 format: Optional[str] = None 1abcdef

183 # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten 

184 # A Vocabulary for the Contents of String-Encoded Data 

185 contentEncoding: Optional[str] = None 1abcdef

186 contentMediaType: Optional[str] = None 1abcdef

187 contentSchema: Optional["SchemaOrBool"] = None 1abcdef

188 # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta 

189 # A Vocabulary for Basic Meta-Data Annotations 

190 title: Optional[str] = None 1abcdef

191 description: Optional[str] = None 1abcdef

192 default: Optional[Any] = None 1abcdef

193 deprecated: Optional[bool] = None 1abcdef

194 readOnly: Optional[bool] = None 1abcdef

195 writeOnly: Optional[bool] = None 1abcdef

196 examples: Optional[List[Any]] = None 1abcdef

197 # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object 

198 # Schema Object 

199 discriminator: Optional[Discriminator] = None 1abcdef

200 xml: Optional[XML] = None 1abcdef

201 externalDocs: Optional[ExternalDocumentation] = None 1abcdef

202 example: Annotated[ 1abcdef

203 Optional[Any], 

204 typing_deprecated( 

205 "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " 

206 "although still supported. Use examples instead." 

207 ), 

208 ] = None 

209 

210 

211# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents 

212# A JSON Schema MUST be an object or a boolean. 

213SchemaOrBool = Union[Schema, bool] 1abcdef

214 

215 

216class Example(TypedDict, total=False): 1abcdef

217 summary: Optional[str] 1abcdef

218 description: Optional[str] 1abcdef

219 value: Optional[Any] 1abcdef

220 externalValue: Optional[AnyUrl] 1abcdef

221 

222 if PYDANTIC_V2: # type: ignore [misc] 1abcdef

223 __pydantic_config__ = {"extra": "allow"} 1abcdef

224 

225 else: 

226 

227 class Config: 1abcdef

228 extra = "allow" 1abcdef

229 

230 

231class ParameterInType(Enum): 1abcdef

232 query = "query" 1abcdef

233 header = "header" 1abcdef

234 path = "path" 1abcdef

235 cookie = "cookie" 1abcdef

236 

237 

238class Encoding(BaseModelWithConfig): 1abcdef

239 contentType: Optional[str] = None 1abcdef

240 headers: Optional[Dict[str, Union["Header", Reference]]] = None 1abcdef

241 style: Optional[str] = None 1abcdef

242 explode: Optional[bool] = None 1abcdef

243 allowReserved: Optional[bool] = None 1abcdef

244 

245 

246class MediaType(BaseModelWithConfig): 1abcdef

247 schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") 1abcdef

248 example: Optional[Any] = None 1abcdef

249 examples: Optional[Dict[str, Union[Example, Reference]]] = None 1abcdef

250 encoding: Optional[Dict[str, Encoding]] = None 1abcdef

251 

252 

253class ParameterBase(BaseModelWithConfig): 1abcdef

254 description: Optional[str] = None 1abcdef

255 required: Optional[bool] = None 1abcdef

256 deprecated: Optional[bool] = None 1abcdef

257 # Serialization rules for simple scenarios 

258 style: Optional[str] = None 1abcdef

259 explode: Optional[bool] = None 1abcdef

260 allowReserved: Optional[bool] = None 1abcdef

261 schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") 1abcdef

262 example: Optional[Any] = None 1abcdef

263 examples: Optional[Dict[str, Union[Example, Reference]]] = None 1abcdef

264 # Serialization rules for more complex scenarios 

265 content: Optional[Dict[str, MediaType]] = None 1abcdef

266 

267 

268class Parameter(ParameterBase): 1abcdef

269 name: str 1abcdef

270 in_: ParameterInType = Field(alias="in") 1abcdef

271 

272 

273class Header(ParameterBase): 1abcdef

274 pass 1abcdef

275 

276 

277class RequestBody(BaseModelWithConfig): 1abcdef

278 description: Optional[str] = None 1abcdef

279 content: Dict[str, MediaType] 1abcdef

280 required: Optional[bool] = None 1abcdef

281 

282 

283class Link(BaseModelWithConfig): 1abcdef

284 operationRef: Optional[str] = None 1abcdef

285 operationId: Optional[str] = None 1abcdef

286 parameters: Optional[Dict[str, Union[Any, str]]] = None 1abcdef

287 requestBody: Optional[Union[Any, str]] = None 1abcdef

288 description: Optional[str] = None 1abcdef

289 server: Optional[Server] = None 1abcdef

290 

291 

292class Response(BaseModelWithConfig): 1abcdef

293 description: str 1abcdef

294 headers: Optional[Dict[str, Union[Header, Reference]]] = None 1abcdef

295 content: Optional[Dict[str, MediaType]] = None 1abcdef

296 links: Optional[Dict[str, Union[Link, Reference]]] = None 1abcdef

297 

298 

299class Operation(BaseModelWithConfig): 1abcdef

300 tags: Optional[List[str]] = None 1abcdef

301 summary: Optional[str] = None 1abcdef

302 description: Optional[str] = None 1abcdef

303 externalDocs: Optional[ExternalDocumentation] = None 1abcdef

304 operationId: Optional[str] = None 1abcdef

305 parameters: Optional[List[Union[Parameter, Reference]]] = None 1abcdef

306 requestBody: Optional[Union[RequestBody, Reference]] = None 1abcdef

307 # Using Any for Specification Extensions 

308 responses: Optional[Dict[str, Union[Response, Any]]] = None 1abcdef

309 callbacks: Optional[Dict[str, Union[Dict[str, "PathItem"], Reference]]] = None 1abcdef

310 deprecated: Optional[bool] = None 1abcdef

311 security: Optional[List[Dict[str, List[str]]]] = None 1abcdef

312 servers: Optional[List[Server]] = None 1abcdef

313 

314 

315class PathItem(BaseModelWithConfig): 1abcdef

316 ref: Optional[str] = Field(default=None, alias="$ref") 1abcdef

317 summary: Optional[str] = None 1abcdef

318 description: Optional[str] = None 1abcdef

319 get: Optional[Operation] = None 1abcdef

320 put: Optional[Operation] = None 1abcdef

321 post: Optional[Operation] = None 1abcdef

322 delete: Optional[Operation] = None 1abcdef

323 options: Optional[Operation] = None 1abcdef

324 head: Optional[Operation] = None 1abcdef

325 patch: Optional[Operation] = None 1abcdef

326 trace: Optional[Operation] = None 1abcdef

327 servers: Optional[List[Server]] = None 1abcdef

328 parameters: Optional[List[Union[Parameter, Reference]]] = None 1abcdef

329 

330 

331class SecuritySchemeType(Enum): 1abcdef

332 apiKey = "apiKey" 1abcdef

333 http = "http" 1abcdef

334 oauth2 = "oauth2" 1abcdef

335 openIdConnect = "openIdConnect" 1abcdef

336 

337 

338class SecurityBase(BaseModelWithConfig): 1abcdef

339 type_: SecuritySchemeType = Field(alias="type") 1abcdef

340 description: Optional[str] = None 1abcdef

341 

342 

343class APIKeyIn(Enum): 1abcdef

344 query = "query" 1abcdef

345 header = "header" 1abcdef

346 cookie = "cookie" 1abcdef

347 

348 

349class APIKey(SecurityBase): 1abcdef

350 type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type") 1abcdef

351 in_: APIKeyIn = Field(alias="in") 1abcdef

352 name: str 1abcdef

353 

354 

355class HTTPBase(SecurityBase): 1abcdef

356 type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type") 1abcdef

357 scheme: str 1abcdef

358 

359 

360class HTTPBearer(HTTPBase): 1abcdef

361 scheme: Literal["bearer"] = "bearer" 1abcdef

362 bearerFormat: Optional[str] = None 1abcdef

363 

364 

365class OAuthFlow(BaseModelWithConfig): 1abcdef

366 refreshUrl: Optional[str] = None 1abcdef

367 scopes: Dict[str, str] = {} 1abcdef

368 

369 

370class OAuthFlowImplicit(OAuthFlow): 1abcdef

371 authorizationUrl: str 1abcdef

372 

373 

374class OAuthFlowPassword(OAuthFlow): 1abcdef

375 tokenUrl: str 1abcdef

376 

377 

378class OAuthFlowClientCredentials(OAuthFlow): 1abcdef

379 tokenUrl: str 1abcdef

380 

381 

382class OAuthFlowAuthorizationCode(OAuthFlow): 1abcdef

383 authorizationUrl: str 1abcdef

384 tokenUrl: str 1abcdef

385 

386 

387class OAuthFlows(BaseModelWithConfig): 1abcdef

388 implicit: Optional[OAuthFlowImplicit] = None 1abcdef

389 password: Optional[OAuthFlowPassword] = None 1abcdef

390 clientCredentials: Optional[OAuthFlowClientCredentials] = None 1abcdef

391 authorizationCode: Optional[OAuthFlowAuthorizationCode] = None 1abcdef

392 

393 

394class OAuth2(SecurityBase): 1abcdef

395 type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type") 1abcdef

396 flows: OAuthFlows 1abcdef

397 

398 

399class OpenIdConnect(SecurityBase): 1abcdef

400 type_: SecuritySchemeType = Field( 1abcdef

401 default=SecuritySchemeType.openIdConnect, alias="type" 

402 ) 

403 openIdConnectUrl: str 1abcdef

404 

405 

406SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer] 1abcdef

407 

408 

409class Components(BaseModelWithConfig): 1abcdef

410 schemas: Optional[Dict[str, Union[Schema, Reference]]] = None 1abcdef

411 responses: Optional[Dict[str, Union[Response, Reference]]] = None 1abcdef

412 parameters: Optional[Dict[str, Union[Parameter, Reference]]] = None 1abcdef

413 examples: Optional[Dict[str, Union[Example, Reference]]] = None 1abcdef

414 requestBodies: Optional[Dict[str, Union[RequestBody, Reference]]] = None 1abcdef

415 headers: Optional[Dict[str, Union[Header, Reference]]] = None 1abcdef

416 securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None 1abcdef

417 links: Optional[Dict[str, Union[Link, Reference]]] = None 1abcdef

418 # Using Any for Specification Extensions 

419 callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None 1abcdef

420 pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None 1abcdef

421 

422 

423class Tag(BaseModelWithConfig): 1abcdef

424 name: str 1abcdef

425 description: Optional[str] = None 1abcdef

426 externalDocs: Optional[ExternalDocumentation] = None 1abcdef

427 

428 

429class OpenAPI(BaseModelWithConfig): 1abcdef

430 openapi: str 1abcdef

431 info: Info 1abcdef

432 jsonSchemaDialect: Optional[str] = None 1abcdef

433 servers: Optional[List[Server]] = None 1abcdef

434 # Using Any for Specification Extensions 

435 paths: Optional[Dict[str, Union[PathItem, Any]]] = None 1abcdef

436 webhooks: Optional[Dict[str, Union[PathItem, Reference]]] = None 1abcdef

437 components: Optional[Components] = None 1abcdef

438 security: Optional[List[Dict[str, List[str]]]] = None 1abcdef

439 tags: Optional[List[Tag]] = None 1abcdef

440 externalDocs: Optional[ExternalDocumentation] = None 1abcdef

441 

442 

443_model_rebuild(Schema) 1abcdef

444_model_rebuild(Operation) 1abcdef

445_model_rebuild(Encoding) 1abcdef