fastapi 0.96.1__py3-none-any.whl → 0.100.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fastapi might be problematic. Click here for more details.

fastapi/encoders.py CHANGED
@@ -1,15 +1,87 @@
1
1
  import dataclasses
2
- from collections import defaultdict
2
+ import datetime
3
+ from collections import defaultdict, deque
4
+ from decimal import Decimal
3
5
  from enum import Enum
4
- from pathlib import PurePath
6
+ from ipaddress import (
7
+ IPv4Address,
8
+ IPv4Interface,
9
+ IPv4Network,
10
+ IPv6Address,
11
+ IPv6Interface,
12
+ IPv6Network,
13
+ )
14
+ from pathlib import Path, PurePath
15
+ from re import Pattern
5
16
  from types import GeneratorType
6
- from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
17
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
18
+ from uuid import UUID
7
19
 
20
+ from fastapi.types import IncEx
8
21
  from pydantic import BaseModel
9
- from pydantic.json import ENCODERS_BY_TYPE
22
+ from pydantic.color import Color
23
+ from pydantic.networks import NameEmail
24
+ from pydantic.types import SecretBytes, SecretStr
10
25
 
11
- SetIntStr = Set[Union[int, str]]
12
- DictIntStrAny = Dict[Union[int, str], Any]
26
+ from ._compat import PYDANTIC_V2, MultiHostUrl, Url, _model_dump
27
+
28
+
29
+ # Taken from Pydantic v1 as is
30
+ def isoformat(o: Union[datetime.date, datetime.time]) -> str:
31
+ return o.isoformat()
32
+
33
+
34
+ # Taken from Pydantic v1 as is
35
+ # TODO: pv2 should this return strings instead?
36
+ def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
37
+ """
38
+ Encodes a Decimal as int of there's no exponent, otherwise float
39
+
40
+ This is useful when we use ConstrainedDecimal to represent Numeric(x,0)
41
+ where a integer (but not int typed) is used. Encoding this as a float
42
+ results in failed round-tripping between encode and parse.
43
+ Our Id type is a prime example of this.
44
+
45
+ >>> decimal_encoder(Decimal("1.0"))
46
+ 1.0
47
+
48
+ >>> decimal_encoder(Decimal("1"))
49
+ 1
50
+ """
51
+ if dec_value.as_tuple().exponent >= 0: # type: ignore[operator]
52
+ return int(dec_value)
53
+ else:
54
+ return float(dec_value)
55
+
56
+
57
+ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
58
+ bytes: lambda o: o.decode(),
59
+ Color: str,
60
+ datetime.date: isoformat,
61
+ datetime.datetime: isoformat,
62
+ datetime.time: isoformat,
63
+ datetime.timedelta: lambda td: td.total_seconds(),
64
+ Decimal: decimal_encoder,
65
+ Enum: lambda o: o.value,
66
+ frozenset: list,
67
+ deque: list,
68
+ GeneratorType: list,
69
+ IPv4Address: str,
70
+ IPv4Interface: str,
71
+ IPv4Network: str,
72
+ IPv6Address: str,
73
+ IPv6Interface: str,
74
+ IPv6Network: str,
75
+ NameEmail: str,
76
+ Path: str,
77
+ Pattern: lambda o: o.pattern,
78
+ SecretBytes: str,
79
+ SecretStr: str,
80
+ set: list,
81
+ UUID: str,
82
+ Url: str,
83
+ MultiHostUrl: str,
84
+ }
13
85
 
14
86
 
15
87
  def generate_encoders_by_class_tuples(
@@ -28,8 +100,8 @@ encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)
28
100
 
