Merge pull request #2404 from freakboy3742/arm64-testing

Add Python3.13 and iOS/macOS ARM64 testing to CI
This commit is contained in:
Malcolm Smith 2024-02-20 16:28:43 +00:00 committed by GitHub
commit c5887fe131
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 112 additions and 57 deletions

View file

@ -21,7 +21,7 @@ defaults:
# Cancel active CI runs for a PR before starting another run
concurrency:
group: ${{ github.ref }}
group: ${{ github.workflow}}-${{ github.ref }}
cancel-in-progress: true
jobs:
@ -60,18 +60,37 @@ jobs:
- "winforms"
core:
runs-on: ${{ matrix.platform }}-latest
runs-on: ${{ matrix.platform }}
needs: [pre-commit, towncrier, package]
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
platform: [ "macos", "ubuntu", "windows" ]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
platform: [ "macos-12", "macos-14", "ubuntu-latest", "windows-latest" ]
python-version: [ "3.8", "3.12", "3.13-dev" ]
include:
- experimental: false
# - python-version: "3.13-dev"
# experimental: true
# Test Python 3.9-3.11 on Ubuntu only
- platform: "ubuntu-latest"
python-version: "3.9"
experimental: false
- platform: "ubuntu-latest"
python-version: "3.10"
experimental: false
- platform: "ubuntu-latest"
python-version: "3.11"
experimental: false
# Allow development Python to fail without failing entire job.
- python-version: "3.13-dev"
experimental: true
exclude:
# macos-14 (i.e. arm64) does not support Python 3.8
- platform: "macos-14"
python-version: "3.8"
# Pillow isn't available for Python 3.13 on Windows
- platform: "windows-latest"
python-version: "3.13-dev"
steps:
- uses: actions/checkout@v4.1.1
- name: Set up Python ${{ matrix.python-version }}
@ -144,22 +163,29 @@ jobs:
strategy:
fail-fast: false
matrix:
backend: [ "macOS", "windows", "linux", "android", "iOS" ]
backend: [ "macOS-x86_64", "macOS-arm64", "windows", "linux", "android", "iOS" ]
include:
- pre-command:
briefcase-run-prefix:
briefcase-run-args:
setup-python: true
- backend: macOS
runs-on: macos-12
- backend: "macOS-x86_64"
platform: "macOS"
runs-on: "macos-12"
app-user-data-path: $HOME/Library/Application Support/org.beeware.toga.testbed
- backend: "macOS-arm64"
platform: "macOS"
runs-on: "macos-14"
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
runs-on: ubuntu-22.04
- backend: "linux"
platform: "linux"
runs-on: "ubuntu-22.04"
# The package list should be the same as in tutorial-0.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
@ -185,17 +211,20 @@ jobs:
setup-python: false # Use the system Python packages.
app-user-data-path: $HOME/.local/share/testbed
- backend: windows
runs-on: windows-latest
- backend: "windows"
platform: "windows"
runs-on: "windows-latest"
app-user-data-path: $HOME\AppData\Local\Tiberius Yak\Toga Testbed\Data
- backend: iOS
runs-on: macos-12
- backend: "iOS"
platform: "iOS"
runs-on: "macos-14"
briefcase-run-args: ' -d "iPhone SE (3rd generation)"'
app-user-data-path: $(xcrun simctl get_app_container booted org.beeware.toga.testbed data)/Documents
- backend: android
runs-on: ubuntu-latest
- backend: "android"
platform: "android"
runs-on: "ubuntu-latest"
briefcase-run-args: " -d '{\"avd\":\"beePhone\",\"skin\":\"pixel_3a\"}' --Xemulator=-no-window --Xemulator=-no-snapshot --Xemulator=-no-audio --Xemulator=-no-boot-anim --shutdown-on-exit"
pre-command: |
# check if virtualization is supported...
@ -230,7 +259,7 @@ jobs:
- name: Test App
working-directory: testbed
timeout-minutes: 15
run: ${{ matrix.briefcase-run-prefix }} briefcase run ${{ matrix.backend }} --test ${{ matrix.briefcase-run-args }}
run: ${{ matrix.briefcase-run-prefix }} briefcase run ${{ matrix.platform }} --test ${{ matrix.briefcase-run-args }}
- name: Upload logs
uses: actions/upload-artifact@v4.3.1

View file

@ -38,6 +38,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

1
changes/2383.bugfix.rst Normal file
View file

@ -0,0 +1 @@
Issues with running the testbed on macOS 14 (Sonoma) were resolved.

View file

@ -0,0 +1 @@
Support for Python 3.13 was added.

View file

@ -0,0 +1 @@
Toga's release processes now include automated testing on ARM64.

View file

@ -39,6 +39,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -18,6 +18,11 @@ class TogaList(NSTableView):
interface = objc_property(object, weak=True)
impl = objc_property(object, weak=True)
@objc_method
def didCloseMenu_withEvent_(self, menu, event) -> None:
# When the menu closes, drop the reference to the menu object.
self.impl._popup = None
@objc_method
def menuForEvent_(self, event):
if self.impl.primary_action_enabled or self.impl.secondary_action_enabled:
@ -49,9 +54,12 @@ class TogaList(NSTableView):
)
secondary_action_item.tag = row
return popup
else:
return None
popup = None
# Preserve a Python reference to the popup for testing purposes.
self.impl._popup = popup
return popup
@objc_method
def primaryActionOnRow_(self, menuitem):

