Skip to main content

A Python extension for UI Automation on Windows.

Project description

Bromium

Bromium as a project aims to provide the required infrastructure to automate tasks in Microsoft Windows Desktop Applications. It is devided in two main components:

  • the bromium Python library that provides bindings to interact with the Windows UI Automation API through Rust. It enables users to automate tasks and interact with Windows UI elements programmatically.
  • the UI Expore Desktop application (inspired by inspect.exe) which allows users to inspect the current Windows Desktop, get xpath locators to any ui element on the desktop and test custom xpah locators. It can be run without a need to install the application and without admin rights. This can be built from source by cloning the github repository https://github.com/dangrazh/bromium/

This is the actual Python library that provides bindings to interact with the Windows UI Automation API.

Key Features of python library

  • Get representation of all UI elements on the current desktop (UI tree)
  • Launch an application or activate an already running appliation window
  • Interact with UI elements on the current desktop
  • Get screen context information (size, scaling, etc.)
  • Take screen shots
  • Get cursor position coordinates
  • Retrieve UI element information at specific coordinates

Installation

pip install bromium

Usage

Here's a basic example of how to use Bromium:

from bromium import WinDriver
import time
import os

def demo_app_launch():
    print("Testing bromium app launch/activation functionality...")
    
    # Initialize Bromium logging
    print("Initializing Bromium logging...")
    Bromium.init_logging(log_path=None, log_level=None, enable_console=True, enable_file=True)

    # Create a WinDriver instance
    print("Getting WinDriver Instance...")
    driver = WinDriver(timeout_ms=5_000)
    print("WinDriver instance obtained.")
    no_of_elements = driver.get_no_of_ui_elements()
    print(f"Driver has {no_of_elements} elements.")
    # Path to Windows Calculator (available on all Windows systems)
    # app_path = r"C:\Windows\System32\calc.exe"
    # XPath for Calculator
    # This is a sample XPath for the Calculator window and the "9" button
    # xpath = r'/Pane[@ClassName="#32769"][@Name="Desktop 1"]/Window[@ClassName="ApplicationFrameWindow"][@Name="Calculator"]/Window[@ClassName="Windows.UI.Core.CoreWindow"][@Name="Calculator"]/Custom[@AutomationId="NavView"]/Group[@ClassName="LandmarkTarget"]/Group[@Name="Number pad"][@AutomationId="NumberPad"]/Button[@Name="Nine"][@AutomationId="num9Button"]'

    # Path to MS Teams
    app_path = r"ms-teams.exe"
    # XPath for MS Teams
    # This is a sample XPath for the Teams window 
    xpath = r"/Pane[@Name='Desktop 1']/Window[@Name='Microsoft Teams']"

    file_name = os.path.basename(app_path)
    print(f"Launching/activating {file_name} with path: {app_path}")
    
    # Try to launch or activate the application
    try:
        app_window = driver.launch_or_activate_app(app_path, xpath)
        print(f"First attempt to launch/activate {file_name} returned: {app_window}")
        print(f"{app_window} should now be in focus")
            
        # Wait a moment to observe the result
        time.sleep(3)
        
        # Reload the driver to ensure we have the latest UI tree
        driver = driver.reload()
        no_of_elements = driver.get_no_of_ui_elements()
        print(f"Driver reloaded to refresh UI tree. It now has {no_of_elements} elements.")
 
        # Teams login - if required
        xpath_login_button = r"//Button[@Name='Sign in']"
        try:
            login_button = driver.get_ui_element_by_xpath(xpath_login_button)
            # if this does not raise an exception, the button was found, hence we need to login
            print("Login button found, performing login...")
            login_button.send_click()
            print("Clicked the login button.")
            # give it some time to process
            time.sleep(2)
            driver.refresh_ui_tree()
            xpath_username = r"//Edit[@Name='E-Mail-Adresse, Telefonnummer oder Skype-Name']"
            try:
                username_field = driver.get_ui_element_by_xpath(xpath_username)
                username_field.send_keys("john.doe@gmail.com")
            except Exception as e:
                print("Username field not found, aborting login.")


        except Exception as e:
            print("Login button not found, assuming already logged in.")
    except Exception as e:
        print(f"Error during launch/activation of {file_name}: {e}")        
    
    print("Test completed!")

if __name__ == "__main__":
    demo_app_launch()

API Reference

