robotframework-openapitools 1.0.0b2__tar.gz → 1.0.0b3__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.0b3}/PKG-INFO +97 -1
- robotframework_openapitools-1.0.0b3/docs/README.md +102 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/pyproject.toml +1 -1
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiDriver/openapidriver.libspec +1 -1
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/openapi_libcore.libspec +1 -1
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/openapi_libgen/spec_parser.py +9 -3
- robotframework_openapitools-1.0.0b2/docs/README.md +0 -6
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/LICENSE +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiDriver/__init__.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiDriver/openapi_executors.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiDriver/openapi_reader.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiDriver/openapidriver.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiDriver/py.typed +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/__init__.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/annotations.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/data_generation/__init__.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/data_generation/body_data_generation.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/data_generation/data_generation_core.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/data_invalidation.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/dto_base.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/dto_utils.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/oas_cache.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/openapi_libcore.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/parameter_utils.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/path_functions.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/path_invalidation.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/protocols.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/py.typed +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/request_data.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/resource_relations.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/validation.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/OpenApiLibCore/value_utils.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/openapi_libgen/__init__.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/openapi_libgen/command_line.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/openapi_libgen/parsing_utils.py +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/src/openapi_libgen/templates/__init__.jinja +0 -0
- {robotframework_openapitools-1.0.0b2 → robotframework_openapitools-1.0.0b3}/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.0b3
|
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
|
@@ -235,3 +235,99 @@ OpenApiTools is a set of libraries centered around the OpenAPI Specification:
|
|
235
235
|
- [OpenApiDriver](./driver.md)
|
236
236
|
- [OpenApiLibCore](./libcore.md)
|
237
237
|
|
238
|
+
|
239
|
+
## New in OpenApiTools v1.0.0
|
240
|
+
|
241
|
+
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.
|
242
|
+
|
243
|
+
### So how does it work?
|
244
|
+
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:
|
245
|
+
|
246
|
+
```
|
247
|
+
$ generate-library
|
248
|
+
Please provide a source for the generation:
|
249
|
+
$ http://127.0.0.1:8000/openapi.json
|
250
|
+
Please provide a path to where the library will be generated:
|
251
|
+
$ ./generated
|
252
|
+
Please provide a name for the library [default: FastAPI]:
|
253
|
+
$ My Generated Library
|
254
|
+
generated/MyGeneratedLibrary/__init__.py created
|
255
|
+
generated/MyGeneratedLibrary/my_generated_library.py created
|
256
|
+
```
|
257
|
+
|
258
|
+
> 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.
|
259
|
+
|
260
|
+
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):
|
261
|
+
|
262
|
+
```{robot}
|
263
|
+
*** Settings ***
|
264
|
+
Library MyGeneratedLibrary
|
265
|
+
... source=${ORIGIN}/openapi.json
|
266
|
+
... origin=${ORIGIN}
|
267
|
+
... base_path=${EMPTY}
|
268
|
+
... mappings_path=${ROOT}/tests/user_implemented/custom_user_mappings.py
|
269
|
+
Variables ${ROOT}/tests/variables.py
|
270
|
+
|
271
|
+
|
272
|
+
*** Variables ***
|
273
|
+
${ORIGIN}= http://localhost:8000
|
274
|
+
|
275
|
+
|
276
|
+
*** Test Cases ***
|
277
|
+
Test Generated Keywords: Get Employees
|
278
|
+
${response}= Get Employees
|
279
|
+
Should Be Equal As Integers ${response.status_code} 200
|
280
|
+
|
281
|
+
Test Generated Keywords: Post Employee
|
282
|
+
VAR &{body} name=Robin the Robot
|
283
|
+
${response}= Post Employee body=${body}
|
284
|
+
# ${response}= Post Employee name=Robin the Robot
|
285
|
+
Should Be Equal As Integers ${response.status_code} 201
|
286
|
+
Should Be Equal ${response.json()}[name] Robin the Robot
|
287
|
+
|
288
|
+
Test Generated Keywords: Get Employee
|
289
|
+
${response}= Get Employee
|
290
|
+
Should Be Equal As Integers ${response.status_code} 200
|
291
|
+
|
292
|
+
Test Generated Keywords: Patch Employee
|
293
|
+
${employee_id}= Get Valid Id For Path path=/employees/{employee_id}
|
294
|
+
VAR &{body} date_of_birth=2021-12-31
|
295
|
+
${response}= Patch Employee employee_id=${employee_id} body=${body}
|
296
|
+
# ${response}= Patch Employee employee_id=${employee_id} date_of_birth=2021-12-31
|
297
|
+
Should Be Equal As Integers ${response.status_code} 403
|
298
|
+
|
299
|
+
Test Generated Keywords: Post WageGroup
|
300
|
+
VAR &{body} hourly_rate=99.99
|
301
|
+
${response}= Post Wagegroup body=${body}
|
302
|
+
# ${response}= Post Wagegroup hourly_rate=99.99
|
303
|
+
Should Be Equal As Integers ${response.status_code} 201
|
304
|
+
Should Be Equal As Numbers ${response.json()}[hourly-rate] 99.99
|
305
|
+
|
306
|
+
Test Generated Keywords: Get Energy Label
|
307
|
+
${response}= Get Energy Label
|
308
|
+
... zipcode=1111AA
|
309
|
+
... home_number=10
|
310
|
+
... extension=too long to be acceptable
|
311
|
+
... validate_against_schema=${FALSE}
|
312
|
+
Should Be Equal As Integers ${response.status_code} 422
|
313
|
+
|
314
|
+
VAR @{omit} extension
|
315
|
+
${response}= Get Energy Label
|
316
|
+
... zipcode=1111AA
|
317
|
+
... home_number=10
|
318
|
+
... extension=too long to be acceptable
|
319
|
+
... omit_parameters=${omit}
|
320
|
+
Should Be Equal As Integers ${response.status_code} 200
|
321
|
+
```
|
322
|
+
|
323
|
+
### Contributions and feedback
|
324
|
+
|
325
|
+
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!
|
326
|
+
Things I'd like to address / improve before an official release:
|
327
|
+
- parameters with union types (e.g. int or float) are currently annotated as Any.
|
328
|
+
- support for lists / arrays is limited (i.e. not supported as body)
|
329
|
+
- objects / dicts are currently only typed as dict; I'm looking into TypedDict annotation for better auto-complete / auto-conversion
|
330
|
+
- a documentation rework
|
331
|
+
|
332
|
+
Subscribe to https://app.slack.com/client/T07PJQ9S7/CKK0X68KD for updates
|
333
|
+
|
@@ -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,5 +1,5 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<keywordspec name="OpenApiDriver" type="LIBRARY" format="HTML" scope="SUITE" generated="2025-04-
|
2
|
+
<keywordspec name="OpenApiDriver" type="LIBRARY" format="HTML" scope="SUITE" generated="2025-04-10T08:09:09+00:00" specversion="6" source="/workspaces/robotframework-openapitools/src/OpenApiDriver/openapidriver.py" lineno="358">
|
3
3
|
<version>1.0.0b2</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>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<keywordspec name="OpenApiLibCore" type="LIBRARY" format="HTML" scope="SUITE" generated="2025-04-
|
2
|
+
<keywordspec name="OpenApiLibCore" type="LIBRARY" format="HTML" scope="SUITE" generated="2025-04-10T08:09:02+00:00" specversion="6" source="/workspaces/robotframework-openapitools/src/OpenApiLibCore/openapi_libcore.py" lineno="170">
|
3
3
|
<version>1.0.0b2</version>
|
4
4
|
<doc><p>Main class providing the keywords and core logic to interact with an OpenAPI server.</p>
|
5
5
|
<p>Visit the <a href="https://github.com/MarketSquare/robotframework-openapi-libcore">library page</a> for an introduction.</p></doc>
|
@@ -40,11 +40,13 @@ BODY_TEMPLATE = BodyTemplate(BODY_TEMPLATE_)
|
|
40
40
|
class OperationDetails:
|
41
41
|
path: str
|
42
42
|
method: str
|
43
|
-
operation_id: str
|
44
43
|
parameters: list[dict[str, Any]]
|
45
44
|
request_body: dict[str, Any]
|
46
45
|
summary: str
|
47
46
|
description: str
|
47
|
+
operation_id: str | None = (
|
48
|
+
None # operationId MUST be unique within the spec, so no default ""
|
49
|
+
)
|
48
50
|
|
49
51
|
|
50
52
|
@dataclass
|
@@ -65,7 +67,7 @@ def get_path_items(paths: dict[str, Any]) -> Generator[OperationDetails, None, N
|
|
65
67
|
operation_details = OperationDetails(
|
66
68
|
path=path,
|
67
69
|
method=method,
|
68
|
-
operation_id=method_item
|
70
|
+
operation_id=method_item.get("operationId", None),
|
69
71
|
parameters=method_item.get("parameters", []),
|
70
72
|
request_body=method_item.get("requestBody", {}),
|
71
73
|
summary=method_item.get("summary"),
|
@@ -114,10 +116,14 @@ def get_keyword_signature(operation_details: OperationDetails) -> str:
|
|
114
116
|
keyword_name = remove_unsafe_characters_from_string(
|
115
117
|
operation_details.summary
|
116
118
|
).lower()
|
117
|
-
|
119
|
+
elif operation_details.operation_id:
|
118
120
|
keyword_name = remove_unsafe_characters_from_string(
|
119
121
|
operation_details.operation_id
|
120
122
|
).lower()
|
123
|
+
else:
|
124
|
+
keyword_name = remove_unsafe_characters_from_string(
|
125
|
+
f"{operation_details.method}_{operation_details.path}"
|
126
|
+
)
|
121
127
|
|
122
128
|
parameters = get_parameter_details(operation_details=operation_details)
|
123
129
|
path_parameters = [p for p in parameters if p.type == "path"]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|