otterapi 0.0.5__py3-none-any.whl → 0.0.6__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.
Files changed (52) hide show
  1. README.md +581 -8
  2. otterapi/__init__.py +73 -0
  3. otterapi/cli.py +327 -29
  4. otterapi/codegen/__init__.py +115 -0
  5. otterapi/codegen/ast_utils.py +134 -5
  6. otterapi/codegen/client.py +1271 -0
  7. otterapi/codegen/codegen.py +1736 -0
  8. otterapi/codegen/dataframes.py +392 -0
  9. otterapi/codegen/emitter.py +473 -0
  10. otterapi/codegen/endpoints.py +2597 -343
  11. otterapi/codegen/pagination.py +1026 -0
  12. otterapi/codegen/schema.py +593 -0
  13. otterapi/codegen/splitting.py +1397 -0
  14. otterapi/codegen/types.py +1345 -0
  15. otterapi/codegen/utils.py +180 -1
  16. otterapi/config.py +1017 -24
  17. otterapi/exceptions.py +231 -0
  18. otterapi/openapi/__init__.py +46 -0
  19. otterapi/openapi/v2/__init__.py +86 -0
  20. otterapi/openapi/v2/spec.json +1607 -0
  21. otterapi/openapi/v2/v2.py +1776 -0
  22. otterapi/openapi/v3/__init__.py +131 -0
  23. otterapi/openapi/v3/spec.json +1651 -0
  24. otterapi/openapi/v3/v3.py +1557 -0
  25. otterapi/openapi/v3_1/__init__.py +133 -0
  26. otterapi/openapi/v3_1/spec.json +1411 -0
  27. otterapi/openapi/v3_1/v3_1.py +798 -0
  28. otterapi/openapi/v3_2/__init__.py +133 -0
  29. otterapi/openapi/v3_2/spec.json +1666 -0
  30. otterapi/openapi/v3_2/v3_2.py +777 -0
  31. otterapi/tests/__init__.py +3 -0
  32. otterapi/tests/fixtures/__init__.py +455 -0
  33. otterapi/tests/test_ast_utils.py +680 -0
  34. otterapi/tests/test_codegen.py +610 -0
  35. otterapi/tests/test_dataframe.py +1038 -0
  36. otterapi/tests/test_exceptions.py +493 -0
  37. otterapi/tests/test_openapi_support.py +616 -0
  38. otterapi/tests/test_openapi_upgrade.py +215 -0
  39. otterapi/tests/test_pagination.py +1101 -0
  40. otterapi/tests/test_splitting_config.py +319 -0
  41. otterapi/tests/test_splitting_integration.py +427 -0
  42. otterapi/tests/test_splitting_resolver.py +512 -0
  43. otterapi/tests/test_splitting_tree.py +525 -0
  44. otterapi-0.0.6.dist-info/METADATA +627 -0
  45. otterapi-0.0.6.dist-info/RECORD +48 -0
  46. {otterapi-0.0.5.dist-info → otterapi-0.0.6.dist-info}/WHEEL +1 -1
  47. otterapi/codegen/generator.py +0 -358
  48. otterapi/codegen/openapi_processor.py +0 -27
  49. otterapi/codegen/type_generator.py +0 -559
  50. otterapi-0.0.5.dist-info/METADATA +0 -54
  51. otterapi-0.0.5.dist-info/RECORD +0 -16
  52. {otterapi-0.0.5.dist-info → otterapi-0.0.6.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,798 @@
1
+ """OpenAPI 3.1 specification models.
2
+
3
+ This module provides Pydantic models for the OpenAPI 3.1 specification,
4
+ which is aligned with JSON Schema 2020-12.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+ from enum import Enum
11
+ from typing import TYPE_CHECKING, Annotated, Any, Union
12
+
13
+ from pydantic import (
14
+ AnyUrl,
15
+ BaseModel,
16
+ ConfigDict,
17
+ Field,
18
+ PositiveFloat,
19
+ RootModel,
20
+ )
21
+
22
+ if TYPE_CHECKING:
23
+ from ..v3_2 import v3_2
24
+
25
+
26
+ class Reference(BaseModel):
27
+ """Reference object for OpenAPI 3.1."""
28
+
29
+ ref: str = Field(..., alias='$ref')
30
+ summary: str | None = None
31
+ description: str | None = None
32
+
33
+
34
+ class Contact(BaseModel):
35
+ """Contact information for the API."""
36
+
37
+ model_config = ConfigDict(extra='forbid')
38
+
39
+ name: str | None = None
40
+ url: str | None = None
41
+ email: str | None = (
42
+ None # Using str instead of EmailStr to avoid optional dependency
43
+ )
44
+
45
+
46
+ class License(BaseModel):
47
+ """License information for the API."""
48
+
49
+ model_config = ConfigDict(extra='forbid')
50
+
51
+ name: str
52
+ identifier: str | None = None
53
+ url: str | None = None
54
+
55
+
56
+ class ServerVariable(BaseModel):
57
+ """Server variable for URL templating."""
58
+
59
+ model_config = ConfigDict(extra='forbid')
60
+
61
+ enum: list[str] | None = None
62
+ default: str
63
+ description: str | None = None
64
+
65
+
66
+ class Type(Enum):
67
+ """JSON Schema types."""
68
+
69
+ array = 'array'
70
+ boolean = 'boolean'
71
+ integer = 'integer'
72
+ number = 'number'
73
+ object = 'object'
74
+ string = 'string'
75
+ null = 'null'
76
+
77
+
78
+ class Discriminator(BaseModel):
79
+ """Discriminator for polymorphism."""
80
+
81
+ propertyName: str
82
+ mapping: dict[str, str] | None = None
83
+
84
+
85
+ class XML(BaseModel):
86
+ """XML representation metadata."""
87
+
88
+ model_config = ConfigDict(extra='forbid')
89
+
90
+ name: str | None = None
91
+ namespace: AnyUrl | None = None
92
+ prefix: str | None = None
93
+ attribute: bool | None = False
94
+ wrapped: bool | None = False
95
+
96
+
97
+ class Example(BaseModel):
98
+ """Example object."""
99
+
100
+ model_config = ConfigDict(extra='forbid')
101
+
102
+ summary: str | None = None
103
+ description: str | None = None
104
+ value: Any | None = None
105
+ externalValue: str | None = None
106
+
107
+
108
+ class Style(Enum):
109
+ """Parameter style for simple parameters."""
110
+
111
+ simple = 'simple'
112
+
113
+
114
+ class SecurityRequirement(RootModel[dict[str, list[str]]]):
115
+ """Security requirement object."""
116
+
117
+ root: dict[str, list[str]]
118
+
119
+
120
+ class ExternalDocumentation(BaseModel):
121
+ """External documentation reference."""
122
+
123
+ model_config = ConfigDict(extra='forbid')
124
+
125
+ description: str | None = None
126
+ url: str
127
+
128
+
129
+ class ExampleXORExamples(RootModel[Any]):
130
+ """Ensures example and examples are mutually exclusive."""
131
+
132
+ root: Any = Field(..., description='Example and examples are mutually exclusive')
133
+
134
+
135
+ class SchemaXORContent1(BaseModel):
136
+ """Helper for schema/content mutual exclusion."""
137
+
138
+ pass
139
+
140
+
141
+ class SchemaXORContent(RootModel[Any | SchemaXORContent1]):
142
+ """Ensures schema and content are mutually exclusive."""
143
+
144
+ root: Any | SchemaXORContent1 = Field(
145
+ ...,
146
+ description='Schema and content are mutually exclusive, at least one is required',
147
+ )
148
+
149
+
150
+ class In(Enum):
151
+ """Path parameter location."""
152
+
153
+ path = 'path'
154
+
155
+
156
+ class Style1(Enum):
157
+ """Path parameter styles."""
158
+
159
+ matrix = 'matrix'
160
+ label = 'label'
161
+ simple = 'simple'
162
+
163
+
164
+ class Required(Enum):
165
+ """Required enum for path parameters."""
166
+
167
+ bool_True = True
168
+
169
+
170
+ class PathParameter(BaseModel):
171
+ """Path parameter definition."""
172
+
173
+ in_: In | None = Field(None, alias='in')
174
+ style: Style1 | None = 'simple'
175
+ required: Required
176
+
177
+
178
+ class In1(Enum):
179
+ """Query parameter location."""
180
+
181
+ query = 'query'
182
+
183
+
184
+ class Style2(Enum):
185
+ """Query parameter styles."""
186
+
187
+ form = 'form'
188
+ spaceDelimited = 'spaceDelimited'
189
+ pipeDelimited = 'pipeDelimited'
190
+ deepObject = 'deepObject'
191
+
192
+
193
+ class QueryParameter(BaseModel):
194
+ """Query parameter definition."""
195
+
196
+ in_: In1 | None = Field(None, alias='in')
197
+ style: Style2 | None = 'form'
198
+
199
+
200
+ class In2(Enum):
201
+ """Header parameter location."""
202
+
203
+ header = 'header'
204
+
205
+
206
+ class Style3(Enum):
207
+ """Header parameter style."""
208
+
209
+ simple = 'simple'
210
+
211
+
212
+ class HeaderParameter(BaseModel):
213
+ """Header parameter definition."""
214
+
215
+ in_: In2 | None = Field(None, alias='in')
216
+ style: Style3 | None = 'simple'
217
+
218
+
219
+ class In3(Enum):
220
+ """Cookie parameter location."""
221
+
222
+ cookie = 'cookie'
223
+
224
+
225
+ class Style4(Enum):
226
+ """Cookie parameter style."""
227
+
228
+ form = 'form'
229
+
230
+
231
+ class CookieParameter(BaseModel):
232
+ """Cookie parameter definition."""
233
+
234
+ in_: In3 | None = Field(None, alias='in')
235
+ style: Style4 | None = 'form'
236
+
237
+
238
+ class Type1(Enum):
239
+ """API Key security type."""
240
+
241
+ apiKey = 'apiKey'
242
+
243
+
244
+ class In4(Enum):
245
+ """API Key location."""
246
+
247
+ header = 'header'
248
+ query = 'query'
249
+ cookie = 'cookie'
250
+
251
+
252
+ class APIKeySecurityScheme(BaseModel):
253
+ """API Key security scheme."""
254
+
255
+ model_config = ConfigDict(extra='forbid')
256
+
257
+ type: Type1
258
+ name: str
259
+ in_: In4 = Field(..., alias='in')
260
+ description: str | None = None
261
+
262
+
263
+ class Type2(Enum):
264
+ """HTTP security type."""
265
+
266
+ http = 'http'
267
+
268
+
269
+ class HTTPSecurityScheme1(BaseModel):
270
+ """HTTP Bearer security scheme."""
271
+
272
+ model_config = ConfigDict(extra='forbid')
273
+
274
+ scheme: Annotated[str, Field(pattern=r'^[Bb][Ee][Aa][Rr][Ee][Rr]$')]
275
+ bearerFormat: str | None = None
276
+ description: str | None = None
277
+ type: Type2
278
+
279
+
280
+ class HTTPSecurityScheme2(BaseModel):
281
+ """HTTP non-Bearer security scheme."""
282
+
283
+ model_config = ConfigDict(extra='forbid')
284
+
285
+ scheme: str
286
+ bearerFormat: str | None = None
287
+ description: str | None = None
288
+ type: Type2
289
+
290
+
291
+ class HTTPSecurityScheme(RootModel[HTTPSecurityScheme1 | HTTPSecurityScheme2]):
292
+ """HTTP security scheme union."""
293
+
294
+ root: HTTPSecurityScheme1 | HTTPSecurityScheme2
295
+
296
+
297
+ class Type4(Enum):
298
+ """OAuth2 security type."""
299
+
300
+ oauth2 = 'oauth2'
301
+
302
+
303
+ class Type5(Enum):
304
+ """OpenID Connect security type."""
305
+
306
+ openIdConnect = 'openIdConnect'
307
+
308
+
309
+ class OpenIdConnectSecurityScheme(BaseModel):
310
+ """OpenID Connect security scheme."""
311
+
312
+ model_config = ConfigDict(extra='forbid')
313
+
314
+ type: Type5
315
+ openIdConnectUrl: str
316
+ description: str | None = None
317
+
318
+
319
+ class ImplicitOAuthFlow(BaseModel):
320
+ """OAuth2 implicit flow."""
321
+
322
+ model_config = ConfigDict(extra='forbid')
323
+
324
+ authorizationUrl: str
325
+ refreshUrl: str | None = None
326
+ scopes: dict[str, str]
327
+
328
+
329
+ class PasswordOAuthFlow(BaseModel):
330
+ """OAuth2 password flow."""
331
+
332
+ model_config = ConfigDict(extra='forbid')
333
+
334
+ tokenUrl: str
335
+ refreshUrl: str | None = None
336
+ scopes: dict[str, str]
337
+
338
+
339
+ class ClientCredentialsFlow(BaseModel):
340
+ """OAuth2 client credentials flow."""
341
+
342
+ model_config = ConfigDict(extra='forbid')
343
+
344
+ tokenUrl: str
345
+ refreshUrl: str | None = None
346
+ scopes: dict[str, str]
347
+
348
+
349
+ class AuthorizationCodeOAuthFlow(BaseModel):
350
+ """OAuth2 authorization code flow."""
351
+
352
+ model_config = ConfigDict(extra='forbid')
353
+
354
+ authorizationUrl: str
355
+ tokenUrl: str
356
+ refreshUrl: str | None = None
357
+ scopes: dict[str, str]
358
+
359
+
360
+ class Callback(RootModel[dict[Annotated[str, Field(pattern=r'^x-')], Any]]):
361
+ """Callback object."""
362
+
363
+ root: dict[Annotated[str, Field(pattern=r'^x-')], Any]
364
+
365
+
366
+ class Style5(Enum):
367
+ """Encoding styles."""
368
+
369
+ form = 'form'
370
+ spaceDelimited = 'spaceDelimited'
371
+ pipeDelimited = 'pipeDelimited'
372
+ deepObject = 'deepObject'
373
+
374
+
375
+ class Info(BaseModel):
376
+ """API metadata."""
377
+
378
+ model_config = ConfigDict(extra='forbid')
379
+
380
+ title: str
381
+ summary: str | None = None
382
+ description: str | None = None
383
+ termsOfService: str | None = None
384
+ contact: Contact | None = None
385
+ license: License | None = None
386
+ version: str
387
+
388
+
389
+ class Server(BaseModel):
390
+ """Server object."""
391
+
392
+ model_config = ConfigDict(extra='forbid')
393
+
394
+ url: str
395
+ description: str | None = None
396
+ variables: dict[str, ServerVariable] | None = None
397
+
398
+
399
+ class Schema(BaseModel):
400
+ """JSON Schema object for OpenAPI 3.1.
401
+
402
+ OpenAPI 3.1 uses JSON Schema 2020-12 with some modifications.
403
+ """
404
+
405
+ model_config = ConfigDict(extra='forbid')
406
+
407
+ # Core JSON Schema keywords
408
+ title: str | None = None
409
+ multipleOf: PositiveFloat | None = None
410
+ maximum: float | None = None
411
+ exclusiveMaximum: float | None = None # Changed from boolean in 3.0
412
+ minimum: float | None = None
413
+ exclusiveMinimum: float | None = None # Changed from boolean in 3.0
414
+ maxLength: Annotated[int, Field(ge=0)] | None = None
415
+ minLength: Annotated[int, Field(ge=0)] | None = 0
416
+ pattern: str | None = None
417
+ maxItems: Annotated[int, Field(ge=0)] | None = None
418
+ minItems: Annotated[int, Field(ge=0)] | None = 0
419
+ uniqueItems: bool | None = False
420
+ maxProperties: Annotated[int, Field(ge=0)] | None = None
421
+ minProperties: Annotated[int, Field(ge=0)] | None = 0
422
+ required: list[str] | None = None
423
+ enum: list[Any] | None = None
424
+
425
+ # Type can now be an array for nullable types
426
+ type: Type | list[Type] | None = None
427
+
428
+ # Composition keywords
429
+ not_: Schema | Reference | None = Field(None, alias='not')
430
+ allOf: list[Schema | Reference] | None = None
431
+ oneOf: list[Schema | Reference] | None = None
432
+ anyOf: list[Schema | Reference] | None = None
433
+
434
+ # Array keywords
435
+ items: Schema | Reference | None = None
436
+ prefixItems: list[Schema | Reference] | None = None # New in 3.1
437
+
438
+ # Object keywords
439
+ properties: dict[str, Schema | Reference] | None = None
440
+ additionalProperties: Schema | Reference | bool | None = True
441
+ patternProperties: dict[str, Schema | Reference] | None = None # New in 3.1
442
+
443
+ # String keywords
444
+ format: str | None = None
445
+
446
+ # Metadata
447
+ description: str | None = None
448
+ default: Any | None = None
449
+
450
+ # OpenAPI-specific keywords
451
+ discriminator: Discriminator | None = None
452
+ readOnly: bool | None = False
453
+ writeOnly: bool | None = False
454
+ example: Any | None = None
455
+ examples: list[Any] | None = None # New in 3.1
456
+ externalDocs: ExternalDocumentation | None = None
457
+ deprecated: bool | None = False
458
+ xml: XML | None = None
459
+
460
+ # Note: nullable is removed in 3.1, use type arrays instead
461
+
462
+
463
+ class Tag(BaseModel):
464
+ """Tag for API operations."""
465
+
466
+ model_config = ConfigDict(extra='forbid')
467
+
468
+ name: str
469
+ description: str | None = None
470
+ externalDocs: ExternalDocumentation | None = None
471
+
472
+
473
+ class OAuthFlows(BaseModel):
474
+ """OAuth2 flows configuration."""
475
+
476
+ model_config = ConfigDict(extra='forbid')
477
+
478
+ implicit: ImplicitOAuthFlow | None = None
479
+ password: PasswordOAuthFlow | None = None
480
+ clientCredentials: ClientCredentialsFlow | None = None
481
+ authorizationCode: AuthorizationCodeOAuthFlow | None = None
482
+
483
+
484
+ class Link(BaseModel):
485
+ """Link object for response links."""
486
+
487
+ model_config = ConfigDict(extra='forbid')
488
+
489
+ operationId: str | None = None
490
+ operationRef: str | None = None
491
+ parameters: dict[str, Any] | None = None
492
+ requestBody: Any | None = None
493
+ description: str | None = None
494
+ server: Server | None = None
495
+
496
+
497
+ class OAuth2SecurityScheme(BaseModel):
498
+ """OAuth2 security scheme."""
499
+
500
+ model_config = ConfigDict(extra='forbid')
501
+
502
+ type: Type4
503
+ flows: OAuthFlows
504
+ description: str | None = None
505
+
506
+
507
+ class SecurityScheme(
508
+ RootModel[
509
+ APIKeySecurityScheme
510
+ | HTTPSecurityScheme
511
+ | OAuth2SecurityScheme
512
+ | OpenIdConnectSecurityScheme
513
+ ]
514
+ ):
515
+ """Security scheme union."""
516
+
517
+ root: (
518
+ APIKeySecurityScheme
519
+ | HTTPSecurityScheme
520
+ | OAuth2SecurityScheme
521
+ | OpenIdConnectSecurityScheme
522
+ )
523
+
524
+
525
+ class Components(BaseModel):
526
+ """Components object for reusable definitions."""
527
+
528
+ model_config = ConfigDict(extra='forbid')
529
+
530
+ schemas: (
531
+ dict[Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')], Schema | Reference]
532
+ | None
533
+ ) = None
534
+ responses: (
535
+ dict[
536
+ Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')], Reference | Response
537
+ ]
538
+ | None
539
+ ) = None
540
+ parameters: (
541
+ dict[
542
+ Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')], Reference | Parameter
543
+ ]
544
+ | None
545
+ ) = None
546
+ examples: (
547
+ dict[Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')], Reference | Example]
548
+ | None
549
+ ) = None
550
+ requestBodies: (
551
+ dict[
552
+ Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')],
553
+ Reference | RequestBody,
554
+ ]
555
+ | None
556
+ ) = None
557
+ headers: (
558
+ dict[Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')], Reference | Header]
559
+ | None
560
+ ) = None
561
+ securitySchemes: (
562
+ dict[
563
+ Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')],
564
+ Reference | SecurityScheme,
565
+ ]
566
+ | None
567
+ ) = None
568
+ links: (
569
+ dict[Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')], Reference | Link]
570
+ | None
571
+ ) = None
572
+ callbacks: (
573
+ dict[
574
+ Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')], Reference | Callback
575
+ ]
576
+ | None
577
+ ) = None
578
+ pathItems: (
579
+ dict[
580
+ Annotated[str, Field(pattern=r'^[a-zA-Z0-9\.\-_]+$')], Reference | PathItem
581
+ ]
582
+ | None
583
+ ) = None # New in 3.1
584
+
585
+
586
+ class Response(BaseModel):
587
+ """Response object."""
588
+
589
+ model_config = ConfigDict(extra='forbid')
590
+
591
+ description: str
592
+ headers: dict[str, Header | Reference] | None = None
593
+ content: dict[str, MediaType] | None = None
594
+ links: dict[str, Link | Reference] | None = None
595
+
596
+
597
+ class MediaType(BaseModel):
598
+ """Media type object."""
599
+
600
+ model_config = ConfigDict(extra='forbid')
601
+
602
+ schema_: Schema | Reference | None = Field(None, alias='schema')
603
+ example: Any | None = None
604
+ examples: dict[str, Example | Reference] | None = None
605
+ encoding: dict[str, Encoding] | None = None
606
+
607
+
608
+ class Header(BaseModel):
609
+ """Header object."""
610
+
611
+ model_config = ConfigDict(extra='forbid')
612
+
613
+ description: str | None = None
614
+ required: bool | None = False
615
+ deprecated: bool | None = False
616
+ allowEmptyValue: bool | None = False
617
+ style: Style | None = 'simple'
618
+ explode: bool | None = None
619
+ allowReserved: bool | None = False
620
+ schema_: Schema | Reference | None = Field(None, alias='schema')
621
+ content: dict[str, MediaType] | None = None
622
+ example: Any | None = None
623
+ examples: dict[str, Example | Reference] | None = None
624
+
625
+
626
+ class Paths(RootModel[dict[str, 'PathItem']]):
627
+ """Paths object.
628
+
629
+ Keys should be path templates (starting with /) or extensions (starting with x-).
630
+ """
631
+
632
+ root: dict[str, PathItem]
633
+
634
+
635
+ class PathItem(BaseModel):
636
+ """Path item object."""
637
+
638
+ model_config = ConfigDict(extra='forbid')
639
+
640
+ field_ref: str | None = Field(None, alias='$ref')
641
+ summary: str | None = None
642
+ description: str | None = None
643
+ get: Operation | None = None
644
+ put: Operation | None = None
645
+ post: Operation | None = None
646
+ delete: Operation | None = None
647
+ options: Operation | None = None
648
+ head: Operation | None = None
649
+ patch: Operation | None = None
650
+ trace: Operation | None = None
651
+ servers: list[Server] | None = None
652
+ parameters: list[Parameter | Reference] | None = None
653
+
654
+
655
+ class Operation(BaseModel):
656
+ """Operation object."""
657
+
658
+ model_config = ConfigDict(extra='forbid')
659
+
660
+ tags: list[str] | None = None
661
+ summary: str | None = None
662
+ description: str | None = None
663
+ externalDocs: ExternalDocumentation | None = None
664
+ operationId: str | None = None
665
+ parameters: list[Parameter | Reference] | None = None
666
+ requestBody: RequestBody | Reference | None = None
667
+ responses: Responses | None = None # Made optional in 3.1
668
+ callbacks: dict[str, Callback | Reference] | None = None
669
+ deprecated: bool | None = False
670
+ security: list[SecurityRequirement] | None = None
671
+ servers: list[Server] | None = None
672
+
673
+
674
+ class Responses(RootModel[dict[str, Response | Reference]]):
675
+ """Responses object containing response definitions by HTTP status code.
676
+
677
+ Keys are HTTP status codes (200, 400, etc.) or 'default'.
678
+ """
679
+
680
+ pass
681
+
682
+
683
+ class Parameter(BaseModel):
684
+ """Parameter object."""
685
+
686
+ model_config = ConfigDict(extra='forbid')
687
+
688
+ name: str
689
+ in_: str = Field(..., alias='in')
690
+ description: str | None = None
691
+ required: bool | None = False
692
+ deprecated: bool | None = False
693
+ allowEmptyValue: bool | None = False
694
+ style: str | None = None
695
+ explode: bool | None = None
696
+ allowReserved: bool | None = False
697
+ schema_: Schema | Reference | None = Field(None, alias='schema')
698
+ content: dict[str, MediaType] | None = None
699
+ example: Any | None = None
700
+ examples: dict[str, Example | Reference] | None = None
701
+
702
+
703
+ class RequestBody(BaseModel):
704
+ """Request body object."""
705
+
706
+ model_config = ConfigDict(extra='forbid')
707
+
708
+ description: str | None = None
709
+ content: dict[str, MediaType]
710
+ required: bool | None = False
711
+
712
+
713
+ class Encoding(BaseModel):
714
+ """Encoding object."""
715
+
716
+ model_config = ConfigDict(extra='forbid')
717
+
718
+ contentType: str | None = None
719
+ headers: dict[str, Header | Reference] | None = None
720
+ style: Style5 | None = None
721
+ explode: bool | None = None
722
+ allowReserved: bool | None = False
723
+
724
+
725
+ class Webhook(RootModel[dict[str, Union['PathItem', Reference]]]):
726
+ """Webhook object (new in OpenAPI 3.1)."""
727
+
728
+ root: dict[str, PathItem | Reference]
729
+
730
+
731
+ class OpenAPI(BaseModel):
732
+ """OpenAPI 3.1 root document."""
733
+
734
+ model_config = ConfigDict(extra='forbid')
735
+
736
+ openapi: Annotated[str, Field(pattern=r'^3\.1\.\d+(-.+)?$')] # Updated for 3.1.x
737
+ info: Info
738
+ jsonSchemaDialect: str | None = (
739
+ 'https://spec.openapis.org/oas/3.1/dialect/base' # New in 3.1
740
+ )
741
+ servers: list[Server] | None = None
742
+ paths: Paths | None = None # Made optional in 3.1
743
+ webhooks: dict[str, PathItem | Reference] | None = None # New in 3.1
744
+ components: Components | None = None
745
+ security: list[SecurityRequirement] | None = None
746
+ tags: list[Tag] | None = None
747
+ externalDocs: ExternalDocumentation | None = None
748
+
749
+ def upgrade(self) -> tuple[v3_2.OpenAPI, list[str]]:
750
+ """Upgrade this OpenAPI 3.1 document to OpenAPI 3.2.
751
+
752
+ Converts the current OpenAPI 3.1 specification to OpenAPI 3.2 format.
753
+ The conversion includes:
754
+ - Updating the openapi version string from 3.1.x to 3.2.0
755
+ - Updating the jsonSchemaDialect to the 3.2 dialect
756
+ - All other fields are compatible and transferred as-is
757
+
758
+ Returns:
759
+ v3_2.OpenAPI: The upgraded OpenAPI 3.2 document
760
+ """
761
+ from ..v3_2 import v3_2
762
+
763
+ # Get the model as a dictionary with aliases (e.g., 'schema' instead of 'schema_')
764
+ data = self.model_dump(mode='json', by_alias=True, exclude_none=False)
765
+
766
+ # Update the openapi version from 3.1.x to 3.2.0
767
+ version_match = re.match(r'^3\.1\.(\d+)(-.+)?$', data['openapi'])
768
+ if version_match:
769
+ # Keep the patch version but change major.minor to 3.2
770
+ patch = version_match.group(1)
771
+ suffix = version_match.group(2) or ''
772
+ data['openapi'] = f'3.2.{patch}{suffix}'
773
+ else:
774
+ # Fallback to 3.2.0 if pattern doesn't match
775
+ data['openapi'] = '3.2.0'
776
+
777
+ # Update jsonSchemaDialect if it's the 3.1 default
778
+ if (
779
+ data.get('jsonSchemaDialect')
780
+ == 'https://spec.openapis.org/oas/3.1/dialect/base'
781
+ ):
782
+ data['jsonSchemaDialect'] = 'https://spec.openapis.org/oas/3.2/dialect/base'
783
+
784
+ # Parse and validate with v3_2.OpenAPI model
785
+ return v3_2.OpenAPI.model_validate(data), []
786
+
787
+
788
+ # Rebuild models to resolve forward references
789
+ Schema.model_rebuild()
790
+ OpenAPI.model_rebuild()
791
+ Components.model_rebuild()
792
+ Response.model_rebuild()
793
+ MediaType.model_rebuild()
794
+ Paths.model_rebuild()
795
+ PathItem.model_rebuild()
796
+ Operation.model_rebuild()
797
+ Parameter.model_rebuild()
798
+ Header.model_rebuild()