robotframework-velo-sapgui 0.2.2__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_velo_sapgui-0.2.2/LICENSE +49 -0
- robotframework_velo_sapgui-0.2.2/PKG-INFO +181 -0
- robotframework_velo_sapgui-0.2.2/README.md +93 -0
- robotframework_velo_sapgui-0.2.2/pyproject.toml +72 -0
- robotframework_velo_sapgui-0.2.2/setup.cfg +4 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/__init__.py +27 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/__init__.py +5 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/base.py +70 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/event_capture.py +78 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/java_gateway.py +126 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/windows_scripting.py +477 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/exceptions.py +30 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/keywords.py +340 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/library.py +120 -0
- robotframework_velo_sapgui-0.2.2/src/SapLibrary/py.typed +0 -0
- robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/PKG-INFO +181 -0
- robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/SOURCES.txt +19 -0
- robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/dependency_links.txt +1 -0
- robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/requires.txt +13 -0
- robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/top_level.txt +1 -0
- robotframework_velo_sapgui-0.2.2/tests/test_client_resolution.py +33 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Copyright (c) 2026 Velo. All rights reserved.
|
|
2
|
+
|
|
3
|
+
PROPRIETARY SOFTWARE LICENSE
|
|
4
|
+
|
|
5
|
+
This software and its source code, documentation, and associated files
|
|
6
|
+
(collectively, the "Software") are the exclusive property of Velo and are
|
|
7
|
+
protected by copyright law and international treaties.
|
|
8
|
+
|
|
9
|
+
GRANT OF LICENSE
|
|
10
|
+
|
|
11
|
+
Velo grants you a limited, non-exclusive, non-transferable, non-sublicensable
|
|
12
|
+
license to use the Software solely for your internal business purposes,
|
|
13
|
+
strictly in accordance with any agreement entered into with Velo.
|
|
14
|
+
|
|
15
|
+
RESTRICTIONS
|
|
16
|
+
|
|
17
|
+
You may not, and you may not permit any third party to:
|
|
18
|
+
|
|
19
|
+
1. Copy, modify, adapt, translate, or create derivative works of the Software;
|
|
20
|
+
2. Reverse engineer, disassemble, decompile, or otherwise attempt to derive
|
|
21
|
+
the source code of the Software;
|
|
22
|
+
3. Sell, sublicense, rent, lease, transfer, or otherwise make the Software
|
|
23
|
+
available to any third party;
|
|
24
|
+
4. Remove or alter any proprietary notices, labels, or marks on the Software;
|
|
25
|
+
5. Use the Software for any purpose other than as expressly permitted
|
|
26
|
+
under this license.
|
|
27
|
+
|
|
28
|
+
NO WARRANTY
|
|
29
|
+
|
|
30
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
31
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
32
|
+
FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL VELO BE
|
|
33
|
+
LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE USE OF
|
|
34
|
+
THE SOFTWARE.
|
|
35
|
+
|
|
36
|
+
TERMINATION
|
|
37
|
+
|
|
38
|
+
This license is effective until terminated. It will terminate automatically
|
|
39
|
+
if you fail to comply with any of its terms. Upon termination, you must
|
|
40
|
+
immediately cease all use of the Software and destroy any copies in your
|
|
41
|
+
possession.
|
|
42
|
+
|
|
43
|
+
GOVERNING LAW
|
|
44
|
+
|
|
45
|
+
This license shall be governed by and construed in accordance with applicable
|
|
46
|
+
law. Any disputes arising under this license shall be subject to the exclusive
|
|
47
|
+
jurisdiction of the competent courts.
|
|
48
|
+
|
|
49
|
+
For licensing inquiries, contact: legal@velo.com
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: robotframework-velo-sapgui
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Robot Framework keyword library for SAP GUI automation (Java and Windows)
|
|
5
|
+
Author-email: Velo <legal@velo.com>
|
|
6
|
+
License: Copyright (c) 2026 Velo. All rights reserved.
|
|
7
|
+
|
|
8
|
+
PROPRIETARY SOFTWARE LICENSE
|
|
9
|
+
|
|
10
|
+
This software and its source code, documentation, and associated files
|
|
11
|
+
(collectively, the "Software") are the exclusive property of Velo and are
|
|
12
|
+
protected by copyright law and international treaties.
|
|
13
|
+
|
|
14
|
+
GRANT OF LICENSE
|
|
15
|
+
|
|
16
|
+
Velo grants you a limited, non-exclusive, non-transferable, non-sublicensable
|
|
17
|
+
license to use the Software solely for your internal business purposes,
|
|
18
|
+
strictly in accordance with any agreement entered into with Velo.
|
|
19
|
+
|
|
20
|
+
RESTRICTIONS
|
|
21
|
+
|
|
22
|
+
You may not, and you may not permit any third party to:
|
|
23
|
+
|
|
24
|
+
1. Copy, modify, adapt, translate, or create derivative works of the Software;
|
|
25
|
+
2. Reverse engineer, disassemble, decompile, or otherwise attempt to derive
|
|
26
|
+
the source code of the Software;
|
|
27
|
+
3. Sell, sublicense, rent, lease, transfer, or otherwise make the Software
|
|
28
|
+
available to any third party;
|
|
29
|
+
4. Remove or alter any proprietary notices, labels, or marks on the Software;
|
|
30
|
+
5. Use the Software for any purpose other than as expressly permitted
|
|
31
|
+
under this license.
|
|
32
|
+
|
|
33
|
+
NO WARRANTY
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
36
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
37
|
+
FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL VELO BE
|
|
38
|
+
LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE USE OF
|
|
39
|
+
THE SOFTWARE.
|
|
40
|
+
|
|
41
|
+
TERMINATION
|
|
42
|
+
|
|
43
|
+
This license is effective until terminated. It will terminate automatically
|
|
44
|
+
if you fail to comply with any of its terms. Upon termination, you must
|
|
45
|
+
immediately cease all use of the Software and destroy any copies in your
|
|
46
|
+
possession.
|
|
47
|
+
|
|
48
|
+
GOVERNING LAW
|
|
49
|
+
|
|
50
|
+
This license shall be governed by and construed in accordance with applicable
|
|
51
|
+
law. Any disputes arising under this license shall be subject to the exclusive
|
|
52
|
+
jurisdiction of the competent courts.
|
|
53
|
+
|
|
54
|
+
For licensing inquiries, contact: legal@velo.com
|
|
55
|
+
Project-URL: Homepage, https://github.com/velo-org/robotframework-velo-sapgui
|
|
56
|
+
Project-URL: Repository, https://github.com/velo-org/robotframework-velo-sapgui
|
|
57
|
+
Project-URL: Bug Tracker, https://github.com/velo-org/robotframework-velo-sapgui/issues
|
|
58
|
+
Project-URL: Changelog, https://github.com/velo-org/robotframework-velo-sapgui/blob/main/CHANGELOG.md
|
|
59
|
+
Keywords: robotframework,SAP,SAP GUI,automation,sapgui,py4j,testing
|
|
60
|
+
Classifier: Development Status :: 3 - Alpha
|
|
61
|
+
Classifier: Intended Audience :: Developers
|
|
62
|
+
Classifier: Intended Audience :: Information Technology
|
|
63
|
+
Classifier: Framework :: Robot Framework
|
|
64
|
+
Classifier: Framework :: Robot Framework :: Library
|
|
65
|
+
Classifier: Topic :: Software Development :: Testing
|
|
66
|
+
Classifier: Topic :: Software Development :: Testing :: Acceptance
|
|
67
|
+
Classifier: Operating System :: OS Independent
|
|
68
|
+
Classifier: Programming Language :: Python :: 3
|
|
69
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
70
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
71
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
72
|
+
Classifier: License :: Other/Proprietary License
|
|
73
|
+
Classifier: Typing :: Typed
|
|
74
|
+
Requires-Python: >=3.10
|
|
75
|
+
Description-Content-Type: text/markdown
|
|
76
|
+
License-File: LICENSE
|
|
77
|
+
Requires-Dist: robotframework<8,>=6.1
|
|
78
|
+
Requires-Dist: py4j<1,>=0.10.9
|
|
79
|
+
Requires-Dist: pywin32>=306; sys_platform == "win32"
|
|
80
|
+
Provides-Extra: dev
|
|
81
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
82
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
83
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
84
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
85
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
86
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
87
|
+
Dynamic: license-file
|
|
88
|
+
|
|
89
|
+
# robotframework-velo-sapgui
|
|
90
|
+
|
|
91
|
+
Robot Framework keyword library for **SAP GUI automation** on Java (py4j) and Windows (COM Scripting).
|
|
92
|
+
|
|
93
|
+
## Backends
|
|
94
|
+
|
|
95
|
+
| Backend | Platform | Prerequisites |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `java` | Linux Docker / Mac via Docker | SAP GUI for Java + `sapgui-engine` gateway on port 8081 |
|
|
98
|
+
| `windows` | Native Windows laptop | Customer-installed SAP GUI for Windows + scripting enabled |
|
|
99
|
+
| `auto` | Default | `windows` on win32, `java` elsewhere |
|
|
100
|
+
|
|
101
|
+
Set `Library SapLibrary client=auto` or export `VELO_SAP_CLIENT=java|windows|auto`.
|
|
102
|
+
|
|
103
|
+
## Architecture
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
.robot suite
|
|
107
|
+
│
|
|
108
|
+
└─► SapLibrary (Python)
|
|
109
|
+
│
|
|
110
|
+
├─► JavaGatewayBackend ── py4j ──► sapgui-engine ──► SAP GUI for Java
|
|
111
|
+
│
|
|
112
|
+
└─► WindowsScriptingBackend ── COM ──► SAP GUI for Windows
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Connection is **lazy** — resources are opened on the first keyword.
|
|
116
|
+
|
|
117
|
+
## Installation
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
pip install robotframework-velo-sapgui
|
|
121
|
+
|
|
122
|
+
# Windows COM backend
|
|
123
|
+
pip install "robotframework-velo-sapgui[windows]"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Usage
|
|
127
|
+
|
|
128
|
+
```robotframework
|
|
129
|
+
*** Settings ***
|
|
130
|
+
Library SapLibrary client=auto port=8081 recording=True
|
|
131
|
+
|
|
132
|
+
*** Test Cases ***
|
|
133
|
+
Create Sales Order
|
|
134
|
+
Connect /H/my-sap-host/S/3200
|
|
135
|
+
Type User MY_USER
|
|
136
|
+
Type Password ${PASSWORD}
|
|
137
|
+
Press Enter
|
|
138
|
+
Open Transaction VA01
|
|
139
|
+
[Teardown] Cleanup
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Credentials and connection strings live **in each suite** so multi-role SAP flows can switch users within one test.
|
|
143
|
+
|
|
144
|
+
## Scripting event capture
|
|
145
|
+
|
|
146
|
+
`recording=True` captures SAP scripting **interaction events** (not video) to `events.jsonl` under `$RESULTS_DIR`:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{"timestamp": "...", "action": "Type", "element_id": "...", "name": "User", "type": "", "value": "MY_USER", "screen_context": "...", "source": "automation"}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Optional keywords: `Start Event Capture`, `Stop Event Capture`, `Get Captured Events`.
|
|
153
|
+
|
|
154
|
+
Video MP4 for cloud runs is produced by the execution container (`entrypoint.sh`), not this library.
|
|
155
|
+
|
|
156
|
+
## Library arguments
|
|
157
|
+
|
|
158
|
+
| Argument | Default | Description |
|
|
159
|
+
|---|---|---|
|
|
160
|
+
| `client` | `auto` | SAP client backend: `auto`, `java`, or `windows` |
|
|
161
|
+
| `port` | `8081` | Java gateway port (`java` backend only) |
|
|
162
|
+
| `recording` | `False` | Start scripting event capture on first connect |
|
|
163
|
+
|
|
164
|
+
## Environment variables
|
|
165
|
+
|
|
166
|
+
| Variable | Description |
|
|
167
|
+
|---|---|
|
|
168
|
+
| `VELO_SAP_CLIENT` | Override `client` library argument |
|
|
169
|
+
| `RESULTS_DIR` | Output directory for screenshots and `events.jsonl` |
|
|
170
|
+
| `VELO_EVENTS_PATH` | Override path for event capture file |
|
|
171
|
+
|
|
172
|
+
## SAP prerequisites
|
|
173
|
+
|
|
174
|
+
- Server: `sapgui/user_scripting = TRUE`
|
|
175
|
+
- Client: SAP GUI scripting enabled
|
|
176
|
+
- Optional: `sapgui/user_scripting_disable_recording = 0` (avoid recorder dialog during event capture)
|
|
177
|
+
|
|
178
|
+
## Error handling
|
|
179
|
+
|
|
180
|
+
- `SapConnectionError` — backend not reachable or scripting disabled
|
|
181
|
+
- `SapKeywordError` — SAP action failed; message included in RF output
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# robotframework-velo-sapgui
|
|
2
|
+
|
|
3
|
+
Robot Framework keyword library for **SAP GUI automation** on Java (py4j) and Windows (COM Scripting).
|
|
4
|
+
|
|
5
|
+
## Backends
|
|
6
|
+
|
|
7
|
+
| Backend | Platform | Prerequisites |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `java` | Linux Docker / Mac via Docker | SAP GUI for Java + `sapgui-engine` gateway on port 8081 |
|
|
10
|
+
| `windows` | Native Windows laptop | Customer-installed SAP GUI for Windows + scripting enabled |
|
|
11
|
+
| `auto` | Default | `windows` on win32, `java` elsewhere |
|
|
12
|
+
|
|
13
|
+
Set `Library SapLibrary client=auto` or export `VELO_SAP_CLIENT=java|windows|auto`.
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
.robot suite
|
|
19
|
+
│
|
|
20
|
+
└─► SapLibrary (Python)
|
|
21
|
+
│
|
|
22
|
+
├─► JavaGatewayBackend ── py4j ──► sapgui-engine ──► SAP GUI for Java
|
|
23
|
+
│
|
|
24
|
+
└─► WindowsScriptingBackend ── COM ──► SAP GUI for Windows
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Connection is **lazy** — resources are opened on the first keyword.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install robotframework-velo-sapgui
|
|
33
|
+
|
|
34
|
+
# Windows COM backend
|
|
35
|
+
pip install "robotframework-velo-sapgui[windows]"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```robotframework
|
|
41
|
+
*** Settings ***
|
|
42
|
+
Library SapLibrary client=auto port=8081 recording=True
|
|
43
|
+
|
|
44
|
+
*** Test Cases ***
|
|
45
|
+
Create Sales Order
|
|
46
|
+
Connect /H/my-sap-host/S/3200
|
|
47
|
+
Type User MY_USER
|
|
48
|
+
Type Password ${PASSWORD}
|
|
49
|
+
Press Enter
|
|
50
|
+
Open Transaction VA01
|
|
51
|
+
[Teardown] Cleanup
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Credentials and connection strings live **in each suite** so multi-role SAP flows can switch users within one test.
|
|
55
|
+
|
|
56
|
+
## Scripting event capture
|
|
57
|
+
|
|
58
|
+
`recording=True` captures SAP scripting **interaction events** (not video) to `events.jsonl` under `$RESULTS_DIR`:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{"timestamp": "...", "action": "Type", "element_id": "...", "name": "User", "type": "", "value": "MY_USER", "screen_context": "...", "source": "automation"}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Optional keywords: `Start Event Capture`, `Stop Event Capture`, `Get Captured Events`.
|
|
65
|
+
|
|
66
|
+
Video MP4 for cloud runs is produced by the execution container (`entrypoint.sh`), not this library.
|
|
67
|
+
|
|
68
|
+
## Library arguments
|
|
69
|
+
|
|
70
|
+
| Argument | Default | Description |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `client` | `auto` | SAP client backend: `auto`, `java`, or `windows` |
|
|
73
|
+
| `port` | `8081` | Java gateway port (`java` backend only) |
|
|
74
|
+
| `recording` | `False` | Start scripting event capture on first connect |
|
|
75
|
+
|
|
76
|
+
## Environment variables
|
|
77
|
+
|
|
78
|
+
| Variable | Description |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `VELO_SAP_CLIENT` | Override `client` library argument |
|
|
81
|
+
| `RESULTS_DIR` | Output directory for screenshots and `events.jsonl` |
|
|
82
|
+
| `VELO_EVENTS_PATH` | Override path for event capture file |
|
|
83
|
+
|
|
84
|
+
## SAP prerequisites
|
|
85
|
+
|
|
86
|
+
- Server: `sapgui/user_scripting = TRUE`
|
|
87
|
+
- Client: SAP GUI scripting enabled
|
|
88
|
+
- Optional: `sapgui/user_scripting_disable_recording = 0` (avoid recorder dialog during event capture)
|
|
89
|
+
|
|
90
|
+
## Error handling
|
|
91
|
+
|
|
92
|
+
- `SapConnectionError` — backend not reachable or scripting disabled
|
|
93
|
+
- `SapKeywordError` — SAP action failed; message included in RF output
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=70,<81", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "robotframework-velo-sapgui"
|
|
7
|
+
version = "0.2.2"
|
|
8
|
+
description = "Robot Framework keyword library for SAP GUI automation (Java and Windows)"
|
|
9
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
authors = [{ name = "Velo", email = "legal@velo.com" }]
|
|
12
|
+
keywords = ["robotframework", "SAP", "SAP GUI", "automation", "sapgui", "py4j", "testing"]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Intended Audience :: Information Technology",
|
|
18
|
+
"Framework :: Robot Framework",
|
|
19
|
+
"Framework :: Robot Framework :: Library",
|
|
20
|
+
"Topic :: Software Development :: Testing",
|
|
21
|
+
"Topic :: Software Development :: Testing :: Acceptance",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"License :: Other/Proprietary License",
|
|
28
|
+
"Typing :: Typed",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"robotframework>=6.1,<8",
|
|
32
|
+
"py4j>=0.10.9,<1",
|
|
33
|
+
"pywin32>=306; sys_platform == 'win32'",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=8",
|
|
39
|
+
"pytest-cov",
|
|
40
|
+
"ruff>=0.4",
|
|
41
|
+
"mypy>=1.10",
|
|
42
|
+
"build>=1.2",
|
|
43
|
+
"twine>=5",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://github.com/velo-org/robotframework-velo-sapgui"
|
|
48
|
+
Repository = "https://github.com/velo-org/robotframework-velo-sapgui"
|
|
49
|
+
"Bug Tracker" = "https://github.com/velo-org/robotframework-velo-sapgui/issues"
|
|
50
|
+
Changelog = "https://github.com/velo-org/robotframework-velo-sapgui/blob/main/CHANGELOG.md"
|
|
51
|
+
|
|
52
|
+
[tool.setuptools.packages.find]
|
|
53
|
+
where = ["src"]
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.package-data]
|
|
56
|
+
SapLibrary = ["py.typed"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
addopts = "--cov=SapLibrary --cov-report=term-missing"
|
|
61
|
+
|
|
62
|
+
[tool.ruff]
|
|
63
|
+
line-length = 100
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
67
|
+
|
|
68
|
+
[tool.mypy]
|
|
69
|
+
python_version = "3.10"
|
|
70
|
+
strict = true
|
|
71
|
+
ignore_missing_imports = true
|
|
72
|
+
warn_return_any = false
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from SapLibrary.exceptions import SapConnectionError, SapKeywordError, SapLibraryError
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
__version__ = version("robotframework-velo-sapgui")
|
|
9
|
+
except PackageNotFoundError:
|
|
10
|
+
__version__ = "unknown"
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"SapLibrary",
|
|
14
|
+
"SapLibraryError",
|
|
15
|
+
"SapConnectionError",
|
|
16
|
+
"SapKeywordError",
|
|
17
|
+
"__version__",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def __getattr__(name: str) -> object:
|
|
22
|
+
if name == "SapLibrary":
|
|
23
|
+
from SapLibrary.library import SapLibrary
|
|
24
|
+
|
|
25
|
+
globals()["SapLibrary"] = SapLibrary
|
|
26
|
+
return SapLibrary
|
|
27
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Backend interface for SAP GUI automation (Java gateway or Windows COM)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def resolve_client(client: str | None = None) -> str:
|
|
12
|
+
"""Resolve SAP client type: ``auto``, ``java``, or ``windows``."""
|
|
13
|
+
raw = (client or os.getenv("VELO_SAP_CLIENT") or "auto").strip().lower()
|
|
14
|
+
if raw not in ("auto", "java", "windows"):
|
|
15
|
+
raise ValueError(f"Invalid SAP client '{client}'. Expected auto, java, or windows.")
|
|
16
|
+
if raw == "auto":
|
|
17
|
+
return "windows" if sys.platform == "win32" else "java"
|
|
18
|
+
if raw == "windows" and sys.platform != "win32":
|
|
19
|
+
raise RuntimeError(
|
|
20
|
+
"SAP GUI for Windows backend requires a Windows host. "
|
|
21
|
+
"Use client=java or VELO_SAP_CLIENT=java for Docker/Java execution."
|
|
22
|
+
)
|
|
23
|
+
return raw
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class BackendResponse:
|
|
27
|
+
"""Minimal response object compatible with Java StepResponse accessors."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, success: bool, message: str = "", result: Any = None) -> None:
|
|
30
|
+
self._success = success
|
|
31
|
+
self._message = message
|
|
32
|
+
self._result = result
|
|
33
|
+
|
|
34
|
+
def isSuccessful(self) -> bool:
|
|
35
|
+
return self._success
|
|
36
|
+
|
|
37
|
+
def getMessage(self) -> str:
|
|
38
|
+
return self._message
|
|
39
|
+
|
|
40
|
+
def getResult(self) -> Any:
|
|
41
|
+
return self._result
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SapAutomationBackend(ABC):
|
|
45
|
+
"""Abstract SAP automation backend."""
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def ensure_connected(self) -> None:
|
|
49
|
+
"""Open backend resources if needed."""
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def call(self, method: str, *args: Any) -> Any:
|
|
53
|
+
"""Invoke a facade method by name."""
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def start_event_capture(self) -> None:
|
|
57
|
+
"""Begin scripting event capture."""
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def stop_event_capture(self) -> str | None:
|
|
61
|
+
"""Stop event capture and return output path."""
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
def cleanup(self, close_app: bool = True, stop_recording: bool = True) -> str:
|
|
65
|
+
"""Release backend resources."""
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
@abstractmethod
|
|
69
|
+
def client_name(self) -> str:
|
|
70
|
+
"""Backend identifier (``java`` or ``windows``)."""
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Normalized scripting event log (events.jsonl) shared by Java and Windows backends."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from threading import Lock
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EventCaptureWriter:
|
|
14
|
+
"""Append-only JSONL writer for SAP GUI scripting interaction events."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, output_path: Path | None = None) -> None:
|
|
17
|
+
results_dir = os.environ.get("RESULTS_DIR", "/results")
|
|
18
|
+
default_path = Path(results_dir) / "events.jsonl"
|
|
19
|
+
env_path = os.environ.get("VELO_EVENTS_PATH")
|
|
20
|
+
self._path = Path(output_path or env_path or default_path)
|
|
21
|
+
self._active = False
|
|
22
|
+
self._lock = Lock()
|
|
23
|
+
self._events: list[dict[str, Any]] = []
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def is_active(self) -> bool:
|
|
27
|
+
return self._active
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def path(self) -> Path:
|
|
31
|
+
return self._path
|
|
32
|
+
|
|
33
|
+
def start(self) -> None:
|
|
34
|
+
with self._lock:
|
|
35
|
+
self._path.parent.mkdir(parents=True, exist_ok=True)
|
|
36
|
+
self._events = []
|
|
37
|
+
self._active = True
|
|
38
|
+
|
|
39
|
+
def record(
|
|
40
|
+
self,
|
|
41
|
+
action: str,
|
|
42
|
+
*,
|
|
43
|
+
element_id: str = "",
|
|
44
|
+
name: str = "",
|
|
45
|
+
element_type: str = "",
|
|
46
|
+
value: str = "",
|
|
47
|
+
screen_context: str = "",
|
|
48
|
+
source: str = "",
|
|
49
|
+
) -> None:
|
|
50
|
+
if not self._active:
|
|
51
|
+
return
|
|
52
|
+
event = {
|
|
53
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
54
|
+
"action": action,
|
|
55
|
+
"element_id": element_id,
|
|
56
|
+
"name": name,
|
|
57
|
+
"type": element_type,
|
|
58
|
+
"value": value,
|
|
59
|
+
"screen_context": screen_context,
|
|
60
|
+
"source": source,
|
|
61
|
+
}
|
|
62
|
+
with self._lock:
|
|
63
|
+
self._events.append(event)
|
|
64
|
+
|
|
65
|
+
def stop(self) -> str:
|
|
66
|
+
with self._lock:
|
|
67
|
+
if not self._active:
|
|
68
|
+
return str(self._path)
|
|
69
|
+
self._path.parent.mkdir(parents=True, exist_ok=True)
|
|
70
|
+
with self._path.open("w", encoding="utf-8") as handle:
|
|
71
|
+
for event in self._events:
|
|
72
|
+
handle.write(json.dumps(event, ensure_ascii=False) + "\n")
|
|
73
|
+
self._active = False
|
|
74
|
+
return str(self._path)
|
|
75
|
+
|
|
76
|
+
def get_events(self) -> list[dict[str, Any]]:
|
|
77
|
+
with self._lock:
|
|
78
|
+
return list(self._events)
|