Skip to main content

🐦 sapsucker

License: MIT Python Version PyPI version Unittests Linting Formatting Coverage

Typed Python wrapper for the SAP GUI Scripting API. For a Go client around the SAP ADT API, check adtler.

sapsucker gives you typed, IDE-friendly access to SAP GUI for Windows. Instead of working with raw COM objects and guessing method names, you get Python classes with autocomplete, type hints, and docstrings for every SAP GUI element.

Named after the sapsucker — a woodpecker that taps into trees to drink their sap. This library taps into SAP GUI to extract your data.

Quickstart

from sapsucker import SapGui

# Connect to running SAP GUI
app = SapGui.connect()
session = app.connections[0].sessions[0]

# Read session info
print(session.info.system_name)   # → "S4H"
print(session.info.user)          # → "DEVELOPER"

# Navigate to a transaction
session.find_by_id("wnd[0]/tbar[0]/okcd").text = "/nSE16"
session.find_by_id("wnd[0]").send_v_key(0)  # Enter

# Read the status bar
print(session.find_by_id("wnd[0]/sbar").text)

Why sapsucker?

  • Read a whole screen in one call — container.dump_tree() walks any screen recursively and returns typed ElementInfo, so you can discover element IDs instead of guessing them (the whole subtree in a single COM round trip on SAP GUI >= 7.70 PL3)
  • 40+ typed wrapper classes — GuiGridView.get_cell_value(), GuiTree.expand_node(), not generic element.read("cell", row, col)
  • IDE autocomplete & type hints on every method and property
  • 430+ unit tests, 50+ integration tests verified against real SAP S/4 HANA
  • API verified against the SAP GUI Scripting API 6.40 PDF (2969 pages)
  • MIT licensed — no GPL restrictions

Installation

pip install sapsucker

Prerequisites

  • SAP GUI for Windows (7.x or 8.x)
  • SAP GUI Scripting enabled — ask your SAP Basis team to set sapgui/user_scripting = TRUE in transaction RZ11, and enable scripting in your SAP GUI options (Customize Local Layout → Accessibility & Scripting)
  • Python 3.11+ on Windows

Usage Examples

Read an entire screen

Don't know a screen's element IDs? Walk it. dump_tree() recurses through every child container and returns validated ElementInfo objects — id, type, name, text, tooltips, accessibility text, geometry and more (sapsucker.models.ElementInfo).

from sapsucker import SapGui
from sapsucker.models import ElementInfo

app = SapGui.connect()
session = app.connections[0].sessions[0]

window = session.find_by_id("wnd[0]")

def walk(elements: list[ElementInfo], depth: int = 0) -> None:
    for element in elements:
        print("  " * depth, element.id, element.type, element.text)
        walk(element.children, depth + 1)   # ElementInfo nests its children

walk(window.dump_tree())                    # full depth by default (safety cap: 200)
# walk(window.dump_tree(max_depth=2))       # or bound it

On SAP GUI for Windows >= 7.70 PL3 dump_tree() uses GuiSession.GetObjectTree under the hood — the whole subtree in a single COM round trip — and falls back automatically to per-property reads on older releases.

Feeding a screen to an LLM? Call session.get_object_tree() directly and ask for only the properties you need instead of the full element record. Unlike dump_tree(), this call has no fallback — it raises on SAP GUI older than 7.70 PL3.

import json

# A JSON *string*, one COM call, only the properties you list
raw = session.get_object_tree("wnd[0]", props=["Id", "Type", "Text"])
tree = json.loads(raw)          # the queried element is tree["children"][0]

# props=None returns Id only — the cheapest possible screen dump
ids_only_json = session.get_object_tree("wnd[0]")

Read an ALV grid

from sapsucker import SapGui
from sapsucker.components.grid import GuiGridView

app = SapGui.connect()
session = app.connections[0].sessions[0]

# Find the grid on the current screen
grid = session.find_by_id("wnd[0]/shellcont/shell")

# Read all rows
for row in range(grid.row_count):
    for col in grid.column_order:
        print(grid.get_cell_value(row, col), end="\t")
    print()

Navigate a tree control

from sapsucker.components.tree import GuiTree

tree = session.find_by_id("wnd[0]/shellcont/shell/shellcont[1]/shell/shellcont[2]/shell")

key = tree.top_node
print(tree.get_node_text_by_key(key))

if tree.is_folder(key):
    tree.expand_node(key)

Fill a form

# Set a text field value
session.find_by_id("wnd[0]/usr/ctxtRS38M-PROGRAMM").text = "RSPARAM"

# Press F8 (Execute)
session.find_by_id("wnd[0]").send_v_key(8)

Context manager

with SapGui.connect() as app:
    session = app.connections[0].sessions[0]
    print(session.info.user)
# All connections closed automatically

More examples

The examples/sapsucker/ directory contains complete runnable scripts, all tested against a real SAP system:

Monitoring a session while a human records

sapsucker.monitor samples a live session so a recording made with SAP GUI's own recorder (Alt+F12 → Script Recording and Playback) can be paired with timestamps. A recorded .vbs has none, so it cannot tell you where the person paused — which is usually where they were deciding — nor that they went back to re-check a field, nor whether the save actually worked.

