12
12
from ..config import Config
13
13
from ..utils import PythonIdentifier
14
14
from .errors import GeneratorError , ParseError , PropertyError
15
- from .properties import Class , EnumProperty , ModelProperty , Property , Schemas , build_schemas , property_from_data
15
+ from .properties import (
16
+ Class ,
17
+ EnumProperty ,
18
+ ModelProperty ,
19
+ Parameters ,
20
+ Property ,
21
+ Schemas ,
22
+ build_parameters ,
23
+ build_schemas ,
24
+ property_from_data ,
25
+ )
26
+ from .properties .schemas import parse_reference_path
16
27
from .responses import Response , response_from_data
17
28
18
29
_PATH_PARAM_REGEX = re .compile ("{([a-zA-Z_][a-zA-Z0-9_]*)}" )
@@ -33,8 +44,8 @@ class EndpointCollection:
33
44
34
45
@staticmethod
35
46
def from_data (
36
- * , data : Dict [str , oai .PathItem ], schemas : Schemas , config : Config
37
- ) -> Tuple [Dict [utils .PythonIdentifier , "EndpointCollection" ], Schemas ]:
47
+ * , data : Dict [str , oai .PathItem ], schemas : Schemas , parameters : Parameters , config : Config
48
+ ) -> Tuple [Dict [utils .PythonIdentifier , "EndpointCollection" ], Schemas , Parameters ]:
38
49
"""Parse the openapi paths data to get EndpointCollections by tag"""
39
50
endpoints_by_tag : Dict [utils .PythonIdentifier , EndpointCollection ] = {}
40
51
@@ -47,13 +58,19 @@ def from_data(
47
58
continue
48
59
tag = utils .PythonIdentifier (value = (operation .tags or ["default" ])[0 ], prefix = "tag" )
49
60
collection = endpoints_by_tag .setdefault (tag , EndpointCollection (tag = tag ))
50
- endpoint , schemas = Endpoint .from_data (
51
- data = operation , path = path , method = method , tag = tag , schemas = schemas , config = config
61
+ endpoint , schemas , parameters = Endpoint .from_data (
62
+ data = operation ,
63
+ path = path ,
64
+ method = method ,
65
+ tag = tag ,
66
+ schemas = schemas ,
67
+ parameters = parameters ,
68
+ config = config ,
52
69
)
53
70
# Add `PathItem` parameters
54
71
if not isinstance (endpoint , ParseError ):
55
- endpoint , schemas = Endpoint .add_parameters (
56
- endpoint = endpoint , data = path_data , schemas = schemas , config = config
72
+ endpoint , schemas , parameters = Endpoint .add_parameters (
73
+ endpoint = endpoint , data = path_data , schemas = schemas , parameters = parameters , config = config
57
74
)
58
75
if not isinstance (endpoint , ParseError ):
59
76
endpoint = Endpoint .sort_parameters (endpoint = endpoint )
@@ -68,7 +85,7 @@ def from_data(
68
85
collection .parse_errors .append (error )
69
86
collection .endpoints .append (endpoint )
70
87
71
- return endpoints_by_tag , schemas
88
+ return endpoints_by_tag , schemas , parameters
72
89
73
90
74
91
def generate_operation_id (* , path : str , method : str ) -> str :
@@ -248,8 +265,13 @@ def _add_responses(
248
265
# pylint: disable=too-many-return-statements
249
266
@staticmethod
250
267
def add_parameters (
251
- * , endpoint : "Endpoint" , data : Union [oai .Operation , oai .PathItem ], schemas : Schemas , config : Config
252
- ) -> Tuple [Union ["Endpoint" , ParseError ], Schemas ]:
268
+ * ,
269
+ endpoint : "Endpoint" ,
270
+ data : Union [oai .Operation , oai .PathItem ],
271
+ schemas : Schemas ,
272
+ parameters : Parameters ,
273
+ config : Config ,
274
+ ) -> Tuple [Union ["Endpoint" , ParseError ], Schemas , Parameters ]:
253
275
"""Process the defined `parameters` for an Endpoint.
254
276
255
277
Any existing parameters will be ignored, so earlier instances of a parameter take precedence. PathItem
@@ -259,6 +281,7 @@ def add_parameters(
259
281
endpoint: The endpoint to add parameters to.
260
282
data: The Operation or PathItem to add parameters from.
261
283
schemas: The cumulative Schemas of processing so far which should contain details for any references.
284
+ parameters: The cumulative Parameters of processing so far which should contain details for any references.
262
285
config: User-provided config for overrides within parameters.
263
286
264
287
Returns:
@@ -271,9 +294,10 @@ def add_parameters(
271
294
- https://swagger.io/docs/specification/paths-and-operations/
272
295
"""
273
296
274
- endpoint = deepcopy (endpoint )
275
297
if data .parameters is None :
276
- return endpoint , schemas
298
+ return endpoint , schemas , parameters
299
+
300
+ endpoint = deepcopy (endpoint )
277
301
278
302
unique_parameters : Set [Tuple [str , oai .ParameterLocation ]] = set ()
279
303
parameters_by_location = {
@@ -283,9 +307,22 @@ def add_parameters(
283
307
oai .ParameterLocation .COOKIE : endpoint .cookie_parameters ,
284
308
}
285
309
286
- for param in data .parameters :
287
- if isinstance (param , oai .Reference ) or param .param_schema is None :
288
- continue
310
+ for _param in data .parameters :
311
+ param : oai .Parameter
312
+
313
+ if _param is None :
314
+ return ParseError (data = data , detail = "Null parameter provided." ), schemas , parameters
315
+
316
+ if isinstance (_param , oai .Reference ):
317
+ ref_path = parse_reference_path (_param .ref )
318
+ if isinstance (ref_path , ParseError ):
319
+ return ref_path , schemas , parameters
320
+ _resolved_class = parameters .classes_by_reference .get (ref_path )
321
+ if _resolved_class is None :
322
+ return ParseError (data = data , detail = f"Reference `{ ref_path } ` not found." ), schemas , parameters
323
+ param = _resolved_class
324
+ elif isinstance (_param , oai .Parameter ):
325
+ param = _param
289
326
290
327
unique_param = (param .name , param .param_in )
291
328
if unique_param in unique_parameters :
@@ -294,9 +331,12 @@ def add_parameters(
294
331
"A unique parameter is defined by a combination of a name and location. "
295
332
f"Duplicated parameters named `{ param .name } ` detected in `{ param .param_in } `."
296
333
)
297
- return ParseError (data = data , detail = duplication_detail ), schemas
334
+ return ParseError (data = data , detail = duplication_detail ), schemas , parameters
298
335
unique_parameters .add (unique_param )
299
336
337
+ if param .param_schema is None :
338
+ continue
339
+
300
340
prop , new_schemas = property_from_data (
301
341
name = param .name ,
302
342
required = param .required ,
@@ -305,13 +345,21 @@ def add_parameters(
305
345
parent_name = endpoint .name ,
306
346
config = config ,
307
347
)
348
+
308
349
if isinstance (prop , ParseError ):
309
- return ParseError (detail = f"cannot parse parameter of endpoint { endpoint .name } " , data = prop .data ), schemas
350
+ return (
351
+ ParseError (detail = f"cannot parse parameter of endpoint { endpoint .name } " , data = prop .data ),
352
+ schemas ,
353
+ parameters ,
354
+ )
355
+
356
+ schemas = new_schemas
357
+
310
358
location_error = prop .validate_location (param .param_in )
311
359
if location_error is not None :
312
360
location_error .data = param
313
- return location_error , schemas
314
- schemas = new_schemas
361
+ return location_error , schemas , parameters
362
+
315
363
if prop .name in parameters_by_location [param .param_in ]:
316
364
# This parameter was defined in the Operation, so ignore the PathItem definition
317
365
continue
@@ -331,6 +379,7 @@ def add_parameters(
331
379
data = data ,
332
380
),
333
381
schemas ,
382
+ parameters ,
334
383
)
335
384
endpoint .used_python_identifiers .add (existing_prop .python_name )
336
385
prop .set_python_name (new_name = f"{ param .name } _{ param .param_in } " , config = config )
@@ -341,6 +390,7 @@ def add_parameters(
341
390
detail = f"Parameters with same Python identifier `{ prop .python_name } ` detected" , data = data
342
391
),
343
392
schemas ,
393
+ parameters ,
344
394
)
345
395
if param .param_in == oai .ParameterLocation .QUERY and (prop .nullable or not prop .required ):
346
396
# There is no NULL for query params, so nullable and not required are the same.
@@ -350,7 +400,7 @@ def add_parameters(
350
400
endpoint .used_python_identifiers .add (prop .python_name )
351
401
parameters_by_location [param .param_in ][prop .name ] = prop
352
402
353
- return endpoint , schemas
403
+ return endpoint , schemas , parameters
354
404
355
405
@staticmethod
356
406
def sort_parameters (* , endpoint : "Endpoint" ) -> Union ["Endpoint" , ParseError ]:
@@ -382,8 +432,15 @@ def sort_parameters(*, endpoint: "Endpoint") -> Union["Endpoint", ParseError]:
382
432
383
433
@staticmethod
384
434
def from_data (
385
- * , data : oai .Operation , path : str , method : str , tag : str , schemas : Schemas , config : Config
386
- ) -> Tuple [Union ["Endpoint" , ParseError ], Schemas ]:
435
+ * ,
436
+ data : oai .Operation ,
437
+ path : str ,
438
+ method : str ,
439
+ tag : str ,
440
+ schemas : Schemas ,
441
+ parameters : Parameters ,
442
+ config : Config ,
443
+ ) -> Tuple [Union ["Endpoint" , ParseError ], Schemas , Parameters ]:
387
444
"""Construct an endpoint from the OpenAPI data"""
388
445
389
446
if data .operationId is None :
@@ -401,13 +458,15 @@ def from_data(
401
458
tag = tag ,
402
459
)
403
460
404
- result , schemas = Endpoint .add_parameters (endpoint = endpoint , data = data , schemas = schemas , config = config )
461
+ result , schemas , parameters = Endpoint .add_parameters (
462
+ endpoint = endpoint , data = data , schemas = schemas , parameters = parameters , config = config
463
+ )
405
464
if isinstance (result , ParseError ):
406
- return result , schemas
465
+ return result , schemas , parameters
407
466
result , schemas = Endpoint ._add_responses (endpoint = result , data = data .responses , schemas = schemas , config = config )
408
467
result , schemas = Endpoint ._add_body (endpoint = result , data = data , schemas = schemas , config = config )
409
468
410
- return result , schemas
469
+ return result , schemas , parameters
411
470
412
471
def response_type (self ) -> str :
413
472
"""Get the Python type of any response from this endpoint"""
@@ -459,10 +518,15 @@ def from_dict(data: Dict[str, Any], *, config: Config) -> Union["GeneratorData",
459
518
)
460
519
return GeneratorError (header = "Failed to parse OpenAPI document" , detail = detail )
461
520
schemas = Schemas ()
521
+ parameters = Parameters ()
462
522
if openapi .components and openapi .components .schemas :
463
523
schemas = build_schemas (components = openapi .components .schemas , schemas = schemas , config = config )
464
- endpoint_collections_by_tag , schemas = EndpointCollection .from_data (
465
- data = openapi .paths , schemas = schemas , config = config
524
+ if openapi .components and openapi .components .parameters :
525
+ parameters = build_parameters (
526
+ components = openapi .components .parameters , schemas = schemas , parameters = parameters , config = config
527
+ )
528
+ endpoint_collections_by_tag , schemas , parameters = EndpointCollection .from_data (
529
+ data = openapi .paths , schemas = schemas , parameters = parameters , config = config
466
530
)
467
531
468
532
enums = (prop for prop in schemas .classes_by_name .values () if isinstance (prop , EnumProperty ))
0 commit comments