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,3 @@
1
+ # Test package initialization
2
+
3
+
@@ -0,0 +1,455 @@
1
+ """Test fixtures for OtterAPI tests.
2
+
3
+ This module provides sample OpenAPI documents and utilities for testing
4
+ the code generation functionality.
5
+ """
6
+
7
+ # Minimal OpenAPI 3.0 spec for basic testing
8
+ MINIMAL_OPENAPI_SPEC = {
9
+ 'openapi': '3.0.0',
10
+ 'info': {'title': 'Minimal API', 'version': '1.0.0'},
11
+ 'paths': {},
12
+ }
13
+
14
+ # Simple API with one endpoint
15
+ SIMPLE_API_SPEC = {
16
+ 'openapi': '3.0.0',
17
+ 'info': {
18
+ 'title': 'Simple API',
19
+ 'version': '1.0.0',
20
+ 'description': 'A simple API for testing',
21
+ },
22
+ 'servers': [{'url': 'https://api.example.com/v1'}],
23
+ 'paths': {
24
+ '/health': {
25
+ 'get': {
26
+ 'operationId': 'getHealth',
27
+ 'summary': 'Health check endpoint',
28
+ 'responses': {
29
+ '200': {
30
+ 'description': 'Successful response',
31
+ 'content': {
32
+ 'application/json': {
33
+ 'schema': {
34
+ 'type': 'object',
35
+ 'properties': {'status': {'type': 'string'}},
36
+ }
37
+ }
38
+ },
39
+ }
40
+ },
41
+ }
42
+ }
43
+ },
44
+ }
45
+
46
+ # Petstore-like API with models and multiple endpoints
47
+ PETSTORE_SPEC = {
48
+ 'openapi': '3.0.0',
49
+ 'info': {
50
+ 'title': 'Petstore API',
51
+ 'version': '1.0.0',
52
+ 'description': 'A sample Petstore API for testing',
53
+ },
54
+ 'servers': [{'url': 'https://petstore.example.com/api/v1'}],
55
+ 'paths': {
56
+ '/pets': {
57
+ 'get': {
58
+ 'operationId': 'listPets',
59
+ 'summary': 'List all pets',
60
+ 'parameters': [
61
+ {
62
+ 'name': 'limit',
63
+ 'in': 'query',
64
+ 'description': 'Maximum number of pets to return',
65
+ 'required': False,
66
+ 'schema': {'type': 'integer', 'format': 'int32'},
67
+ },
68
+ {
69
+ 'name': 'status',
70
+ 'in': 'query',
71
+ 'description': 'Filter by status',
72
+ 'required': False,
73
+ 'schema': {
74
+ 'type': 'string',
75
+ 'enum': ['available', 'pending', 'sold'],
76
+ },
77
+ },
78
+ ],
79
+ 'responses': {
80
+ '200': {
81
+ 'description': 'A list of pets',
82
+ 'content': {
83
+ 'application/json': {
84
+ 'schema': {
85
+ 'type': 'array',
86
+ 'items': {'$ref': '#/components/schemas/Pet'},
87
+ }
88
+ }
89
+ },
90
+ }
91
+ },
92
+ },
93
+ 'post': {
94
+ 'operationId': 'createPet',
95
+ 'summary': 'Create a pet',
96
+ 'requestBody': {
97
+ 'description': 'Pet to create',
98
+ 'required': True,
99
+ 'content': {
100
+ 'application/json': {
101
+ 'schema': {'$ref': '#/components/schemas/CreatePetRequest'}
102
+ }
103
+ },
104
+ },
105
+ 'responses': {
106
+ '201': {
107
+ 'description': 'Pet created',
108
+ 'content': {
109
+ 'application/json': {
110
+ 'schema': {'$ref': '#/components/schemas/Pet'}
111
+ }
112
+ },
113
+ },
114
+ '400': {
115
+ 'description': 'Invalid input',
116
+ 'content': {
117
+ 'application/json': {
118
+ 'schema': {'$ref': '#/components/schemas/Error'}
119
+ }
120
+ },
121
+ },
122
+ },
123
+ },
124
+ },
125
+ '/pets/{petId}': {
126
+ 'get': {
127
+ 'operationId': 'getPetById',
128
+ 'summary': 'Get a pet by ID',
129
+ 'parameters': [
130
+ {
131
+ 'name': 'petId',
132
+ 'in': 'path',
133
+ 'description': 'ID of pet to return',
134
+ 'required': True,
135
+ 'schema': {'type': 'integer', 'format': 'int64'},
136
+ }
137
+ ],
138
+ 'responses': {
139
+ '200': {
140
+ 'description': 'Successful operation',
141
+ 'content': {
142
+ 'application/json': {
143
+ 'schema': {'$ref': '#/components/schemas/Pet'}
144
+ }
145
+ },
146
+ },
147
+ '404': {
148
+ 'description': 'Pet not found',
149
+ 'content': {
150
+ 'application/json': {
151
+ 'schema': {'$ref': '#/components/schemas/Error'}
152
+ }
153
+ },
154
+ },
155
+ },
156
+ },
157
+ 'put': {
158
+ 'operationId': 'updatePet',
159
+ 'summary': 'Update a pet',
160
+ 'parameters': [
161
+ {
162
+ 'name': 'petId',
163
+ 'in': 'path',
164
+ 'required': True,
165
+ 'schema': {'type': 'integer', 'format': 'int64'},
166
+ }
167
+ ],
168
+ 'requestBody': {
169
+ 'required': True,
170
+ 'content': {
171
+ 'application/json': {
172
+ 'schema': {'$ref': '#/components/schemas/UpdatePetRequest'}
173
+ }
174
+ },
175
+ },
176
+ 'responses': {
177
+ '200': {
178
+ 'description': 'Pet updated',
179
+ 'content': {
180
+ 'application/json': {
181
+ 'schema': {'$ref': '#/components/schemas/Pet'}
182
+ }
183
+ },
184
+ }
185
+ },
186
+ },
187
+ 'delete': {
188
+ 'operationId': 'deletePet',
189
+ 'summary': 'Delete a pet',
190
+ 'parameters': [
191
+ {
192
+ 'name': 'petId',
193
+ 'in': 'path',
194
+ 'required': True,
195
+ 'schema': {'type': 'integer', 'format': 'int64'},
196
+ }
197
+ ],
198
+ 'responses': {'204': {'description': 'Pet deleted'}},
199
+ },
200
+ },
201
+ },
202
+ 'components': {
203
+ 'schemas': {
204
+ 'Pet': {
205
+ 'type': 'object',
206
+ 'required': ['id', 'name'],
207
+ 'properties': {
208
+ 'id': {'type': 'integer', 'format': 'int64'},
209
+ 'name': {'type': 'string'},
210
+ 'tag': {'type': 'string'},
211
+ 'status': {
212
+ 'type': 'string',
213
+ 'enum': ['available', 'pending', 'sold'],
214
+ },
215
+ 'category': {'$ref': '#/components/schemas/Category'},
216
+ },
217
+ },
218
+ 'Category': {
219
+ 'type': 'object',
220
+ 'properties': {
221
+ 'id': {'type': 'integer', 'format': 'int64'},
222
+ 'name': {'type': 'string'},
223
+ },
224
+ },
225
+ 'CreatePetRequest': {
226
+ 'type': 'object',
227
+ 'required': ['name'],
228
+ 'properties': {
229
+ 'name': {'type': 'string'},
230
+ 'tag': {'type': 'string'},
231
+ 'categoryId': {'type': 'integer', 'format': 'int64'},
232
+ },
233
+ },
234
+ 'UpdatePetRequest': {
235
+ 'type': 'object',
236
+ 'properties': {
237
+ 'name': {'type': 'string'},
238
+ 'tag': {'type': 'string'},
239
+ 'status': {
240
+ 'type': 'string',
241
+ 'enum': ['available', 'pending', 'sold'],
242
+ },
243
+ },
244
+ },
245
+ 'Error': {
246
+ 'type': 'object',
247
+ 'required': ['code', 'message'],
248
+ 'properties': {
249
+ 'code': {'type': 'integer', 'format': 'int32'},
250
+ 'message': {'type': 'string'},
251
+ },
252
+ },
253
+ }
254
+ },
255
+ }
256
+
257
+ # API with complex types for testing type generation
258
+ COMPLEX_TYPES_SPEC = {
259
+ 'openapi': '3.0.0',
260
+ 'info': {'title': 'Complex Types API', 'version': '1.0.0'},
261
+ 'paths': {
262
+ '/complex': {
263
+ 'post': {
264
+ 'operationId': 'createComplex',
265
+ 'requestBody': {
266
+ 'content': {
267
+ 'application/json': {
268
+ 'schema': {'$ref': '#/components/schemas/ComplexObject'}
269
+ }
270
+ }
271
+ },
272
+ 'responses': {
273
+ '200': {
274
+ 'description': 'Success',
275
+ 'content': {
276
+ 'application/json': {
277
+ 'schema': {'$ref': '#/components/schemas/ComplexObject'}
278
+ }
279
+ },
280
+ }
281
+ },
282
+ }
283
+ }
284
+ },
285
+ 'components': {
286
+ 'schemas': {
287
+ 'ComplexObject': {
288
+ 'type': 'object',
289
+ 'properties': {
290
+ 'stringField': {'type': 'string'},
291
+ 'intField': {'type': 'integer'},
292
+ 'floatField': {'type': 'number', 'format': 'float'},
293
+ 'doubleField': {'type': 'number', 'format': 'double'},
294
+ 'boolField': {'type': 'boolean'},
295
+ 'dateField': {'type': 'string', 'format': 'date'},
296
+ 'dateTimeField': {'type': 'string', 'format': 'date-time'},
297
+ 'uuidField': {'type': 'string', 'format': 'uuid'},
298
+ 'arrayField': {'type': 'array', 'items': {'type': 'string'}},
299
+ 'nestedObject': {'$ref': '#/components/schemas/NestedObject'},
300
+ 'nestedArray': {
301
+ 'type': 'array',
302
+ 'items': {'$ref': '#/components/schemas/NestedObject'},
303
+ },
304
+ 'mapField': {
305
+ 'type': 'object',
306
+ 'additionalProperties': {'type': 'string'},
307
+ },
308
+ 'enumField': {
309
+ 'type': 'string',
310
+ 'enum': ['VALUE_A', 'VALUE_B', 'VALUE_C'],
311
+ },
312
+ 'nullableField': {'type': 'string', 'nullable': True},
313
+ 'unionField': {'oneOf': [{'type': 'string'}, {'type': 'integer'}]},
314
+ },
315
+ },
316
+ 'NestedObject': {
317
+ 'type': 'object',
318
+ 'properties': {'id': {'type': 'integer'}, 'value': {'type': 'string'}},
319
+ },
320
+ }
321
+ },
322
+ }
323
+
324
+ # API with authentication definitions
325
+ AUTH_API_SPEC = {
326
+ 'openapi': '3.0.0',
327
+ 'info': {'title': 'Auth API', 'version': '1.0.0'},
328
+ 'servers': [{'url': 'https://api.auth-example.com'}],
329
+ 'paths': {
330
+ '/protected': {
331
+ 'get': {
332
+ 'operationId': 'getProtected',
333
+ 'security': [{'bearerAuth': []}],
334
+ 'responses': {
335
+ '200': {
336
+ 'description': 'Success',
337
+ 'content': {
338
+ 'application/json': {
339
+ 'schema': {
340
+ 'type': 'object',
341
+ 'properties': {'data': {'type': 'string'}},
342
+ }
343
+ }
344
+ },
345
+ },
346
+ '401': {'description': 'Unauthorized'},
347
+ },
348
+ }
349
+ },
350
+ '/api-key-protected': {
351
+ 'get': {
352
+ 'operationId': 'getApiKeyProtected',
353
+ 'security': [{'apiKey': []}],
354
+ 'responses': {'200': {'description': 'Success'}},
355
+ }
356
+ },
357
+ },
358
+ 'components': {
359
+ 'securitySchemes': {
360
+ 'bearerAuth': {'type': 'http', 'scheme': 'bearer', 'bearerFormat': 'JWT'},
361
+ 'apiKey': {'type': 'apiKey', 'in': 'header', 'name': 'X-API-Key'},
362
+ 'basicAuth': {'type': 'http', 'scheme': 'basic'},
363
+ }
364
+ },
365
+ }
366
+
367
+ # API with various parameter types
368
+ PARAMETERS_SPEC = {
369
+ 'openapi': '3.0.0',
370
+ 'info': {'title': 'Parameters API', 'version': '1.0.0'},
371
+ 'servers': [{'url': 'https://api.params-example.com'}],
372
+ 'paths': {
373
+ '/items/{itemId}': {
374
+ 'get': {
375
+ 'operationId': 'getItem',
376
+ 'parameters': [
377
+ {
378
+ 'name': 'itemId',
379
+ 'in': 'path',
380
+ 'required': True,
381
+ 'schema': {'type': 'string'},
382
+ },
383
+ {
384
+ 'name': 'include',
385
+ 'in': 'query',
386
+ 'schema': {'type': 'array', 'items': {'type': 'string'}},
387
+ },
388
+ {
389
+ 'name': 'X-Request-ID',
390
+ 'in': 'header',
391
+ 'schema': {'type': 'string', 'format': 'uuid'},
392
+ },
393
+ {'name': 'session', 'in': 'cookie', 'schema': {'type': 'string'}},
394
+ ],
395
+ 'responses': {'200': {'description': 'Success'}},
396
+ }
397
+ }
398
+ },
399
+ }
400
+
401
+ # OpenAPI 3.1 spec for testing version compatibility
402
+ OPENAPI_31_SPEC = {
403
+ 'openapi': '3.1.0',
404
+ 'info': {
405
+ 'title': 'OpenAPI 3.1 API',
406
+ 'version': '1.0.0',
407
+ 'summary': 'An API using OpenAPI 3.1 features',
408
+ },
409
+ 'paths': {
410
+ '/items': {
411
+ 'get': {
412
+ 'operationId': 'listItems',
413
+ 'responses': {
414
+ '200': {
415
+ 'description': 'Success',
416
+ 'content': {
417
+ 'application/json': {
418
+ 'schema': {
419
+ 'type': 'array',
420
+ 'items': {'$ref': '#/components/schemas/Item'},
421
+ }
422
+ }
423
+ },
424
+ }
425
+ },
426
+ }
427
+ }
428
+ },
429
+ 'components': {
430
+ 'schemas': {
431
+ 'Item': {
432
+ 'type': 'object',
433
+ 'properties': {
434
+ 'id': {'type': 'integer'},
435
+ 'name': {'type': 'string'},
436
+ 'tags': {'type': ['array', 'null'], 'items': {'type': 'string'}},
437
+ },
438
+ }
439
+ }
440
+ },
441
+ }
442
+
443
+
444
+ def get_spec_as_json(spec: dict) -> str:
445
+ """Convert a spec dictionary to JSON string."""
446
+ import json
447
+
448
+ return json.dumps(spec, indent=2)
449
+
450
+
451
+ def get_spec_as_yaml(spec: dict) -> str:
452
+ """Convert a spec dictionary to YAML string."""
453
+ import yaml
454
+
455
+ return yaml.dump(spec, default_flow_style=False)