pip install sapsucker[cli]

sapsucker-monitor -o timing.jsonl \
  --watch "wnd[0]/shellcont/shell:FirstVisibleRow"

Start it, start the recorder, do the task, stop both. --watch takes any element_id:ComProperty pair and is repeatable — the example above timestamps each individual ALV scroll.

A prebuilt Windows .exe is attached to each release for machines without a Python toolchain.

As a library:

from sapsucker.monitor import SessionMonitor, Watch

monitor = SessionMonitor(session, watches=[Watch(element_id="wnd[0]/shellcont/shell", prop="FirstVisibleRow")])
for sample in monitor.samples():      # generator: the caller owns the loop, and the thread
    if sample.changed:
        print(sample.elapsed, sample.changed, sample.gap_since_change)

samples() never starts a thread. COM is STA, so a monitor loop occupies its thread for its whole lifetime — see the sapsucker.monitor module docstring.

Architecture

sapsucker wraps the SAP GUI Scripting COM API as a hierarchy of typed Python classes:

GuiApplication
  └── GuiConnection
       └── GuiSession
            └── GuiMainWindow
                 ├── GuiToolbar
                 ├── GuiMenubar
                 ├── GuiStatusbar
                 └── GuiUserArea
                      ├── GuiTextField, GuiLabel, GuiButton, ...
                      ├── GuiTableControl (classic dynpro tables)
                      ├── GuiGridView (ALV grids)
                      ├── GuiTree (tree controls)
                      ├── GuiTabStrip → GuiTab
                      └── GuiAbapEditor / GuiTextedit

Elements are discovered via session.find_by_id(sap_id), which returns the correct typed wrapper automatically (e.g., GuiGridView for an ALV grid, GuiTree for a tree control). The factory dispatches on TypeAsNumber and SubType COM properties.

Thread Safety

COM objects use the Single-Threaded Apartment (STA) model. All calls to a given SAP GUI session must happen from the same thread that called pythoncom.CoInitialize(). See the _com.py module docstring for details and an asyncio.to_thread() example.

API Overview

Class / method Description
SapGui Entry point — SapGui.connect() returns GuiApplication
GuiApplication Root object, manages connections
GuiConnection A TCP connection to an SAP server
GuiSession A session (mode) within a connection
GuiMainWindow The main SAP window
GuiTextField Single-line input field
GuiButton Push button
GuiCheckBox Checkbox
GuiComboBox Dropdown list
GuiGridView ALV grid (most common data display)
GuiTableControl Classic dynpro table
GuiTree Tree control (simple, list, or column)
GuiAbapEditor ABAP source code editor
GuiStatusbar Status bar at bottom of window
.dump_tree() Method on any visual container (GuiVContainer) — recursive screen dump, returns list[ElementInfo]

Contributing

Contributions are welcome! Please open an issue first to discuss what you'd like to change.

For detailed setup instructions (uv dependency groups, CI, linting, formatting, etc.), see the Hochfrequenz Python Template Repository.

# Clone and install dev dependencies
git clone https://github.com/Hochfrequenz/sapsucker.git
cd sapsucker
uv sync --group dev

# Run unit tests (no SAP required, works on any OS)
uv run pytest unittests/ -v

Integration tests against real SAP

Integration tests run against a real SAP GUI system and are automatically skipped on machines without SAP access. To run them locally:

  1. SAP GUI for Windows must be running with scripting enabled
  2. Create a .env file with your SAP credentials:
    SAP_CONNECTION_NAME=your_connection
    SAP_USER=your_user
    SAP_PASSWORD=your_password
    SAP_MANDANT=your_client
    SAP_LANGUAGE=EN
    
  3. Run:
    uv run pytest unittests/ -k integration -v
    

Integration tests run by default on any local machine and are automatically skipped in CI (GitHub Actions). Set SAP_SKIP_INTEGRATION=1 to skip them locally. They cover SE80, SE16N, SE37, SE38, and SM37 — all read-only, no SAP data is modified.

License

MIT

Metadata

Release files for sapsucker 1.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sapsucker 1.4.0
File Size Uploaded
sapsucker-1.4.0.tar.gz 160.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sapsucker 1.4.0
File Interpreter ABI Platform
sapsucker-1.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 229.0 kB

Release files / sapsucker-1.4.0.tar.gz

Download URL sapsucker-1.4.0.tar.gz
Size 160.6 kB
Tags Source
SHA-256 checksum
How to use checksums
2ab3fc0d4d92f8c1134372fe8e38eba97515562811502e64986cb18ae5320284
BLAKE2b-256 checksum
How to use checksums
8555aeff0b45d3a63b572114508648091ba9b1fa33fa6a9e06b80d2be0ab6de9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / sapsucker-1.4.0-py3-none-any.whl

Download URL sapsucker-1.4.0-py3-none-any.whl
Size 68.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b15a9b1495481e97af54b2f14f0daa28c913150b69352cd821c9ac70f65ddd1c
BLAKE2b-256 checksum
How to use checksums
fead8bd88f810dbea5fe05b361dad070a9c17d4baf80f2b216df5938fb980fc6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

1.5.0

2 release files

This release

1.4.0 This release

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page