View file

@ -99,7 +99,12 @@ class RefreshableClipView(NSClipView):
argtypes=[NSPoint],
)
if self.superview and self.superview.is_refreshing:
# FIXME: This has been marked no-cover so that ARM64 testing can be enabled;
# ARM64 CI can only run on Sonoma, and it looks like Sonoma has turned off
# scroll elasticity by default, which prevents pull-to-refresh from working.
# See Toga#2412 for details. If that ticket is closed, it should be possible
# to remove this this no-cover.
if self.superview and self.superview.is_refreshing: # pragma: no cover
return NSMakePoint(
constrained.x,
max(

View file

@ -179,9 +179,10 @@ class DetailedListProbe(SimpleProbe):
while self.scroll_position < 0:
await asyncio.sleep(0.01)
async def _perform_action(self, row, offset):
async def _perform_action(self, row, index):
point = self.row_position(row)
# First click to show menu
# Click to show menu
await self.mouse_event(
NSEventType.RightMouseDown,
point,
@ -189,29 +190,17 @@ class DetailedListProbe(SimpleProbe):
)
await self.redraw("Action menu has been displayed")
# Pick a point a little to the right of the point where the menu was displayed,
# and slightly lower (in reversed y coordinates) to select a menu item.
point2 = NSPoint(point.x + 10, point.y - offset)
await self.mouse_event(
NSEventType.LeftMouseDown,
point2,
delay=0.1,
)
await self.mouse_event(
NSEventType.LeftMouseUp,
point2,
delay=0.1,
)
popup = self.impl._popup
if popup:
popup.performActionForItemAtIndex(index)
popup.cancelTracking()
# Wait until the popup menu is fully disposed.
while self.impl._popup is not None:
await self.redraw("Action has been selected", delay=0.1)
async def perform_primary_action(self, row, active=True):
# 10px is enough to select the first menu item. It doesn't matter whether the
# action is active or not; if the action is inactive, it will either press the
# wrong action, or press empty space.
await self._perform_action(row, 10)
await self._perform_action(row, 0)
async def perform_secondary_action(self, row, active=True):
# 30px is enough to select the second menu item. However the secondary action
# will be in position 1 on the menu if the primary action is disabled. It
# doesn't matter whether the action is active or not; if the action is inactive,
# it will either press the wrong action, or press empty space.
await self._perform_action(row, 30 if self.impl.primary_action_enabled else 10)
await self._perform_action(row, 1 if self.impl.primary_action_enabled else 0)

View file

@ -46,8 +46,5 @@ class SelectionProbe(SimpleProbe):
# Use a short delaly instead.
await self.mouse_event(NSEventType.LeftMouseDown, point, delay=0.1)
# macOS coordinate systems are backwards, so to select the item *above*
# the current selection, you need to *add* height.
point.y = point.y + self.height
await self.mouse_event(NSEventType.LeftMouseDown, point, delay=0.1)
await self.mouse_event(NSEventType.LeftMouseUp, point, delay=0.1)
self.native.menu.performActionForItemAtIndex(1)
self.native.menu.cancelTracking()

View file

@ -50,6 +50,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -45,6 +45,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -37,6 +37,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -40,6 +40,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -38,6 +38,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -1,7 +1,7 @@
import asyncio
import platform
import os
from rubicon.objc.api import Block
from rubicon.objc.api import Block, ObjCClass
from toga_iOS.libs import (
NSIndexPath,
@ -13,6 +13,8 @@ from toga_iOS.libs import (
from .base import SimpleProbe, UIControlEventValueChanged
UIDevice = ObjCClass("UIDevice")
class DetailedListProbe(SimpleProbe):
native_class = UITableView
@ -50,11 +52,17 @@ class DetailedListProbe(SimpleProbe):
@property
def max_scroll_position(self):
max_value = int(self.native.contentSize.height - self.native.frame.size.height)
# The max value is a little higher on iOS 17.
# Not sure where the 34 extra pixels are coming from. It appears to be
# a constant, independent of the number of rows of data.
if int(platform.release().split(".")[0]) >= 17:
# The max value is a dependent on the device; devices that don't have a physical
# button report as being a little larger. A physical device will give you the
# model identifier as part of UIDevice.currentDevice.model; however, simulators
# return "iPhone" as the model, so we need to check the environment as well to
# reliably get the device identifier. "iPhone14,6" is an iPhone SE 3rd edition.
# As of Feb 2023, it's the only device currently sold that has a physical
# button.
model = os.getenv("SIMULATOR_MODEL_IDENTIFIER", UIDevice.currentDevice.model)
if model != "iPhone14,6":
max_value += 34
return max(0, max_value)
@property

View file

@ -39,6 +39,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -38,6 +38,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -39,6 +39,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -39,6 +39,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -39,6 +39,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -39,6 +39,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -50,6 +50,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -7,7 +7,7 @@ extend-ignore =
E203,
# The leading comma generates the "py" environment.
[testenv:py{,38,39,310,311,312}]
[testenv:py{,38,39,310,311,312,313}]
skip_install = True
setenv =
TOGA_BACKEND = toga_dummy

View file

@ -40,6 +40,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",

View file

@ -39,6 +39,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",