vericue 0.3.5__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.
- vericue-0.3.5/PKG-INFO +12 -0
- vericue-0.3.5/README.md +87 -0
- vericue-0.3.5/examples/event_subscriptions.py +78 -0
- vericue-0.3.5/examples/keyboard_and_drag.py +88 -0
- vericue-0.3.5/examples/model_data_access.py +190 -0
- vericue-0.3.5/examples/ping_example.py +23 -0
- vericue-0.3.5/examples/qml_task_manager.py +244 -0
- vericue-0.3.5/examples/record_and_replay.py +89 -0
- vericue-0.3.5/examples/test_with_report.py +140 -0
- vericue-0.3.5/examples/touch_demo_screenshot.png +0 -0
- vericue-0.3.5/examples/touch_gestures.py +240 -0
- vericue-0.3.5/examples/visual_regression.py +127 -0
- vericue-0.3.5/examples/wait_for_signals.py +100 -0
- vericue-0.3.5/pyproject.toml +24 -0
- vericue-0.3.5/setup.cfg +4 -0
- vericue-0.3.5/tests/conftest.py +221 -0
- vericue-0.3.5/tests/robot/smoke.robot +26 -0
- vericue-0.3.5/tests/test_client.py +70 -0
- vericue-0.3.5/tests/test_fixtures.py +37 -0
- vericue-0.3.5/tests/test_integration.py +426 -0
- vericue-0.3.5/tests/test_interaction.py +167 -0
- vericue-0.3.5/tests/test_license_integration.py +236 -0
- vericue-0.3.5/tests/test_model_data.py +154 -0
- vericue-0.3.5/tests/test_multi.py +49 -0
- vericue-0.3.5/tests/test_new_features.py +346 -0
- vericue-0.3.5/tests/test_object_commands.py +339 -0
- vericue-0.3.5/tests/test_protocol.py +76 -0
- vericue-0.3.5/tests/test_robot.py +85 -0
- vericue-0.3.5/tests/test_touch.py +122 -0
- vericue-0.3.5/vericue/__init__.py +19 -0
- vericue-0.3.5/vericue/__main__.py +316 -0
- vericue-0.3.5/vericue/client.py +614 -0
- vericue-0.3.5/vericue/conftest_plugin.py +213 -0
- vericue-0.3.5/vericue/errors.py +20 -0
- vericue-0.3.5/vericue/inspector.py +297 -0
- vericue-0.3.5/vericue/multi.py +120 -0
- vericue-0.3.5/vericue/protocol.py +45 -0
- vericue-0.3.5/vericue/recorder.py +38 -0
- vericue-0.3.5/vericue/reporter.py +188 -0
- vericue-0.3.5/vericue/robot.py +213 -0
- vericue-0.3.5/vericue.egg-info/PKG-INFO +12 -0
- vericue-0.3.5/vericue.egg-info/SOURCES.txt +44 -0
- vericue-0.3.5/vericue.egg-info/dependency_links.txt +1 -0
- vericue-0.3.5/vericue.egg-info/entry_points.txt +5 -0
- vericue-0.3.5/vericue.egg-info/requires.txt +10 -0
- vericue-0.3.5/vericue.egg-info/top_level.txt +1 -0
vericue-0.3.5/PKG-INFO
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vericue
|
|
3
|
+
Version: 0.3.5
|
|
4
|
+
Summary: Python client library for veriCue test automation framework
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Provides-Extra: dev
|
|
7
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
8
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
9
|
+
Provides-Extra: inspector
|
|
10
|
+
Requires-Dist: rich>=13.0; extra == "inspector"
|
|
11
|
+
Provides-Extra: robot
|
|
12
|
+
Requires-Dist: robotframework>=6.0; extra == "robot"
|
vericue-0.3.5/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# veriCue Python Client
|
|
2
|
+
|
|
3
|
+
An asynchronous Python client library for communicating with the veriCue server. Built on asyncio.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install from the client directory
|
|
9
|
+
pip install -e client/python
|
|
10
|
+
|
|
11
|
+
# With development dependencies (pytest)
|
|
12
|
+
pip install -e "client/python[dev]"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import asyncio
|
|
19
|
+
from vericue import VeriCueClient
|
|
20
|
+
|
|
21
|
+
async def main():
|
|
22
|
+
async with VeriCueClient() as client:
|
|
23
|
+
await client.connect("127.0.0.1", 4242)
|
|
24
|
+
|
|
25
|
+
pong = await client.ping()
|
|
26
|
+
print(f"Ping: {pong}") # True
|
|
27
|
+
|
|
28
|
+
version = await client.version()
|
|
29
|
+
print(f"Server: {version}") # {"server": "vericue", "version": "0.1.0", ...}
|
|
30
|
+
|
|
31
|
+
echo = await client.echo("hello")
|
|
32
|
+
print(f"Echo: {echo}") # "hello"
|
|
33
|
+
|
|
34
|
+
asyncio.run(main())
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
class VeriCueClient:
|
|
41
|
+
async def connect(host="127.0.0.1", port=4242) -> None
|
|
42
|
+
async def disconnect() -> None
|
|
43
|
+
is_connected: bool
|
|
44
|
+
|
|
45
|
+
# High-level commands
|
|
46
|
+
async def ping() -> bool
|
|
47
|
+
async def version() -> dict
|
|
48
|
+
async def echo(text: str) -> str
|
|
49
|
+
|
|
50
|
+
# Low-level command
|
|
51
|
+
async def send_request(method: str, params: dict = None) -> dict
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Supports async context manager (`async with`). Default timeout: 10 seconds (configurable via `VeriCueClient(timeout=30.0)`).
|
|
55
|
+
|
|
56
|
+
## Error Handling
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from vericue import VeriCueClient, ServerError, ConnectionError, ProtocolError
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
result = await client.send_request("unknown_method")
|
|
63
|
+
except ServerError as e:
|
|
64
|
+
print(e.code, e.message) # 1003, "Unknown method: unknown_method"
|
|
65
|
+
except ConnectionError:
|
|
66
|
+
print("Not connected to server")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Testing
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pytest client/python/tests/
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Tests use a mock TCP server (asyncio) — no running veriCue server required.
|
|
76
|
+
|
|
77
|
+
## Structure
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
vericue/
|
|
81
|
+
├── __init__.py — public exports
|
|
82
|
+
├── client.py — VeriCueClient (asyncio)
|
|
83
|
+
├── protocol.py — framing and message building
|
|
84
|
+
└── errors.py — exceptions (VeriCueError, ServerError, ConnectionError, ProtocolError)
|
|
85
|
+
examples/ — usage examples
|
|
86
|
+
tests/ — unit and integration tests
|
|
87
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Live event subscription example.
|
|
2
|
+
|
|
3
|
+
Subscribes to a button's ``clicked`` signal and a line-edit's ``text``
|
|
4
|
+
property, simulates input, then prints every push event the server
|
|
5
|
+
sends. Demonstrates both per-subscription callbacks and the shared
|
|
6
|
+
``events()`` async iterator.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
# Start the test app first (in another shell):
|
|
10
|
+
QT_QPA_PLATFORM=offscreen \
|
|
11
|
+
LD_LIBRARY_PATH=build/server:$QT_LIB \
|
|
12
|
+
build/examples/test_app/vericue-test-app --port 4242
|
|
13
|
+
|
|
14
|
+
python client/python/examples/event_subscriptions.py
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import asyncio
|
|
20
|
+
|
|
21
|
+
from vericue import VeriCueClient
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def main() -> None:
|
|
25
|
+
async with VeriCueClient() as client:
|
|
26
|
+
await client.connect("127.0.0.1", 4242)
|
|
27
|
+
|
|
28
|
+
# 1. Subscribe with a per-event callback.
|
|
29
|
+
async def on_click(event: dict) -> None:
|
|
30
|
+
print(f" → callback got click event at {event['timestamp']}")
|
|
31
|
+
|
|
32
|
+
click_id = await client.subscribe_signal(
|
|
33
|
+
"TestWindow/centralWidget/testButton", "clicked", callback=on_click,
|
|
34
|
+
)
|
|
35
|
+
print(f"Subscribed to clicked: {click_id}")
|
|
36
|
+
|
|
37
|
+
# 2. Subscribe to a property and just consume from the queue.
|
|
38
|
+
text_id = await client.subscribe_property(
|
|
39
|
+
"TestWindow/centralWidget/testInput", "text",
|
|
40
|
+
)
|
|
41
|
+
print(f"Subscribed to text property: {text_id}")
|
|
42
|
+
|
|
43
|
+
# 3. Subscribe to destroyed.
|
|
44
|
+
destroyed_id = await client.subscribe_destroyed(
|
|
45
|
+
"TestWindow/centralWidget/testLabel",
|
|
46
|
+
)
|
|
47
|
+
print(f"Subscribed to destroyed: {destroyed_id}")
|
|
48
|
+
|
|
49
|
+
# Inspect what's active server-side.
|
|
50
|
+
active = await client.list_subscriptions()
|
|
51
|
+
print(f"Active subscriptions: {[s['subscription_id'] for s in active]}")
|
|
52
|
+
|
|
53
|
+
# Simulate some activity that should produce events.
|
|
54
|
+
await client.mouse_click("TestWindow/centralWidget/testButton")
|
|
55
|
+
await client.set_property(
|
|
56
|
+
"TestWindow/centralWidget/testInput", "text", "hello world",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Drain a few events.
|
|
60
|
+
for _ in range(2):
|
|
61
|
+
try:
|
|
62
|
+
event = await client.next_event(timeout=2.0)
|
|
63
|
+
print(
|
|
64
|
+
f" ← {event['event']:18s} sub={event['subscription_id']} "
|
|
65
|
+
f"data={event['data']}"
|
|
66
|
+
)
|
|
67
|
+
except asyncio.TimeoutError:
|
|
68
|
+
print(" (no more events within 2s)")
|
|
69
|
+
break
|
|
70
|
+
|
|
71
|
+
await client.unsubscribe(click_id)
|
|
72
|
+
await client.unsubscribe(text_id)
|
|
73
|
+
await client.unsubscribe(destroyed_id)
|
|
74
|
+
print("All subscriptions removed.")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Keyboard shortcuts and drag & drop example.
|
|
2
|
+
|
|
3
|
+
Demonstrates key_press (special keys, modifier combos) and drag commands.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
1. Start a demo app: ./build/examples/demo_app/vericue-demo-app
|
|
7
|
+
2. Run this script: python examples/keyboard_and_drag.py
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
15
|
+
|
|
16
|
+
from vericue import VeriCueClient
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async def main():
|
|
20
|
+
async with VeriCueClient() as client:
|
|
21
|
+
await client.connect("127.0.0.1", 4242)
|
|
22
|
+
print("Connected.\n")
|
|
23
|
+
|
|
24
|
+
# --- Keyboard shortcuts ---
|
|
25
|
+
print("=== Keyboard Shortcuts ===")
|
|
26
|
+
|
|
27
|
+
# Click on input field and type, then use keyboard to select all + delete
|
|
28
|
+
input_path = "DemoMainWindow/centralWidget/inputField"
|
|
29
|
+
|
|
30
|
+
await client.mouse_click(input_path)
|
|
31
|
+
await client.type_text(input_path, "Hello World")
|
|
32
|
+
print("Typed 'Hello World'")
|
|
33
|
+
|
|
34
|
+
# Select all with Ctrl+A
|
|
35
|
+
await client.key_press(input_path, "ctrl+a")
|
|
36
|
+
print("Pressed Ctrl+A (select all)")
|
|
37
|
+
|
|
38
|
+
# Delete selection
|
|
39
|
+
await client.key_press(input_path, "delete")
|
|
40
|
+
print("Pressed Delete")
|
|
41
|
+
|
|
42
|
+
# Type new text and press Enter
|
|
43
|
+
await client.type_text(input_path, "New content")
|
|
44
|
+
await client.key_press(input_path, "enter")
|
|
45
|
+
print("Typed 'New content' + Enter")
|
|
46
|
+
|
|
47
|
+
# Tab to next widget
|
|
48
|
+
await client.key_press(input_path, "tab")
|
|
49
|
+
print("Pressed Tab (focus next widget)")
|
|
50
|
+
|
|
51
|
+
# Arrow keys
|
|
52
|
+
await client.key_press(input_path, "up", repeat=3)
|
|
53
|
+
print("Pressed Up x3")
|
|
54
|
+
|
|
55
|
+
# Escape
|
|
56
|
+
await client.key_press(input_path, "escape")
|
|
57
|
+
print("Pressed Escape")
|
|
58
|
+
|
|
59
|
+
# Function key
|
|
60
|
+
await client.key_press(input_path, "f1")
|
|
61
|
+
print("Pressed F1")
|
|
62
|
+
|
|
63
|
+
# --- Drag ---
|
|
64
|
+
print("\n=== Drag & Drop ===")
|
|
65
|
+
|
|
66
|
+
# Drag on the progress bar (simulates slider drag)
|
|
67
|
+
progress_path = "DemoMainWindow/centralWidget/progressBar"
|
|
68
|
+
|
|
69
|
+
result = await client.drag(progress_path, 10, 10, 150, 10)
|
|
70
|
+
print(f"Dragged from ({result['from']['x']},{result['from']['y']}) "
|
|
71
|
+
f"to ({result['to']['x']},{result['to']['y']})")
|
|
72
|
+
|
|
73
|
+
# Drag with right button
|
|
74
|
+
result = await client.drag(progress_path, 0, 0, 50, 50, button="right")
|
|
75
|
+
print(f"Right-button drag completed")
|
|
76
|
+
|
|
77
|
+
# Drag with modifier (Ctrl+drag for copy in many apps)
|
|
78
|
+
result = await client.drag(
|
|
79
|
+
progress_path, 20, 15, 180, 15,
|
|
80
|
+
modifiers=["ctrl"]
|
|
81
|
+
)
|
|
82
|
+
print(f"Ctrl+drag completed")
|
|
83
|
+
|
|
84
|
+
print("\nDone!")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Model/View data access example.
|
|
2
|
+
|
|
3
|
+
Demonstrates reading data from QTableView, QTreeView, and QListView models:
|
|
4
|
+
model info (row/column counts, headers), single cell reads, range queries,
|
|
5
|
+
and filtering.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
1. Build and start the table demo:
|
|
9
|
+
cmake --build build --parallel
|
|
10
|
+
./build/examples/table_app/vericue-table-app --port 4245
|
|
11
|
+
2. Run this script:
|
|
12
|
+
python examples/model_data_access.py
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
20
|
+
|
|
21
|
+
from vericue import VeriCueClient, ServerError
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
HOST = "127.0.0.1"
|
|
25
|
+
PORT = 4245
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def log(msg: str) -> None:
|
|
29
|
+
print(f" >> {msg}")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async def main():
|
|
33
|
+
async with VeriCueClient(timeout=15.0) as client:
|
|
34
|
+
await client.connect(HOST, PORT)
|
|
35
|
+
log("Connected to Table Demo app\n")
|
|
36
|
+
|
|
37
|
+
# ──────────────────────────────────────────
|
|
38
|
+
# 1. EMPLOYEE TABLE — model info
|
|
39
|
+
# ──────────────────────────────────────────
|
|
40
|
+
print("=" * 60)
|
|
41
|
+
print(" 1. EMPLOYEE TABLE — Model Info")
|
|
42
|
+
print("=" * 60)
|
|
43
|
+
|
|
44
|
+
table_path = (await client.find_object(object_name="employeeTable"))["path"]
|
|
45
|
+
info = await client.get_model_info(table_path)
|
|
46
|
+
|
|
47
|
+
log(f"Model class: {info['model_class']}")
|
|
48
|
+
log(f"Rows: {info['row_count']}")
|
|
49
|
+
log(f"Columns: {info['column_count']}")
|
|
50
|
+
log(f"Headers: {info['horizontal_headers']}")
|
|
51
|
+
|
|
52
|
+
# ──────────────────────────────────────────
|
|
53
|
+
# 2. EMPLOYEE TABLE — single cell reads
|
|
54
|
+
# ──────────────────────────────────────────
|
|
55
|
+
print(f"\n{'=' * 60}")
|
|
56
|
+
print(" 2. EMPLOYEE TABLE — Single Cell Reads")
|
|
57
|
+
print("=" * 60)
|
|
58
|
+
|
|
59
|
+
for row in range(min(5, info["row_count"])):
|
|
60
|
+
name = await client.get_model_data(table_path, row=row, column=0)
|
|
61
|
+
dept = await client.get_model_data(table_path, row=row, column=1)
|
|
62
|
+
salary = await client.get_model_data(table_path, row=row, column=2)
|
|
63
|
+
log(f"Row {row}: {name['value']:20s} | {dept['value']:15s} | ${salary['value']}")
|
|
64
|
+
|
|
65
|
+
# ──────────────────────────────────────────
|
|
66
|
+
# 3. EMPLOYEE TABLE — range query (all rows)
|
|
67
|
+
# ──────────────────────────────────────────
|
|
68
|
+
print(f"\n{'=' * 60}")
|
|
69
|
+
print(" 3. EMPLOYEE TABLE — Full Range Query")
|
|
70
|
+
print("=" * 60)
|
|
71
|
+
|
|
72
|
+
data = await client.get_model_data(table_path)
|
|
73
|
+
log(f"Fetched {data['row_count']} rows")
|
|
74
|
+
|
|
75
|
+
# Print as formatted table
|
|
76
|
+
headers = info["horizontal_headers"]
|
|
77
|
+
col_widths = [max(len(str(h)), 15) for h in headers]
|
|
78
|
+
|
|
79
|
+
header_line = " | ".join(f"{h:<{w}}" for h, w in zip(headers, col_widths))
|
|
80
|
+
log(header_line)
|
|
81
|
+
log("-" * len(header_line))
|
|
82
|
+
|
|
83
|
+
for row_data in data["rows"]:
|
|
84
|
+
cells = row_data["cells"]
|
|
85
|
+
values = [str(cells.get(str(i), "")) for i in range(len(headers))]
|
|
86
|
+
line = " | ".join(f"{v:<{w}}" for v, w in zip(values, col_widths))
|
|
87
|
+
log(line)
|
|
88
|
+
|
|
89
|
+
# ──────────────────────────────────────────
|
|
90
|
+
# 4. EMPLOYEE TABLE — filtered columns
|
|
91
|
+
# ──────────────────────────────────────────
|
|
92
|
+
print(f"\n{'=' * 60}")
|
|
93
|
+
print(" 4. EMPLOYEE TABLE — Name and City Only (columns 0, 3)")
|
|
94
|
+
print("=" * 60)
|
|
95
|
+
|
|
96
|
+
data = await client.get_model_data(table_path, columns=[0, 3])
|
|
97
|
+
for row_data in data["rows"]:
|
|
98
|
+
cells = row_data["cells"]
|
|
99
|
+
name = cells.get("0", "")
|
|
100
|
+
city = cells.get("3", "")
|
|
101
|
+
log(f"{name:20s} → {city}")
|
|
102
|
+
|
|
103
|
+
# ──────────────────────────────────────────
|
|
104
|
+
# 5. EMPLOYEE TABLE — partial range
|
|
105
|
+
# ──────────────────────────────────────────
|
|
106
|
+
print(f"\n{'=' * 60}")
|
|
107
|
+
print(" 5. EMPLOYEE TABLE — Rows 3-7 only")
|
|
108
|
+
print("=" * 60)
|
|
109
|
+
|
|
110
|
+
data = await client.get_model_data(table_path, start_row=3, end_row=7)
|
|
111
|
+
log(f"Fetched rows {data['start_row']}-{data['end_row']} ({data['row_count']} rows)")
|
|
112
|
+
for row_data in data["rows"]:
|
|
113
|
+
cells = row_data["cells"]
|
|
114
|
+
log(f" Row {row_data['row']}: {cells.get('0', '')} — {cells.get('1', '')}")
|
|
115
|
+
|
|
116
|
+
# ──────────────────────────────────────────
|
|
117
|
+
# 6. CITY LIST — model info + data
|
|
118
|
+
# ──────────────────────────────────────────
|
|
119
|
+
print(f"\n{'=' * 60}")
|
|
120
|
+
print(" 6. CITY LIST")
|
|
121
|
+
print("=" * 60)
|
|
122
|
+
|
|
123
|
+
list_path = (await client.find_object(object_name="cityList"))["path"]
|
|
124
|
+
list_info = await client.get_model_info(list_path)
|
|
125
|
+
log(f"Model: {list_info['model_class']}, {list_info['row_count']} items")
|
|
126
|
+
|
|
127
|
+
list_data = await client.get_model_data(list_path)
|
|
128
|
+
cities = [row["cells"]["0"] for row in list_data["rows"]]
|
|
129
|
+
log(f"Cities: {', '.join(cities)}")
|
|
130
|
+
|
|
131
|
+
# ──────────────────────────────────────────
|
|
132
|
+
# 7. FILE TREE — model info + data
|
|
133
|
+
# ──────────────────────────────────────────
|
|
134
|
+
print(f"\n{'=' * 60}")
|
|
135
|
+
print(" 7. FILE TREE")
|
|
136
|
+
print("=" * 60)
|
|
137
|
+
|
|
138
|
+
tree_path = (await client.find_object(object_name="fileTree"))["path"]
|
|
139
|
+
tree_info = await client.get_model_info(tree_path)
|
|
140
|
+
log(f"Model: {tree_info['model_class']}")
|
|
141
|
+
log(f"Top-level rows: {tree_info['row_count']}, columns: {tree_info['column_count']}")
|
|
142
|
+
log(f"Headers: {tree_info['horizontal_headers']}")
|
|
143
|
+
|
|
144
|
+
tree_data = await client.get_model_data(tree_path)
|
|
145
|
+
for row_data in tree_data["rows"]:
|
|
146
|
+
cells = row_data["cells"]
|
|
147
|
+
log(f" {cells.get('0', '')} {cells.get('1', '')}")
|
|
148
|
+
|
|
149
|
+
# ──────────────────────────────────────────
|
|
150
|
+
# 8. SEARCH — find employees by department
|
|
151
|
+
# ──────────────────────────────────────────
|
|
152
|
+
print(f"\n{'=' * 60}")
|
|
153
|
+
print(" 8. SEARCH — Engineering Department")
|
|
154
|
+
print("=" * 60)
|
|
155
|
+
|
|
156
|
+
all_data = await client.get_model_data(table_path)
|
|
157
|
+
engineering = [
|
|
158
|
+
row for row in all_data["rows"]
|
|
159
|
+
if row["cells"].get("1") == "Engineering"
|
|
160
|
+
]
|
|
161
|
+
log(f"Found {len(engineering)} engineers:")
|
|
162
|
+
for row_data in engineering:
|
|
163
|
+
cells = row_data["cells"]
|
|
164
|
+
log(f" {cells['0']:20s} ${cells['2']} in {cells['3']}")
|
|
165
|
+
|
|
166
|
+
# ──────────────────────────────────────────
|
|
167
|
+
# 9. AGGREGATION — average salary by department
|
|
168
|
+
# ──────────────────────────────────────────
|
|
169
|
+
print(f"\n{'=' * 60}")
|
|
170
|
+
print(" 9. SALARY SUMMARY")
|
|
171
|
+
print("=" * 60)
|
|
172
|
+
|
|
173
|
+
departments: dict[str, list[int]] = {}
|
|
174
|
+
for row_data in all_data["rows"]:
|
|
175
|
+
cells = row_data["cells"]
|
|
176
|
+
dept = cells.get("1", "")
|
|
177
|
+
salary = int(cells.get("2", "0"))
|
|
178
|
+
departments.setdefault(dept, []).append(salary)
|
|
179
|
+
|
|
180
|
+
for dept, salaries in sorted(departments.items()):
|
|
181
|
+
avg = sum(salaries) / len(salaries)
|
|
182
|
+
log(f" {dept:15s} avg: ${avg:>10,.0f} headcount: {len(salaries)}")
|
|
183
|
+
|
|
184
|
+
print(f"\n{'=' * 60}")
|
|
185
|
+
print(" DONE — all model data access completed")
|
|
186
|
+
print("=" * 60)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
if __name__ == "__main__":
|
|
190
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Minimal example: connect to a veriCue server and run basic commands."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from vericue import VeriCueClient
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def main():
|
|
9
|
+
async with VeriCueClient() as client:
|
|
10
|
+
await client.connect("127.0.0.1", 4242)
|
|
11
|
+
|
|
12
|
+
pong = await client.ping()
|
|
13
|
+
print(f"Ping: {pong}")
|
|
14
|
+
|
|
15
|
+
version = await client.version()
|
|
16
|
+
print(f"Version: {version}")
|
|
17
|
+
|
|
18
|
+
echo = await client.echo("hello vericue")
|
|
19
|
+
print(f"Echo: {echo}")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == "__main__":
|
|
23
|
+
asyncio.run(main())
|