29
101
  def jsonable_encoder(
30
102
  obj: Any,
31
- include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
32
- exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
103
+ include: Optional[IncEx] = None,
104
+ exclude: Optional[IncEx] = None,
33
105
  by_alias: bool = True,
34
106
  exclude_unset: bool = False,
35
107
  exclude_defaults: bool = False,
@@ -50,10 +122,15 @@ def jsonable_encoder(
50
122
  if exclude is not None and not isinstance(exclude, (set, dict)):
51
123
  exclude = set(exclude)
52
124
  if isinstance(obj, BaseModel):
53
- encoder = getattr(obj.__config__, "json_encoders", {})
54
- if custom_encoder:
55
- encoder.update(custom_encoder)
56
- obj_dict = obj.dict(
125
+ # TODO: remove when deprecating Pydantic v1
126
+ encoders: Dict[Any, Any] = {}
127
+ if not PYDANTIC_V2:
128
+ encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
129
+ if custom_encoder:
130
+ encoders.update(custom_encoder)
131
+ obj_dict = _model_dump(
132
+ obj,
133
+ mode="json",
57
134
  include=include,
58
135
  exclude=exclude,
59
136
  by_alias=by_alias,
@@ -67,7 +144,8 @@ def jsonable_encoder(
67
144
  obj_dict,
68
145
  exclude_none=exclude_none,
69
146
  exclude_defaults=exclude_defaults,
70
- custom_encoder=encoder,
147
+ # TODO: remove when deprecating Pydantic v1
148
+ custom_encoder=encoders,
71
149
  sqlalchemy_safe=sqlalchemy_safe,
72
150
  )
73
151
  if dataclasses.is_dataclass(obj):
@@ -1,10 +1,11 @@
1
1
  from fastapi.encoders import jsonable_encoder
2
- from fastapi.exceptions import RequestValidationError
2
+ from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
3
3
  from fastapi.utils import is_body_allowed_for_status_code
4
+ from fastapi.websockets import WebSocket
4
5
  from starlette.exceptions import HTTPException
5
6
  from starlette.requests import Request
6
7
  from starlette.responses import JSONResponse, Response
7
- from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
8
+ from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION
8
9
 
9
10
 
10
11
  async def http_exception_handler(request: Request, exc: HTTPException) -> Response:
@@ -23,3 +24,11 @@ async def request_validation_exception_handler(
23
24
  status_code=HTTP_422_UNPROCESSABLE_ENTITY,
24
25
  content={"detail": jsonable_encoder(exc.errors())},
25
26
  )
27
+
28
+
29
+ async def websocket_request_validation_exception_handler(
30
+ websocket: WebSocket, exc: WebSocketRequestValidationError
31
+ ) -> None:
32
+ await websocket.close(
33
+ code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors())
34
+ )
fastapi/exceptions.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from typing import Any, Dict, Optional, Sequence, Type
2
2
 
3
- from pydantic import BaseModel, ValidationError, create_model
4
- from pydantic.error_wrappers import ErrorList
3
+ from pydantic import BaseModel, create_model
5
4
  from starlette.exceptions import HTTPException as StarletteHTTPException
6
5
  from starlette.exceptions import WebSocketException as WebSocketException # noqa: F401
7
6
 
@@ -26,12 +25,25 @@ class FastAPIError(RuntimeError):
26
25
  """
27
26
 
28
27
 
29
- class RequestValidationError(ValidationError):
30
- def __init__(self, errors: Sequence[ErrorList], *, body: Any = None) -> None:
28
+ class ValidationException(Exception):
29
+ def __init__(self, errors: Sequence[Any]) -> None:
30
+ self._errors = errors
31
+
32
+ def errors(self) -> Sequence[Any]:
33
+ return self._errors
34
+
35
+
36
+ class RequestValidationError(ValidationException):
37
+ def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
38
+ super().__init__(errors)
31
39
  self.body = body
32
- super().__init__(errors, RequestErrorModel)
33
40
 
34
41
 
35
- class WebSocketRequestValidationError(ValidationError):
36
- def __init__(self, errors: Sequence[ErrorList]) -> None:
37
- super().__init__(errors, WebSocketErrorModel)
42
+ class WebSocketRequestValidationError(ValidationException):
43
+ pass
44
+
45
+
46
+ class ResponseValidationError(ValidationException):
47
+ def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
48
+ super().__init__(errors)
49
+ self.body = body
@@ -10,19 +10,16 @@ class AsyncExitStackMiddleware:
10
10
  self.context_name = context_name
11
11
 
12
12
  async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
13
- if AsyncExitStack:
14
- dependency_exception: Optional[Exception] = None
15
- async with AsyncExitStack() as stack:
16
- scope[self.context_name] = stack
17
- try:
18
- await self.app(scope, receive, send)
19
- except Exception as e:
20
- dependency_exception = e
21
- raise e
22
- if dependency_exception:
23
- # This exception was possibly handled by the dependency but it should
24
- # still bubble up so that the ServerErrorMiddleware can return a 500
25
- # or the ExceptionMiddleware can catch and handle any other exceptions
26
- raise dependency_exception
27
- else:
28
- await self.app(scope, receive, send) # pragma: no cover
13
+ dependency_exception: Optional[Exception] = None
14
+ async with AsyncExitStack() as stack:
15
+ scope[self.context_name] = stack
16
+ try:
17
+ await self.app(scope, receive, send)
18
+ except Exception as e:
19
+ dependency_exception = e
20
+ raise e
21
+ if dependency_exception:
22
+ # This exception was possibly handled by the dependency but it should
23
+ # still bubble up so that the ServerErrorMiddleware can return a 500
24
+ # or the ExceptionMiddleware can catch and handle any other exceptions
25
+ raise dependency_exception
@@ -1,2 +1,3 @@
1
1
  METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"}
2
2
  REF_PREFIX = "#/components/schemas/"
3
+ REF_TEMPLATE = "#/components/schemas/{model}"
fastapi/openapi/models.py CHANGED
@@ -1,11 +1,20 @@
1
1
  from enum import Enum
2
- from typing import Any, Callable, Dict, Iterable, List, Optional, Union
3
-
2
+ from typing import Any, Callable, Dict, Iterable, List, Optional, Type, Union
3
+
4
+ from fastapi._compat import (
5
+ PYDANTIC_V2,
6
+ CoreSchema,
7
+ GetJsonSchemaHandler,
8
+ JsonSchemaValue,
9
+ _model_rebuild,
10
+ general_plain_validator_function,
11
+ )
4
12
  from fastapi.logger import logger
5
13
  from pydantic import AnyUrl, BaseModel, Field
14
+ from typing_extensions import Literal
6
15
 
7
16
  try:
8
- import email_validator # type: ignore
17
+ import email_validator
9
18
 
10
19
  assert email_validator # make autoflake ignore the unused import
11
20
  from pydantic import EmailStr
@@ -24,22 +33,52 @@ except ImportError: # pragma: no cover
24
33
  )
25
34
  return str(v)
26
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: CoreSchema, handler: GetJsonSchemaHandler
47
+ ) -> JsonSchemaValue:
48
+ return {"type": "string", "format": "email"}
49
+
50
+ @classmethod
51
+ def __get_pydantic_core_schema__(
52
+ cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
53
+ ) -> CoreSchema:
54
+ return general_plain_validator_function(cls._validate)
55
+
27
56
 
28
57
  class Contact(BaseModel):
29
58
  name: Optional[str] = None
30
59
  url: Optional[AnyUrl] = None
31
60
  email: Optional[EmailStr] = None
32
61
 
33
- class Config:
34
- extra = "allow"
62
+ if PYDANTIC_V2:
63
+ model_config = {"extra": "allow"}
64
+
65
+ else:
66
+
67
+ class Config:
68
+ extra = "allow"
35
69
 
36
70
 
37
71
  class License(BaseModel):
38
72
  name: str
39
73
  url: Optional[AnyUrl] = None
40
74
 
41
- class Config:
42
- extra = "allow"
75
+ if PYDANTIC_V2:
76
+ model_config = {"extra": "allow"}
77
+
78
+ else:
79
+
80
+ class Config:
81
+ extra = "allow"
43
82
 
44
83
 
45
84
  class Info(BaseModel):
@@ -50,8 +89,13 @@ class Info(BaseModel):
50
89
  license: Optional[License] = None
51
90
  version: str
52
91
 
53
- class Config:
54
- extra = "allow"
92
+ if PYDANTIC_V2:
93
+ model_config = {"extra": "allow"}
94
+
95
+ else:
96
+
97
+ class Config:
98
+ extra = "allow"
55
99
 
56
100
 
57
101
  class ServerVariable(BaseModel):
@@ -59,8 +103,13 @@ class ServerVariable(BaseModel):
59
103
  default: str
60
104
  description: Optional[str] = None
61
105
 
62
- class Config:
63
- extra = "allow"
106
+ if PYDANTIC_V2:
107
+ model_config = {"extra": "allow"}
108
+
109
+ else:
110
+
111
+ class Config:
112
+ extra = "allow"
64
113
 
65
114
 
66
115
  class Server(BaseModel):
@@ -68,8 +117,13 @@ class Server(BaseModel):
68
117
  description: Optional[str] = None
69
118
  variables: Optional[Dict[str, ServerVariable]] = None
70
119
 
71
- class Config:
72
- extra = "allow"
120
+ if PYDANTIC_V2:
121
+ model_config = {"extra": "allow"}
122
+
123
+ else:
124
+
125
+ class Config:
126
+ extra = "allow"
73
127
 
74
128
 
75
129
  class Reference(BaseModel):
@@ -88,16 +142,26 @@ class XML(BaseModel):
88
142
  attribute: Optional[bool] = None
89
143
  wrapped: Optional[bool] = None
90
144
 
91
- class Config:
92
- extra = "allow"
145
+ if PYDANTIC_V2:
146
+ model_config = {"extra": "allow"}
147
+
148
+ else:
149
+
150
+ class Config:
151
+ extra = "allow"
93
152
 
94
153
 
95
154
  class ExternalDocumentation(BaseModel):
96
155
  description: Optional[str] = None
97
156
  url: AnyUrl
98
157
 
99
- class Config:
100
- extra = "allow"
158
+ if PYDANTIC_V2:
159
+ model_config = {"extra": "allow"}
160
+
161
+ else:
162
+
163
+ class Config:
164
+ extra = "allow"
101
165
 
102
166
 
103
167
  class Schema(BaseModel):
@@ -138,8 +202,13 @@ class Schema(BaseModel):
138
202
  example: Optional[Any] = None
139
203
  deprecated: Optional[bool] = None
140
204
 
141
- class Config:
142
- extra: str = "allow"
205
+ if PYDANTIC_V2:
206
+ model_config = {"extra": "allow"}
207
+
208
+ else:
209
+
210
+ class Config:
211
+ extra = "allow"
143
212
 
144
213
 
145
214
  class Example(BaseModel):
@@ -148,8 +217,13 @@ class Example(BaseModel):
148
217
  value: Optional[Any] = None
149
218
  externalValue: Optional[AnyUrl] = None
150
219
 
151
- class Config:
152
- extra = "allow"
220
+ if PYDANTIC_V2:
221
+ model_config = {"extra": "allow"}
222
+
223
+ else:
224
+
225
+ class Config:
226
+ extra = "allow"
153
227
 
154
228
 
155
229
  class ParameterInType(Enum):
@@ -166,8 +240,13 @@ class Encoding(BaseModel):
166
240
  explode: Optional[bool] = None
167
241
  allowReserved: Optional[bool] = None
168
242
 
169
- class Config:
170
- extra = "allow"
243
+ if PYDANTIC_V2:
244
+ model_config = {"extra": "allow"}
245
+
246
+ else:
247
+
248
+ class Config:
249
+ extra = "allow"
171
250
 
172
251
 
173
252
  class MediaType(BaseModel):
@@ -176,8 +255,13 @@ class MediaType(BaseModel):
176
255
  examples: Optional[Dict[str, Union[Example, Reference]]] = None
177
256
  encoding: Optional[Dict[str, Encoding]] = None
178
257
 
179
- class Config:
180
- extra = "allow"
258
+ if PYDANTIC_V2:
259
+ model_config = {"extra": "allow"}
260
+
261
+ else:
262
+
263
+ class Config:
264
+ extra = "allow"
181
265
 
182
266
 
183
267
  class ParameterBase(BaseModel):
@@ -194,8 +278,13 @@ class ParameterBase(BaseModel):
194
278
  # Serialization rules for more complex scenarios
195
279
  content: Optional[Dict[str, MediaType]] = None
196
280
 
197
- class Config:
198
- extra = "allow"
281
+ if PYDANTIC_V2:
282
+ model_config = {"extra": "allow"}
283
+
284
+ else:
285
+
286
+ class Config:
287
+ extra = "allow"
199
288
 
200
289
 
201
290
  class Parameter(ParameterBase):
@@ -212,8 +301,13 @@ class RequestBody(BaseModel):
212
301
  content: Dict[str, MediaType]
213
302
  required: Optional[bool] = None
214
303
 
215
- class Config:
216
- extra = "allow"
304
+ if PYDANTIC_V2:
305
+ model_config = {"extra": "allow"}
306
+
307
+ else:
308
+
309
+ class Config:
310
+ extra = "allow"
217
311
 
218
312
 
219
313
  class Link(BaseModel):
@@ -224,8 +318,13 @@ class Link(BaseModel):
224
318
  description: Optional[str] = None
225
319
  server: Optional[Server] = None
226
320
 
227
- class Config:
228
- extra = "allow"
321
+ if PYDANTIC_V2:
322
+ model_config = {"extra": "allow"}
323
+
324
+ else:
325
+
326
+ class Config:
327
+ extra = "allow"
229
328
 
230
329
 
231
330
  class Response(BaseModel):
@@ -234,8 +333,13 @@ class Response(BaseModel):
234
333
  content: Optional[Dict[str, MediaType]] = None
235
334
  links: Optional[Dict[str, Union[Link, Reference]]] = None
236
335
 
237
- class Config:
238
- extra = "allow"
336
+ if PYDANTIC_V2:
337
+ model_config = {"extra": "allow"}
338
+
339
+ else:
340
+
341
+ class Config:
342
+ extra = "allow"
239
343
 
240
344
 
241
345
  class Operation(BaseModel):
@@ -253,8 +357,13 @@ class Operation(BaseModel):
253
357
  security: Optional[List[Dict[str, List[str]]]] = None
254
358
  servers: Optional[List[Server]] = None
255
359
 
256
- class Config:
257
- extra = "allow"
360
+ if PYDANTIC_V2:
361
+ model_config = {"extra": "allow"}
362
+
363
+ else:
364
+
365
+ class Config:
366
+ extra = "allow"
258
367
 
259
368
 
260
369
  class PathItem(BaseModel):
@@ -272,8 +381,13 @@ class PathItem(BaseModel):
272
381
  servers: Optional[List[Server]] = None
273
382
  parameters: Optional[List[Union[Parameter, Reference]]] = None
274
383
 
275
- class Config:
276
- extra = "allow"
384
+ if PYDANTIC_V2:
385
+ model_config = {"extra": "allow"}
386
+
387
+ else:
388
+
389
+ class Config:
390
+ extra = "allow"
277
391
 
278
392
 
279
393
  class SecuritySchemeType(Enum):
@@ -287,8 +401,13 @@ class SecurityBase(BaseModel):
287
401
  type_: SecuritySchemeType = Field(alias="type")
288
402
  description: Optional[str] = None
289
403
 
290
- class Config:
291
- extra = "allow"
404
+ if PYDANTIC_V2:
405
+ model_config = {"extra": "allow"}
406
+
407
+ else:
408
+
409
+ class Config:
410
+ extra = "allow"
292
411
 
293
412
 
294
413
  class APIKeyIn(Enum):
@@ -298,18 +417,18 @@ class APIKeyIn(Enum):
298
417
 
299
418
 
300
419
  class APIKey(SecurityBase):
301
- type_ = Field(SecuritySchemeType.apiKey, alias="type")
420
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type")
302
421
  in_: APIKeyIn = Field(alias="in")
303
422
  name: str
304
423
 
305
424
 
306
425
  class HTTPBase(SecurityBase):
307
- type_ = Field(SecuritySchemeType.http, alias="type")
426
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type")
308
427
  scheme: str
309
428
 
310
429
 
311
430
  class HTTPBearer(HTTPBase):
312
- scheme = "bearer"
431
+ scheme: Literal["bearer"] = "bearer"
313
432
  bearerFormat: Optional[str] = None
314
433
 
315
434
 
@@ -317,8 +436,13 @@ class OAuthFlow(BaseModel):
317
436
  refreshUrl: Optional[str] = None
318
437
  scopes: Dict[str, str] = {}
319
438
 
320
- class Config:
321
- extra = "allow"
439
+ if PYDANTIC_V2:
440
+ model_config = {"extra": "allow"}
441
+
442
+ else:
443
+
444
+ class Config:
445
+ extra = "allow"
322
446
 
323
447
 
324
448
  class OAuthFlowImplicit(OAuthFlow):
@@ -344,17 +468,24 @@ class OAuthFlows(BaseModel):
344
468
  clientCredentials: Optional[OAuthFlowClientCredentials] = None
345
469
  authorizationCode: Optional[OAuthFlowAuthorizationCode] = None
346
470
 
347
- class Config:
348
- extra = "allow"
471
+ if PYDANTIC_V2:
472
+ model_config = {"extra": "allow"}
473
+
474
+ else:
475
+
476
+ class Config:
477
+ extra = "allow"
349
478
 
350
479
 
351
480
  class OAuth2(SecurityBase):
352
- type_ = Field(SecuritySchemeType.oauth2, alias="type")
481
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type")
353
482
  flows: OAuthFlows
354
483
 
355
484
 
356
485
  class OpenIdConnect(SecurityBase):
357
- type_ = Field(SecuritySchemeType.openIdConnect, alias="type")
486
+ type_: SecuritySchemeType = Field(
487
+ default=SecuritySchemeType.openIdConnect, alias="type"
488
+ )
358
489
  openIdConnectUrl: str
359
490
 
360
491
 
@@ -373,8 +504,13 @@ class Components(BaseModel):
373
504
  # Using Any for Specification Extensions
374
505
  callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None
375
506
 
376
- class Config:
377
- extra = "allow"
507
+ if PYDANTIC_V2:
508
+ model_config = {"extra": "allow"}
509
+
510
+ else:
511
+
512
+ class Config:
513
+ extra = "allow"
378
514
 
379
515
 
380
516
  class Tag(BaseModel):
@@ -382,8 +518,13 @@ class Tag(BaseModel):
382
518
  description: Optional[str] = None
383
519
  externalDocs: Optional[ExternalDocumentation] = None
384
520
 
385
- class Config:
386
- extra = "allow"
521
+ if PYDANTIC_V2:
522
+ model_config = {"extra": "allow"}
523
+
524
+ else:
525
+
526
+ class Config:
527
+ extra = "allow"
387
528
 
388
529
 
389
530
  class OpenAPI(BaseModel):
@@ -397,10 +538,15 @@ class OpenAPI(BaseModel):
397
538
  tags: Optional[List[Tag]] = None
398
539
  externalDocs: Optional[ExternalDocumentation] = None
399
540
 
400
- class Config:
401
- extra = "allow"
541
+ if PYDANTIC_V2:
542
+ model_config = {"extra": "allow"}
543
+
544
+ else:
545
+
546
+ class Config:
547
+ extra = "allow"
402
548
 
403
549
 
404
- Schema.update_forward_refs()
405
- Operation.update_forward_refs()
406
- Encoding.update_forward_refs()
550
+ _model_rebuild(Schema)
551
+ _model_rebuild(Operation)
552
+ _model_rebuild(Encoding)