robotframework-openapitools 1.0.0b2__tar.gz → 1.0.0b4__tar.gz
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.
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/PKG-INFO +98 -1
- robotframework_openapitools-1.0.0b4/docs/README.md +102 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/pyproject.toml +4 -4
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiDriver/openapi_executors.py +8 -8
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiDriver/openapi_reader.py +12 -13
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiDriver/openapidriver.libspec +4 -41
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/__init__.py +0 -2
- robotframework_openapitools-1.0.0b4/src/OpenApiLibCore/annotations.py +10 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/data_generation/__init__.py +0 -2
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/data_generation/body_data_generation.py +52 -71
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/data_generation/data_generation_core.py +82 -62
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/data_invalidation.py +37 -20
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/dto_base.py +20 -86
- robotframework_openapitools-1.0.0b4/src/OpenApiLibCore/localized_faker.py +88 -0
- robotframework_openapitools-1.0.0b4/src/OpenApiLibCore/models.py +715 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/openapi_libcore.libspec +47 -283
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/openapi_libcore.py +20 -46
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/parameter_utils.py +23 -17
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/path_functions.py +5 -4
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/protocols.py +7 -5
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/request_data.py +67 -102
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/resource_relations.py +2 -3
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/validation.py +49 -161
- robotframework_openapitools-1.0.0b4/src/OpenApiLibCore/value_utils.py +216 -0
- robotframework_openapitools-1.0.0b4/src/openapi_libgen/__init__.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/openapi_libgen/command_line.py +7 -19
- robotframework_openapitools-1.0.0b4/src/openapi_libgen/generator.py +84 -0
- robotframework_openapitools-1.0.0b4/src/openapi_libgen/spec_parser.py +154 -0
- robotframework_openapitools-1.0.0b2/docs/README.md +0 -6
- robotframework_openapitools-1.0.0b2/src/OpenApiLibCore/annotations.py +0 -3
- robotframework_openapitools-1.0.0b2/src/OpenApiLibCore/value_utils.py +0 -528
- robotframework_openapitools-1.0.0b2/src/openapi_libgen/__init__.py +0 -46
- robotframework_openapitools-1.0.0b2/src/openapi_libgen/spec_parser.py +0 -221
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/LICENSE +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiDriver/__init__.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiDriver/openapidriver.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiDriver/py.typed +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/dto_utils.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/oas_cache.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/path_invalidation.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/OpenApiLibCore/py.typed +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/openapi_libgen/parsing_utils.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/openapi_libgen/templates/__init__.jinja +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b4}/src/openapi_libgen/templates/library.jinja +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: robotframework-openapitools
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.0b4
|
4
4
|
Summary: A set of Robot Framework libraries to test APIs for which the OAS is available.
|
5
5
|
License: Apache License
|
6
6
|
Version 2.0, January 2004
|
@@ -220,6 +220,7 @@ Requires-Dist: Jinja2 (>=3.1.2)
|
|
220
220
|
Requires-Dist: black (>=24.1.0)
|
221
221
|
Requires-Dist: openapi-core (>=0.19.0)
|
222
222
|
Requires-Dist: prance[cli] (>=23)
|
223
|
+
Requires-Dist: pydantic (>=2.11.0)
|
223
224
|
Requires-Dist: requests (>=2.31.0)
|
224
225
|
Requires-Dist: rich_click (>=1.7.0)
|
225
226
|
Requires-Dist: robotframework (>=6.0.0,!=7.0.0)
|
@@ -235,3 +236,99 @@ OpenApiTools is a set of libraries centered around the OpenAPI Specification:
|
|
235
236
|
- [OpenApiDriver](./driver.md)
|
236
237
|
- [OpenApiLibCore](./libcore.md)
|
237
238
|
|
239
|
+
|
240
|
+
## New in OpenApiTools v1.0.0
|
241
|
+
|
242
|
+
Inspired by the work Bartlomiej and Mateusz did on #roboswag, I've created a CLI tool that generates a fully functional Robot Framework (Python) library that builds on OpenApiLibCore for automatic request data generation and request execution.
|
243
|
+
|
244
|
+
### So how does it work?
|
245
|
+
After installing / updating to the v1.0.0 beta (`pip install robotframework-openapitools==1.0.0b3`) , there's a new CLI command available in your (virtual) environment: `generate-library`. You'll have to provide a path to the openapi spec (json or yaml, can be a url or path to the file), provide a path to where to generate the library and (optionally) a name for the library:
|
246
|
+
|
247
|
+
```
|
248
|
+
$ generate-library
|
249
|
+
Please provide a source for the generation:
|
250
|
+
$ http://127.0.0.1:8000/openapi.json
|
251
|
+
Please provide a path to where the library will be generated:
|
252
|
+
$ ./generated
|
253
|
+
Please provide a name for the library [default: FastAPI]:
|
254
|
+
$ My Generated Library
|
255
|
+
generated/MyGeneratedLibrary/__init__.py created
|
256
|
+
generated/MyGeneratedLibrary/my_generated_library.py created
|
257
|
+
```
|
258
|
+
|
259
|
+
> Note: there's currently 2 environment variables that are taken into account by the generator; USE_SUMMARY_AS_KEYWORD_NAME can result in nicer keyword names (but: uniqueness is not guaranteed, so you might need to rename some of the generated keywords manually) and EXPAND_BODY_ARGUMENTS is what a recent poll in #api-testing was about.
|
260
|
+
|
261
|
+
If the location where the library is located is in your Python search path, you'll be able to use it like a regular Robot Framework library (in fact, it's a drop-in replacement for OpenApiLibCore):
|
262
|
+
|
263
|
+
```{robot}
|
264
|
+
*** Settings ***
|
265
|
+
Library MyGeneratedLibrary
|
266
|
+
... source=${ORIGIN}/openapi.json
|
267
|
+
... origin=${ORIGIN}
|
268
|
+
... base_path=${EMPTY}
|
269
|
+
... mappings_path=${ROOT}/tests/user_implemented/custom_user_mappings.py
|
270
|
+
Variables ${ROOT}/tests/variables.py
|
271
|
+
|
272
|
+
|
273
|
+
*** Variables ***
|
274
|
+
${ORIGIN}= http://localhost:8000
|
275
|
+
|
276
|
+
|
277
|
+
*** Test Cases ***
|
278
|
+
Test Generated Keywords: Get Employees
|
279
|
+
${response}= Get Employees
|
280
|
+
Should Be Equal As Integers ${response.status_code} 200
|
281
|
+
|
282
|
+
Test Generated Keywords: Post Employee
|
283
|
+
VAR &{body} name=Robin the Robot
|
284
|
+
${response}= Post Employee body=${body}
|
285
|
+
# ${response}= Post Employee name=Robin the Robot
|
286
|
+
Should Be Equal As Integers ${response.status_code} 201
|
287
|
+
Should Be Equal ${response.json()}[name] Robin the Robot
|
288
|
+
|
289
|
+
Test Generated Keywords: Get Employee
|
290
|
+
${response}= Get Employee
|
291
|
+
Should Be Equal As Integers ${response.status_code} 200
|
292
|
+
|
293
|
+
Test Generated Keywords: Patch Employee
|
294
|
+
${employee_id}= Get Valid Id For Path path=/employees/{employee_id}
|
295
|
+
VAR &{body} date_of_birth=2021-12-31
|
296
|
+
${response}= Patch Employee employee_id=${employee_id} body=${body}
|
297
|
+
# ${response}= Patch Employee employee_id=${employee_id} date_of_birth=2021-12-31
|
298
|
+
Should Be Equal As Integers ${response.status_code} 403
|
299
|
+
|
300
|
+
Test Generated Keywords: Post WageGroup
|
301
|
+
VAR &{body} hourly_rate=99.99
|
302
|
+
${response}= Post Wagegroup body=${body}
|
303
|
+
# ${response}= Post Wagegroup hourly_rate=99.99
|
304
|
+
Should Be Equal As Integers ${response.status_code} 201
|
305
|
+
Should Be Equal As Numbers ${response.json()}[hourly-rate] 99.99
|
306
|
+
|
307
|
+
Test Generated Keywords: Get Energy Label
|
308
|
+
${response}= Get Energy Label
|
309
|
+
... zipcode=1111AA
|
310
|
+
... home_number=10
|
311
|
+
... extension=too long to be acceptable
|
312
|
+
... validate_against_schema=${FALSE}
|
313
|
+
Should Be Equal As Integers ${response.status_code} 422
|
314
|
+
|
315
|
+
VAR @{omit} extension
|
316
|
+
${response}= Get Energy Label
|
317
|
+
... zipcode=1111AA
|
318
|
+
... home_number=10
|
319
|
+
... extension=too long to be acceptable
|
320
|
+
... omit_parameters=${omit}
|
321
|
+
Should Be Equal As Integers ${response.status_code} 200
|
322
|
+
```
|
323
|
+
|
324
|
+
### Contributions and feedback
|
325
|
+
|
326
|
+
So now I need your feedback! Does the library generator work for your openapi spec? Does the library work / do all the generated keywords work? Please let me know of any issues you run into!
|
327
|
+
Things I'd like to address / improve before an official release:
|
328
|
+
- parameters with union types (e.g. int or float) are currently annotated as Any.
|
329
|
+
- support for lists / arrays is limited (i.e. not supported as body)
|
330
|
+
- objects / dicts are currently only typed as dict; I'm looking into TypedDict annotation for better auto-complete / auto-conversion
|
331
|
+
- a documentation rework
|
332
|
+
|
333
|
+
Subscribe to https://app.slack.com/client/T07PJQ9S7/CKK0X68KD for updates
|
334
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# OpenApiTools for Robot Framework
|
2
|
+
|
3
|
+
OpenApiTools is a set of libraries centered around the OpenAPI Specification:
|
4
|
+
|
5
|
+
- [OpenApiDriver](./driver.md)
|
6
|
+
- [OpenApiLibCore](./libcore.md)
|
7
|
+
|
8
|
+
|
9
|
+
## New in OpenApiTools v1.0.0
|
10
|
+
|
11
|
+
Inspired by the work Bartlomiej and Mateusz did on #roboswag, I've created a CLI tool that generates a fully functional Robot Framework (Python) library that builds on OpenApiLibCore for automatic request data generation and request execution.
|
12
|
+
|
13
|
+
### So how does it work?
|
14
|
+
After installing / updating to the v1.0.0 beta (`pip install robotframework-openapitools==1.0.0b3`) , there's a new CLI command available in your (virtual) environment: `generate-library`. You'll have to provide a path to the openapi spec (json or yaml, can be a url or path to the file), provide a path to where to generate the library and (optionally) a name for the library:
|
15
|
+
|
16
|
+
```
|
17
|
+
$ generate-library
|
18
|
+
Please provide a source for the generation:
|
19
|
+
$ http://127.0.0.1:8000/openapi.json
|
20
|
+
Please provide a path to where the library will be generated:
|
21
|
+
$ ./generated
|
22
|
+
Please provide a name for the library [default: FastAPI]:
|
23
|
+
$ My Generated Library
|
24
|
+
generated/MyGeneratedLibrary/__init__.py created
|
25
|
+
generated/MyGeneratedLibrary/my_generated_library.py created
|
26
|
+
```
|
27
|
+
|
28
|
+
> Note: there's currently 2 environment variables that are taken into account by the generator; USE_SUMMARY_AS_KEYWORD_NAME can result in nicer keyword names (but: uniqueness is not guaranteed, so you might need to rename some of the generated keywords manually) and EXPAND_BODY_ARGUMENTS is what a recent poll in #api-testing was about.
|
29
|
+
|
30
|
+
If the location where the library is located is in your Python search path, you'll be able to use it like a regular Robot Framework library (in fact, it's a drop-in replacement for OpenApiLibCore):
|
31
|
+
|
32
|
+
```{robot}
|
33
|
+
*** Settings ***
|
34
|
+
Library MyGeneratedLibrary
|
35
|
+
... source=${ORIGIN}/openapi.json
|
36
|
+
... origin=${ORIGIN}
|
37
|
+
... base_path=${EMPTY}
|
38
|
+
... mappings_path=${ROOT}/tests/user_implemented/custom_user_mappings.py
|
39
|
+
Variables ${ROOT}/tests/variables.py
|
40
|
+
|
41
|
+
|
42
|
+
*** Variables ***
|
43
|
+
${ORIGIN}= http://localhost:8000
|
44
|
+
|
45
|
+
|
46
|
+
*** Test Cases ***
|
47
|
+
Test Generated Keywords: Get Employees
|
48
|
+
${response}= Get Employees
|
49
|
+
Should Be Equal As Integers ${response.status_code} 200
|
50
|
+
|
51
|
+
Test Generated Keywords: Post Employee
|
52
|
+
VAR &{body} name=Robin the Robot
|
53
|
+
${response}= Post Employee body=${body}
|
54
|
+
# ${response}= Post Employee name=Robin the Robot
|
55
|
+
Should Be Equal As Integers ${response.status_code} 201
|
56
|
+
Should Be Equal ${response.json()}[name] Robin the Robot
|
57
|
+
|
58
|
+
Test Generated Keywords: Get Employee
|
59
|
+
${response}= Get Employee
|
60
|
+
Should Be Equal As Integers ${response.status_code} 200
|
61
|
+
|
62
|
+
Test Generated Keywords: Patch Employee
|
63
|
+
${employee_id}= Get Valid Id For Path path=/employees/{employee_id}
|
64
|
+
VAR &{body} date_of_birth=2021-12-31
|
65
|
+
${response}= Patch Employee employee_id=${employee_id} body=${body}
|
66
|
+
# ${response}= Patch Employee employee_id=${employee_id} date_of_birth=2021-12-31
|
67
|
+
Should Be Equal As Integers ${response.status_code} 403
|
68
|
+
|
69
|
+
Test Generated Keywords: Post WageGroup
|
70
|
+
VAR &{body} hourly_rate=99.99
|
71
|
+
${response}= Post Wagegroup body=${body}
|
72
|
+
# ${response}= Post Wagegroup hourly_rate=99.99
|
73
|
+
Should Be Equal As Integers ${response.status_code} 201
|
74
|
+
Should Be Equal As Numbers ${response.json()}[hourly-rate] 99.99
|
75
|
+
|
76
|
+
Test Generated Keywords: Get Energy Label
|
77
|
+
${response}= Get Energy Label
|
78
|
+
... zipcode=1111AA
|
79
|
+
... home_number=10
|
80
|
+
... extension=too long to be acceptable
|
81
|
+
... validate_against_schema=${FALSE}
|
82
|
+
Should Be Equal As Integers ${response.status_code} 422
|
83
|
+
|
84
|
+
VAR @{omit} extension
|
85
|
+
${response}= Get Energy Label
|
86
|
+
... zipcode=1111AA
|
87
|
+
... home_number=10
|
88
|
+
... extension=too long to be acceptable
|
89
|
+
... omit_parameters=${omit}
|
90
|
+
Should Be Equal As Integers ${response.status_code} 200
|
91
|
+
```
|
92
|
+
|
93
|
+
### Contributions and feedback
|
94
|
+
|
95
|
+
So now I need your feedback! Does the library generator work for your openapi spec? Does the library work / do all the generated keywords work? Please let me know of any issues you run into!
|
96
|
+
Things I'd like to address / improve before an official release:
|
97
|
+
- parameters with union types (e.g. int or float) are currently annotated as Any.
|
98
|
+
- support for lists / arrays is limited (i.e. not supported as body)
|
99
|
+
- objects / dicts are currently only typed as dict; I'm looking into TypedDict annotation for better auto-complete / auto-conversion
|
100
|
+
- a documentation rework
|
101
|
+
|
102
|
+
Subscribe to https://app.slack.com/client/T07PJQ9S7/CKK0X68KD for updates
|
@@ -1,11 +1,9 @@
|
|
1
1
|
[project]
|
2
2
|
name="robotframework-openapitools"
|
3
|
-
version = "1.0.
|
3
|
+
version = "1.0.0b4"
|
4
4
|
description = "A set of Robot Framework libraries to test APIs for which the OAS is available."
|
5
5
|
authors = [
|
6
6
|
{name = "Robin Mackaij", email = "r.a.mackaij@gmail.com"},
|
7
|
-
{name = "Bartlomiej Hirsz", email = "bartek.hirsz@gmail.com"},
|
8
|
-
{name = "Mateusz Nojek", email = "matnojek@gmail.com"},
|
9
7
|
]
|
10
8
|
maintainers = [
|
11
9
|
{name = "Robin Mackaij", email = "r.a.mackaij@gmail.com"},
|
@@ -33,6 +31,7 @@ dependencies = [
|
|
33
31
|
"rich_click >= 1.7.0",
|
34
32
|
"black >= 24.1.0",
|
35
33
|
"Jinja2 >= 3.1.2",
|
34
|
+
"pydantic >= 2.11.0",
|
36
35
|
]
|
37
36
|
|
38
37
|
[dependency-groups]
|
@@ -101,7 +100,8 @@ build-backend = "poetry.core.masonry.api"
|
|
101
100
|
[tool.coverage.run]
|
102
101
|
branch = true
|
103
102
|
parallel = true
|
104
|
-
source = ["src/OpenApiDriver", "src/OpenApiLibCore"]
|
103
|
+
source = ["src/OpenApiDriver", "src/OpenApiLibCore", "src/openapi_libgen"]
|
104
|
+
omit = ["src/openapi_libgen/command_line.py"]
|
105
105
|
|
106
106
|
[tool.coverage.report]
|
107
107
|
exclude_lines = [
|
@@ -185,8 +185,8 @@ class OpenApiExecutors(OpenApiLibCore):
|
|
185
185
|
# in case of a status code indicating an error, ensure the error occurs
|
186
186
|
if status_code >= int(HTTPStatus.BAD_REQUEST):
|
187
187
|
invalidation_keyword_data = {
|
188
|
-
"
|
189
|
-
"
|
188
|
+
"get_invalid_body_data": [
|
189
|
+
"get_invalid_body_data",
|
190
190
|
url,
|
191
191
|
method,
|
192
192
|
status_code,
|
@@ -201,13 +201,13 @@ class OpenApiExecutors(OpenApiLibCore):
|
|
201
201
|
invalidation_keywords = []
|
202
202
|
|
203
203
|
if request_data.dto.get_body_relations_for_error_code(status_code):
|
204
|
-
invalidation_keywords.append("
|
204
|
+
invalidation_keywords.append("get_invalid_body_data")
|
205
205
|
if request_data.dto.get_parameter_relations_for_error_code(status_code):
|
206
206
|
invalidation_keywords.append("get_invalidated_parameters")
|
207
207
|
if invalidation_keywords:
|
208
208
|
if (
|
209
209
|
invalidation_keyword := choice(invalidation_keywords)
|
210
|
-
) == "
|
210
|
+
) == "get_invalid_body_data":
|
211
211
|
json_data = run_keyword(
|
212
212
|
*invalidation_keyword_data[invalidation_keyword]
|
213
213
|
)
|
@@ -225,13 +225,13 @@ class OpenApiExecutors(OpenApiLibCore):
|
|
225
225
|
params, headers = run_keyword(
|
226
226
|
*invalidation_keyword_data["get_invalidated_parameters"]
|
227
227
|
)
|
228
|
-
if request_data.
|
228
|
+
if request_data.body_schema:
|
229
229
|
json_data = run_keyword(
|
230
|
-
*invalidation_keyword_data["
|
230
|
+
*invalidation_keyword_data["get_invalid_body_data"]
|
231
231
|
)
|
232
|
-
elif request_data.
|
232
|
+
elif request_data.body_schema:
|
233
233
|
json_data = run_keyword(
|
234
|
-
*invalidation_keyword_data["
|
234
|
+
*invalidation_keyword_data["get_invalid_body_data"]
|
235
235
|
)
|
236
236
|
else:
|
237
237
|
raise SkipExecution(
|
@@ -1,10 +1,12 @@
|
|
1
1
|
"""Module holding the OpenApiReader reader_class implementation."""
|
2
2
|
|
3
|
-
from typing import
|
3
|
+
from typing import Sequence
|
4
4
|
|
5
5
|
from DataDriver.AbstractReaderClass import AbstractReaderClass
|
6
6
|
from DataDriver.ReaderConfig import TestCaseData
|
7
7
|
|
8
|
+
from OpenApiLibCore.models import PathItemObject
|
9
|
+
|
8
10
|
|
9
11
|
class Test:
|
10
12
|
"""
|
@@ -16,7 +18,7 @@ class Test:
|
|
16
18
|
self.method = method.lower()
|
17
19
|
self.response = str(response)
|
18
20
|
|
19
|
-
def __eq__(self, other:
|
21
|
+
def __eq__(self, other: object) -> bool:
|
20
22
|
if not isinstance(other, type(self)):
|
21
23
|
return False
|
22
24
|
return (
|
@@ -33,7 +35,7 @@ class OpenApiReader(AbstractReaderClass):
|
|
33
35
|
test_data: list[TestCaseData] = []
|
34
36
|
|
35
37
|
read_paths_method = getattr(self, "read_paths_method")
|
36
|
-
paths: dict[str,
|
38
|
+
paths: dict[str, PathItemObject] = read_paths_method()
|
37
39
|
self._filter_paths(paths)
|
38
40
|
|
39
41
|
ignored_responses_ = [
|
@@ -43,15 +45,12 @@ class OpenApiReader(AbstractReaderClass):
|
|
43
45
|
ignored_tests = [Test(*test) for test in getattr(self, "ignored_testcases", [])]
|
44
46
|
|
45
47
|
for path, path_item in paths.items():
|
48
|
+
path_operations = path_item.get_operations()
|
49
|
+
|
46
50
|
# by reseversing the items, post/put operations come before get and delete
|
47
|
-
for
|
48
|
-
|
49
|
-
|
50
|
-
if item_name not in ["get", "put", "post", "delete", "patch"]:
|
51
|
-
continue
|
52
|
-
method, method_data = item_name, item_data
|
53
|
-
tags_from_spec = method_data.get("tags", [])
|
54
|
-
for response in method_data.get("responses"):
|
51
|
+
for method, operation_data in reversed(path_operations.items()):
|
52
|
+
tags_from_spec = operation_data.tags
|
53
|
+
for response in operation_data.responses.keys():
|
55
54
|
# 'default' applies to all status codes that are not specified, in
|
56
55
|
# which case we don't know what to expect and therefore can't verify
|
57
56
|
if (
|
@@ -76,7 +75,7 @@ class OpenApiReader(AbstractReaderClass):
|
|
76
75
|
)
|
77
76
|
return test_data
|
78
77
|
|
79
|
-
def _filter_paths(self, paths: dict[str,
|
78
|
+
def _filter_paths(self, paths: dict[str, PathItemObject]) -> None:
|
80
79
|
def matches_include_pattern(path: str) -> bool:
|
81
80
|
for included_path in included_paths:
|
82
81
|
if path == included_path:
|
@@ -111,5 +110,5 @@ class OpenApiReader(AbstractReaderClass):
|
|
111
110
|
paths.pop(path)
|
112
111
|
|
113
112
|
|
114
|
-
def _get_tag_list(tags:
|
113
|
+
def _get_tag_list(tags: Sequence[str], method: str, response: str) -> list[str]:
|
115
114
|
return [*tags, f"Method: {method.upper()}", f"Response: {response}"]
|
@@ -1,12 +1,12 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<keywordspec name="OpenApiDriver" type="LIBRARY" format="HTML" scope="SUITE" generated="2025-
|
3
|
-
<version>1.0.
|
2
|
+
<keywordspec name="OpenApiDriver" type="LIBRARY" format="HTML" scope="SUITE" generated="2025-05-11T17:23:01+00:00" specversion="6" source="/workspaces/robotframework-openapitools/src/OpenApiDriver/openapidriver.py" lineno="358">
|
3
|
+
<version>1.0.0b3</version>
|
4
4
|
<doc><p>Visit the <a href="https://github.com/MarketSquare/robotframework-openapidriver">library page</a> for an introduction and examples.</p></doc>
|
5
5
|
<tags>
|
6
6
|
</tags>
|
7
7
|
<inits>
|
8
8
|
<init name="__init__" lineno="150">
|
9
|
-
<arguments repr="source: str, origin: str = , base_path: str = , included_paths: Iterable[str] = frozenset(), ignored_paths: Iterable[str] = frozenset(), ignored_responses: Iterable[int] = frozenset(), ignored_testcases: Iterable[tuple[str, str, int]] = frozenset(), response_validation: ValidationLevel = WARN, disable_server_validation: bool = True, mappings_path: str | Path = , invalid_property_default_response: int = 422, default_id_property_name: str = id, faker_locale: str | list[str] = , require_body_for_invalid_url: bool = False, recursion_limit: int = 1, recursion_default:
|
9
|
+
<arguments repr="source: str, origin: str = , base_path: str = , included_paths: Iterable[str] = frozenset(), ignored_paths: Iterable[str] = frozenset(), ignored_responses: Iterable[int] = frozenset(), ignored_testcases: Iterable[tuple[str, str, int]] = frozenset(), response_validation: ValidationLevel = WARN, disable_server_validation: bool = True, mappings_path: str | Path = , invalid_property_default_response: int = 422, default_id_property_name: str = id, faker_locale: str | list[str] = , require_body_for_invalid_url: bool = False, recursion_limit: int = 1, recursion_default: JSON = {}, username: str = , password: str = , security_token: str = , auth: AuthBase | None = None, cert: str | tuple[str, str] = , verify_tls: bool | str = True, extra_headers: Mapping[str, str] = {}, cookies: MutableMapping[str, str] | RequestsCookieJar | None = None, proxies: MutableMapping[str, str] | None = None">
|
10
10
|
<arg kind="POSITIONAL_OR_NAMED" required="true" repr="source: str">
|
11
11
|
<name>source</name>
|
12
12
|
<type name="str" typedoc="string"/>
|
@@ -101,23 +101,9 @@
|
|
101
101
|
<type name="int" typedoc="integer"/>
|
102
102
|
<default>1</default>
|
103
103
|
</arg>
|
104
|
-
<arg kind="POSITIONAL_OR_NAMED" required="false" repr="recursion_default:
|
104
|
+
<arg kind="POSITIONAL_OR_NAMED" required="false" repr="recursion_default: JSON = {}">
|
105
105
|
<name>recursion_default</name>
|
106
|
-
<type name="Union" union="true">
|
107
|
-
<type name="dict" typedoc="dictionary">
|
108
|
-
<type name="str" typedoc="string"/>
|
109
106
|
<type name="JSON"/>
|
110
|
-
</type>
|
111
|
-
<type name="list" typedoc="list">
|
112
|
-
<type name="JSON"/>
|
113
|
-
</type>
|
114
|
-
<type name="str" typedoc="string"/>
|
115
|
-
<type name="bytes" typedoc="bytes"/>
|
116
|
-
<type name="int" typedoc="integer"/>
|
117
|
-
<type name="float" typedoc="float"/>
|
118
|
-
<type name="bool" typedoc="boolean"/>
|
119
|
-
<type name="None" typedoc="None"/>
|
120
|
-
</type>
|
121
107
|
<default>{}</default>
|
122
108
|
</arg>
|
123
109
|
<arg kind="POSITIONAL_OR_NAMED" required="false" repr="username: str = ">
|
@@ -350,17 +336,6 @@
|
|
350
336
|
<usage>__init__</usage>
|
351
337
|
</usages>
|
352
338
|
</type>
|
353
|
-
<type name="bytes" type="Standard">
|
354
|
-
<doc><p>Strings are converted to bytes so that each Unicode code point below 256 is directly mapped to a matching byte. Higher code points are not allowed. Robot Framework's <code>\xHH</code> escape syntax is convenient with bytes having non-printable values.</p>
|
355
|
-
<p>Examples: <code>good</code>, <code>hyvä</code> (same as <code>hyv\xE4</code>), <code>\x00</code> (the null byte)</p></doc>
|
356
|
-
<accepts>
|
357
|
-
<type>string</type>
|
358
|
-
<type>bytearray</type>
|
359
|
-
</accepts>
|
360
|
-
<usages>
|
361
|
-
<usage>__init__</usage>
|
362
|
-
</usages>
|
363
|
-
</type>
|
364
339
|
<type name="dictionary" type="Standard">
|
365
340
|
<doc><p>Strings must be Python <a href="https://docs.python.org/library/stdtypes.html#dict">dictionary</a> literals. They are converted to actual dictionaries using the <a href="https://docs.python.org/library/ast.html#ast.literal_eval">ast.literal_eval</a> function. They can contain any values <code>ast.literal_eval</code> supports, including dictionaries and other containers.</p>
|
366
341
|
<p>If the type has nested types like <code>dict[str, int]</code>, items are converted to those types automatically. This in new in Robot Framework 6.0.</p>
|
@@ -373,18 +348,6 @@
|
|
373
348
|
<usage>__init__</usage>
|
374
349
|
</usages>
|
375
350
|
</type>
|
376
|
-
<type name="float" type="Standard">
|
377
|
-
<doc><p>Conversion is done using Python's <a href="https://docs.python.org/library/functions.html#float">float</a> built-in function.</p>
|
378
|
-
<p>Starting from RF 4.1, spaces and underscores can be used as visual separators for digit grouping purposes.</p>
|
379
|
-
<p>Examples: <code>3.14</code>, <code>2.9979e8</code>, <code>10 000.000 01</code></p></doc>
|
380
|
-
<accepts>
|
381
|
-
<type>string</type>
|
382
|
-
<type>Real</type>
|
383
|
-
</accepts>
|
384
|
-
<usages>
|
385
|
-
<usage>__init__</usage>
|
386
|
-
</usages>
|
387
|
-
</type>
|
388
351
|
<type name="integer" type="Standard">
|
389
352
|
<doc><p>Conversion is done using Python's <a href="https://docs.python.org/library/functions.html#int">int</a> built-in function. Floating point numbers are accepted only if they can be represented as integers exactly. For example, <code>1.0</code> is accepted and <code>1.1</code> is not.</p>
|
390
353
|
<p>Starting from RF 4.1, it is possible to use hexadecimal, octal and binary numbers by prefixing values with <code>0x</code>, <code>0o</code> and <code>0b</code>, respectively.</p>
|
@@ -21,7 +21,6 @@ from OpenApiLibCore.dto_base import (
|
|
21
21
|
PropertyValueConstraint,
|
22
22
|
ResourceRelation,
|
23
23
|
UniquePropertyValueConstraint,
|
24
|
-
resolve_schema,
|
25
24
|
)
|
26
25
|
from OpenApiLibCore.dto_utils import DefaultDto
|
27
26
|
from OpenApiLibCore.openapi_libcore import (
|
@@ -52,5 +51,4 @@ __all__ = [
|
|
52
51
|
"ResourceRelation",
|
53
52
|
"UniquePropertyValueConstraint",
|
54
53
|
"ValidationLevel",
|
55
|
-
"resolve_schema",
|
56
54
|
]
|
@@ -3,10 +3,8 @@ Module holding the functions related to data generation
|
|
3
3
|
for the requests made as part of keyword exection.
|
4
4
|
"""
|
5
5
|
|
6
|
-
from .body_data_generation import get_json_data_for_dto_class
|
7
6
|
from .data_generation_core import get_request_data
|
8
7
|
|
9
8
|
__all__ = [
|
10
|
-
"get_json_data_for_dto_class",
|
11
9
|
"get_request_data",
|
12
10
|
]
|