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

276 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-08 03:53 +0000

1from enum import Enum 1abcde

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

3 

4from fastapi._compat import ( 1abcde

5 PYDANTIC_V2, 

6 CoreSchema, 

7 GetJsonSchemaHandler, 

8 JsonSchemaValue, 

9 _model_rebuild, 

10 with_info_plain_validator_function, 

11) 

12from fastapi.logger import logger 1abcde

13from pydantic import AnyUrl, BaseModel, Field 1abcde

14from typing_extensions import Annotated, Literal, TypedDict 1abcde

15from typing_extensions import deprecated as typing_deprecated 1abcde

16 

17try: 1abcde

18 import email_validator 1abcde

19 

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

21 from pydantic import EmailStr 1abcde

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

59 if PYDANTIC_V2: 1abcde

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

61 

62 else: 

63 

64 class Config: 1abcde

65 extra = "allow" 1abcde

66 

67 

68class Contact(BaseModelWithConfig): 1abcde

69 name: Optional[str] = None 1abcde

70 url: Optional[AnyUrl] = None 1abcde

71 email: Optional[EmailStr] = None 1abcde

72 

73 

74class License(BaseModelWithConfig): 1abcde

75 name: str 1abcde

76 identifier: Optional[str] = None 1abcde

77 url: Optional[AnyUrl] = None 1abcde

78 

79 

80class Info(BaseModelWithConfig): 1abcde

81 title: str 1abcde

82 summary: Optional[str] = None 1abcde

83 description: Optional[str] = None 1abcde

84 termsOfService: Optional[str] = None 1abcde

85 contact: Optional[Contact] = None 1abcde

86 license: Optional[License] = None 1abcde

87 version: str 1abcde

88 

89 

90class ServerVariable(BaseModelWithConfig): 1abcde

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

92 default: str 1abcde

93 description: Optional[str] = None 1abcde

94 

95 

96class Server(BaseModelWithConfig): 1abcde

97 url: Union[AnyUrl, str] 1abcde

98 description: Optional[str] = None 1abcde

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

100 

101 

102class Reference(BaseModel): 1abcde

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

104 

105 

106class Discriminator(BaseModel): 1abcde

107 propertyName: str 1abcde

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

109 

110 

111class XML(BaseModelWithConfig): 1abcde

112 name: Optional[str] = None 1abcde

113 namespace: Optional[str] = None 1abcde

114 prefix: Optional[str] = None 1abcde

115 attribute: Optional[bool] = None 1abcde

116 wrapped: Optional[bool] = None 1abcde

117 

118 

119class ExternalDocumentation(BaseModelWithConfig): 1abcde

120 description: Optional[str] = None 1abcde

121 url: AnyUrl 1abcde

122 

123 

124class Schema(BaseModelWithConfig): 1abcde

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") 1abcde

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

162 const: Optional[Any] = None 1abcde

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

164 maximum: Optional[float] = None 1abcde

165 exclusiveMaximum: Optional[float] = None 1abcde

166 minimum: Optional[float] = None 1abcde

167 exclusiveMinimum: Optional[float] = None 1abcde

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

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

170 pattern: Optional[str] = None 1abcde

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

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

173 uniqueItems: Optional[bool] = None 1abcde

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

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

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

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

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

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

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

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

186 contentMediaType: Optional[str] = None 1abcde

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

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

191 description: Optional[str] = None 1abcde

192 default: Optional[Any] = None 1abcde

193 deprecated: Optional[bool] = None 1abcde

194 readOnly: Optional[bool] = None 1abcde

195 writeOnly: Optional[bool] = None 1abcde

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

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

200 xml: Optional[XML] = None 1abcde

201 externalDocs: Optional[ExternalDocumentation] = None 1abcde

