robotframework-openapitools 0.3.0__py3-none-any.whl → 1.0.0__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.
- OpenApiDriver/__init__.py +45 -41
- OpenApiDriver/openapi_executors.py +83 -49
- OpenApiDriver/openapi_reader.py +114 -116
- OpenApiDriver/openapidriver.libspec +209 -133
- OpenApiDriver/openapidriver.py +31 -296
- OpenApiLibCore/__init__.py +39 -13
- OpenApiLibCore/annotations.py +10 -0
- OpenApiLibCore/data_generation/__init__.py +10 -0
- OpenApiLibCore/data_generation/body_data_generation.py +250 -0
- OpenApiLibCore/data_generation/data_generation_core.py +233 -0
- OpenApiLibCore/data_invalidation.py +294 -0
- OpenApiLibCore/dto_base.py +75 -129
- OpenApiLibCore/dto_utils.py +125 -85
- OpenApiLibCore/localized_faker.py +88 -0
- OpenApiLibCore/models.py +723 -0
- OpenApiLibCore/oas_cache.py +14 -13
- OpenApiLibCore/openapi_libcore.libspec +363 -322
- OpenApiLibCore/openapi_libcore.py +388 -1903
- OpenApiLibCore/parameter_utils.py +97 -0
- OpenApiLibCore/path_functions.py +215 -0
- OpenApiLibCore/path_invalidation.py +42 -0
- OpenApiLibCore/protocols.py +38 -0
- OpenApiLibCore/request_data.py +246 -0
- OpenApiLibCore/resource_relations.py +55 -0
- OpenApiLibCore/validation.py +380 -0
- OpenApiLibCore/value_utils.py +216 -481
- openapi_libgen/__init__.py +3 -0
- openapi_libgen/command_line.py +75 -0
- openapi_libgen/generator.py +82 -0
- openapi_libgen/parsing_utils.py +30 -0
- openapi_libgen/spec_parser.py +154 -0
- openapi_libgen/templates/__init__.jinja +3 -0
- openapi_libgen/templates/library.jinja +30 -0
- robotframework_openapitools-1.0.0.dist-info/METADATA +249 -0
- robotframework_openapitools-1.0.0.dist-info/RECORD +40 -0
- {robotframework_openapitools-0.3.0.dist-info → robotframework_openapitools-1.0.0.dist-info}/WHEEL +1 -1
- robotframework_openapitools-1.0.0.dist-info/entry_points.txt +3 -0
- roboswag/__init__.py +0 -9
- roboswag/__main__.py +0 -3
- roboswag/auth.py +0 -44
- roboswag/cli.py +0 -80
- roboswag/core.py +0 -85
- roboswag/generate/__init__.py +0 -1
- roboswag/generate/generate.py +0 -121
- roboswag/generate/models/__init__.py +0 -0
- roboswag/generate/models/api.py +0 -219
- roboswag/generate/models/definition.py +0 -28
- roboswag/generate/models/endpoint.py +0 -68
- roboswag/generate/models/parameter.py +0 -25
- roboswag/generate/models/response.py +0 -8
- roboswag/generate/models/tag.py +0 -16
- roboswag/generate/models/utils.py +0 -60
- roboswag/generate/templates/api_init.jinja +0 -15
- roboswag/generate/templates/models.jinja +0 -7
- roboswag/generate/templates/paths.jinja +0 -68
- roboswag/logger.py +0 -33
- roboswag/validate/__init__.py +0 -6
- roboswag/validate/core.py +0 -3
- roboswag/validate/schema.py +0 -21
- roboswag/validate/text_response.py +0 -14
- robotframework_openapitools-0.3.0.dist-info/METADATA +0 -41
- robotframework_openapitools-0.3.0.dist-info/RECORD +0 -41
- {robotframework_openapitools-0.3.0.dist-info → robotframework_openapitools-1.0.0.dist-info}/LICENSE +0 -0
@@ -0,0 +1,250 @@
|
|
1
|
+
"""
|
2
|
+
Module holding the functions related to (json) data generation
|
3
|
+
for the body of requests made as part of keyword exection.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from random import choice, randint, sample
|
7
|
+
from typing import Any
|
8
|
+
|
9
|
+
from robot.api import logger
|
10
|
+
|
11
|
+
import OpenApiLibCore.path_functions as _path_functions
|
12
|
+
from OpenApiLibCore.annotations import JSON
|
13
|
+
from OpenApiLibCore.dto_base import (
|
14
|
+
Dto,
|
15
|
+
IdDependency,
|
16
|
+
PropertyValueConstraint,
|
17
|
+
)
|
18
|
+
from OpenApiLibCore.dto_utils import DefaultDto
|
19
|
+
from OpenApiLibCore.models import (
|
20
|
+
ArraySchema,
|
21
|
+
ObjectSchema,
|
22
|
+
SchemaObjectTypes,
|
23
|
+
UnionTypeSchema,
|
24
|
+
)
|
25
|
+
from OpenApiLibCore.parameter_utils import get_safe_name_for_oas_name
|
26
|
+
from OpenApiLibCore.protocols import GetIdPropertyNameType
|
27
|
+
from OpenApiLibCore.value_utils import IGNORE
|
28
|
+
|
29
|
+
|
30
|
+
def get_json_data_for_dto_class(
|
31
|
+
schema: SchemaObjectTypes,
|
32
|
+
dto_class: type[Dto],
|
33
|
+
get_id_property_name: GetIdPropertyNameType,
|
34
|
+
operation_id: str | None = None,
|
35
|
+
) -> JSON:
|
36
|
+
if isinstance(schema, UnionTypeSchema):
|
37
|
+
chosen_schema = choice(schema.resolved_schemas)
|
38
|
+
return get_json_data_for_dto_class(
|
39
|
+
schema=chosen_schema,
|
40
|
+
dto_class=dto_class,
|
41
|
+
get_id_property_name=get_id_property_name,
|
42
|
+
operation_id=operation_id,
|
43
|
+
)
|
44
|
+
|
45
|
+
match schema:
|
46
|
+
case ObjectSchema():
|
47
|
+
return get_dict_data_for_dto_class(
|
48
|
+
schema=schema,
|
49
|
+
dto_class=dto_class,
|
50
|
+
get_id_property_name=get_id_property_name,
|
51
|
+
operation_id=operation_id,
|
52
|
+
)
|
53
|
+
case ArraySchema():
|
54
|
+
return get_list_data_for_dto_class(
|
55
|
+
schema=schema,
|
56
|
+
dto_class=dto_class,
|
57
|
+
get_id_property_name=get_id_property_name,
|
58
|
+
operation_id=operation_id,
|
59
|
+
)
|
60
|
+
case _:
|
61
|
+
return schema.get_valid_value()
|
62
|
+
|
63
|
+
|
64
|
+
def get_dict_data_for_dto_class(
|
65
|
+
schema: ObjectSchema,
|
66
|
+
dto_class: type[Dto],
|
67
|
+
get_id_property_name: GetIdPropertyNameType,
|
68
|
+
operation_id: str | None = None,
|
69
|
+
) -> dict[str, Any]:
|
70
|
+
json_data: dict[str, Any] = {}
|
71
|
+
|
72
|
+
property_names = get_property_names_to_process(schema=schema, dto_class=dto_class)
|
73
|
+
|
74
|
+
for property_name in property_names:
|
75
|
+
property_schema = schema.properties.root[property_name] # type: ignore[union-attr]
|
76
|
+
if property_schema.readOnly:
|
77
|
+
continue
|
78
|
+
|
79
|
+
json_data[property_name] = get_data_for_property(
|
80
|
+
property_name=property_name,
|
81
|
+
property_schema=property_schema,
|
82
|
+
get_id_property_name=get_id_property_name,
|
83
|
+
dto_class=dto_class,
|
84
|
+
operation_id=operation_id,
|
85
|
+
)
|
86
|
+
|
87
|
+
return json_data
|
88
|
+
|
89
|
+
|
90
|
+
def get_list_data_for_dto_class(
|
91
|
+
schema: ArraySchema,
|
92
|
+
dto_class: type[Dto],
|
93
|
+
get_id_property_name: GetIdPropertyNameType,
|
94
|
+
operation_id: str | None = None,
|
95
|
+
) -> list[JSON]:
|
96
|
+
json_data: list[JSON] = []
|
97
|
+
list_item_schema = schema.items
|
98
|
+
min_items = schema.minItems if schema.minItems is not None else 0
|
99
|
+
max_items = schema.maxItems if schema.maxItems is not None else 1
|
100
|
+
number_of_items_to_generate = randint(min_items, max_items)
|
101
|
+
for _ in range(number_of_items_to_generate):
|
102
|
+
list_item_data = get_json_data_for_dto_class(
|
103
|
+
schema=list_item_schema,
|
104
|
+
dto_class=dto_class,
|
105
|
+
get_id_property_name=get_id_property_name,
|
106
|
+
operation_id=operation_id,
|
107
|
+
)
|
108
|
+
json_data.append(list_item_data)
|
109
|
+
return json_data
|
110
|
+
|
111
|
+
|
112
|
+
def get_data_for_property(
|
113
|
+
property_name: str,
|
114
|
+
property_schema: SchemaObjectTypes,
|
115
|
+
get_id_property_name: GetIdPropertyNameType,
|
116
|
+
dto_class: type[Dto],
|
117
|
+
operation_id: str | None,
|
118
|
+
) -> JSON:
|
119
|
+
if constrained_values := get_constrained_values(
|
120
|
+
dto_class=dto_class, property_name=property_name
|
121
|
+
):
|
122
|
+
constrained_value = choice(constrained_values)
|
123
|
+
# Check if the chosen value is a nested Dto; since a Dto is never
|
124
|
+
# instantiated, we can use isinstance(..., type) for this.
|
125
|
+
if isinstance(constrained_value, type):
|
126
|
+
return get_value_constrained_by_nested_dto(
|
127
|
+
property_schema=property_schema,
|
128
|
+
nested_dto_class=constrained_value,
|
129
|
+
get_id_property_name=get_id_property_name,
|
130
|
+
operation_id=operation_id,
|
131
|
+
)
|
132
|
+
return constrained_value
|
133
|
+
|
134
|
+
if (
|
135
|
+
dependent_id := get_dependent_id(
|
136
|
+
dto_class=dto_class,
|
137
|
+
property_name=property_name,
|
138
|
+
operation_id=operation_id,
|
139
|
+
get_id_property_name=get_id_property_name,
|
140
|
+
)
|
141
|
+
) is not None:
|
142
|
+
return dependent_id
|
143
|
+
|
144
|
+
return get_json_data_for_dto_class(
|
145
|
+
schema=property_schema,
|
146
|
+
dto_class=DefaultDto,
|
147
|
+
get_id_property_name=get_id_property_name,
|
148
|
+
)
|
149
|
+
|
150
|
+
|
151
|
+
def get_value_constrained_by_nested_dto(
|
152
|
+
property_schema: SchemaObjectTypes,
|
153
|
+
nested_dto_class: type[Dto],
|
154
|
+
get_id_property_name: GetIdPropertyNameType,
|
155
|
+
operation_id: str | None,
|
156
|
+
) -> JSON:
|
157
|
+
nested_schema = get_schema_for_nested_dto(property_schema=property_schema)
|
158
|
+
nested_value = get_json_data_for_dto_class(
|
159
|
+
schema=nested_schema,
|
160
|
+
dto_class=nested_dto_class,
|
161
|
+
get_id_property_name=get_id_property_name,
|
162
|
+
operation_id=operation_id,
|
163
|
+
)
|
164
|
+
return nested_value
|
165
|
+
|
166
|
+
|
167
|
+
def get_schema_for_nested_dto(property_schema: SchemaObjectTypes) -> SchemaObjectTypes:
|
168
|
+
if isinstance(property_schema, UnionTypeSchema):
|
169
|
+
chosen_schema = choice(property_schema.resolved_schemas)
|
170
|
+
return get_schema_for_nested_dto(chosen_schema)
|
171
|
+
|
172
|
+
return property_schema
|
173
|
+
|
174
|
+
|
175
|
+
def get_property_names_to_process(
|
176
|
+
schema: ObjectSchema,
|
177
|
+
dto_class: type[Dto],
|
178
|
+
) -> list[str]:
|
179
|
+
property_names = []
|
180
|
+
|
181
|
+
for property_name in schema.properties.root: # type: ignore[union-attr]
|
182
|
+
# register the oas_name
|
183
|
+
_ = get_safe_name_for_oas_name(property_name)
|
184
|
+
if constrained_values := get_constrained_values(
|
185
|
+
dto_class=dto_class, property_name=property_name
|
186
|
+
):
|
187
|
+
# do not add properties that are configured to be ignored
|
188
|
+
if IGNORE in constrained_values: # type: ignore[comparison-overlap]
|
189
|
+
continue
|
190
|
+
property_names.append(property_name)
|
191
|
+
|
192
|
+
max_properties = schema.maxProperties
|
193
|
+
if max_properties and len(property_names) > max_properties:
|
194
|
+
required_properties = schema.required
|
195
|
+
number_of_optional_properties = max_properties - len(required_properties)
|
196
|
+
optional_properties = [
|
197
|
+
name for name in property_names if name not in required_properties
|
198
|
+
]
|
199
|
+
selected_optional_properties = sample(
|
200
|
+
optional_properties, number_of_optional_properties
|
201
|
+
)
|
202
|
+
property_names = required_properties + selected_optional_properties
|
203
|
+
|
204
|
+
return property_names
|
205
|
+
|
206
|
+
|
207
|
+
def get_constrained_values(
|
208
|
+
dto_class: type[Dto], property_name: str
|
209
|
+
) -> list[JSON | type[Dto]]:
|
210
|
+
relations = dto_class.get_relations()
|
211
|
+
values_list = [
|
212
|
+
c.values
|
213
|
+
for c in relations
|
214
|
+
if (isinstance(c, PropertyValueConstraint) and c.property_name == property_name)
|
215
|
+
]
|
216
|
+
# values should be empty or contain 1 list of allowed values
|
217
|
+
return values_list.pop() if values_list else []
|
218
|
+
|
219
|
+
|
220
|
+
def get_dependent_id(
|
221
|
+
dto_class: type[Dto],
|
222
|
+
property_name: str,
|
223
|
+
operation_id: str | None,
|
224
|
+
get_id_property_name: GetIdPropertyNameType,
|
225
|
+
) -> str | int | float | None:
|
226
|
+
relations = dto_class.get_relations()
|
227
|
+
# multiple get paths are possible based on the operation being performed
|
228
|
+
id_get_paths = [
|
229
|
+
(d.get_path, d.operation_id)
|
230
|
+
for d in relations
|
231
|
+
if (isinstance(d, IdDependency) and d.property_name == property_name)
|
232
|
+
]
|
233
|
+
if not id_get_paths:
|
234
|
+
return None
|
235
|
+
if len(id_get_paths) == 1:
|
236
|
+
id_get_path, _ = id_get_paths.pop()
|
237
|
+
else:
|
238
|
+
try:
|
239
|
+
[id_get_path] = [
|
240
|
+
path for path, operation in id_get_paths if operation == operation_id
|
241
|
+
]
|
242
|
+
# There could be multiple get_paths, but not one for the current operation
|
243
|
+
except ValueError:
|
244
|
+
return None
|
245
|
+
|
246
|
+
valid_id = _path_functions.get_valid_id_for_path(
|
247
|
+
path=id_get_path, get_id_property_name=get_id_property_name
|
248
|
+
)
|
249
|
+
logger.debug(f"get_dependent_id for {id_get_path} returned {valid_id}")
|
250
|
+
return valid_id
|
@@ -0,0 +1,233 @@
|
|
1
|
+
"""
|
2
|
+
Module holding the main functions related to data generation
|
3
|
+
for the requests made as part of keyword exection.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from dataclasses import Field, field, make_dataclass
|
7
|
+
from random import choice
|
8
|
+
from typing import Any, cast
|
9
|
+
|
10
|
+
from robot.api import logger
|
11
|
+
|
12
|
+
import OpenApiLibCore.path_functions as _path_functions
|
13
|
+
from OpenApiLibCore.annotations import JSON
|
14
|
+
from OpenApiLibCore.dto_base import (
|
15
|
+
Dto,
|
16
|
+
PropertyValueConstraint,
|
17
|
+
ResourceRelation,
|
18
|
+
)
|
19
|
+
from OpenApiLibCore.dto_utils import DefaultDto
|
20
|
+
from OpenApiLibCore.models import (
|
21
|
+
ObjectSchema,
|
22
|
+
OpenApiObject,
|
23
|
+
OperationObject,
|
24
|
+
ParameterObject,
|
25
|
+
UnionTypeSchema,
|
26
|
+
)
|
27
|
+
from OpenApiLibCore.parameter_utils import get_safe_name_for_oas_name
|
28
|
+
from OpenApiLibCore.protocols import GetDtoClassType, GetIdPropertyNameType
|
29
|
+
from OpenApiLibCore.request_data import RequestData
|
30
|
+
from OpenApiLibCore.value_utils import IGNORE
|
31
|
+
|
32
|
+
from .body_data_generation import (
|
33
|
+
get_json_data_for_dto_class as _get_json_data_for_dto_class,
|
34
|
+
)
|
35
|
+
|
36
|
+
|
37
|
+
def get_request_data(
|
38
|
+
path: str,
|
39
|
+
method: str,
|
40
|
+
get_dto_class: GetDtoClassType,
|
41
|
+
get_id_property_name: GetIdPropertyNameType,
|
42
|
+
openapi_spec: OpenApiObject,
|
43
|
+
) -> RequestData:
|
44
|
+
method = method.lower()
|
45
|
+
dto_cls_name = get_dto_cls_name(path=path, method=method)
|
46
|
+
# The path can contain already resolved Ids that have to be matched
|
47
|
+
# against the parametrized paths in the paths section.
|
48
|
+
spec_path = _path_functions.get_parametrized_path(
|
49
|
+
path=path, openapi_spec=openapi_spec
|
50
|
+
)
|
51
|
+
dto_class = get_dto_class(path=spec_path, method=method)
|
52
|
+
try:
|
53
|
+
path_item = openapi_spec.paths[spec_path]
|
54
|
+
operation_spec: OperationObject | None = getattr(path_item, method)
|
55
|
+
if operation_spec is None:
|
56
|
+
raise AttributeError
|
57
|
+
except AttributeError:
|
58
|
+
logger.info(
|
59
|
+
f"method '{method}' not supported on '{spec_path}, using empty spec."
|
60
|
+
)
|
61
|
+
operation_spec = OperationObject(operationId="")
|
62
|
+
|
63
|
+
parameters, params, headers = get_request_parameters(
|
64
|
+
dto_class=dto_class, method_spec=operation_spec
|
65
|
+
)
|
66
|
+
if operation_spec.requestBody is None:
|
67
|
+
dto_instance = _get_dto_instance_for_empty_body(
|
68
|
+
dto_class=dto_class,
|
69
|
+
dto_cls_name=dto_cls_name,
|
70
|
+
method_spec=operation_spec,
|
71
|
+
)
|
72
|
+
return RequestData(
|
73
|
+
dto=dto_instance,
|
74
|
+
parameters=parameters,
|
75
|
+
params=params,
|
76
|
+
headers=headers,
|
77
|
+
has_body=False,
|
78
|
+
)
|
79
|
+
|
80
|
+
body_schema = operation_spec.requestBody.schema_
|
81
|
+
|
82
|
+
if not body_schema:
|
83
|
+
raise ValueError(
|
84
|
+
f"No supported content schema found: {operation_spec.requestBody.content}"
|
85
|
+
)
|
86
|
+
|
87
|
+
headers.update({"content-type": operation_spec.requestBody.mime_type})
|
88
|
+
|
89
|
+
if isinstance(body_schema, UnionTypeSchema):
|
90
|
+
resolved_schemas = body_schema.resolved_schemas
|
91
|
+
body_schema = choice(resolved_schemas)
|
92
|
+
|
93
|
+
if not isinstance(body_schema, ObjectSchema):
|
94
|
+
raise ValueError(f"Selected schema is not an object schema: {body_schema}")
|
95
|
+
|
96
|
+
dto_data = _get_json_data_for_dto_class(
|
97
|
+
schema=body_schema,
|
98
|
+
dto_class=dto_class,
|
99
|
+
get_id_property_name=get_id_property_name,
|
100
|
+
operation_id=operation_spec.operationId,
|
101
|
+
)
|
102
|
+
dto_instance = _get_dto_instance_from_dto_data(
|
103
|
+
object_schema=body_schema,
|
104
|
+
dto_class=dto_class,
|
105
|
+
dto_data=dto_data,
|
106
|
+
method_spec=operation_spec,
|
107
|
+
dto_cls_name=dto_cls_name,
|
108
|
+
)
|
109
|
+
return RequestData(
|
110
|
+
dto=dto_instance,
|
111
|
+
body_schema=body_schema,
|
112
|
+
parameters=parameters,
|
113
|
+
params=params,
|
114
|
+
headers=headers,
|
115
|
+
)
|
116
|
+
|
117
|
+
|
118
|
+
def _get_dto_instance_for_empty_body(
|
119
|
+
dto_class: type[Dto],
|
120
|
+
dto_cls_name: str,
|
121
|
+
method_spec: OperationObject,
|
122
|
+
) -> Dto:
|
123
|
+
if dto_class == DefaultDto:
|
124
|
+
dto_instance: Dto = DefaultDto()
|
125
|
+
else:
|
126
|
+
cls_name = method_spec.operationId if method_spec.operationId else dto_cls_name
|
127
|
+
dto_class = make_dataclass(
|
128
|
+
cls_name=cls_name,
|
129
|
+
fields=[],
|
130
|
+
bases=(dto_class,),
|
131
|
+
)
|
132
|
+
dto_instance = dto_class()
|
133
|
+
return dto_instance
|
134
|
+
|
135
|
+
|
136
|
+
def _get_dto_instance_from_dto_data(
|
137
|
+
object_schema: ObjectSchema,
|
138
|
+
dto_class: type[Dto],
|
139
|
+
dto_data: JSON,
|
140
|
+
method_spec: OperationObject,
|
141
|
+
dto_cls_name: str,
|
142
|
+
) -> Dto:
|
143
|
+
if not isinstance(dto_data, (dict, list)):
|
144
|
+
return DefaultDto()
|
145
|
+
|
146
|
+
if isinstance(dto_data, list):
|
147
|
+
raise NotImplementedError
|
148
|
+
|
149
|
+
fields = get_fields_from_dto_data(object_schema, dto_data)
|
150
|
+
cls_name = method_spec.operationId if method_spec.operationId else dto_cls_name
|
151
|
+
dto_class_ = make_dataclass(
|
152
|
+
cls_name=cls_name,
|
153
|
+
fields=fields,
|
154
|
+
bases=(dto_class,),
|
155
|
+
)
|
156
|
+
# dto_data = {get_safe_key(key): value for key, value in dto_data.items()}
|
157
|
+
dto_data = {
|
158
|
+
get_safe_name_for_oas_name(key): value for key, value in dto_data.items()
|
159
|
+
}
|
160
|
+
return cast(Dto, dto_class_(**dto_data))
|
161
|
+
|
162
|
+
|
163
|
+
def get_fields_from_dto_data(
|
164
|
+
object_schema: ObjectSchema, dto_data: dict[str, JSON]
|
165
|
+
) -> list[tuple[str, type[object], Field[object]]]:
|
166
|
+
"""Get a dataclasses fields list based on the content_schema and dto_data."""
|
167
|
+
fields: list[tuple[str, type[object], Field[object]]] = []
|
168
|
+
|
169
|
+
for key, value in dto_data.items():
|
170
|
+
# safe_key = get_safe_key(key)
|
171
|
+
safe_key = get_safe_name_for_oas_name(key)
|
172
|
+
# metadata = {"original_property_name": key}
|
173
|
+
if key in object_schema.required:
|
174
|
+
# The fields list is used to create a dataclass, so non-default fields
|
175
|
+
# must go before fields with a default
|
176
|
+
field_ = cast(Field[Any], field()) # pylint: disable=invalid-field-call
|
177
|
+
fields.insert(0, (safe_key, type(value), field_))
|
178
|
+
else:
|
179
|
+
field_ = cast(Field[Any], field(default=None)) # pylint: disable=invalid-field-call
|
180
|
+
fields.append((safe_key, type(value), field_))
|
181
|
+
return fields
|
182
|
+
|
183
|
+
|
184
|
+
def get_dto_cls_name(path: str, method: str) -> str:
|
185
|
+
method = method.capitalize()
|
186
|
+
path = path.translate({ord(i): None for i in "{}"})
|
187
|
+
path_parts = path.split("/")
|
188
|
+
path_parts = [p.capitalize() for p in path_parts]
|
189
|
+
result = "".join([method, *path_parts])
|
190
|
+
return result
|
191
|
+
|
192
|
+
|
193
|
+
def get_request_parameters(
|
194
|
+
dto_class: Dto | type[Dto], method_spec: OperationObject
|
195
|
+
) -> tuple[list[ParameterObject], dict[str, Any], dict[str, str]]:
|
196
|
+
"""Get the methods parameter spec and params and headers with valid data."""
|
197
|
+
parameters = method_spec.parameters if method_spec.parameters else []
|
198
|
+
parameter_relations = dto_class.get_parameter_relations()
|
199
|
+
query_params = [p for p in parameters if p.in_ == "query"]
|
200
|
+
header_params = [p for p in parameters if p.in_ == "header"]
|
201
|
+
params = get_parameter_data(query_params, parameter_relations)
|
202
|
+
headers = get_parameter_data(header_params, parameter_relations)
|
203
|
+
return parameters, params, headers
|
204
|
+
|
205
|
+
|
206
|
+
def get_parameter_data(
|
207
|
+
parameters: list[ParameterObject],
|
208
|
+
parameter_relations: list[ResourceRelation],
|
209
|
+
) -> dict[str, str]:
|
210
|
+
"""Generate a valid list of key-value pairs for all parameters."""
|
211
|
+
result: dict[str, str] = {}
|
212
|
+
value: Any = None
|
213
|
+
for parameter in parameters:
|
214
|
+
parameter_name = parameter.name
|
215
|
+
# register the oas_name
|
216
|
+
_ = get_safe_name_for_oas_name(parameter_name)
|
217
|
+
relations = [
|
218
|
+
r for r in parameter_relations if r.property_name == parameter_name
|
219
|
+
]
|
220
|
+
if constrained_values := [
|
221
|
+
r.values for r in relations if isinstance(r, PropertyValueConstraint)
|
222
|
+
]:
|
223
|
+
value = choice(*constrained_values)
|
224
|
+
if value is IGNORE:
|
225
|
+
continue
|
226
|
+
result[parameter_name] = value
|
227
|
+
continue
|
228
|
+
|
229
|
+
if parameter.schema_ is None:
|
230
|
+
continue
|
231
|
+
value = parameter.schema_.get_valid_value()
|
232
|
+
result[parameter_name] = value
|
233
|
+
return result
|