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

272 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-04-06 01:24 +0000

1from collections.abc import Callable, Iterable, Mapping 1adbc

2from enum import Enum 1adbc

3from typing import Annotated, Any, Literal, Optional, Union 1adbc

4 

5from fastapi._compat import with_info_plain_validator_function 1adbc

6from fastapi.logger import logger 1adbc

7from pydantic import ( 1adbc

8 AnyUrl, 

9 BaseModel, 

10 Field, 

11 GetJsonSchemaHandler, 

12) 

13from typing_extensions import TypedDict 1adbc

14from typing_extensions import deprecated as typing_deprecated 1adbc

15 

16try: 1adbc

17 import email_validator 1adbc

18 

19 assert email_validator # make autoflake ignore the unused import 1adbc

20 from pydantic import EmailStr 1adbc

21except ImportError: # pragma: no cover 

22 

23 class EmailStr(str): # type: ignore 

24 @classmethod 

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

26 yield cls.validate 

27 

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) 

35 

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) 

43 

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"} 

49 

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) 

55 

56 

57class BaseModelWithConfig(BaseModel): 1adbc

58 model_config = {"extra": "allow"} 1adbc

59 

60 

61class Contact(BaseModelWithConfig): 1adbc

62 name: str | None = None 1adbc

63 url: AnyUrl | None = None 1adbc

64 email: EmailStr | None = None 1adbc

65 

66 

67class License(BaseModelWithConfig): 1adbc

68 name: str 1abc

69 identifier: str | None = None 1adbc

70 url: AnyUrl | None = None 1adbc

71 

72 

73class Info(BaseModelWithConfig): 1adbc

74 title: str 1abc

75 summary: str | None = None 1adbc

76 description: str | None = None 1adbc

77 termsOfService: str | None = None 1adbc

78 contact: Contact | None = None 1adbc

79 license: License | None = None 1adbc

80 version: str 1abc

81 

82 

83class ServerVariable(BaseModelWithConfig): 1adbc

84 enum: Annotated[list[str] | None, Field(min_length=1)] = None 1adbc

85 default: str 1abc

86 description: str | None = None 1adbc

87 

88 

89class Server(BaseModelWithConfig): 1adbc

90 url: AnyUrl | str 1abc

91 description: str | None = None 1adbc

92 variables: dict[str, ServerVariable] | None = None 1adbc

93 

94 

95class Reference(BaseModel): 1adbc

96 ref: str = Field(alias="$ref") 1adbc

97 

98 

99class Discriminator(BaseModel): 1adbc

100 propertyName: str 1abc

101 mapping: dict[str, str] | None = None 1adbc

102 

103 

104class XML(BaseModelWithConfig): 1adbc

105 name: str | None = None 1adbc

106 namespace: str | None = None 1adbc

107 prefix: str | None = None 1adbc

108 attribute: bool | None = None 1adbc

109 wrapped: bool | None = None 1adbc

110 

111 

112class ExternalDocumentation(BaseModelWithConfig): 1adbc

113 description: str | None = None 1adbc

114 url: AnyUrl 1abc

115 

116 

117# Ref JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation#name-type 

118SchemaType = Literal[ 1adbc

119 "array", "boolean", "integer", "null", "number", "object", "string" 

120] 

121 

122 

123class Schema(BaseModelWithConfig): 1adbc

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

127 vocabulary: str | None = Field(default=None, alias="$vocabulary") 1adbc

128 id: str | None = Field(default=None, alias="$id") 1adbc

129 anchor: str | None = Field(default=None, alias="$anchor") 1adbc

130 dynamicAnchor: str | None = Field(default=None, alias="$dynamicAnchor") 1adbc

131 ref: str | None = Field(default=None, alias="$ref") 1adbc

132 dynamicRef: str | None = Field(default=None, alias="$dynamicRef") 1adbc

133 defs: dict[str, "SchemaOrBool"] | None = Field(default=None, alias="$defs") 1adbc