Bromium

A class providing access to static methods to initialize and control the logging system of bromium and allowing to obtain new WinDriver instances (simply wrapping a call to the constructor of the WinDriver Class).

Static Methods

  • get_version() -> str: Returns the current version of the bromium module.
  • get_win_driver(timeout_ms: int, window_title: Optional[str]) -> WinDriver: Return a new WinDriver object.
  • init_logging(log_path: Optional[str], log_level: Optional[Literal["Off", "Error", "Warn", "Info", "Debug", "Trace"]], enable_console: Optional[bool], enable_file: Optional[bool]) -> None: Initializes logging with the given parameters.
  • get_log_file() -> str: Returns the current log file path. Returns default path if not set.
  • set_log_file(path: str) -> None: Sets the full path for the log file. Creates parent directories if needed.
  • set_log_directory(dir_path: str) -> None: Sets a custom directory for log files. A timestamped log file will be created in this directory.
  • set_log_level(level: Literal["Off", "Error", "Warn", "Info", "Debug", "Trace"]) -> None: Sets the logging level for the bromium module.
  • get_log_level() -> str: Returns the current logging level.
  • enable_console_logging(enable: bool) -> None: Enable or disable console logging.
  • enable_file_logging(enable: bool) -> None: Enable or disable file logging.
  • reset_log_file() -> None: Clear all contents from the current log file.

WinDriver

The main class for interacting with the Windows UI tree.

Constructor

  • __init__(timeout_ms: int, window_title: Optional[str]) -> None: Initializes the WinDriver instance with a timeout in milliseconds.

Methods

  • get_timeout() -> int: Returns the current timeout value in milliseconds.
  • set_timeout(timeout_ms: int) -> None: Sets a new timeout value in milliseconds.
  • get_curser_pos() -> tuple[int, int]: Returns the current cursor position as a tuple of (x, y) coordinates.
  • get_ui_element_by_coordinates(x: int, y: int) -> Element: Returns the UI element at the given pixel coordinates.
  • get_ui_element_by_xpath(xpath: str) -> Element: Returns the UI element matching the given XPath. Uses a three-step search approach: exact match, subtree search with single match, and pattern matching across multiple matches.
  • get_screen_context() -> ScreenContext: Returns screen size and scale information for all displays.
  • get_no_of_ui_elements() -> int: Returns the number of UI elements in the current UI tree.
  • launch_or_activate_app(app_path: str, xpath: str) -> Element: Launches a new application or activates an existing window. Returns the Element matching the provided XPath.
  • take_screenshot() -> str: Takes a screenshot of the current screen, saves it to a temporary directory, and returns the file path.
  • refresh() -> None: Refreshes the internal UI tree representation by scanning the current window state. Runs in a separate thread to avoid blocking.
  • reload() -> WinDriver: Reloads the WinDriver instance to refresh its internal state and returns a new WinDriver instance.

Element

Represents a Windows UI Automation element.

Attributes

  • name (str): The name of the UI element.
  • xpath (str): The XPath locator for the UI element.
  • handle (int): The window handle of the UI element.
  • control_type (str): The control type of the UI element.
  • runtime_id (list[int]): The runtime ID of the UI element.
  • bounding_rectangle (tuple[int, int, int, int]): The bounding rectangle coordinates (left, top, right, bottom).

Methods

  • get_name() -> str: Returns the name of the UI element.
  • get_xpath() -> str: Returns the XPath locator of the UI element.
  • get_handle() -> int: Returns the window handle of the UI element.
  • get_control_type() -> str: Returns the control type of the UI element.
  • get_runtime_id() -> list[int]: Returns the runtime ID of the UI element.
  • send_click() -> None: Sends a left mouse click to the element.
  • send_double_click() -> None: Sends a double click to the element.
  • send_right_click() -> None: Sends a right click to the element.
  • hold_click(holdkeys: str) -> None: Performs a click while holding specified keys (e.g., "ctrl", "shift", "alt").
  • send_keys(keys: str) -> None: Sends keyboard input with a 20ms interval between keystrokes. Supports special key syntax with {} (e.g., {ctrl}{alt}{delete}) and grouping with () (e.g., {ctrl}(AB) for Ctrl+A+B).
  • send_text(text: str) -> None: Sends plain text input with a 20ms interval between characters. Use this for text without special keys.
  • hold_send_keys(holdkeys: str, keys: str, interval: int) -> None: Sends keys while holding modifier keys with a specified interval in milliseconds between keystrokes.
  • show_context_menu() -> None: Shows the context menu for the element.

