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.
Files changed (21) hide show
  1. robotframework_velo_sapgui-0.2.2/LICENSE +49 -0
  2. robotframework_velo_sapgui-0.2.2/PKG-INFO +181 -0
  3. robotframework_velo_sapgui-0.2.2/README.md +93 -0
  4. robotframework_velo_sapgui-0.2.2/pyproject.toml +72 -0
  5. robotframework_velo_sapgui-0.2.2/setup.cfg +4 -0
  6. robotframework_velo_sapgui-0.2.2/src/SapLibrary/__init__.py +27 -0
  7. robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/__init__.py +5 -0
  8. robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/base.py +70 -0
  9. robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/event_capture.py +78 -0
  10. robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/java_gateway.py +126 -0
  11. robotframework_velo_sapgui-0.2.2/src/SapLibrary/backends/windows_scripting.py +477 -0
  12. robotframework_velo_sapgui-0.2.2/src/SapLibrary/exceptions.py +30 -0
  13. robotframework_velo_sapgui-0.2.2/src/SapLibrary/keywords.py +340 -0
  14. robotframework_velo_sapgui-0.2.2/src/SapLibrary/library.py +120 -0
  15. robotframework_velo_sapgui-0.2.2/src/SapLibrary/py.typed +0 -0
  16. robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/PKG-INFO +181 -0
  17. robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/SOURCES.txt +19 -0
  18. robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/dependency_links.txt +1 -0
  19. robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/requires.txt +13 -0
  20. robotframework_velo_sapgui-0.2.2/src/robotframework_velo_sapgui.egg-info/top_level.txt +1 -0
  21. 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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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,5 @@
1
+ """SAP automation backends (Java gateway and Windows COM)."""
2
+
3
+ from SapLibrary.backends.base import SapAutomationBackend, resolve_client
4
+
5
+ __all__ = ["SapAutomationBackend", "resolve_client"]
@@ -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)