134 comment: str | None = Field(default=None, alias="$comment") 1adbc

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

138 anyOf: list["SchemaOrBool"] | None = None 1adbc

139 oneOf: list["SchemaOrBool"] | None = None 1adbc

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

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

142 then: Optional["SchemaOrBool"] = None 1adbc

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

144 dependentSchemas: dict[str, "SchemaOrBool"] | None = None 1adbc

145 prefixItems: list["SchemaOrBool"] | None = None 1adbc

146 items: Optional["SchemaOrBool"] = None 1adbc

147 contains: Optional["SchemaOrBool"] = None 1adbc

148 properties: dict[str, "SchemaOrBool"] | None = None 1adbc

149 patternProperties: dict[str, "SchemaOrBool"] | None = None 1adbc

150 additionalProperties: Optional["SchemaOrBool"] = None 1adbc

151 propertyNames: Optional["SchemaOrBool"] = None 1adbc

152 unevaluatedItems: Optional["SchemaOrBool"] = None 1adbc

153 unevaluatedProperties: Optional["SchemaOrBool"] = None 1adbc

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

157 enum: list[Any] | None = None 1adbc

158 const: Any | None = None 1adbc

159 multipleOf: float | None = Field(default=None, gt=0) 1adbc

160 maximum: float | None = None 1adbc

161 exclusiveMaximum: float | None = None 1adbc

162 minimum: float | None = None 1adbc

163 exclusiveMinimum: float | None = None 1adbc

164 maxLength: int | None = Field(default=None, ge=0) 1adbc

165 minLength: int | None = Field(default=None, ge=0) 1adbc

166 pattern: str | None = None 1adbc

167 maxItems: int | None = Field(default=None, ge=0) 1adbc

168 minItems: int | None = Field(default=None, ge=0) 1adbc

169 uniqueItems: bool | None = None 1adbc

170 maxContains: int | None = Field(default=None, ge=0) 1adbc

171 minContains: int | None = Field(default=None, ge=0) 1adbc

172 maxProperties: int | None = Field(default=None, ge=0) 1adbc

173 minProperties: int | None = Field(default=None, ge=0) 1adbc

174 required: list[str] | None = None 1adbc

175 dependentRequired: dict[str, set[str]] | None = None 1adbc

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

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

182 contentMediaType: str | None = None 1adbc

183 contentSchema: Optional["SchemaOrBool"] = None 1adbc

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

187 description: str | None = None 1adbc

188 default: Any | None = None 1adbc

189 deprecated: bool | None = None 1adbc

190 readOnly: bool | None = None 1adbc

191 writeOnly: bool | None = None 1adbc

192 examples: list[Any] | None = None 1adbc

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

196 xml: XML | None = None 1adbc

197 externalDocs: ExternalDocumentation | None = None 1adbc

