Skip to content

Commit cb1e568

Browse files
committed
Include CI changes for testing widget frameworks
1 parent 4226276 commit cb1e568

File tree

3 files changed

+67
-14
lines changed

3 files changed

+67
-14
lines changed

.github/workflows/ci.yml

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,52 @@ jobs:
2222
- run: pipx run check-manifest
2323

2424
lint:
25-
runs-on: ubuntu-latest
25+
# We lint on Windows so we can lint wx code.
26+
runs-on: windows-latest
2627
steps:
2728
- uses: actions/checkout@v4
2829
- uses: astral-sh/setup-uv@v6
2930
with:
3031
enable-cache: true
3132
python-version: "3.13"
32-
- uses: tox-dev/action-pre-commit-uv@v1
33-
with:
34-
extra_args: --all-files --verbose
33+
- run: uvx pre-commit run --all-files --verbose
3534

3635
test:
37-
name: test ${{ matrix.os }} py${{ matrix.python-version }} ${{ matrix.gfx }}
36+
name: test ${{ matrix.os }} py${{ matrix.python-version }} ${{ matrix.gfx }} ${{ matrix.canvas }}
3837
runs-on: ${{ matrix.os }}
39-
env:
40-
UV_FROZEN: 1
4138
strategy:
4239
fail-fast: false
4340
matrix:
4441
os: [ubuntu-latest, macos-latest, windows-latest]
45-
python-version: ["3.10", "3.11", "3.12", "3.13"]
42+
python-version: ["3.10", "3.13"]
4643
gfx: [pygfx, vispy]
44+
canvas: [pyqt, jupyter, wx]
45+
exclude:
46+
# glfw.GLFWError: (65545) b'NSGL: Failed to find a suitable pixel format'
47+
# (Under the hood GLFW gives vispy the OpenGL context.)
48+
- os: macos-latest
49+
canvas: jupyter
50+
gfx: vispy
51+
# wxpython does not build wheels for ubuntu or macos-latest py3.10
52+
- os: ubuntu-latest
53+
canvas: wx
54+
- os: macos-latest
55+
canvas: wx
56+
python-version: "3.10"
57+
# FIXME: On CI: AttributeError: 'Shared' object has no attribute '_device'. Did you mean: 'device'?
58+
# Related to pygfx v0.13.0
59+
# Tests pass locally
60+
- os: windows-latest
61+
gfx: pygfx
62+
include:
63+
- python-version: "3.11"
64+
gfx: pygfx
65+
canvas: pyqt
66+
os: ubuntu-latest
67+
- python-version: "3.12"
68+
gfx: pygfx
69+
canvas: pyqt
70+
os: ubuntu-latest
4771

4872
steps:
4973
- uses: actions/checkout@v4
@@ -61,7 +85,7 @@ jobs:
6185
sudo apt install -y libegl1-mesa-dev libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
6286
6387
- name: Install dependencies
64-
run: uv sync --no-dev --group test --extra ${{ matrix.gfx }} ${{ matrix.python-version != '3.10' && '--extra imgui' || '' }}
88+
run: uv sync --no-dev --group test --extra ${{ matrix.gfx }} --extra ${{matrix.canvas}} ${{ matrix.python-version != '3.10' && '--extra imgui' || '' }} ${{ matrix.canvas == 'pyqt' && '--group testqt' || '' }}
6589

6690
- name: Test
6791
shell: bash
@@ -70,7 +94,7 @@ jobs:
7094
- name: Upload coverage
7195
uses: actions/upload-artifact@v4
7296
with:
73-
name: covreport-${{ matrix.os }}-py${{ matrix.python-version }}-${{ matrix.gfx }}
97+
name: covreport-${{ matrix.os }}-py${{ matrix.python-version }}-${{ matrix.gfx }}-${{ matrix.canvas }}
7498
path: ./.coverage*
7599
include-hidden-files: true
76100

src/scenex/adaptors/_pygfx/_canvas.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import TYPE_CHECKING, Any, TypeGuard, cast
44

55
from scenex.adaptors._base import CanvasAdaptor
6-
from scenex.app import app
6+
from scenex.app import app, determine_app, GuiFrontend
77

88
from ._adaptor_registry import adaptors
99

@@ -25,13 +25,41 @@ def supports_hide_show(obj: Any) -> TypeGuard[SupportsHideShow]:
2525
return hasattr(obj, "show") and hasattr(obj, "hide")
2626

2727

28+
def _rendercanvas_class() -> BaseRenderCanvas:
29+
"""Obtains the appropriate class for the current GUI backend.
30+
31+
Explicit since PyGFX's backend selection process may be different from ours.
32+
"""
33+
frontend = determine_app()
34+
35+
if frontend == GuiFrontend.QT:
36+
from qtpy.QtCore import QSize # pyright: ignore[reportMissingImports]
37+
from rendercanvas.qt import QRenderWidget
38+
39+
class _QRenderWidget(QRenderWidget):
40+
def sizeHint(self) -> QSize:
41+
return QSize(self.width(), self.height())
42+
43+
# Init Qt Application - otherwise we can't create the widget
44+
app()
45+
return _QRenderWidget() # type: ignore[no-untyped-call]
46+
47+
if frontend == GuiFrontend.JUPYTER:
48+
import rendercanvas.jupyter
49+
50+
return rendercanvas.jupyter.JupyterRenderCanvas()
51+
if frontend == GuiFrontend.WX:
52+
import rendercanvas.wx
53+
54+
return rendercanvas.wx.WxRenderCanvas()
55+
56+
raise ValueError("No suitable render canvas found")
57+
2858
class Canvas(CanvasAdaptor):
2959
"""Canvas interface for pygfx Backend."""
3060

3161
def __init__(self, canvas: model.Canvas, **backend_kwargs: Any) -> None:
32-
from rendercanvas.auto import RenderCanvas
33-
34-
self._wgpu_canvas = RenderCanvas()
62+
self._wgpu_canvas = _rendercanvas_class()
3563
# Qt RenderCanvas calls show() in its __init__ method, so we need to hide it
3664
if supports_hide_show(self._wgpu_canvas):
3765
self._wgpu_canvas.hide()

tests/app/test_jupyter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ def test_resize(evented_canvas: snx.Canvas) -> None:
236236
"event_type": "resize",
237237
"width": new_size[0],
238238
"height": new_size[1],
239+
"pixel_ratio": 1.0,
239240
}
240241
)
241242
assert evented_canvas.width == new_size[0]

0 commit comments

Comments
 (0)