Python SDK Reference
Getting Started
Python SDK Reference
this page details the python sdk for interacting with the terminator server. it provides examples for common ui automation tasks, primarily focusing on windows applications.
setup
first, ensure the terminator server is running (see Getting Started).
installation
pip install desktop-use
importing
from desktop_use import DesktopUseClient, Locator, ApiError, sleep, ElementResponse
# import other response models or exceptions as needed
client = DesktopUseClient() # connects to default 127.0.0.1:3000
# client = DesktopUseClient(base_url='127.0.0.1:3001') # or specify host:port
basic operations
opening applications and urls
def launch_apps():
try:
# open windows calculator
print('opening calculator...')
client.open_application('calc')
print('calculator opened.')
# wait a bit
sleep(1000)
# open notepad
print('opening notepad...')
client.open_application('notepad')
print('notepad opened.')
# open a url
print('opening url...')
client.open_url('https://github.com/mediar-ai/terminator')
print('url opened.')
except ApiError as e:
print(f'api error (status: {e.status}): {e}')
except Exception as e:
print(f'an unexpected error occurred: {e}')
# launch_apps()
locating elements
the locator()
method starts a chain. selectors use the format Strategy:Value
.
# locate the calculator window (windows 11 example)
calc_window = client.locator('window:Calculator')
# locate the 'seven' button within the calculator window
seven_button = calc_window.locator('role:button').locator('name:Seven')
# locate the main text area in notepad (use accessibility insights tool to find correct class/id)
notepad_editor = client.locator('window:Notepad').locator('role:richedit')
# directly locate the 'eight' button
eight_button = client.locator('window:Calculator').locator('role:button').locator('name:Eight')
interacting with elements
def interact_with_calc():
try:
print('opening calculator...')
client.open_application('calc')
sleep(1500) # give calc time to open
# locate elements
calc_window = client.locator('window:Calculator')
seven = calc_window.locator('role:Button').locator('name:Seven')
plus = calc_window.locator('role:Button').locator('name:Plus')
eight = calc_window.locator('role:Button').locator('name:Eight')
equals = calc_window.locator('role:Button').locator('name:Equals')
display = calc_window.locator('name:CalculatorResults')
print('clicking 7...')
seven.click()
sleep(200)
print('clicking +...')
plus.click()
sleep(200)
print('clicking 8...')
eight.click()
sleep(200)
print('clicking =...')
equals.click()
sleep(500)
# get the result
result = display.get_text()
print(f'calculation result: {result.text}') # e.g., "display is 15"
except ApiError as e:
print(f'api error interacting with calculator: {e}')
except Exception as e:
print(f'an unexpected error occurred: {e}')
# interact_with_calc()
def interact_with_notepad():
try:
print('opening notepad...')
client.open_application('notepad')
sleep(1000)
editor = client.locator('window:Notepad').locator('role:RichEdit')
print('typing text...')
editor.type_text('hello from terminator!\nthis is a python test.')
sleep(500)
print('pressing enter...')
editor.press_key('{Enter}')
sleep(200)
editor.type_text('done.')
content = editor.get_text()
print(f'notepad content retrieved: {content.text}')
except ApiError as e:
print(f'api error interacting with notepad: {e}')
except Exception as e:
print(f'an unexpected error occurred: {e}')
# interact_with_notepad()
note: element selectors can vary. use tools like windows’ accessibility insights to find correct selectors.
getting element state and attributes
def check_element_state():
try:
client.open_application('calc')
sleep(1000)
equals_button = client.locator('window:Calculator').locator('role:Button').locator('Name:Equals')
visible = equals_button.is_visible()
print(f'is equals button visible? {visible}')
attributes = equals_button.get_attributes()
print(f'equals button attributes: {attributes}') # attributes is a dataclass
bounds = equals_button.get_bounds()
print(f'equals button bounds: x={bounds.x}, y={bounds.y}, width={bounds.width}, height={bounds.height}')
except ApiError as e:
print(f'api error checking element state: {e}')
except Exception as e:
print(f'an unexpected error occurred: {e}')
# check_element_state()
expectations
use expect_*
methods to wait for conditions.
def use_expectations():
try:
print('opening notepad...')
client.open_application('notepad')
editor_locator = client.locator('window:Notepad').locator('role:RichEdit')
# wait for the editor element to be visible (default timeout)
print('waiting for editor to be visible...')
editor_element: ElementResponse = editor_locator.expect_visible()
print(f'editor is visible! id: {editor_element.id}')
# wait for it to be enabled (with a 5-second timeout)
print('waiting for editor to be enabled...')
editor_locator.expect_enabled(timeout=5000)
print('editor is enabled!')
editor_locator.type_text('initial text.')
sleep(1000)
# wait for the text to exactly match 'initial text.'
print('waiting for text to match...')
editor_locator.expect_text_equals('initial text.', timeout=3000)
print('text matched!')
# this would likely fail and raise ApiError after the timeout
# print('waiting for incorrect text (will timeout)...')
# editor_locator.expect_text_equals('wrong text', timeout=2000)
except ApiError as e:
print(f'expectation error: {e}')
except Exception as e:
print(f'an unexpected error occurred: {e}')
# use_expectations()
error handling
use try...except
blocks, catching ApiError
for server/automation issues and potentially ConnectionError
for network problems.
try:
# attempt to find a non-existent element
non_existent = client.locator('name:DoesNotExist')
non_existent.click()
except ApiError as e:
# handle specific api errors (e.g., element not found, timeout)
print(f'terminator api error (status: {e.status}): {e}')
except ConnectionError as e:
print(f'connection error: {e}. is the server running?')
except Exception as e:
# handle other unexpected errors
print(f'an unexpected python error occurred: {e}')
Was this page helpful?