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.
- README.md +581 -8
- otterapi/__init__.py +73 -0
- otterapi/cli.py +327 -29
- otterapi/codegen/__init__.py +115 -0
- otterapi/codegen/ast_utils.py +134 -5
- otterapi/codegen/client.py +1271 -0
- otterapi/codegen/codegen.py +1736 -0
- otterapi/codegen/dataframes.py +392 -0
- otterapi/codegen/emitter.py +473 -0
- otterapi/codegen/endpoints.py +2597 -343
- otterapi/codegen/pagination.py +1026 -0
- otterapi/codegen/schema.py +593 -0
- otterapi/codegen/splitting.py +1397 -0
- otterapi/codegen/types.py +1345 -0
- otterapi/codegen/utils.py +180 -1
- otterapi/config.py +1017 -24
- otterapi/exceptions.py +231 -0
- otterapi/openapi/__init__.py +46 -0
- otterapi/openapi/v2/__init__.py +86 -0
- otterapi/openapi/v2/spec.json +1607 -0
- otterapi/openapi/v2/v2.py +1776 -0
- otterapi/openapi/v3/__init__.py +131 -0
- otterapi/openapi/v3/spec.json +1651 -0
- otterapi/openapi/v3/v3.py +1557 -0
- otterapi/openapi/v3_1/__init__.py +133 -0
- otterapi/openapi/v3_1/spec.json +1411 -0
- otterapi/openapi/v3_1/v3_1.py +798 -0
- otterapi/openapi/v3_2/__init__.py +133 -0
- otterapi/openapi/v3_2/spec.json +1666 -0
- otterapi/openapi/v3_2/v3_2.py +777 -0
- otterapi/tests/__init__.py +3 -0
- otterapi/tests/fixtures/__init__.py +455 -0
- otterapi/tests/test_ast_utils.py +680 -0
- otterapi/tests/test_codegen.py +610 -0
- otterapi/tests/test_dataframe.py +1038 -0
- otterapi/tests/test_exceptions.py +493 -0
- otterapi/tests/test_openapi_support.py +616 -0
- otterapi/tests/test_openapi_upgrade.py +215 -0
- otterapi/tests/test_pagination.py +1101 -0
- otterapi/tests/test_splitting_config.py +319 -0
- otterapi/tests/test_splitting_integration.py +427 -0
- otterapi/tests/test_splitting_resolver.py +512 -0
- otterapi/tests/test_splitting_tree.py +525 -0
- otterapi-0.0.6.dist-info/METADATA +627 -0
- otterapi-0.0.6.dist-info/RECORD +48 -0
- {otterapi-0.0.5.dist-info → otterapi-0.0.6.dist-info}/WHEEL +1 -1
- otterapi/codegen/generator.py +0 -358
- otterapi/codegen/openapi_processor.py +0 -27
- otterapi/codegen/type_generator.py +0 -559
- otterapi-0.0.5.dist-info/METADATA +0 -54
- otterapi-0.0.5.dist-info/RECORD +0 -16
- {otterapi-0.0.5.dist-info → otterapi-0.0.6.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""Tests for OpenAPI version upgrade functionality."""
|
|
2
|
+
|
|
3
|
+
from otterapi.openapi.v3_1.v3_1 import OpenAPI as OpenAPI31
|
|
4
|
+
from otterapi.openapi.v3_2.v3_2 import OpenAPI as OpenAPI32
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestOpenAPIUpgrade:
|
|
8
|
+
"""Test suite for upgrading OpenAPI 3.1 to 3.2."""
|
|
9
|
+
|
|
10
|
+
def test_basic_upgrade(self):
|
|
11
|
+
"""Test basic upgrade from 3.1 to 3.2."""
|
|
12
|
+
doc_31 = OpenAPI31.model_validate(
|
|
13
|
+
{'openapi': '3.1.0', 'info': {'title': 'Test API', 'version': '1.0.0'}}
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
doc_32, _ = doc_31.upgrade()
|
|
17
|
+
|
|
18
|
+
assert isinstance(doc_32, OpenAPI32)
|
|
19
|
+
assert doc_32.openapi == '3.2.0'
|
|
20
|
+
assert doc_32.info.title == 'Test API'
|
|
21
|
+
assert doc_32.info.version == '1.0.0'
|
|
22
|
+
|
|
23
|
+
def test_version_upgrade_preserves_patch(self):
|
|
24
|
+
"""Test that patch version is preserved during upgrade."""
|
|
25
|
+
doc_31 = OpenAPI31.model_validate(
|
|
26
|
+
{'openapi': '3.1.5', 'info': {'title': 'Test API', 'version': '1.0.0'}}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
doc_32, _ = doc_31.upgrade()
|
|
30
|
+
|
|
31
|
+
assert doc_32.openapi == '3.2.5'
|
|
32
|
+
|
|
33
|
+
def test_version_upgrade_preserves_suffix(self):
|
|
34
|
+
"""Test that version suffix (e.g., -beta) is preserved."""
|
|
35
|
+
doc_31 = OpenAPI31.model_validate(
|
|
36
|
+
{
|
|
37
|
+
'openapi': '3.1.0-beta1',
|
|
38
|
+
'info': {'title': 'Test API', 'version': '1.0.0'},
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
doc_32, _ = doc_31.upgrade()
|
|
43
|
+
|
|
44
|
+
assert doc_32.openapi == '3.2.0-beta1'
|
|
45
|
+
|
|
46
|
+
def test_json_schema_dialect_upgrade(self):
|
|
47
|
+
"""Test that default jsonSchemaDialect is updated to 3.2."""
|
|
48
|
+
doc_31 = OpenAPI31.model_validate(
|
|
49
|
+
{
|
|
50
|
+
'openapi': '3.1.0',
|
|
51
|
+
'info': {'title': 'Test API', 'version': '1.0.0'},
|
|
52
|
+
'jsonSchemaDialect': 'https://spec.openapis.org/oas/3.1/dialect/base',
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
doc_32, _ = doc_31.upgrade()
|
|
57
|
+
|
|
58
|
+
assert (
|
|
59
|
+
doc_32.jsonSchemaDialect == 'https://spec.openapis.org/oas/3.2/dialect/base'
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def test_custom_json_schema_dialect_preserved(self):
|
|
63
|
+
"""Test that custom jsonSchemaDialect is preserved."""
|
|
64
|
+
custom_dialect = 'https://json-schema.org/draft/2020-12/schema'
|
|
65
|
+
doc_31 = OpenAPI31.model_validate(
|
|
66
|
+
{
|
|
67
|
+
'openapi': '3.1.0',
|
|
68
|
+
'info': {'title': 'Test API', 'version': '1.0.0'},
|
|
69
|
+
'jsonSchemaDialect': custom_dialect,
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
doc_32, _ = doc_31.upgrade()
|
|
74
|
+
|
|
75
|
+
assert doc_32.jsonSchemaDialect == custom_dialect
|
|
76
|
+
|
|
77
|
+
def test_complex_document_upgrade(self):
|
|
78
|
+
"""Test upgrade of complex document with paths, schemas, and servers."""
|
|
79
|
+
doc_31 = OpenAPI31.model_validate(
|
|
80
|
+
{
|
|
81
|
+
'openapi': '3.1.0',
|
|
82
|
+
'info': {
|
|
83
|
+
'title': 'Pet Store API',
|
|
84
|
+
'version': '1.0.0',
|
|
85
|
+
'description': 'A sample API',
|
|
86
|
+
},
|
|
87
|
+
'servers': [{'url': 'https://api.example.com/v1'}],
|
|
88
|
+
'paths': {
|
|
89
|
+
'/pets': {
|
|
90
|
+
'get': {
|
|
91
|
+
'operationId': 'listPets',
|
|
92
|
+
'summary': 'List all pets',
|
|
93
|
+
'responses': {
|
|
94
|
+
'default': {
|
|
95
|
+
'description': 'A list of pets',
|
|
96
|
+
'content': {
|
|
97
|
+
'application/json': {
|
|
98
|
+
'schema': {
|
|
99
|
+
'type': 'array',
|
|
100
|
+
'items': {'type': 'object'},
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
'components': {
|
|
110
|
+
'schemas': {
|
|
111
|
+
'Pet': {
|
|
112
|
+
'type': 'object',
|
|
113
|
+
'required': ['name'],
|
|
114
|
+
'properties': {
|
|
115
|
+
'name': {'type': 'string'},
|
|
116
|
+
'age': {'type': 'integer', 'minimum': 0},
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
doc_32, _ = doc_31.upgrade()
|
|
125
|
+
|
|
126
|
+
# Verify structure is preserved
|
|
127
|
+
assert doc_32.info.title == 'Pet Store API'
|
|
128
|
+
assert doc_32.info.description == 'A sample API'
|
|
129
|
+
assert len(doc_32.servers) == 1
|
|
130
|
+
assert doc_32.servers[0].url == 'https://api.example.com/v1'
|
|
131
|
+
assert '/pets' in doc_32.paths.root
|
|
132
|
+
assert 'Pet' in doc_32.components.schemas
|
|
133
|
+
|
|
134
|
+
# Verify nested schema
|
|
135
|
+
pet_schema = doc_32.components.schemas['Pet']
|
|
136
|
+
assert pet_schema.type.value == 'object'
|
|
137
|
+
assert pet_schema.required == ['name']
|
|
138
|
+
assert 'name' in pet_schema.properties
|
|
139
|
+
assert 'age' in pet_schema.properties
|
|
140
|
+
|
|
141
|
+
def test_webhooks_upgrade(self):
|
|
142
|
+
"""Test that webhooks (new in 3.1) are preserved during upgrade."""
|
|
143
|
+
doc_31 = OpenAPI31.model_validate(
|
|
144
|
+
{
|
|
145
|
+
'openapi': '3.1.0',
|
|
146
|
+
'info': {'title': 'Webhook API', 'version': '1.0.0'},
|
|
147
|
+
'webhooks': {
|
|
148
|
+
'newPet': {
|
|
149
|
+
'post': {
|
|
150
|
+
'summary': 'New pet notification',
|
|
151
|
+
'requestBody': {
|
|
152
|
+
'content': {
|
|
153
|
+
'application/json': {
|
|
154
|
+
'schema': {
|
|
155
|
+
'type': 'object',
|
|
156
|
+
'properties': {
|
|
157
|
+
'id': {'type': 'integer'},
|
|
158
|
+
'name': {'type': 'string'},
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
'responses': {
|
|
165
|
+
'default': {'description': 'Webhook received'}
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
doc_32, _ = doc_31.upgrade()
|
|
174
|
+
|
|
175
|
+
assert doc_32.webhooks is not None
|
|
176
|
+
assert 'newPet' in doc_32.webhooks
|
|
177
|
+
assert doc_32.webhooks['newPet'].post.summary == 'New pet notification'
|
|
178
|
+
|
|
179
|
+
def test_minimal_document_upgrade(self):
|
|
180
|
+
"""Test upgrade of minimal valid document."""
|
|
181
|
+
doc_31 = OpenAPI31.model_validate(
|
|
182
|
+
{'openapi': '3.1.0', 'info': {'title': 'Minimal API', 'version': '0.1.0'}}
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
doc_32, _ = doc_31.upgrade()
|
|
186
|
+
|
|
187
|
+
assert isinstance(doc_32, OpenAPI32)
|
|
188
|
+
assert doc_32.openapi == '3.2.0'
|
|
189
|
+
assert doc_32.info.title == 'Minimal API'
|
|
190
|
+
|
|
191
|
+
def test_security_schemes_upgrade(self):
|
|
192
|
+
"""Test that security schemes are preserved during upgrade."""
|
|
193
|
+
doc_31 = OpenAPI31.model_validate(
|
|
194
|
+
{
|
|
195
|
+
'openapi': '3.1.0',
|
|
196
|
+
'info': {'title': 'Secure API', 'version': '1.0.0'},
|
|
197
|
+
'components': {
|
|
198
|
+
'securitySchemes': {
|
|
199
|
+
'bearerAuth': {
|
|
200
|
+
'type': 'http',
|
|
201
|
+
'scheme': 'bearer',
|
|
202
|
+
'bearerFormat': 'JWT',
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
'security': [{'bearerAuth': []}],
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
doc_32, _ = doc_31.upgrade()
|
|
211
|
+
|
|
212
|
+
assert doc_32.components.securitySchemes is not None
|
|
213
|
+
assert 'bearerAuth' in doc_32.components.securitySchemes
|
|
214
|
+
assert doc_32.security is not None
|
|
215
|
+
assert len(doc_32.security) == 1
|