Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CI envs for PyQt 6.5-6.7, PySide 6.5-6.7 & Python 3.12; fix Readthedocs and matplotlib 3.9, Qt6 failures #17

Merged
merged 6 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions .github/workflows/ci_workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ jobs:
- linux: py38-test-pyqt514-all
- linux: py39-test-pyqt515
- linux: py310-test-pyqt63-all
- linux: py310-test-pyqt64-all
- linux: py311-test-pyqt64
- linux: py312-test-pyqt65
- linux: py311-test-pyqt66-all
- linux: py311-test-pyqt514
- linux: py311-test-pyqt515-lts-all

Expand All @@ -53,19 +55,22 @@ jobs:
- macos: py311-docs-pyqt64
coverage: false

# Test a few configurations on macOS
# Test a few configurations on macOS 12 (Intel) and 14 (ARM)
- macos: py38-test-pyqt514-all
- macos: py310-test-pyqt515
- macos: py310-test-pyqt64
- macos: py311-test-pyqt515
- macos: py311-test-pyqt66
- macos: py312-test-pyqt67

# Test some configurations on Windows
- windows: py38-test-pyqt514
- windows: py310-test-pyqt63
- windows: py311-test-pyqt65
- windows: py312-test-pyqt66

# Test against latest developer versions of some packages
- linux: py310-test-pyqt515-dev-all
- linux: py311-test-pyqt64-dev
- linux: py312-test-pyqt515-dev
- linux: py312-test-pyqt67-dev-all

allowed_failures:
needs: initial_checks
Expand All @@ -92,13 +97,18 @@ jobs:

# PySide6 6.4 failures due to https://github.com/spyder-ide/qtpy/issues/373
# and https://github.com/matplotlib/matplotlib/issues/24155
# PyQt5 / < 6.6 segfaulting under macOS 14 (on arm64) in TestGlueDataDialog or TestLinkEditor
# Python 3.11.0 failing on Windows in test_image.py on
# > assert df.find_factory(fname) is df.img_data
- linux: py310-test-pyside64-skipexitcode
- linux: py311-test-pyside64-skipexitcode
- linux: py311-test-pyside65-skipexitcode
- linux: py312-test-pyside67-skipexitcode
- macos: py310-test-pyside63-skipexitcode
- macos: py311-test-pyside64-skipexitcode
- macos: py312-test-pyside67-skipexitcode
- macos: py310-test-pyqt515
- windows: py310-test-pyside64
- windows: py312-test-pyside66
- windows: py311-test-pyqt515

# Windows docs build
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: 2
build:
os: "ubuntu-22.04"
tools:
python: "3"
python: "3.12"

sphinx:
builder: html
Expand Down
10 changes: 7 additions & 3 deletions glue_qt/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
try:
from qtpy import PYSIDE2, PYSIDE6
except Exception:
PYSIDE2 = False
PYSIDE2 = PYSIDE6 = False

Check warning on line 10 in glue_qt/conftest.py

View check run for this annotation

Codecov / codecov/patch

glue_qt/conftest.py#L10

Added line #L10 was not covered by tests

from glue.config import CFG_DIR as CFG_DIR_ORIG

Expand Down Expand Up @@ -50,11 +50,15 @@

if config.getoption('no_optional_skip'):
from glue.tests import helpers
from glue_qt.tests import helpers as qt_helpers

Check warning on line 53 in glue_qt/conftest.py

View check run for this annotation

Codecov / codecov/patch

glue_qt/conftest.py#L53

Added line #L53 was not covered by tests
for attr in helpers.__dict__:
if attr.startswith('requires_'):
# The following line replaces the decorators with a function
# that does noting, effectively disabling it.
# that does nothing, effectively disabling it.
setattr(helpers, attr, lambda f: f)
for attr in qt_helpers.__dict__:
if attr.startswith('requires_'):
setattr(qt_helpers, attr, lambda f: f)

Check warning on line 61 in glue_qt/conftest.py

View check run for this annotation

Codecov / codecov/patch

glue_qt/conftest.py#L59-L61

Added lines #L59 - L61 were not covered by tests

