platynui-native
================
Native Python bindings for PlatynUI using PyO3 + maturin.
Quick start (local develop):
- uv sync --dev
- uv run maturin develop -m packages/native/Cargo.toml --release --features mock-provider
Then in Python:
```python
from platynui_native import core, runtime
pt = core.Point(1.0, 2.0)
rt = runtime.Runtime()
items = rt.evaluate("/control:Desktop", None)
```
Run smoke tests (uses mock provider feature):
```
uv run maturin develop -m packages/native/Cargo.toml --release --features mock-provider
uv run pytest -q packages/native/tests
```
API overview
- Module layout
- `platynui_native.core`: `Point`/`Size`/`Rect`, `Namespace`, IDs, `attribute_names()`
- `platynui_native.runtime`: `Runtime`, `UiNode`, `UiAttribute`, `EvaluatedAttribute`, pointer/keyboard methods
- New: `Runtime.keyboard_known_key_names()` returns a list of supported key names from the active keyboard device.
- Creating a Runtime
- `rt = runtime.Runtime()`
- Pointer buttons
- Accepts: `'left' | 'middle' | 'right'`, `runtime.PointerButton` enum, or `int`.
- Mapping: `1 → LEFT`, `2 → MIDDLE`, `3 → RIGHT`, other ints → `Other(n)`.
- Pointer overrides (class)
- Timing (milliseconds unless noted):
- `after_move_delay_ms`, `after_input_delay_ms`, `press_release_delay_ms`,
`after_click_delay_ms`, `before_next_click_delay_ms`, `multi_click_delay_ms`,
`ensure_move_timeout_ms`, `scroll_delay_ms`, `max_move_duration_ms`.
- `move_time_per_pixel_us` (microseconds per pixel)
- Motion/profile:
- `speed_factor: float`
- `acceleration_profile: 'constant'|'ease_in'|'ease_out'|'smooth_step'`
- Origin (choose one):
- `'desktop'`
- `core.Point(x, y)` → absolute desktop point
- `core.Rect(x, y, w, h)` → relative to rect (top-left origin)
- Scrolling:
- `scroll_step: (h: float, v: float)`; `scroll_delay_ms`
- Other:
- `ensure_move_threshold: float`
- Properties: all fields are exposed read‑only (e.g. `ov.speed_factor`, `ov.origin`, `ov.after_move_delay_ms`).
- Keyboard overrides (class, milliseconds)
- `press_delay_ms`, `release_delay_ms`, `between_keys_delay_ms`,
`chord_press_delay_ms`, `chord_release_delay_ms`,
`after_sequence_delay_ms`, `after_text_delay_ms`.
- Properties: `kov.press_delay_ms`, `kov.between_keys_delay_ms`, etc.
Examples
```python
from platynui_native import core, runtime
rt = runtime.Runtime()
# Move & click with overrides
ov = runtime.PointerOverrides(speed_factor=1.5, after_move_delay_ms=15, origin='desktop')
rt.pointer_move_to(core.Point(100, 200), overrides=ov)
rt.pointer_click(core.Point(100, 200), button=runtime.PointerButton.LEFT,
overrides=runtime.PointerOverrides(multi_click_delay_ms=240))
# Click at current pointer position (no move)
rt.pointer_click(None, button=runtime.PointerButton.LEFT)
# Drag with relative origin
rt.pointer_drag(core.Point(10, 10), core.Point(180, 140), button=runtime.PointerButton.LEFT,
overrides=runtime.PointerOverrides(origin=core.Rect(50, 60, 200, 200)))
# Keyboard with custom timings
rt.keyboard_type("Hello", overrides=runtime.KeyboardOverrides(between_keys_delay_ms=5))
rt.keyboard_press("<Ctrl+C>")
rt.keyboard_release("<Ctrl+C>")
# Inspect available key names from the active device
names = rt.keyboard_known_key_names()
print(names[:20])
```
Notes
- The mock provider feature (`--features mock-provider`) is intended for local development without platform backends. Some pointer/keyboard calls may raise `PointerError`/`KeyboardError` if the device is not available; structure/typing of arguments is still validated.
- Evaluate results
- `Runtime.evaluate()` returns a list of `UiNode`, `EvaluatedAttribute`, or plain values (`UiValue`).
- `UiNode.attributes()` returns `list[UiAttribute]` (no owner).
- `EvaluatedAttribute` includes an `owner()` reference back to the `UiNode` it belongs to.
Reference
- Pointer defaults (from runtime profile/settings)
- double_click_time: 500 ms; double_click_size: (4.0, 4.0); default_button: left
- mode: Linear; steps_per_pixel: 1.5; speed_factor: 1.0
- max_move_duration: 600 ms; move_time_per_pixel: 800 µs
- acceleration_profile: SmoothStep
- after_move_delay: 40 ms; after_input_delay: 35 ms
- press_release_delay: 50 ms; after_click_delay: 80 ms
- before_next_click_delay: 120 ms; multi_click_delay: 500 ms
- ensure_move_position: true; ensure_move_threshold: 2.0; ensure_move_timeout: 250 ms
- scroll_step: (0.0, -120.0); scroll_delay: 40 ms
- Keyboard defaults (KeyboardSettings.default)
- press_delay: 35 ms; release_delay: 25 ms
- between_keys_delay: 40 ms
- chord_press_delay: 45 ms; chord_release_delay: 45 ms
- after_sequence_delay: 75 ms; after_text_delay: 20 ms
Robot Framework usage (example)
Wrap the native runtime into a simple Python library and import it in Robot suites:
1) Create `examples/robot/platynui_lib.py`:
```python
from platynui_native import runtime
class PlatynUILib:
def __init__(self):
self.rt = runtime.Runtime()
def pointer_move_to(self, x: float, y: float):
self.rt.pointer_move_to((float(x), float(y)))
def keyboard_type(self, sequence: str):
self.rt.keyboard_type(sequence)
```
2) Create `examples/robot/quickstart.robot`:
```
*** Settings ***
Library examples/robot/platynui_lib.py
*** Test Cases ***
Pointer And Keyboard Smoke
Pointer Move To 100 200
Keyboard Type Hello
```
3) Run with the mock feature installed:
```
uv run maturin develop -m packages/native/Cargo.toml --release --features mock-provider
uv run robot examples/robot/quickstart.robot
Troubleshooting
## Mock Providers and Platform Devices
Mock providers do NOT auto-register in the inventory system. They are explicitly exposed as Python handles for testing:
### Available Mock Components
- **`MOCK_PROVIDER`** - Mock UI tree provider (provides a test UI tree)
- **`MOCK_PLATFORM`** - Mock desktop info provider (provides MockOS desktop with 3 monitors)
- **`MOCK_HIGHLIGHT_PROVIDER`** - Mock highlight provider
- **`MOCK_SCREENSHOT_PROVIDER`** - Mock screenshot provider
- **`MOCK_POINTER_DEVICE`** - Mock pointer/mouse device
- **`MOCK_KEYBOARD_DEVICE`** - Mock keyboard device
### Usage Examples
**Basic Runtime with Mock Provider:**
```python
from platynui_native import Runtime, MOCK_PROVIDER
rt = Runtime.new_with_providers([MOCK_PROVIDER])
# Uses OS platform devices (may fail if not available)
```
**Full Mock Runtime (for testing):**
```python
from platynui_native import (
Runtime, PlatformOverrides,
MOCK_PROVIDER, MOCK_PLATFORM,
MOCK_POINTER_DEVICE, MOCK_KEYBOARD_DEVICE,
MOCK_SCREENSHOT_PROVIDER, MOCK_HIGHLIGHT_PROVIDER
)
# Configure platform overrides
overrides = PlatformOverrides()
overrides.desktop_info = MOCK_PLATFORM
overrides.pointer = MOCK_POINTER_DEVICE
overrides.keyboard = MOCK_KEYBOARD_DEVICE
overrides.screenshot = MOCK_SCREENSHOT_PROVIDER
overrides.highlight = MOCK_HIGHLIGHT_PROVIDER
# Create runtime with all mock components
rt = Runtime.new_with_providers_and_platforms([MOCK_PROVIDER], overrides)
# Now all operations work without real OS providers
info = rt.desktop_info()
print(info["os_name"]) # Output: "MockOS"
```
### Build Requirements
The `mock-provider` feature links the mock crates, making the handles available:
```bash
uv run maturin develop -m packages/native/Cargo.toml --features mock-provider
```
### Common Issues
- **"no PointerDevice registered"**: Pass `MOCK_POINTER_DEVICE` in `PlatformOverrides`
- **"no KeyboardDevice registered"**: Pass `MOCK_KEYBOARD_DEVICE` in `PlatformOverrides`
- **Want mock desktop info**: Pass `MOCK_PLATFORM` in `overrides.desktop_info`
## Other Issues
- If `maturin` complains about the manifest path, always pass `-m packages/native/Cargo.toml` for mixed projects.
- If your shell shows a VIRTUAL_ENV mismatch, prefer `uv run --active ...` to target the active environment explicitly.
```
- Multi‑click: `Runtime.pointer_multi_click(point=None, clicks=2, ...)` uses 2 clicks by default.
Raw data
{
"_id": null,
"home_page": null,
"name": "platynui-native",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": "Daniel Biehl <daniel.biehl@imbus.de>",
"keywords": "robotframework, platynui, gui, automation, desktop",
"author": null,
"author_email": "Daniel Biehl <daniel.biehl@imbus.de>",
"download_url": null,
"platform": null,
"description": "platynui-native\r\n================\r\n\r\nNative Python bindings for PlatynUI using PyO3 + maturin.\r\n\r\nQuick start (local develop):\r\n\r\n- uv sync --dev\r\n- uv run maturin develop -m packages/native/Cargo.toml --release --features mock-provider\r\n\r\nThen in Python:\r\n\r\n```python\r\nfrom platynui_native import core, runtime\r\npt = core.Point(1.0, 2.0)\r\nrt = runtime.Runtime()\r\nitems = rt.evaluate(\"/control:Desktop\", None)\r\n```\r\n\r\nRun smoke tests (uses mock provider feature):\r\n\r\n```\r\nuv run maturin develop -m packages/native/Cargo.toml --release --features mock-provider\r\nuv run pytest -q packages/native/tests\r\n```\r\n\r\nAPI overview\r\n\r\n- Module layout\r\n - `platynui_native.core`: `Point`/`Size`/`Rect`, `Namespace`, IDs, `attribute_names()`\r\n - `platynui_native.runtime`: `Runtime`, `UiNode`, `UiAttribute`, `EvaluatedAttribute`, pointer/keyboard methods\r\n - New: `Runtime.keyboard_known_key_names()` returns a list of supported key names from the active keyboard device.\r\n\r\n- Creating a Runtime\r\n - `rt = runtime.Runtime()`\r\n\r\n- Pointer buttons\r\n - Accepts: `'left' | 'middle' | 'right'`, `runtime.PointerButton` enum, or `int`.\r\n - Mapping: `1 \u2192 LEFT`, `2 \u2192 MIDDLE`, `3 \u2192 RIGHT`, other ints \u2192 `Other(n)`.\r\n\r\n- Pointer overrides (class)\r\n - Timing (milliseconds unless noted):\r\n - `after_move_delay_ms`, `after_input_delay_ms`, `press_release_delay_ms`,\r\n `after_click_delay_ms`, `before_next_click_delay_ms`, `multi_click_delay_ms`,\r\n `ensure_move_timeout_ms`, `scroll_delay_ms`, `max_move_duration_ms`.\r\n - `move_time_per_pixel_us` (microseconds per pixel)\r\n - Motion/profile:\r\n - `speed_factor: float`\r\n - `acceleration_profile: 'constant'|'ease_in'|'ease_out'|'smooth_step'`\r\n - Origin (choose one):\r\n - `'desktop'`\r\n - `core.Point(x, y)` \u2192 absolute desktop point\r\n - `core.Rect(x, y, w, h)` \u2192 relative to rect (top-left origin)\r\n - Scrolling:\r\n - `scroll_step: (h: float, v: float)`; `scroll_delay_ms`\r\n - Other:\r\n - `ensure_move_threshold: float`\r\n - Properties: all fields are exposed read\u2011only (e.g. `ov.speed_factor`, `ov.origin`, `ov.after_move_delay_ms`).\r\n\r\n- Keyboard overrides (class, milliseconds)\r\n - `press_delay_ms`, `release_delay_ms`, `between_keys_delay_ms`,\r\n `chord_press_delay_ms`, `chord_release_delay_ms`,\r\n `after_sequence_delay_ms`, `after_text_delay_ms`.\r\n - Properties: `kov.press_delay_ms`, `kov.between_keys_delay_ms`, etc.\r\n\r\nExamples\r\n\r\n```python\r\nfrom platynui_native import core, runtime\r\nrt = runtime.Runtime()\r\n\r\n# Move & click with overrides\r\nov = runtime.PointerOverrides(speed_factor=1.5, after_move_delay_ms=15, origin='desktop')\r\nrt.pointer_move_to(core.Point(100, 200), overrides=ov)\r\nrt.pointer_click(core.Point(100, 200), button=runtime.PointerButton.LEFT,\r\n overrides=runtime.PointerOverrides(multi_click_delay_ms=240))\r\n\r\n# Click at current pointer position (no move)\r\nrt.pointer_click(None, button=runtime.PointerButton.LEFT)\r\n\r\n# Drag with relative origin\r\nrt.pointer_drag(core.Point(10, 10), core.Point(180, 140), button=runtime.PointerButton.LEFT,\r\n overrides=runtime.PointerOverrides(origin=core.Rect(50, 60, 200, 200)))\r\n\r\n# Keyboard with custom timings\r\nrt.keyboard_type(\"Hello\", overrides=runtime.KeyboardOverrides(between_keys_delay_ms=5))\r\nrt.keyboard_press(\"<Ctrl+C>\")\r\nrt.keyboard_release(\"<Ctrl+C>\")\r\n\r\n# Inspect available key names from the active device\r\nnames = rt.keyboard_known_key_names()\r\nprint(names[:20])\r\n```\r\n\r\nNotes\r\n\r\n- The mock provider feature (`--features mock-provider`) is intended for local development without platform backends. Some pointer/keyboard calls may raise `PointerError`/`KeyboardError` if the device is not available; structure/typing of arguments is still validated.\r\n\r\n- Evaluate results\r\n - `Runtime.evaluate()` returns a list of `UiNode`, `EvaluatedAttribute`, or plain values (`UiValue`).\r\n - `UiNode.attributes()` returns `list[UiAttribute]` (no owner).\r\n - `EvaluatedAttribute` includes an `owner()` reference back to the `UiNode` it belongs to.\r\n\r\nReference\r\n\r\n- Pointer defaults (from runtime profile/settings)\r\n - double_click_time: 500 ms; double_click_size: (4.0, 4.0); default_button: left\r\n - mode: Linear; steps_per_pixel: 1.5; speed_factor: 1.0\r\n - max_move_duration: 600 ms; move_time_per_pixel: 800 \u00b5s\r\n - acceleration_profile: SmoothStep\r\n - after_move_delay: 40 ms; after_input_delay: 35 ms\r\n - press_release_delay: 50 ms; after_click_delay: 80 ms\r\n - before_next_click_delay: 120 ms; multi_click_delay: 500 ms\r\n - ensure_move_position: true; ensure_move_threshold: 2.0; ensure_move_timeout: 250 ms\r\n - scroll_step: (0.0, -120.0); scroll_delay: 40 ms\r\n\r\n- Keyboard defaults (KeyboardSettings.default)\r\n - press_delay: 35 ms; release_delay: 25 ms\r\n - between_keys_delay: 40 ms\r\n - chord_press_delay: 45 ms; chord_release_delay: 45 ms\r\n - after_sequence_delay: 75 ms; after_text_delay: 20 ms\r\n\r\nRobot Framework usage (example)\r\n\r\nWrap the native runtime into a simple Python library and import it in Robot suites:\r\n\r\n1) Create `examples/robot/platynui_lib.py`:\r\n\r\n```python\r\nfrom platynui_native import runtime\r\n\r\nclass PlatynUILib:\r\n def __init__(self):\r\n self.rt = runtime.Runtime()\r\n\r\n def pointer_move_to(self, x: float, y: float):\r\n self.rt.pointer_move_to((float(x), float(y)))\r\n\r\n def keyboard_type(self, sequence: str):\r\n self.rt.keyboard_type(sequence)\r\n```\r\n\r\n2) Create `examples/robot/quickstart.robot`:\r\n\r\n```\r\n*** Settings ***\r\nLibrary examples/robot/platynui_lib.py\r\n\r\n*** Test Cases ***\r\nPointer And Keyboard Smoke\r\n Pointer Move To 100 200\r\n Keyboard Type Hello\r\n```\r\n\r\n3) Run with the mock feature installed:\r\n\r\n```\r\nuv run maturin develop -m packages/native/Cargo.toml --release --features mock-provider\r\nuv run robot examples/robot/quickstart.robot\r\n\r\nTroubleshooting\r\n\r\n## Mock Providers and Platform Devices\r\n\r\nMock providers do NOT auto-register in the inventory system. They are explicitly exposed as Python handles for testing:\r\n\r\n### Available Mock Components\r\n\r\n- **`MOCK_PROVIDER`** - Mock UI tree provider (provides a test UI tree)\r\n- **`MOCK_PLATFORM`** - Mock desktop info provider (provides MockOS desktop with 3 monitors)\r\n- **`MOCK_HIGHLIGHT_PROVIDER`** - Mock highlight provider\r\n- **`MOCK_SCREENSHOT_PROVIDER`** - Mock screenshot provider\r\n- **`MOCK_POINTER_DEVICE`** - Mock pointer/mouse device\r\n- **`MOCK_KEYBOARD_DEVICE`** - Mock keyboard device\r\n\r\n### Usage Examples\r\n\r\n**Basic Runtime with Mock Provider:**\r\n```python\r\nfrom platynui_native import Runtime, MOCK_PROVIDER\r\n\r\nrt = Runtime.new_with_providers([MOCK_PROVIDER])\r\n# Uses OS platform devices (may fail if not available)\r\n```\r\n\r\n**Full Mock Runtime (for testing):**\r\n```python\r\nfrom platynui_native import (\r\n Runtime, PlatformOverrides,\r\n MOCK_PROVIDER, MOCK_PLATFORM,\r\n MOCK_POINTER_DEVICE, MOCK_KEYBOARD_DEVICE,\r\n MOCK_SCREENSHOT_PROVIDER, MOCK_HIGHLIGHT_PROVIDER\r\n)\r\n\r\n# Configure platform overrides\r\noverrides = PlatformOverrides()\r\noverrides.desktop_info = MOCK_PLATFORM\r\noverrides.pointer = MOCK_POINTER_DEVICE\r\noverrides.keyboard = MOCK_KEYBOARD_DEVICE\r\noverrides.screenshot = MOCK_SCREENSHOT_PROVIDER\r\noverrides.highlight = MOCK_HIGHLIGHT_PROVIDER\r\n\r\n# Create runtime with all mock components\r\nrt = Runtime.new_with_providers_and_platforms([MOCK_PROVIDER], overrides)\r\n\r\n# Now all operations work without real OS providers\r\ninfo = rt.desktop_info()\r\nprint(info[\"os_name\"]) # Output: \"MockOS\"\r\n```\r\n\r\n### Build Requirements\r\n\r\nThe `mock-provider` feature links the mock crates, making the handles available:\r\n\r\n```bash\r\nuv run maturin develop -m packages/native/Cargo.toml --features mock-provider\r\n```\r\n\r\n### Common Issues\r\n\r\n- **\"no PointerDevice registered\"**: Pass `MOCK_POINTER_DEVICE` in `PlatformOverrides`\r\n- **\"no KeyboardDevice registered\"**: Pass `MOCK_KEYBOARD_DEVICE` in `PlatformOverrides`\r\n- **Want mock desktop info**: Pass `MOCK_PLATFORM` in `overrides.desktop_info`\r\n\r\n## Other Issues\r\n\r\n- If `maturin` complains about the manifest path, always pass `-m packages/native/Cargo.toml` for mixed projects.\r\n- If your shell shows a VIRTUAL_ENV mismatch, prefer `uv run --active ...` to target the active environment explicitly.\r\n```\r\n- Multi\u2011click: `Runtime.pointer_multi_click(point=None, clicks=2, ...)` uses 2 clicks by default.\r\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Native Python bindings for PlatynUI (core types + runtime)",
"version": "0.12.0.dev3",
"project_urls": {
"Changelog": "https://github.com/imbus/robotframework-PlatynUI/blob/main/CHANGELOG.md",
"Documentation": "https://github.com/imbus/robotframework-PlatynUI#readme",
"Homepage": "https://github.com/imbus/robotframework-PlatynUI",
"Issues": "https://github.com/imbus/robotframework-PlatynUI/issues",
"Source": "https://github.com/imbus/robotframework-PlatynUI"
},
"split_keywords": [
"robotframework",
" platynui",
" gui",
" automation",
" desktop"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "e3a413ebbf9e82ea7406cb5b007fd841d5fc5fe44f17c8e8df54435016160b47",
"md5": "90b0fa44ffbfe95159ba78e8e7e55dac",
"sha256": "b16fa62cd268398aee3a244b0f543e1333a371b0e9ba913d5501ed63e906877d"
},
"downloads": -1,
"filename": "platynui_native-0.12.0.dev3-cp310-abi3-win_amd64.whl",
"has_sig": false,
"md5_digest": "90b0fa44ffbfe95159ba78e8e7e55dac",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 2489230,
"upload_time": "2025-10-23T12:18:39",
"upload_time_iso_8601": "2025-10-23T12:18:39.775001Z",
"url": "https://files.pythonhosted.org/packages/e3/a4/13ebbf9e82ea7406cb5b007fd841d5fc5fe44f17c8e8df54435016160b47/platynui_native-0.12.0.dev3-cp310-abi3-win_amd64.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-23 12:18:39",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "imbus",
"github_project": "robotframework-PlatynUI",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "platynui-native"
}