Skip to content

reference code style guide and clarify this doc #12257

reference code style guide and clarify this doc

reference code style guide and clarify this doc #12257

Workflow file for this run

name: CI
on:
pull_request:
push:
branches:
- main
workflow_call:
inputs:
attest-package:
description: "Create GitHub provenance attestation for the package."
default: "false"
type: string
outputs:
artifact-basename:
description: "Base name of the uploaded artifacts; use for artifact retrieval."
value: ${{ jobs.package.outputs.artifact-basename }}
env:
min_python_version: "3.10"
FORCE_COLOR: "1"
defaults:
run:
shell: bash
# Cancel active CI runs for a PR before starting another run
concurrency:
group: ${{ github.workflow}}-${{ github.ref }}
cancel-in-progress: true
jobs:
pre-commit:
name: Pre-commit checks
uses: beeware/.github/.github/workflows/pre-commit-run.yml@main
with:
pre-commit-source: "--group pre-commit"
towncrier:
name: Check towncrier
uses: beeware/.github/.github/workflows/towncrier-run.yml@main
with:
tox-source: "--group tox-uv"
package:
name: Package Toga
permissions:
id-token: write
contents: read
attestations: write
strategy:
matrix:
subdir:
- "android"
- "cocoa"
- "core"
- "demo"
- "dummy"
- "gtk"
- "qt"
- "iOS"
- "toga"
- "positron"
- "travertino"
- "textual"
- "web"
- "winforms"
uses: beeware/.github/.github/workflows/python-package-create.yml@main
with:
build-subdirectory: ${{ matrix.subdir }}
attest: ${{ inputs.attest-package }}
docs-lint:
name: Documentation linting
needs: [ pre-commit ]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 1
- name: Set up Python
uses: actions/setup-python@v6.2.0
with:
python-version: "3.X"
cache: pip
cache-dependency-path: |
pyproject.toml
.pre-commit-config.yaml
- name: Install system dependencies
run: |
sudo apt-get install aspell aspell-en
- name: Update pip
run: python -m pip install -U pip
- name: Install Tox
run: python -m pip install --group 'tox-uv'
- name: Perform lint checks
run: python -m tox -e docs-lint
core-and-travertino:
name: Test ${{ matrix.package }} (${{ matrix.platform }}, ${{ matrix.python-version }})
runs-on: ${{ matrix.platform }}
needs: [ pre-commit, towncrier, package ]
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
platform: [ "macos-latest", "ubuntu-latest", "windows-latest" ]
python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ]
package: ["core", "travertino"]
exclude:
- package: travertino
platform: macos-latest
- package: travertino
platform: windows-latest
include:
- experimental: false
- package: "core"
tox-suffix: ""
- package: "travertino"
tox-suffix: "-trav"
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6.2.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install Tox
run: python -m pip install --group tox-uv
- name: Get Packages
uses: actions/download-artifact@v8.0.0
with:
pattern: ${{ format('{0}-*', needs.package.outputs.artifact-basename) }}
merge-multiple: true
path: dist
- name: Test
run: |
# The $(ls ...) shell expansion is done in the GitHub environment; the value of
# TOGA_INSTALL_COMMAND will be a literal string without any shell expansions to
# perform.
export TOGA_INSTALL_COMMAND="uv pip install ../$(ls dist/toga_core-*.whl) ../$(ls dist/travertino-*.whl) ../$(ls dist/toga_dummy-*.whl) --group test"
tox -e py-cov${{ matrix.tox-suffix }}
tox -qe coverage$(tr -dc "0-9" <<< "${{ matrix.python-version }}")${{ matrix.tox-suffix }}
mv ${{ matrix.package }}/.coverage ${{ matrix.package }}/.coverage.${{ matrix.platform }}.${{ matrix.python-version }}
- name: Store Coverage Data
uses: actions/upload-artifact@v7.0.0
with:
name: ${{ matrix.package }}-coverage-data-${{ matrix.platform }}-${{ matrix.python-version }}
path: "${{ matrix.package }}/.coverage.*"
if-no-files-found: error
include-hidden-files: true
core-and-travertino-coverage:
name: "Coverage: ${{ matrix.package }}"
needs: core-and-travertino
runs-on: ubuntu-latest
strategy:
matrix:
package: ["core", "travertino"]
include:
- package: "core"
tox-suffix: ""
- package: "travertino"
tox-suffix: "-trav"
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Set up Python ${{ env.min_python_version }}
uses: actions/setup-python@v6.2.0
with:
# Use minimum version of python for coverage to avoid phantom branches
# https://github.com/nedbat/coveragepy/issues/1572#issuecomment-1522546425
python-version: ${{ env.min_python_version }}
- name: Install Tox
run: python -m pip install --group tox-uv
- name: Retrieve Coverage Data
uses: actions/download-artifact@v8.0.0
with:
pattern: ${{ matrix.package }}-coverage-data-*
path: ${{ matrix.package }}
merge-multiple: true
- name: Generate Coverage Report
run: tox -e coverage${{ matrix.tox-suffix }}-html-platform
- name: Upload HTML Coverage Report
uses: actions/upload-artifact@v7.0.0
if: failure()
with:
name: html-coverage-report
path: ${{ matrix.package }}/htmlcov
travertino-backwards-compatibility:
name: Test Travertino backwards compatibility with Toga 0.4.8
runs-on: "ubuntu-latest"
needs: [ pre-commit, towncrier, package ]
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6.2.0
with:
python-version: ${{ env.min_python_version }}
- name: Install Tox
run: python -m pip install --group tox-uv
- name: Get Package
uses: actions/download-artifact@v8.0.0
with:
pattern: ${{ format('{0}-*', needs.package.outputs.artifact-basename) }}
merge-multiple: true
path: dist
- name: Test
run: |
export TRAVERTINO_INSTALL_COMMAND="uv pip install ../$(ls dist/travertino-*.whl)"
tox -e trav-compat
testbed:
name: Testbed (${{ matrix.backend }})
needs: [ package, core-and-travertino ]
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
backend:
- "macOS-x86_64"
- "macOS-arm64"
- "windows"
- "linux-x11-gtk3"
- "linux-wayland-gtk3"
- "linux-wayland-gtk4"
- "linux-wayland-gtk4-adw"
- "linux-wayland-qt"
- "linux-x11-qt"
- "android"
- "iOS"
- "textual-linux"
- "textual-macOS"
- "textual-windows"
include:
- pre-command: ""
briefcase-run-prefix: ""
briefcase-run-args: ""
setup-python: true
testbed-app: "testbed"
copy-command: "cp -r"
- backend: "macOS-x86_64"
platform: "macOS"
runs-on: "macos-15-intel"
app-user-data-path: "$HOME/Library/Application Support/org.beeware.toga.testbed"
- backend: "macOS-arm64"
platform: "macOS"
runs-on: "macos-latest"
app-user-data-path: "$HOME/Library/Application Support/org.beeware.toga.testbed"
# We use a fixed Ubuntu version rather than `-latest` because at some point,
# `-latest` will be updated, but it will be a soft changeover, which would cause
# the system Python version to become inconsistent from run to run.
- backend: "linux-x11-gtk3"
platform: "linux"
runs-on: "ubuntu-24.04"
# The package list should be the same as in unix-prerequisites.rst, and the BeeWare
# tutorial, plus blackbox to provide a window manager. We need a window
# manager that is reasonably lightweight, honors full screen mode, and
# treats the window position as the top-left corner of the *window*, not the
# top-left corner of the window *content*. The default GNOME window managers of
# most distros meet these requirements, but they're heavyweight; flwm doesn't
# work either. Blackbox is the lightest WM we've found that works.
pre-command: |
sudo apt update -y
sudo apt install -y --no-install-recommends \
blackbox pkg-config python3-dev libgirepository-2.0-dev libcairo2-dev \
gir1.2-webkit2-4.1 gir1.2-xapp-1.0 gir1.2-geoclue-2.0 gir1.2-flatpak-1.0
# Start Virtual X Server
echo "Start X server..."
Xvfb :99 -screen 0 2048x1536x24 &
sleep 1
# Start Window Mmanager
echo "Start window manager..."
DISPLAY=:99 blackbox &
sleep 1
briefcase-run-prefix: 'DISPLAY=:99'
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed"
- backend: "linux-wayland-gtk3"
platform: "linux"
runs-on: "ubuntu-24.04"
# The package list should be the same as in unix-prerequisites.md, and the BeeWare
# tutorial, plus mutter to provide a window manager.
pre-command: |
sudo apt update -y
sudo apt install -y --no-install-recommends \
mutter pkg-config python3-dev libgirepository-2.0-dev libcairo2-dev \
gir1.2-webkit2-4.1 gir1.2-xapp-1.0 gir1.2-geoclue-2.0 gir1.2-flatpak-1.0
# Start Virtual X Server
echo "Start X server..."
Xvfb :99 -screen 0 2048x1536x24 &
sleep 1
# Start Window Manager
echo "Start window manager..."
# mutter is being run inside a virtual X server because mutter's headless
# mode does not provide a Gdk.Display
DISPLAY=:99 MUTTER_DEBUG_DUMMY_MODE_SPECS=2048x1536 \
mutter --nested --wayland --no-x11 --wayland-display toga &
sleep 1
briefcase-run-prefix: "WAYLAND_DISPLAY=toga"
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed"
- backend: "linux-wayland-gtk4"
platform: "linux"
runs-on: "ubuntu-24.04"
env:
XDG_RUNTIME_DIR: "/tmp"
# The package list should be build on the same base as unix-prerequisites.md,
# and the BeeWare tutorial. Additional packages will be added for window
# management, and features such as web views and geolocation that aren't part
# of the default/tutorial environment.
pre-command: |
sudo apt update -y
sudo apt install -y --no-install-recommends \
mutter pkg-config python3-dev libgirepository-2.0-dev libcairo2-dev \
gir1.2-webkit-6.0 gir1.2-xapp-1.0 gir1.2-geoclue-2.0 gir1.2-flatpak-1.0 \
gir1.2-gtk-4.0
# Start Virtual X Server
echo "Start X server..."
Xvfb :99 -screen 0 2048x1536x24 &
sleep 1
# Start Window Manager
echo "Start window manager..."
# mutter is being run inside a virtual X server because mutter's headless
# mode does not provide a Gdk.Display
DISPLAY=:99 MUTTER_DEBUG_DUMMY_MODE_SPECS=2048x1536 \
mutter --nested --wayland --no-x11 --wayland-display toga &
sleep 1
briefcase-run-prefix: "WAYLAND_DISPLAY=toga TOGA_GTK=4"
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed"
- backend: "linux-wayland-gtk4-adw"
platform: "linux"
runs-on: "ubuntu-24.04"
env:
XDG_RUNTIME_DIR: "/tmp"
# The package list should be build on the same base as unix-prerequisites.md,
# and the BeeWare tutorial. Additional packages will be added for window
# management, and features such as web views and geolocation that aren't part
# of the default/tutorial environment.
pre-command: |
sudo apt update -y
sudo apt install -y --no-install-recommends \
mutter pkg-config python3-dev libgirepository-2.0-dev libcairo2-dev \
gir1.2-webkit-6.0 gir1.2-xapp-1.0 gir1.2-geoclue-2.0 gir1.2-flatpak-1.0 \
gir1.2-gtk-4.0 gir1.2-adw-1
# Start Virtual X Server
echo "Start X server..."
Xvfb :99 -screen 0 2048x1536x24 &
sleep 1
# Start Window Manager
echo "Start window manager..."
# mutter is being run inside a virtual X server because mutter's headless
# mode does not provide a Gdk.Display
DISPLAY=:99 MUTTER_DEBUG_DUMMY_MODE_SPECS=2048x1536 \
mutter --nested --wayland --no-x11 --wayland-display toga &
sleep 1
briefcase-run-prefix: "WAYLAND_DISPLAY=toga TOGA_GTK=4 TOGA_GTKLIB=Adw"
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed"
- backend: "linux-x11-qt"
platform: "linux"
runs-on: "ubuntu-24.04"
testbed-app: "testbed-qt"
# The package list should be dependencies listed in unix-prerequsites.md, plus we need a window
# manager that is reasonably lightweight, honors full screen mode, and
# treats the window position as the top-left corner of the *window*, not the
# top-left corner of the window *content*. The default GNOME window managers of
# most distros meet these requirements, but they're heavyweight; flwm doesn't
# work either. Blackbox is the lightest WM we've found that works.
# PySide6 must be installed in VM to test that system-pyside6 works properly.
pre-command: |
sudo apt update -y
sudo apt install -y --no-install-recommends \
blackbox python3-dev xvfb \
gnome-session-canberra build-essential \
libfontconfig1-dev libfreetype-dev libgtk-3-dev \
libx11-dev libx11-xcb-dev libxext-dev \
libxfixes-dev libxi-dev libxkbcommon-dev \
libxkbcommon-x11-dev libxrender-dev 'libxcb*-dev' \
# Start Virtual X Server
echo "Start X server..."
Xvfb :99 -screen 0 2048x1536x24 &
sleep 1
# Start Window Mmanager
echo "Start window manager..."
DISPLAY=:99 blackbox &
sleep 1
briefcase-run-prefix: 'DISPLAY=:99'
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed-qt"
- backend: "linux-wayland-qt"
platform: "linux"
runs-on: "ubuntu-24.04"
testbed-app: "testbed-qt"
# The package list should be unix-prerequisites.md, plus mutter to provide a window
# manager.
pre-command: |
sudo apt update -y
sudo apt install -y --no-install-recommends \
mutter python3-dev xvfb \
gnome-session-canberra \
libwayland-dev libwayland-egl1-mesa libwayland-server0 \
libgles2-mesa-dev libxkbcommon-dev
# Start Virtual X Server
echo "Start X server..."
Xvfb :99 -screen 0 2048x1536x24 &
sleep 1
# Start Window Manager
echo "Start window manager..."
# mutter is being run inside a virtual X server because mutter's headless
# mode does not provide a Gdk.Display
DISPLAY=:99 MUTTER_DEBUG_DUMMY_MODE_SPECS=2048x1536 \
mutter --nested --wayland --no-x11 --wayland-display toga &
sleep 1
briefcase-run-prefix: "WAYLAND_DISPLAY=toga"
setup-python: false # Use the system Python packages
app-user-data-path: "$HOME/.local/share/testbed-qt"
- backend: "textual-linux"
platform: "linux"
runs-on: "ubuntu-latest"
setup-python: false # Use the system Python packages
briefcase-run-args: --config 'requires=["toga-core", "toga-textual"]' --config 'console_app=true'
app-user-data-path: "$HOME/.local/share/testbed"
# install the meta-package build-essential since Briefcase explicitly checks for it
pre-command: sudo apt update -y && sudo apt install -y build-essential
- backend: "textual-macOS"
platform: "macOS"
runs-on: "macos-latest"
briefcase-run-args: --config 'requires=["toga-core", "toga-textual"]' --config 'console_app=true'
app-user-data-path: "$HOME/Library/Application Support/org.beeware.toga.testbed"
- backend: "textual-windows"
platform: "windows"
runs-on: "windows-latest"
briefcase-run-args: --config 'requires=["toga-core", "toga-textual"]' --config 'console_app=true'
app-user-data-path: '$HOME\AppData\Local\Tiberius Yak\Toga Testbed\Data'
- backend: "windows"
platform: "windows"
runs-on: "windows-latest"
app-user-data-path: '$HOME\AppData\Local\Tiberius Yak\Toga Testbed\Data'
- backend: "iOS"
platform: "iOS"
runs-on: "macos-latest"
pre-command: |
# 2025-08-15 - Github Actions are in the process of switching how they
# manage Xcode, so they can save disk space.
# See https://github.com/actions/runner-images/issues/12541
# and https://github.com/actions/runner-images/issues/12751; see
# also https://github.com/actions/runner-images/issues/12758 for
# a discussion of transition issues.
sudo xcode-select --switch /Applications/Xcode_16.4.app
briefcase-run-args: "--device 'iPhone SE (3rd generation)::iOS 18.5'"
app-user-data-path: "$(xcrun simctl get_app_container booted org.beeware.toga.testbed data)/Documents"
- backend: "android"
platform: "android"
runs-on: "ubuntu-latest"
briefcase-run-prefix: JAVA_HOME=${JAVA_HOME_17_X64}
briefcase-run-args: >-
--device '{"avd":"beePhone","skin":"pixel_3a"}'
--Xemulator=-no-window
--Xemulator=-no-snapshot
--Xemulator=-no-audio
--Xemulator=-no-boot-anim
pre-command: |
# allow access to KVM to run the emulator
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
| sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
app-user-data-path: /data/user/0/org.beeware.toga.testbed/files/data/
copy-command: ADB=$ANDROID_HOME/platform-tools/adb && $ADB root && $ADB pull
steps:
# GitHub runners seem to have intermittent connectivity issues.
# See https://github.com/beeware/toga/issues/2632
- name: Tune GitHub-hosted runner network
uses: smorimoto/tune-github-hosted-runner-network@v1.0.0
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6.2.0
if: matrix.setup-python
with:
python-version: "3.12"
- name: Install Dependencies
env:
PIP_BREAK_SYSTEM_PACKAGES: "1"
run: |
${{ matrix.pre-command }}
# Use the development version of Briefcase
python -m pip install -U pip
python -m pip install git+https://github.com/beeware/briefcase.git
- name: Get Packages
uses: actions/download-artifact@v8.0.0
with:
pattern: ${{ format('{0}-*', needs.package.outputs.artifact-basename) }}
merge-multiple: true
path: dist
- name: Test App
working-directory: testbed
timeout-minutes: 20
run: |
${{ matrix.briefcase-run-prefix }} \
briefcase run ${{ matrix.platform }} --log --test \
${{ matrix.briefcase-run-args }} --app ${{ matrix.testbed-app }} -- --ci
- name: Upload Logs
uses: actions/upload-artifact@v7.0.0
if: failure()
with:
name: testbed-failure-logs-${{ matrix.backend }}
path: testbed/logs/*
- name: Copy App Generated User Data
if: failure()
run: |
mkdir -p testbed/app_data
${{ matrix.copy-command }} "${{ matrix.app-user-data-path }}" testbed/app_data/testbed-app_data-${{ matrix.backend }}
- name: Upload App Data
uses: actions/upload-artifact@v7.0.0
if: failure()
with:
name: testbed-failure-app-data-${{ matrix.backend }}
path: testbed/app_data/*
# This step is only needed if you're trying to diagnose test failures that
# only occur in CI, and can't be reproduced locally. When it runs, it will
# open an SSH server (URL reported in the logs) so you can ssh into the CI
# machine.
# - name: Setup tmate session
# uses: mxschmitt/action-tmate@v3
# if: failure()
bootstraps:
name: "Bootstrap"
needs: [ package ]
runs-on: "ubuntu-24.04"
strategy:
fail-fast: false
matrix:
bootstrap:
- "Positron (Django)"
- "Positron (Static)"
- "Positron (Site-specific)"
include:
- bootstrap: "Positron (Django)"
new-options: '-Q "bootstrap=Toga Positron (Django server)"'
- bootstrap: "Positron (Static)"
new-options: '-Q "bootstrap=Toga Positron (Static server)"'
- bootstrap: "Positron (Site-specific)"
new-options: '-Q "bootstrap=Toga Positron (Site-specific browser)" -Q "site_url=https://github.com/"'
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6.2.0
with:
python-version: "3.12"
- name: Get Packages
uses: actions/download-artifact@v8.0.0
with:
pattern: ${{ format('{0}-*', needs.package.outputs.artifact-basename) }}
merge-multiple: true
path: dist
- name: Test Bootstrap
run: |
mkdir bootstrap-test
cd bootstrap-test
python3 -m venv venv
source venv/bin/activate
pip install -U pip
pip install ../dist/toga_positron-*.whl
echo
echo "===== Create Briefcase project with ${{ matrix.bootstrap }} bootstrap ====="
briefcase new --no-input -Q "formal_name=Hello Bootstrap" ${{ matrix.new-options }}