# Make sure we don't affect the real glue config dir
import tempfile
Expand Down Expand Up @@ -105,7 +109,7 @@
# objgraph.show_most_common_types(limit=100)


# With PySide2, tests can fail in a non-deterministic way on a teardown error
# With PySide2/6, tests can fail in a non-deterministic way on a teardown error
# or with the following error:
#
# AttributeError: 'PySide2.QtGui.QStandardItem' object has no attribute '...'
Expand Down
26 changes: 23 additions & 3 deletions glue_qt/tests/helpers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
# Define decorators that can be used for pytest tests

import pytest

from glue.tests.helpers import PYQT5_INSTALLED, PYQT6_INSTALLED, PYSIDE2_INSTALLED, PYSIDE6_INSTALLED
from glue.tests.helpers import make_skipper

PYQT5_INSTALLED, requires_pyqt5 = make_skipper('PyQt5')
PYQT6_INSTALLED, requires_pyqt6 = make_skipper('PyQt6')
PYSIDE2_INSTALLED, requires_pyside2 = make_skipper('PySide2')
PYSIDE6_INSTALLED, requires_pyside6 = make_skipper('PySide6')

PYQT_INSTALLED = PYQT5_INSTALLED or PYQT6_INSTALLED
PYSIDE_INSTALLED = PYSIDE2_INSTALLED or PYSIDE6_INSTALLED
QT_INSTALLED = PYQT_INSTALLED or PYSIDE_INSTALLED