202 example: Annotated[ 1abcde

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

214 

215 

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

217 summary: Optional[str] 1abcde

218 description: Optional[str] 1abcde

219 value: Optional[Any] 1abcde

220 externalValue: Optional[AnyUrl] 1abcde

221 

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

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

224 

225 else: 

226 

227 class Config: 1abcde

228 extra = "allow" 1abcde

229 

230 

231class ParameterInType(Enum): 1abcde

232 query = "query" 1abcde

233 header = "header" 1abcde

234 path = "path" 1abcde

235 cookie = "cookie" 1abcde

236 

237 

238class Encoding(BaseModelWithConfig): 1abcde

239 contentType: Optional[str] = None 1abcde

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

241 style: Optional[str] = None 1abcde

242 explode: Optional[bool] = None 1abcde

243 allowReserved: Optional[bool] = None 1abcde

244 

245 

246class MediaType(BaseModelWithConfig): 1abcde

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

248 example: Optional[Any] = None 1abcde

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

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

251 

252 

253class ParameterBase(BaseModelWithConfig): 1abcde

254 description: Optional[str] = None 1abcde

255 required: Optional[bool] = None 1abcde

256 deprecated: Optional[bool] = None 1abcde

257 # Serialization rules for simple scenarios 

258 style: Optional[str] = None 1abcde

259 explode: Optional[bool] = None 1abcde

260 allowReserved: Optional[bool] = None 1abcde

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

262 example: Optional[Any] = None 1abcde

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

264 # Serialization rules for more complex scenarios 

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

266 

267 

268class Parameter(ParameterBase): 1abcde

269 name: str 1abcde

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

271 

272 

273class Header(ParameterBase): 1abcde

274 pass 1abcde

275 

276 

277class RequestBody(BaseModelWithConfig): 1abcde

278 description: Optional[str] = None 1abcde

279 content: Dict[str, MediaType] 1abcde

280 required: Optional[bool] = None 1abcde

281 

282 

283class Link(BaseModelWithConfig): 1abcde

284 operationRef: Optional[str] = None 1abcde

285 operationId: Optional[str] = None 1abcde

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

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

288 description: Optional[str] = None 1abcde

289 server: Optional[Server] = None 1abcde

290 

291 

292class Response(BaseModelWithConfig): 1abcde

293 description: str 1abcde

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

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

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

297 

298 

299class Operation(BaseModelWithConfig): 1abcde

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

301 summary: Optional[str] = None 1abcde

302 description: Optional[str] = None 1abcde

303 externalDocs: Optional[ExternalDocumentation] = None 1abcde

304 operationId: Optional[str] = None 1abcde

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

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

307 # Using Any for Specification Extensions 

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

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

310 deprecated: Optional[bool] = None 1abcde

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

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

313 

314 

315class PathItem(BaseModelWithConfig): 1abcde

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

317 summary: Optional[str] = None 1abcde

318 description: Optional[str] = None 1abcde

319 get: Optional[Operation] = None 1abcde

320 put: Optional[Operation] = None 1abcde

321 post: Optional[Operation] = None 1abcde

322 delete: Optional[Operation] = None 1abcde

323 options: Optional[Operation] = None 1abcde

324 head: Optional[Operation] = None 1abcde

325 patch: Optional[Operation] = None 1abcde

326 trace: Optional[Operation] = None 1abcde

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

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

329 

330 

331class SecuritySchemeType(Enum): 1abcde

332 apiKey = "apiKey" 1abcde

333 http = "http" 1abcde

334 oauth2 = "oauth2" 1abcde

335 openIdConnect = "openIdConnect" 1abcde

336 

337 

338class SecurityBase(BaseModelWithConfig): 1abcde

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

340 description: Optional[str] = None 1abcde

341 

342 

343class APIKeyIn(Enum): 1abcde

344 query = "query" 1abcde

345 header = "header" 1abcde

346 cookie = "cookie" 1abcde

347 

348 

349class APIKey(SecurityBase): 1abcde

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

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

352 name: str 1abcde

353 

354 

355class HTTPBase(SecurityBase): 1abcde

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

357 scheme: str 1abcde

358 

359 

360class HTTPBearer(HTTPBase): 1abcde

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

362 bearerFormat: Optional[str] = None 1abcde

363 

364 

365class OAuthFlow(BaseModelWithConfig): 1abcde

366 refreshUrl: Optional[str] = None 1abcde

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

368 

369 

370class OAuthFlowImplicit(OAuthFlow): 1abcde

371 authorizationUrl: str 1abcde

372 

373 

374class OAuthFlowPassword(OAuthFlow): 1abcde

375 tokenUrl: str 1abcde

376 

377 

378class OAuthFlowClientCredentials(OAuthFlow): 1abcde

379 tokenUrl: str 1abcde

380 

381 

382class OAuthFlowAuthorizationCode(OAuthFlow): 1abcde

383 authorizationUrl: str 1abcde

384 tokenUrl: str 1abcde

385 

386 

387class OAuthFlows(BaseModelWithConfig): 1abcde

388 implicit: Optional[OAuthFlowImplicit] = None 1abcde

389 password: Optional[OAuthFlowPassword] = None 1abcde

390 clientCredentials: Optional[OAuthFlowClientCredentials] = None 1abcde

391 authorizationCode: Optional[OAuthFlowAuthorizationCode] = None 1abcde

392 

393 

394class OAuth2(SecurityBase): 1abcde

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

396 flows: OAuthFlows 1abcde

397 

398 

399class OpenIdConnect(SecurityBase): 1abcde

400 type_: SecuritySchemeType = Field( 1abcde

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

402 ) 

403 openIdConnectUrl: str 1abcde

404 

405 

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

407 

408 

409class Components(BaseModelWithConfig): 1abcde

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

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

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

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

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

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

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

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

418 # Using Any for Specification Extensions 

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

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

421 

422 

423class Tag(BaseModelWithConfig): 1abcde

424 name: str 1abcde

425 description: Optional[str] = None 1abcde

426 externalDocs: Optional[ExternalDocumentation] = None 1abcde

427 

428 

429class OpenAPI(BaseModelWithConfig): 1abcde

430 openapi: str 1abcde

431 info: Info 1abcde

432 jsonSchemaDialect: Optional[str] = None 1abcde

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

434 # Using Any for Specification Extensions 

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

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

437 components: Optional[Components] = None 1abcde

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

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

440 externalDocs: Optional[ExternalDocumentation] = None 1abcde

441 

442 

443_model_rebuild(Schema) 1abcde

444_model_rebuild(Operation) 1abcde

445_model_rebuild(Encoding) 1abcde