Skip to content

Commit 9f2aebd

Browse files
authored
Run loop tests with more loop classes (#156)
1 parent 46f937f commit 9f2aebd

File tree

5 files changed

+223
-50
lines changed

5 files changed

+223
-50
lines changed

.github/workflows/ci.yml

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ concurrency:
1616

1717
jobs:
1818

19+
# Tests for code integrity and code formatting
1920
lint:
2021
name: Linting
2122
runs-on: ubuntu-latest
@@ -38,6 +39,7 @@ jobs:
3839
run: |
3940
ruff format --check .
4041
42+
# Test that make sure the docs build without errors or warnings
4143
docs:
4244
name: Docs
4345
runs-on: ubuntu-latest
@@ -58,24 +60,21 @@ jobs:
5860
cd docs
5961
make html SPHINXOPTS="-W --keep-going"
6062
61-
tests:
62-
name: ${{ matrix.name }}
63+
# Test majority of code for a variety of Python versions
64+
test-pythons:
65+
name: 'Test Python ${{ matrix.pyversion }} on ${{ matrix.os }}'
6366
runs-on: ${{ matrix.os }}
6467
strategy:
6568
fail-fast: false
6669
matrix:
6770
include:
68-
- name: Test py310
69-
os: ubuntu-latest
71+
- os: ubuntu-latest
7072
pyversion: '3.10'
71-
- name: Test py311
72-
os: ubuntu-latest
73+
- os: ubuntu-latest
7374
pyversion: '3.11'
74-
- name: Test py312
75-
os: ubuntu-latest
75+
- os: ubuntu-latest
7676
pyversion: '3.12'
77-
- name: Test py313
78-
os: ubuntu-latest
77+
- os: ubuntu-latest
7978
pyversion: '3.13'
8079
steps:
8180
- uses: actions/checkout@v4
@@ -92,15 +91,15 @@ jobs:
9291
run: |
9392
pytest -v tests
9493
94+
# Test that wgpu is indeed optional
9595
test-without-wgpu:
96-
name: ${{ matrix.name }} without wgpu
96+
name: 'Test Python ${{ matrix.pyversion }} without wgpu'
9797
runs-on: ${{ matrix.os }}
9898
strategy:
9999
fail-fast: false
100100
matrix:
101101
include:
102-
- name: Test py313
103-
os: ubuntu-latest
102+
- os: ubuntu-latest
104103
pyversion: '3.13'
105104
steps:
106105
- uses: actions/checkout@v4
@@ -125,8 +124,60 @@ jobs:
125124
"
126125
pytest -v tests
127126
127+
# Test for the few GUI frameworks that we support.
128+
test-gui-frameworks:
129+
name: 'Test gui ${{ matrix.guilib }}'
130+
runs-on: ubuntu-latest
131+
strategy:
132+
fail-fast: false
133+
matrix:
134+
include:
135+
- guilib: 'glfw'
136+
backendname: 'glfw'
137+
loopname: 'AsyncioLoop'
138+
- guilib: 'PySide6'
139+
backendname: 'pyside6'
140+
loopname: 'PySide6Loop'
141+
- guilib: 'PyQt6'
142+
backendname: 'pyqt6'
143+
loopname: 'PyQt6Loop'
144+
- guilib: 'PyQt5'
145+
backendname: 'pyqt5'
146+
loopname: 'PyQt5Loop'
147+
# - guilib: 'wxPython' CI tries to build wx from scratch
148+
# backendname: 'wx'
149+
# loopname: 'WxLoop'
150+
steps:
151+
- uses: actions/checkout@v4
152+
- name: Set up Python
153+
uses: actions/setup-python@v5
154+
with:
155+
python-version: '3.13'
156+
- name: Install xvfb and Vulkan drivers
157+
run: |
158+
sudo apt update -y -qq
159+
sudo apt install -y xvfb
160+
sudo apt install --no-install-recommends -y libegl1-mesa-dev libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
161+
- name: Install package and dev dependencies
162+
run: |
163+
python -m pip install --upgrade pip
164+
pip install .[tests]
165+
pip install ${{ matrix.guilib }}
166+
rm -r rendercanvas
167+
- name: Test import
168+
run: |
169+
xvfb-run python -c 'import rendercanvas.${{ matrix.backendname }}'
170+
# - name: Test loop - Unfortunately, all Qt libs abort on the first test.
171+
# run: |
172+
# xvfb-run pytest -v tests/test_loop.py -k ${{ matrix.loopname }}
173+
- name: Test GUI canvas
174+
if: matrix.backendname == 'glfw'
175+
run: |
176+
xvfb-run pytest -v tests/test_gui_${{ matrix.backendname }}.py
177+
178+
# Test that the examples run without error, and screenshots match
128179
test-examples:
129-
name: Test examples ${{ matrix.pyversion }}
180+
name: Test examples on ${{ matrix.pyversion }}
130181
runs-on: ${{ matrix.os }}
131182
strategy:
132183
fail-fast: false
@@ -144,8 +195,8 @@ jobs:
144195
python-version: 3.12
145196
- name: Install llvmpipe and lavapipe for offscreen canvas
146197
run: |
147-
sudo apt-get update -y -qq
148-
sudo apt-get install --no-install-recommends -y libegl1-mesa-dev libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
198+
sudo apt update -y -qq
199+
sudo apt install --no-install-recommends -y libegl1-mesa-dev libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
149200
- name: Install dev dependencies
150201
run: |
151202
python -m pip install --upgrade pip
@@ -164,6 +215,7 @@ jobs:
164215
name: screenshots{{ matrix.pyversion }}
165216
path: examples/screenshots
166217

218+
# Test that rendercanvas works with pyinstaller
167219
test-pyinstaller:
168220
name: Test pyinstaller
169221
runs-on: ubuntu-latest
@@ -183,6 +235,7 @@ jobs:
183235
pushd $HOME
184236
pytest -v --pyargs rendercanvas.__pyinstaller
185237
238+
# Build package
186239
build-release:
187240
name: Build release artifacts
188241
runs-on: ubuntu-latest
@@ -224,10 +277,11 @@ jobs:
224277
path: dist
225278
name: dist
226279

280+
# Publish to Github and Pypi
227281
publish:
228282
name: Publish release to Github and Pypi
229283
runs-on: ubuntu-latest
230-
needs: [tests, build-release]
284+
needs: [test-pythons, build-release]
231285
if: success() && startsWith(github.ref, 'refs/tags/v')
232286
environment:
233287
name: pypi

docs/backends.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ somewhat when the render area is large.
205205
Support for wx
206206
--------------
207207

208-
RenderCanvas has support for wxPython.
208+
RenderCanvas has support for wxPython. However, because of wx's specific behavior, this backend is less well tested than the other backends.
209209
For a toplevel widget, the ``rendercanvas.wx.RenderCanvas`` class can be imported. If you want to
210210
embed the canvas as a subwidget, use ``rendercanvas.wx.RenderWidget`` instead.
211211

rendercanvas/qt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def _rc_init(self):
231231
self._app = QtWidgets.QApplication([])
232232
# We do detect when the canvas-widget is closed, and also when *our* toplevel wrapper is closed,
233233
# but when embedded in an application, it seems hard/impossible to detect the canvas being closed
234-
# when the app closes. So we explicitly detect that instead.
234+
# when the app closes. So we explicitly detect the app-closing instead.
235235
# Note that we should not use app.setQuitOnLastWindowClosed(False), because we (may) rely on the
236236
# application's closing mechanic.
237237
self._app.aboutToQuit.connect(lambda: self.stop(force=True))
Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
like the canvas context and surface texture.
44
"""
55

6+
import os
67
import time
78
import weakref
89
import asyncio
@@ -24,10 +25,13 @@ def setup_module():
2425

2526

2627
def teardown_module():
28+
import glfw
2729
from rendercanvas.glfw import poll_glfw_briefly
2830

2931
poll_glfw_briefly()
30-
pass # Do not glfw.terminate() because other tests may still need glfw
32+
33+
# Terminate; otherwise it gets in the way of tests for the Qt loop.
34+
glfw.terminate()
3135

3236

3337
def test_is_canvas_base():
@@ -123,6 +127,10 @@ def run_briefly():
123127
device = wgpu.gpu.request_adapter_sync().request_device_sync()
124128
draw_frame1 = _get_draw_function(device, canvas)
125129

130+
allowed_frames = (1,)
131+
if os.getenv("CI"):
132+
allowed_frames = (1, 2, 3)
133+
126134
frame_counter = 0
127135

128136
def draw_frame2():
@@ -135,22 +143,25 @@ def draw_frame2():
135143
run_briefly()
136144
# There should have been exactly one draw now
137145
# This assumes ondemand scheduling mode
138-
assert frame_counter == 1
146+
assert frame_counter in allowed_frames
147+
frame_counter = 0
139148

140149
# Ask for a lot of draws
141150
for i in range(5):
142151
canvas.request_draw()
143152
# Process evens for a while
144153
run_briefly()
145154
# We should have had just one draw
146-
assert frame_counter == 2
155+
assert frame_counter in allowed_frames
156+
frame_counter = 0
147157

148158
# Change the canvas size
149159
canvas.set_logical_size(300, 200)
150160
canvas.set_logical_size(400, 300)
151-
# We should have had just one draw
161+
# We should have had just one draw, but sometimes (more so on CI) we can have more
152162
run_briefly()
153-
assert frame_counter == 3
163+
assert frame_counter in allowed_frames
164+
frame_counter = 0
154165

155166
# Stopping
156167
assert not loop_task.done()

0 commit comments

Comments
 (0)