requires_pyqt = pytest.mark.skipif(str(not PYQT5_INSTALLED and not PYQT6_INSTALLED),
requires_pyqt = pytest.mark.skipif(str(not PYQT_INSTALLED),
reason='An installation of PyQt is required')

requires_pyside = pytest.mark.skipif(str(not PYSIDE2_INSTALLED and not PYSIDE6_INSTALLED),
requires_pyside = pytest.mark.skipif(str(not PYSIDE_INSTALLED),
reason='An installation of PySide is required')

requires_qt = pytest.mark.skipif(str(not QT_INSTALLED),
reason='An installation of Qt is required')

PYQT_GT_59, _ = make_skipper('PyQt5', version='5.10')

requires_pyqt_gt_59_or_pyside = pytest.mark.skipif(str(not (PYQT_GT_59 or PYQT6_INSTALLED or
PYSIDE_INSTALLED)),
reason='Requires PyQt > 5.9 or PySide2/6')
4 changes: 2 additions & 2 deletions glue_qt/tests/test_session_back_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import pytest
import numpy as np

from glue.tests.helpers import requires_astropy, requires_h5py, requires_qt
from glue_qt.tests.helpers import requires_pyqt
from glue.tests.helpers import requires_astropy, requires_h5py
from glue_qt.tests.helpers import requires_pyqt, requires_qt
from glue.core.component import CoordinateComponent, Component
from glue.core.state import GlueUnSerializer
from glue.core.component_id import PixelComponentID
Expand Down
12 changes: 7 additions & 5 deletions glue_qt/viewers/profile/mouse_mode.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from echo import CallbackProperty, delay_callback
from glue.core.state_objects import State
from glue.viewers.matplotlib.mouse_mode import MouseMode
from matplotlib.patches import Rectangle

__all__ = ['NavigateMouseMode', 'RangeMouseMode']

Expand Down Expand Up @@ -155,11 +156,12 @@ def _update_artist(self, *args):
else:
self._lines[0].set_data([self.state.x_min, self.state.x_min], [0, 1])
self._lines[1].set_data([self.state.x_max, self.state.x_max], [0, 1])
self._interval.set_xy([[self.state.x_min, 0],
[self.state.x_min, 1],
[self.state.x_max, 1],
[self.state.x_max, 0],
[self.state.x_min, 0]])
if isinstance(self._interval, Rectangle):
self._interval.set_xy([self.state.x_min, self.state.x_max])
else:
self._interval.set_xy([[self.state.x_min, 0], [self.state.x_min, 1],
[self.state.x_max, 1], [self.state.x_max, 0],
[self.state.x_min, 0]])
else:
if self.state.x_min is not None and self.state.x_max is not None:
self._lines = (self._axes.axvline(self.state.x_min, color=COLOR),
Expand Down
27 changes: 18 additions & 9 deletions glue_qt/viewers/table/tests/test_data_viewer.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import pytest
import numpy as np
from packaging.version import Version
from unittest.mock import MagicMock, patch

from qtpy import QtCore, QtGui
from qtpy import QtCore, QtGui, QT_VERSION
from qtpy.QtCore import Qt

from glue_qt.utils import get_qapp, process_events
from glue.core import Data, DataCollection, BaseData
from glue_qt.utils import qt_to_mpl_color
from glue_qt.app import GlueApplication
from glue.core import Data, DataCollection, BaseData
from glue_qt.tests.helpers import requires_pyqt_gt_59_or_pyside
from glue_qt.utils import get_qapp, process_events, qt_to_mpl_color

from ..data_viewer import DataTableModel, TableViewer

Expand Down Expand Up @@ -178,10 +179,15 @@ def press_key(key):
press_key(Qt.Key_Down)
press_key(Qt.Key_Down)

process_events()

process_events(0.5)
indices = selection.selectedRows()

# On newer Qt6 down keys seem to be a bit "sticky"...

if len(indices) == 0 or indices[0].row() < 2:
press_key(Qt.Key_Down)
indices = selection.selectedRows()

# We make sure that the third row is selected

assert len(indices) == 1
Expand Down Expand Up @@ -460,6 +466,7 @@ def test_incompatible_subset():
assert refresh2.call_count == 0


@requires_pyqt_gt_59_or_pyside
def test_table_incompatible_attribute():
"""
Regression test for a bug where the table viewer generates an
Expand Down Expand Up @@ -628,7 +635,7 @@ def press_key(key):
press_key(Qt.Key_Down)
press_key(Qt.Key_Enter)

process_events()
process_events(0.5)

# Check that the table model is still the same, which it
# should be since we aren't changing the viewer Data
Expand All @@ -641,7 +648,9 @@ def press_key(key):
color = d.subsets[0].style.color
colors[1] = color

check_values_and_color(post_model, data, colors)
# Skip on higher versions, where `PyQt6.QtGui.QBrush` is not correctly cleared on 2nd pass
if Version(QT_VERSION) < Version('6.6'):
check_values_and_color(post_model, data, colors)


def test_table_widget_filter(tmpdir):
Expand Down Expand Up @@ -799,7 +808,7 @@ def test_table_sorts_after_update_data():

d.update_components({d.components[2]: [3.2, 1.2, 4.5, 2.5, 3.4]})

process_events()
process_events(0.5)

data = {'a': [2, 4, 1, 5, 3],
'b': [1.2, 2.5, 3.2, 3.4, 4.5],
Expand Down
11 changes: 10 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tox]
envlist =
py{38,39,310,311}-{codestyle,test,docs}-{pyqt514,pyqt515,pyside514,pyside515,pyqt63,pyside63}-all-{dev,legacy}
py{38,39,310,311,312}-{codestyle,test,docs}-{pyqt514,pyqt515,pyside514,pyside515,pyqt63,pyqt64,pyqt66,pyqt67,pyqt65,pyqt63,pyside66,pyside67}-all-{dev,legacy}
requires = pip >= 18.0
setuptools >= 30.3.0

Expand All @@ -27,10 +27,19 @@ deps =
pyqt63: PyQt6-Qt6==6.3.*
pyqt64: PyQt6==6.4.*
pyqt64: PyQt6-Qt6==6.4.*
pyqt65: PyQt6-Qt6==6.5.*
pyqt65: PyQt6==6.5.*
pyqt66: PyQt6-Qt6==6.6.*
pyqt66: PyQt6==6.6.*
pyqt67: PyQt6-Qt6==6.7.*
pyqt67: PyQt6==6.7.*
pyside514: PySide2==5.14.*
pyside515: PySide2==5.15.*
pyside63: PySide6==6.3.*
pyside64: PySide6==6.4.*
pyside65: PySide6==6.5.*
pyside66: PySide6==6.6.*
pyside67: PySide6==6.7.*
dev: git+https://github.com/numpy/numpy
dev: git+https://github.com/astropy/astropy
lts: astropy==5.0.*
Expand Down
Loading