ScreenContext

Contains information about all display screens in the system.

Methods

  • get_primary_screen() -> ScreenInfo: Returns information about the primary display screen.
  • get_screens() -> list[ScreenInfo]: Returns information about all available display screens.

ScreenInfo

Represents information about a single display screen.

Attributes

  • id (int): Unique identifier associated with the display.
  • name (str): The display name.
  • friendly_name (str): The display friendly name.
  • x (int): The display x coordinate.
  • y (int): The display y coordinate.
  • width (int): The display pixel width.
  • height (int): The display pixel height.
  • width_mm (int): The width of the display in millimeters (may be 0).
  • height_mm (int): The height of the display in millimeters (may be 0).
  • rotation (float): Screen rotation in clock-wise degrees (0, 90, 180, 270).
  • scale_factor (float): Output device's pixel scale factor.
  • frequency (float): The display refresh rate.
  • is_primary (bool): Whether the screen is the primary display.

Methods

  • get_id() -> int: Returns the unique identifier associated with the display.
  • get_name() -> str: Returns the display name.
  • get_friendly_name() -> str: Returns the display friendly name.
  • get_x() -> int: Returns the display x coordinate.
  • get_y() -> int: Returns the display y coordinate.
  • get_width() -> int: Returns the display pixel width.
  • get_height() -> int: Returns the display pixel height.
  • get_width_mm() -> int: Returns the width of the display in millimeters.
  • get_height_mm() -> int: Returns the height of the display in millimeters.
  • get_rotation() -> float: Returns the screen rotation in clock-wise degrees.
  • get_scale_factor() -> float: Returns the output device's pixel scale factor.
  • get_frequency() -> float: Returns the display refresh rate.
  • is_primary() -> bool: Returns whether this screen is the primary display.

Logging Functions

  • set_log_level(level: LogLevel) -> None: Sets the logging level for the bromium module. Use LogLevel.Error, LogLevel.Warn, LogLevel.Info, LogLevel.Debug, or LogLevel.Trace.
  • get_log_level() -> str: Returns the current logging level as a string.
  • set_log_file(path: str) -> None: Sets the full path for the log file. Creates parent directories if needed.
  • set_log_directory(dir_path: str) -> None: Sets a custom directory for log files. A timestamped log file will be created in this directory.
  • get_log_file() -> str: Returns the current log file path. Returns the default path if not set.
  • get_default_log_directory() -> str: Returns the default log directory path (C:\bromium_logs on Windows).

Requirements

  • Python 3.8 or higher
  • Windows operating system

Building from Source

To build the project from source, you'll need:

  1. Rust toolchain (cargo, rustc)
  2. Python 3.8+
  3. maturin (for building Python wheels)
# Clone the repository
git clone https://github.com/yourusername/bromium.git
cd bromium

# Build the project using maturin
maturin build

# Install in development mode
maturin develop

License

Apache License 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bromium-0.6.4.tar.gz (821.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bromium-0.6.4-cp312-cp312-win_amd64.whl (3.0 MB view details)

Uploaded CPython 3.12Windows x86-64

File details

Details for the file bromium-0.6.4.tar.gz.

File metadata

  • Download URL: bromium-0.6.4.tar.gz
  • Upload date:
  • Size: 821.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.11.5

File hashes

Hashes for bromium-0.6.4.tar.gz
Algorithm Hash digest
SHA256 43971ded5d475408e0d50d69cc21aa9cc113b153f708ca6cb5ae228c537820ab
MD5 f42087e8715a861694df26a96809bee6
BLAKE2b-256 8fa29600b9bb8107b656ca34e1de8df766996d32d579241c9527194ffe7f91f9

See more details on using hashes here.

File details

Details for the file bromium-0.6.4-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: bromium-0.6.4-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 3.0 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.11.5

File hashes

Hashes for bromium-0.6.4-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 8b02516299797e44a4ef7c4872e60cc60ed2b095c24806a16b89d5111cfbb050
MD5 041bbabeba8bea811995cee0df5f6a74
BLAKE2b-256 56a0fa4d2d4565b14cfcbb28c592897e95a0072fbda6086f099d7fa311caeb74

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page