198 example: Annotated[ 1adbc

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 

205 

206 

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

210 

211 

212class Example(TypedDict, total=False): 1adbc

213 summary: str | None 1abc

214 description: str | None 1abc

215 value: Any | None 1abc

216 externalValue: AnyUrl | None 1abc

217 

218 __pydantic_config__ = {"extra": "allow"} # type: ignore[misc] 1adbc

219 

220 

221class ParameterInType(Enum): 1adbc

222 query = "query" 1adbc

223 header = "header" 1adbc

224 path = "path" 1adbc

225 cookie = "cookie" 1adbc

226 

227 

228class Encoding(BaseModelWithConfig): 1adbc

229 contentType: str | None = None 1adbc

230 headers: dict[str, Union["Header", Reference]] | None = None 1adbc

231 style: str | None = None 1adbc

232 explode: bool | None = None 1adbc

233 allowReserved: bool | None = None 1adbc

234 

235 

236class MediaType(BaseModelWithConfig): 1adbc

237 schema_: Schema | Reference | None = Field(default=None, alias="schema") 1adbc

238 example: Any | None = None 1adbc

239 examples: dict[str, Example | Reference] | None = None 1adbc

240 encoding: dict[str, Encoding] | None = None 1adbc

241 

242 

243class ParameterBase(BaseModelWithConfig): 1adbc

244 description: str | None = None 1adbc

245 required: bool | None = None 1adbc

246 deprecated: bool | None = None 1adbc

247 # Serialization rules for simple scenarios 

248 style: str | None = None 1adbc

249 explode: bool | None = None 1adbc

250 allowReserved: bool | None = None 1adbc

251 schema_: Schema | Reference | None = Field(default=None, alias="schema") 1adbc

252 example: Any | None = None 1adbc

253 examples: dict[str, Example | Reference] | None = None 1adbc

254 # Serialization rules for more complex scenarios 

255 content: dict[str, MediaType] | None = None 1adbc

256 

257 

258class Parameter(ParameterBase): 1adbc

259 name: str 1abc

260 in_: ParameterInType = Field(alias="in") 1adbc

261 

262 

263class Header(ParameterBase): 1adbc

264 pass 1adbc

265 

266 

267class RequestBody(BaseModelWithConfig): 1adbc

268 description: str | None = None 1adbc

269 content: dict[str, MediaType] 1abc

270 required: bool | None = None 1adbc

271 

272 

273class Link(BaseModelWithConfig): 1adbc

274 operationRef: str | None = None 1adbc

275 operationId: str | None = None 1adbc

276 parameters: dict[str, Any | str] | None = None 1adbc

277 requestBody: Any | str | None = None 1adbc

278 description: str | None = None 1adbc

279 server: Server | None = None 1adbc

280 

281 

282class Response(BaseModelWithConfig): 1adbc

283 description: str 1abc

284 headers: dict[str, Header | Reference] | None = None 1adbc

285 content: dict[str, MediaType] | None = None 1adbc

286 links: dict[str, Link | Reference] | None = None 1adbc

287 

288 

289class Operation(BaseModelWithConfig): 1adbc

290 tags: list[str] | None = None 1adbc

291 summary: str | None = None 1adbc

292 description: str | None = None 1adbc

293 externalDocs: ExternalDocumentation | None = None 1adbc

294 operationId: str | None = None 1adbc

295 parameters: list[Parameter | Reference] | None = None 1adbc

296 requestBody: RequestBody | Reference | None = None 1adbc

297 # Using Any for Specification Extensions 

298 responses: dict[str, Response | Any] | None = None 1adbc

299 callbacks: dict[str, dict[str, "PathItem"] | Reference] | None = None 1adbc

300 deprecated: bool | None = None 1adbc

301 security: list[dict[str, list[str]]] | None = None 1adbc

302 servers: list[Server] | None = None 1adbc

303 

304 

305class PathItem(BaseModelWithConfig): 1adbc

306 ref: str | None = Field(default=None, alias="$ref") 1adbc

307 summary: str | None = None 1adbc

308 description: str | None = None 1adbc

309 get: Operation | None = None 1adbc

310 put: Operation | None = None 1adbc

311 post: Operation | None = None 1adbc

312 delete: Operation | None = None 1adbc

313 options: Operation | None = None 1adbc

314 head: Operation | None = None 1adbc

315 patch: Operation | None = None 1adbc

316 trace: Operation | None = None 1adbc

317 servers: list[Server] | None = None 1adbc

318 parameters: list[Parameter | Reference] | None = None 1adbc

319 

320 

321class SecuritySchemeType(Enum): 1adbc

322 apiKey = "apiKey" 1adbc

323 http = "http" 1adbc

324 oauth2 = "oauth2" 1adbc

325 openIdConnect = "openIdConnect" 1adbc

326 

327 

328class SecurityBase(BaseModelWithConfig): 1adbc

329 type_: SecuritySchemeType = Field(alias="type") 1adbc

330 description: str | None = None 1adbc

331 

332 

333class APIKeyIn(Enum): 1adbc

334 query = "query" 1adbc

335 header = "header" 1adbc

336 cookie = "cookie" 1adbc

337 

338 

339class APIKey(SecurityBase): 1adbc

340 type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type") 1adbc

341 in_: APIKeyIn = Field(alias="in") 1adbc

342 name: str 1abc

343 

344 

345class HTTPBase(SecurityBase): 1adbc

346 type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type") 1adbc

347 scheme: str 1abc

348 

349 

350class HTTPBearer(HTTPBase): 1adbc

351 scheme: Literal["bearer"] = "bearer" 1adbc

352 bearerFormat: str | None = None 1adbc

353 

354 

355class OAuthFlow(BaseModelWithConfig): 1adbc

356 refreshUrl: str | None = None 1adbc

357 scopes: dict[str, str] = {} 1adbc

358 

359 

360class OAuthFlowImplicit(OAuthFlow): 1adbc

361 authorizationUrl: str 1abc

362 

363 

364class OAuthFlowPassword(OAuthFlow): 1adbc

365 tokenUrl: str 1abc

366 

367 

368class OAuthFlowClientCredentials(OAuthFlow): 1adbc

369 tokenUrl: str 1abc

370 

371 

372class OAuthFlowAuthorizationCode(OAuthFlow): 1adbc

373 authorizationUrl: str 1abc

374 tokenUrl: str 1abc

375 

376 

377class OAuthFlows(BaseModelWithConfig): 1adbc

378 implicit: OAuthFlowImplicit | None = None 1adbc

379 password: OAuthFlowPassword | None = None 1adbc

380 clientCredentials: OAuthFlowClientCredentials | None = None 1adbc

381 authorizationCode: OAuthFlowAuthorizationCode | None = None 1adbc

382 

383 

384class OAuth2(SecurityBase): 1adbc

385 type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type") 1adbc

386 flows: OAuthFlows 1abc

387 

388 

389class OpenIdConnect(SecurityBase): 1adbc

390 type_: SecuritySchemeType = Field( 1adbc

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

392 ) 

393 openIdConnectUrl: str 1abc

394 

395 

396SecurityScheme = APIKey | HTTPBase | OAuth2 | OpenIdConnect | HTTPBearer 1adbc

397 

398 

399class Components(BaseModelWithConfig): 1adbc

400 schemas: dict[str, Schema | Reference] | None = None 1adbc

401 responses: dict[str, Response | Reference] | None = None 1adbc

402 parameters: dict[str, Parameter | Reference] | None = None 1adbc

403 examples: dict[str, Example | Reference] | None = None 1adbc

404 requestBodies: dict[str, RequestBody | Reference] | None = None 1adbc

405 headers: dict[str, Header | Reference] | None = None 1adbc

406 securitySchemes: dict[str, SecurityScheme | Reference] | None = None 1adbc

407 links: dict[str, Link | Reference] | None = None 1adbc

408 # Using Any for Specification Extensions 

409 callbacks: dict[str, dict[str, PathItem] | Reference | Any] | None = None 1adbc

410 pathItems: dict[str, PathItem | Reference] | None = None 1adbc

411 

412 

413class Tag(BaseModelWithConfig): 1adbc

414 name: str 1abc

415 description: str | None = None 1adbc

416 externalDocs: ExternalDocumentation | None = None 1adbc

417 

418 

419class OpenAPI(BaseModelWithConfig): 1adbc

420 openapi: str 1abc

421 info: Info 1abc

422 jsonSchemaDialect: str | None = None 1adbc

423 servers: list[Server] | None = None 1adbc

424 # Using Any for Specification Extensions 

425 paths: dict[str, PathItem | Any] | None = None 1adbc

426 webhooks: dict[str, PathItem | Reference] | None = None 1adbc

427 components: Components | None = None 1adbc

428 security: list[dict[str, list[str]]] | None = None 1adbc

429 tags: list[Tag] | None = None 1adbc

430 externalDocs: ExternalDocumentation | None = None 1adbc

431 

432 

433Schema.model_rebuild() 1adbc

434Operation.model_rebuild() 1adbc

435Encoding.model_rebuild() 1adbc