From 47d95867fa50303bdc2c7fc162665f7243d47576 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 17 Mar 2023 10:46:57 +0000 Subject: [PATCH 01/30] First cut at getting TraitsUI working on Python 3.11 and PySide 6.4 --- setup.cfg => .flake8 | 0 .github/actions/apt-get-qt-deps/README.md | 10 +- .github/actions/apt-get-qt-deps/action.yml | 55 ++- .github/workflows/run-tests.yml | 74 ++++ pyproject.toml | 79 +++- setup.py | 375 ------------------ traitsui/__init__.py | 50 +-- traitsui/qt4/tabular_editor.py | 14 +- traitsui/qt4/tests/test_ui_base.py | 3 +- traitsui/tests/editors/test_date_editor.py | 2 +- .../tests/editors/test_date_range_editor.py | 2 +- traitsui/wx/list_str_editor.py | 8 +- traitsui/wx/tabular_editor.py | 8 +- 13 files changed, 203 insertions(+), 477 deletions(-) rename setup.cfg => .flake8 (100%) create mode 100644 .github/workflows/run-tests.yml delete mode 100644 setup.py diff --git a/setup.cfg b/.flake8 similarity index 100% rename from setup.cfg rename to .flake8 diff --git a/.github/actions/apt-get-qt-deps/README.md b/.github/actions/apt-get-qt-deps/README.md index 872c7221f..47c86e009 100644 --- a/.github/actions/apt-get-qt-deps/README.md +++ b/.github/actions/apt-get-qt-deps/README.md @@ -1,4 +1,4 @@ -# Install Qt dependencies on Ubuntu +# Install Qt dependencies This action calls `apt-get` to install packages required for running Qt on Ubuntu. @@ -19,11 +19,9 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - toolkit: ['pyqt5'] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - name: Install Qt dependencies for Linux - uses: ./.github/actions/apt-get-qt-deps - if: startsWith(matrix.os, 'ubuntu') + - uses: actions/checkout@v3 + - name: Install Qt dependencies + uses: ./.github/actions/install-qt-support ``` diff --git a/.github/actions/apt-get-qt-deps/action.yml b/.github/actions/apt-get-qt-deps/action.yml index 760eb7f64..15e7a22a6 100644 --- a/.github/actions/apt-get-qt-deps/action.yml +++ b/.github/actions/apt-get-qt-deps/action.yml @@ -1,30 +1,29 @@ -# This action installs dependencies for Qt on Ubuntu -# It does not install any Qt-Python wrapper. - -name: 'Install Ubuntu packages for Qt' -description: 'This action should only be run on Ubuntu' +name: install-qt-support +description: 'Install supporting OS packages for Qt-using code' runs: - using: "composite" + using: composite steps: - - run: | - sudo apt-get update - sudo apt-get install qtbase5-dev - sudo apt-get install qtchooser - sudo apt-get install qt5-qmake - sudo apt-get install qtbase5-dev-tools - sudo apt-get install libegl1 - sudo apt-get install libxkbcommon-x11-0 - sudo apt-get install libxcb-icccm4 - sudo apt-get install libxcb-image0 - sudo apt-get install libxcb-keysyms1 - sudo apt-get install libxcb-randr0 - sudo apt-get install libxcb-render-util0 - sudo apt-get install libxcb-xinerama0 - sudo apt-get install libxcb-shape0 - sudo apt-get install pulseaudio - sudo apt-get install libpulse-mainloop-glib0 - # Needed to work around https://bugreports.qt.io/browse/PYSIDE-1547 - sudo apt-get install libopengl0 - # Needed for Qt6 video playback - sudo apt-get install libgstreamer-gl1.0-0 - shell: bash + - name: Install Linux packages for Qt + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install qtbase5-dev + sudo apt-get install qtchooser + sudo apt-get install qt5-qmake + sudo apt-get install qtbase5-dev-tools + sudo apt-get install libegl1 + sudo apt-get install libxkbcommon-x11-0 + sudo apt-get install libxcb-icccm4 + sudo apt-get install libxcb-image0 + sudo apt-get install libxcb-keysyms1 + sudo apt-get install libxcb-randr0 + sudo apt-get install libxcb-render-util0 + sudo apt-get install libxcb-xinerama0 + sudo apt-get install libxcb-shape0 + sudo apt-get install pulseaudio + sudo apt-get install libpulse-mainloop-glib0 + # Needed to work around https://bugreports.qt.io/browse/PYSIDE-1547 + sudo apt-get install libopengl0 + # Needed for Qt6 video playback + sudo apt-get install libgstreamer-gl1.0-0 + shell: bash diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 000000000..8f27bfc2f --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,74 @@ +name: Run test suite for Qt and wxPython + +on: [pull_request, workflow_dispatch] + +env: + PYTHONUNBUFFERED: 1 + +jobs: + tests-qt: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.8', '3.10', '3.11'] + qt-api: ['pyqt5', 'pyside2', 'pyside6'] + exclude: + - python-version: '3.11' + qt-api: 'pyside2' + fail-fast: false + + env: + ETS_TOOLKIT: qt + + runs-on: ${{ matrix.os }} + timeout-minutes: 20 # should be plenty, it's usually < 5 + + steps: + - name: Check out the target commit + uses: actions/checkout@v3 + - name: Install Qt dependencies + uses: ./.github/actions/install-qt-support + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies and local packages + run: | + python -m pip install ".[${{ matrix.qt-api }},editors,examples,test]" + - name: Create clean test directory + run: | + mkdir testdir + - name: Run the test suite (Linux) + run: cd testdir && xvfb-run -a python -X faulthandler -m unittest discover -v traitsui + if: matrix.os == 'ubuntu-latest' + - name: Run the test suite (Windows/macOS) + run: cd testdir && python -X faulthandler -m unittest discover -v traitsui + if: matrix.os != 'ubuntu-latest' + + tests-wx: + strategy: + matrix: + os: [windows-latest] + python-version: ['3.8', '3.10'] + fail-fast: false + + env: + ETS_TOOLKIT: wx + + runs-on: ${{ matrix.os }} + + steps: + - name: Check out the target commit + uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies and local packages + run: | + python -m pip install ".[wx,editors,examples,test]" + - name: Create clean test directory + run: | + mkdir testdir + - name: Run the test suite (Windows/macOS) + run: cd testdir && python -X faulthandler -m unittest discover -v traitsui diff --git a/pyproject.toml b/pyproject.toml index f658121cd..b4e2ee5e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,79 @@ +[project] +name = 'traitsui' +description = 'Traits-capable user interfaces' +readme = 'README.rst' +requires-python = '>=3.7' +authors = [{name='Enthought', email='info@enthought.com'}] +keywords = ['gui', 'traits', 'traitsui', 'pyqt', 'pyside', 'wxpython'] +classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', +] +dependencies = [ + 'traits>=6.2', + 'pyface>=7.4.1', +] +license = {file = "LICENSE.txt"} +dynamic = ["version"] + +[project.entry-points.'traitsui.toolkits'] +qt = 'traitsui.qt4:toolkit' +qt4 = 'traitsui.qt4:toolkit' +wx = 'traitsui.wx:toolkit' +null = 'traitsui.null:toolkit' + +[project.entry-points.'etsdemo_data'] +demo = 'traitsui.extras._demo_info:info' + +[project.optional-dependencies] +docs = ['enthought-sphinx-theme', 'sphinx', 'sphinx-copybutton'] +editors = ['numpy', 'pandas'] +examples = ['apptools', 'h5py', 'numpy', 'pandas', 'pillow', 'tables'] +pyqt5 = ['pyqt5', 'pygments'] +pyqt6 = ['pyqt6', 'pygments'] +pyside2 = ['pyside2', 'pygments'] +pyside6 = ['pyside6', 'pygments'] +test = ['packaging', 'numpy'] +wx = ['wxPython>=4', 'numpy'] + +[project.urls] +source = 'https://github.com/enthought/traitsui' +docs = 'https://docs.enthought.com/traitsui' + +[build-system] +requires = ['setuptools>=61', 'wheel'] +build-backend = 'setuptools.build_meta' + [tool.black] line-length = 79 -target-version = ['py36', 'py37', 'py38'] -skip-string-normalization = true +target-version = ['py38'] + +[tool.isort] +profile = 'black' +sections = ['FUTURE', 'STDLIB', 'THIRDPARTY', 'ENTHOUGHT', 'FIRSTPARTY', 'LOCALFOLDER'] +known_third_party = ['wx', 'PyQt5', 'PyQt6', 'PySide2', 'PySide6', 'PIL', 'pygments', 'numpy'] +known_enthought = ['apptools', 'pyface', 'traits'] +line_length = 79 +order_by_type = false + +[tool.setuptools] +packages = ['traitsui'] + +[tool.setuptools.dynamic] +version = {attr = "traitsui.__version__"} + +[tool.setuptools.package-data] +traitsui = [ + 'examples/demo/*', + 'examples/demo/*/*', + 'examples/demo/*/*/*', + 'extras/images/*', + 'image/library/*.zip', + 'images/*', + 'wx/images/*', + 'qt4/images/*', + 'testing/data/*', +] diff --git a/setup.py b/setup.py deleted file mode 100644 index fabb9860a..000000000 --- a/setup.py +++ /dev/null @@ -1,375 +0,0 @@ -# (C) Copyright 2004-2023 Enthought, Inc., Austin, TX -# All rights reserved. -# -# This software is provided without warranty under the terms of the BSD -# license included in LICENSE.txt and may be redistributed only under -# the conditions described in the aforementioned license. The license -# is also available online at http://www.enthought.com/licenses/BSD.txt -# -# Thanks for using Enthought open source! - -import os -import re -import runpy -import subprocess - -from setuptools import setup, find_packages -from io import open - -# Version information; update this by hand when making a new bugfix or feature -# release. The actual package version is autogenerated from this information -# together with information from the version control system, and then injected -# into the package source. -MAJOR = 7 -MINOR = 5 -MICRO = 0 -PRERELEASE = "" -IS_RELEASED = False - -# If this file is part of a Git export (for example created with "git archive", -# or downloaded from GitHub), ARCHIVE_COMMIT_HASH gives the full hash of the -# commit that was exported. -ARCHIVE_COMMIT_HASH = "$Format:%H$" - -# Templates for version strings. -RELEASED_VERSION = "{major}.{minor}.{micro}{prerelease}" -UNRELEASED_VERSION = "{major}.{minor}.{micro}{prerelease}.dev{dev}" - -# Paths to the autogenerated version file and the Git directory. -HERE = os.path.abspath(os.path.dirname(__file__)) -VERSION_FILE = os.path.join(HERE, "traitsui", "_version.py") -GIT_DIRECTORY = os.path.join(HERE, ".git") - -# Template for the autogenerated version file. -VERSION_FILE_TEMPLATE = """\ -# (C) Copyright 2004-2023 Enthought, Inc., Austin, TX -# All rights reserved. -# -# This software is provided without warranty under the terms of the BSD -# license included in LICENSE.txt and may be redistributed only under -# the conditions described in the aforementioned license. The license -# is also available online at http://www.enthought.com/licenses/BSD.txt -# -# Thanks for using Enthought open source! - -# THIS FILE IS GENERATED FROM SETUP.PY - -#: The full version of the package, including a development suffix -#: for unreleased versions of the package. -version = '{version}' - -#: The full version of the package, same as 'version' -#: Kept for backward compatibility -full_version = version - -#: The Git revision from which this release was made. -git_revision = '{git_revision}' - -#: Flag whether this is a final release -is_released = {is_released} -""" - - -def read_module(module, package='traitsui'): - """Read a simple .py file from traitsui in a safe way. - - It would be simpler to import the file, but that can be problematic in an - unknown system, so we exec the file instead and extract the variables. - - This will fail if things get too complex in the file being read, but is - sufficient to get version and requirements information. - """ - base_dir = os.path.dirname(__file__) - module_name = package + '.' + module - path = os.path.join(base_dir, package, module + '.py') - with open(path, 'r', encoding='utf-8') as fp: - code = compile(fp.read(), module_name, 'exec') - context = {} - exec(code, context) - return context - - -# Return the git revision as a string -def _git_info(): - """ - Get information about the given commit from Git. - - Returns - ------- - git_count : int - Number of revisions from this commit to the initial commit. - git_revision : str - Commit hash for HEAD. - - Raises - ------ - EnvironmentError - If Git is not available. - subprocess.CalledProcessError - If Git is available, but the version command fails (most likely - because there's no Git repository here). - """ - - def _minimal_ext_cmd(cmd): - # construct minimal environment - env = {} - for k in ['SYSTEMROOT', 'PATH']: - v = os.environ.get(k) - if v is not None: - env[k] = v - # LANGUAGE is used on win32 - env['LANGUAGE'] = 'C' - env['LANG'] = 'C' - env['LC_ALL'] = 'C' - out = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - env=env, - ).communicate()[0] - return out - - try: - out = _minimal_ext_cmd(['git', 'describe', '--tags']) - except OSError: - out = '' - - git_description = out.strip().decode('ascii') - expr = r'.*?\-(?P\d+)-g(?P[a-fA-F0-9]+)' - match = re.match(expr, git_description) - if match is None: - git_revision, git_count = 'Unknown', '0' - else: - git_revision, git_count = match.group('hash'), match.group('count') - - return git_count, git_revision - - -def git_version(): - """ - Construct version information from local variables and Git. - - Returns - ------- - version : str - Package version. - git_revision : str - The full commit hash for the current Git revision. - - Raises - ------ - EnvironmentError - If Git is not available. - subprocess.CalledProcessError - If Git is available, but the version command fails (most likely - because there's no Git repository here). - """ - git_count, git_revision = _git_info() - version_template = RELEASED_VERSION if IS_RELEASED else UNRELEASED_VERSION - version = version_template.format( - major=MAJOR, - minor=MINOR, - micro=MICRO, - prerelease=PRERELEASE, - dev=git_count, - ) - return version, git_revision - - -def archive_version(): - """ - Construct version information for an archive. - - Returns - ------- - version : str - Package version. - git_revision : str - The full commit hash for the current Git revision. - - Raises - ------ - ValueError - If this does not appear to be an archive. - """ - if "$" in ARCHIVE_COMMIT_HASH: - raise ValueError("This does not appear to be an archive.") - - version_template = RELEASED_VERSION if IS_RELEASED else UNRELEASED_VERSION - version = version_template.format( - major=MAJOR, - minor=MINOR, - micro=MICRO, - prerelease=PRERELEASE, - dev="-unknown", - ) - return version, ARCHIVE_COMMIT_HASH - - -def write_version_file(version, git_revision, filename=VERSION_FILE): - """ - Write version information to the version file. - - Overwrites any existing version file. - - Parameters - ---------- - version : str - Package version. - git_revision : str - The full commit hash for the current Git revision. - filename : str - Path to the version file. - """ - with open(filename, "w", encoding="utf-8") as version_file: - version_file.write( - VERSION_FILE_TEMPLATE.format( - version=version, - git_revision=git_revision, - is_released=IS_RELEASED, - ) - ) - - -def read_version_file(): - """ - Read version information from the version file, if it exists. - - Returns - ------- - version : str - The full version, including any development suffix. - git_revision : str - The full commit hash for the current Git revision. - - Raises - ------ - EnvironmentError - If the version file does not exist. - """ - version_info = runpy.run_path(VERSION_FILE) - return (version_info["version"], version_info["git_revision"]) - - -def resolve_version(): - """ - Process version information and write a version file if necessary. - - Returns the current version information. - - Returns - ------- - version : str - Package version. - git_revision : str - The full commit hash for the current Git revision. - """ - if os.path.isdir(GIT_DIRECTORY): - # This is a local clone; compute version information and write - # it to the version file, overwriting any existing information. - version = git_version() - print("Computed package version: {}".format(version)) - print("Writing version to version file {}.".format(VERSION_FILE)) - write_version_file(*version) - elif "$" not in ARCHIVE_COMMIT_HASH: - # This is a source archive. - version = archive_version() - print("Archive package version: {}".format(version)) - print("Writing version to version file {}.".format(VERSION_FILE)) - write_version_file(*version) - elif os.path.isfile(VERSION_FILE): - # This is a source distribution. Read the version information. - print("Reading version file {}".format(VERSION_FILE)) - version = read_version_file() - print("Package version from version file: {}".format(version)) - else: - raise RuntimeError( - "Unable to determine package version. No local Git clone " - "detected, and no version file found at {}.".format(VERSION_FILE) - ) - - return version - - -if __name__ == "__main__": - __version__, _ = resolve_version() - data = read_module('__init__') - __requires__ = data['__requires__'] - __extras_require__ = data['__extras_require__'] - with open("README.rst", "r", encoding="utf-8") as readme: - LONG_DESCRIPTION = readme.read().split(".. end_of_long_description")[0] - - def additional_commands(): - try: - from sphinx.setup_command import BuildDoc - except ImportError: - return {} - else: - return {'documentation': BuildDoc} - - setup( - name='traitsui', - version=__version__, - author='David C. Morrill, et. al.', - author_email='dmorrill@enthought.com', - classifiers=[ - c.strip() - for c in """\ - Development Status :: 5 - Production/Stable - Intended Audience :: Developers - Intended Audience :: Science/Research - License :: OSI Approved :: BSD License - Operating System :: MacOS - Operating System :: Microsoft :: Windows - Operating System :: OS Independent - Operating System :: POSIX - Operating System :: Unix - Programming Language :: Python - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Topic :: Scientific/Engineering - Topic :: Software Development - Topic :: Software Development :: Libraries - """.splitlines() - if len(c.strip()) > 0 - ], - description='traitsui: traits-capable user interfaces', - long_description=LONG_DESCRIPTION, - long_description_content_type="text/x-rst", - url='http://docs.enthought.com/traitsui', - download_url='https://github.com/enthought/traitsui', - install_requires=__requires__, - extras_require=__extras_require__, - license='BSD', - maintainer='ETS Developers', - maintainer_email='enthought-dev@enthought.com', - package_data=dict( - traitsui=[ - 'examples/demo/*', - 'examples/demo/*/*', - 'examples/demo/*/*/*', - 'extras/images/*', - 'image/library/*.zip', - 'images/*', - 'wx/images/*', - 'qt4/images/*', - 'testing/data/*', - ] - ), - packages=find_packages(), - entry_points={ - 'traitsui.toolkits': [ - 'qt4 = traitsui.qt4:toolkit', - 'wx = traitsui.wx:toolkit', - 'qt = traitsui.qt4:toolkit', - 'null = traitsui.null:toolkit', - ], - 'etsdemo_data': [ - 'demo = traitsui.extras._demo_info:info', - ], - }, - platforms=["Windows", "Linux", "Mac OS-X", "Unix", "Solaris"], - python_requires=">=3.6", - zip_safe=False, - ) diff --git a/traitsui/__init__.py b/traitsui/__init__.py index 6d5668a19..14370ca42 100644 --- a/traitsui/__init__.py +++ b/traitsui/__init__.py @@ -8,55 +8,7 @@ # # Thanks for using Enthought open source! - -try: - from traitsui._version import full_version as __version__ -except ImportError: - __version__ = "not-built" - -__requires__ = ["traits>=6.2.0", "pyface>=7.4.1"] -__extras_require__ = { - "wx": ["wxpython>=4", "numpy"], - "pyqt": ["pyqt>=4.10", "pygments"], - "pyqt5": ["pyqt5", "pygments"], - "pyside2": ["pyside2", "pygments"], - "pyside6": [ - # Avoid https://bugreports.qt.io/browse/PYSIDE-1797, which causes - # some versions of PySide6 to be unimportable on Python 3.6 and 3.7. - # Also avoid PySide 6.4 until enum issue is resolved. - "pyside6!=6.2.2,!=6.2.2.1,!=6.2.3,!=6.2.4,!=6.3.0,<6.4.0; python_version<'3.8'", - "pyside6<6.4.0; python_version>='3.8'", - "pygments", - ], - "docs": ["enthought-sphinx-theme", "sphinx", "sphinx-copybutton"], - "demo": [ - # to be deprecated, see enthought/traitsui#950 - "configobj", - "docutils", - ], - "examples": [ - # Dependencies for examples - "apptools", - "h5py", - "numpy", - "pandas", - "pillow", - "tables", - ], - "editors": [ - # Optional dependencies for certain editors which may not be needed by - # projects. If they are absent, ``traitsui.api``` should still be - # importable and the relevant tests should be skipped. - "numpy", # For ArrayEditor and DataFrameEditor - "pandas", # For DataFrameEditor - ], - "test": [ - # Dependencies for running test suites. - "packaging", - "numpy", - ], -} - +__version__ = "8.0.0.dev0" # ============================= Test Loader ================================== def load_tests(loader, standard_tests, pattern): diff --git a/traitsui/qt4/tabular_editor.py b/traitsui/qt4/tabular_editor.py index 7905c3ea3..17adab7d0 100644 --- a/traitsui/qt4/tabular_editor.py +++ b/traitsui/qt4/tabular_editor.py @@ -40,10 +40,10 @@ from .tabular_model import TabularModel SCROLL_TO_POSITION_HINT_MAP = { - "center": QtGui.QTableView.PositionAtCenter, - "top": QtGui.QTableView.PositionAtTop, - "bottom": QtGui.QTableView.PositionAtBottom, - "visible": QtGui.QTableView.EnsureVisible, + "center": QtGui.QTableView.ScrollHint.PositionAtCenter, + "top": QtGui.QTableView.ScrollHint.PositionAtTop, + "bottom": QtGui.QTableView.ScrollHint.PositionAtBottom, + "visible": QtGui.QTableView.ScrollHint.EnsureVisible, } @@ -506,7 +506,8 @@ def _selected_column_changed(self, selected_column): def _scroll_to_row_changed(self, row): """Scroll to the given row.""" scroll_hint = SCROLL_TO_POSITION_HINT_MAP.get( - self.factory.scroll_to_position_hint, self.control.EnsureVisible + self.factory.scroll_to_position_hint, + self.control.ScrollHint.EnsureVisible ) self.control.scrollTo( self.model.index(row, max(self.selected_column, 0)), scroll_hint @@ -515,7 +516,8 @@ def _scroll_to_row_changed(self, row): def _scroll_to_column_changed(self, column): """Scroll to the given column.""" scroll_hint = SCROLL_TO_POSITION_HINT_MAP.get( - self.factory.scroll_to_position_hint, self.control.EnsureVisible + self.factory.scroll_to_position_hint, + self.control.ScrollHint.EnsureVisible ) self.control.scrollTo( self.model.index(max(self.selected_row, 0), column), scroll_hint diff --git a/traitsui/qt4/tests/test_ui_base.py b/traitsui/qt4/tests/test_ui_base.py index 8482aaa00..f0c73519b 100644 --- a/traitsui/qt4/tests/test_ui_base.py +++ b/traitsui/qt4/tests/test_ui_base.py @@ -37,5 +37,6 @@ def test_sticky_dialog_with_parent(self): from pyface.qt import QtCore self.assertFalse( - ui2.control.windowFlags() & QtCore.Qt.WindowState.WindowMaximized + ui2.control.windowState() + & QtCore.Qt.WindowStates.WindowMaximized ) diff --git a/traitsui/tests/editors/test_date_editor.py b/traitsui/tests/editors/test_date_editor.py index 372e9c1ea..37f3ee208 100644 --- a/traitsui/tests/editors/test_date_editor.py +++ b/traitsui/tests/editors/test_date_editor.py @@ -151,7 +151,7 @@ def check_select_status(self, editor, date, selected): ) self.assertEqual( textformat.background().style(), - 0, # Qt.BrushStyle.NoBrush, + QtCore.Qt.BrushStyle.NoBrush, "Expected brush to have been reset.", ) self.check_date_bgcolor(editor, date, (0, 0, 0)) diff --git a/traitsui/tests/editors/test_date_range_editor.py b/traitsui/tests/editors/test_date_range_editor.py index b4f662c6d..150945b1c 100644 --- a/traitsui/tests/editors/test_date_range_editor.py +++ b/traitsui/tests/editors/test_date_range_editor.py @@ -255,7 +255,7 @@ def check_select_status(self, editor, date, selected): ) self.assertEqual( textformat.background().style(), - 0, # Qt.BrushStyle.NoBrush, + QtCore.Qt.BrushStyle.NoBrush, "Expected brush to have been reset.", ) self.assertEqual( diff --git a/traitsui/wx/list_str_editor.py b/traitsui/wx/list_str_editor.py index 911996c96..540fa48c6 100644 --- a/traitsui/wx/list_str_editor.py +++ b/traitsui/wx/list_str_editor.py @@ -317,7 +317,7 @@ def update_editor(self): if index is None: visible = top + pn - 2 if visible >= 0 and visible < control.GetItemCount(): - control.EnsureVisible(visible) + control.ScrollHint.EnsureVisible(visible) if self.factory.multi_select: for index in self.multi_selected_indices: if 0 <= index < n: @@ -336,15 +336,15 @@ def update_editor(self): return if 0 <= (index - top) < pn: - control.EnsureVisible( + control.ScrollHint.EnsureVisible( min(top + pn - 2, control.GetItemCount() - 1) ) elif index < top: - control.EnsureVisible( + control.ScrollHint.EnsureVisible( min(index + pn - 1, control.GetItemCount() - 1) ) else: - control.EnsureVisible(index) + control.ScrollHint.EnsureVisible(index) control.SetItemState( index, diff --git a/traitsui/wx/tabular_editor.py b/traitsui/wx/tabular_editor.py index d148bf200..d0f7d7cd3 100644 --- a/traitsui/wx/tabular_editor.py +++ b/traitsui/wx/tabular_editor.py @@ -494,19 +494,19 @@ def update_editor(self): if row is None: visible = bottom if visible >= 0 and visible < control.GetItemCount(): - control.EnsureVisible(visible) + control.ScrollHint.EnsureVisible(visible) return if 0 <= (row - top) < pn: - control.EnsureVisible( + control.ScrollHint.EnsureVisible( min(top + pn - 2, control.GetItemCount() - 1) ) elif row < top: - control.EnsureVisible( + control.ScrollHint.EnsureVisible( min(row + pn - 1, control.GetItemCount() - 1) ) else: - control.EnsureVisible(row) + control.ScrollHint.EnsureVisible(row) control.SetItemState( row, From 0dca980151f703bca6313764f0effc894688a6db Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 17 Mar 2023 10:51:54 +0000 Subject: [PATCH 02/30] Rename linux install workflow --- .../actions/{apt-get-qt-deps => install-qt-support}/README.md | 0 .../actions/{apt-get-qt-deps => install-qt-support}/action.yml | 0 .github/workflows/bleeding-edge.yml | 2 +- .github/workflows/integration-tests.yml | 2 +- .github/workflows/test-etsdemo.yml | 2 +- .github/workflows/test-with-edm.yml | 2 +- .github/workflows/test-with-pip.yml | 2 +- 7 files changed, 5 insertions(+), 5 deletions(-) rename .github/actions/{apt-get-qt-deps => install-qt-support}/README.md (100%) rename .github/actions/{apt-get-qt-deps => install-qt-support}/action.yml (100%) diff --git a/.github/actions/apt-get-qt-deps/README.md b/.github/actions/install-qt-support/README.md similarity index 100% rename from .github/actions/apt-get-qt-deps/README.md rename to .github/actions/install-qt-support/README.md diff --git a/.github/actions/apt-get-qt-deps/action.yml b/.github/actions/install-qt-support/action.yml similarity index 100% rename from .github/actions/apt-get-qt-deps/action.yml rename to .github/actions/install-qt-support/action.yml diff --git a/.github/workflows/bleeding-edge.yml b/.github/workflows/bleeding-edge.yml index 36bcb7d1f..69c9f7a76 100644 --- a/.github/workflows/bleeding-edge.yml +++ b/.github/workflows/bleeding-edge.yml @@ -29,7 +29,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Install Qt dependencies for Linux - uses: ./.github/actions/apt-get-qt-deps + uses: ./.github/actions/install-qt-support if: startsWith(matrix.os, 'ubuntu') - name: Install local packages run: python -m pip install .[${{ matrix.toolkit }},editors,test] diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 257f689a5..af6e7d22f 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -27,7 +27,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Install Qt dependencies for Linux - uses: ./.github/actions/apt-get-qt-deps + uses: ./.github/actions/install-qt-support if: startsWith(matrix.os, 'ubuntu') - name: Install Swig run: sudo apt-get install swig diff --git a/.github/workflows/test-etsdemo.yml b/.github/workflows/test-etsdemo.yml index 82d161161..5f36aafe8 100644 --- a/.github/workflows/test-etsdemo.yml +++ b/.github/workflows/test-etsdemo.yml @@ -22,7 +22,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Qt dependencies for Linux - uses: ./.github/actions/apt-get-qt-deps + uses: ./.github/actions/install-qt-support if: startsWith(matrix.os, 'ubuntu') - name: Cache EDM packages uses: actions/cache@v2 diff --git a/.github/workflows/test-with-edm.yml b/.github/workflows/test-with-edm.yml index a38b2dacc..ad78dfa9e 100644 --- a/.github/workflows/test-with-edm.yml +++ b/.github/workflows/test-with-edm.yml @@ -51,7 +51,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Qt dependencies for Linux - uses: ./.github/actions/apt-get-qt-deps + uses: ./.github/actions/install-qt-support if: startsWith(matrix.os, 'ubuntu') && matrix.toolkit != 'wx' && matrix.toolkit != 'null' - name: Cache EDM packages uses: actions/cache@v2 diff --git a/.github/workflows/test-with-pip.yml b/.github/workflows/test-with-pip.yml index 835153f0a..5782d6cc3 100644 --- a/.github/workflows/test-with-pip.yml +++ b/.github/workflows/test-with-pip.yml @@ -35,7 +35,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Install Qt dependencies for Linux - uses: ./.github/actions/apt-get-qt-deps + uses: ./.github/actions/install-qt-support if: startsWith(matrix.os, 'ubuntu') - name: Update pip, setuptools and wheel run: python -m pip install --upgrade pip setuptools wheel From 86cf84950f053c469b4fc528155fe344c069dc32 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 17 Mar 2023 10:53:40 +0000 Subject: [PATCH 03/30] Flake8 fixes. --- traitsui/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/traitsui/__init__.py b/traitsui/__init__.py index 14370ca42..230450db3 100644 --- a/traitsui/__init__.py +++ b/traitsui/__init__.py @@ -10,7 +10,9 @@ __version__ = "8.0.0.dev0" + # ============================= Test Loader ================================== + def load_tests(loader, standard_tests, pattern): """Custom test loading function that enables test filtering using regex exclusion pattern. From 5f56f324cd855d87ae8f2f51d00d2cf208f0a858 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 17 Mar 2023 11:07:56 +0000 Subject: [PATCH 04/30] Remove uses of setup.py; fix enum usage --- etstool.py | 19 ++----------------- traitsui/qt4/tests/test_ui_base.py | 2 +- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/etstool.py b/etstool.py index 836783504..c6a4e7d11 100644 --- a/etstool.py +++ b/etstool.py @@ -118,7 +118,7 @@ # Default toolkit to use if none specified. DEFAULT_TOOLKIT = 'null' -# Required runtime dependencies. Should match install_requires in setup.py +# Required runtime dependencies. Should match pyproject.toml. dependencies = { # temporarily get pyface from pip until EDM release # "pyface>=7.4.1", @@ -133,7 +133,7 @@ "traits": "git+http://github.com/enthought/traits.git#egg=traits", } -# The following should match extras_require in setup.py but with package +# The following should match extras_require in pyproject.toml but with package # names compatible with EDM extra_dependencies = { 'pyside2': { @@ -300,7 +300,6 @@ def install(runtime, toolkit, environment, editable, source): commands.extend( [ "edm -c {config} run -e {environment} -- pip install --force-reinstall -r ci-src-requirements.txt --no-dependencies", - "edm -c {config} run -e {environment} -- python setup.py clean --all", ] ) @@ -395,7 +394,6 @@ def cleanup(runtime, toolkit, environment): """Remove a development environment.""" parameters = get_parameters(runtime, toolkit, environment) commands = [ - "edm -c {config} run -e {environment} -- python setup.py clean", "edm -c {config} environments remove {environment} --purge -y", ] click.echo("Cleaning up environment '{environment}'".format(**parameters)) @@ -416,19 +414,6 @@ def test_clean(runtime, toolkit): cleanup(args=args, standalone_mode=False) -@cli.command() -@click.option('--runtime', default=DEFAULT_RUNTIME) -@click.option('--toolkit', default=DEFAULT_TOOLKIT) -@click.option('--environment', default=None) -def update(runtime, toolkit, environment): - """Update/Reinstall package into environment.""" - parameters = get_parameters(runtime, toolkit, environment) - commands = ["edm -c {config} run -e {environment} -- python setup.py install"] - click.echo("Re-installing in '{environment}'".format(**parameters)) - execute(commands, parameters) - click.echo('Done update') - - @cli.command() @click.option('--runtime', default=DEFAULT_RUNTIME) @click.option('--toolkit', default=DEFAULT_TOOLKIT) diff --git a/traitsui/qt4/tests/test_ui_base.py b/traitsui/qt4/tests/test_ui_base.py index f0c73519b..72309f3c0 100644 --- a/traitsui/qt4/tests/test_ui_base.py +++ b/traitsui/qt4/tests/test_ui_base.py @@ -38,5 +38,5 @@ def test_sticky_dialog_with_parent(self): self.assertFalse( ui2.control.windowState() - & QtCore.Qt.WindowStates.WindowMaximized + & QtCore.Qt.WindowState.WindowMaximized ) From 37351637817d5ef06b8a301d3b06fef0ddf66782 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 08:57:19 +0000 Subject: [PATCH 05/30] WIP test runners; update handling of __version__ --- .../{run-tests.yml => basic-tests.yml} | 16 ++-- .github/workflows/bleeding-edge-tests.yml | 84 ++++++++++++++++++ .github/workflows/bleeding-edge.yml | 74 ---------------- .github/workflows/full-qt-tests.yml | 85 +++++++++++++++++++ .github/workflows/integration-tests.yml | 17 ++-- ...inimal-deps.yml => minimal-deps-tests.yml} | 4 +- .github/workflows/style-checks.yml | 2 +- .github/workflows/test-etsdemo.yml | 16 ++-- .github/workflows/test-with-edm.yml | 17 ++-- .github/workflows/test-with-pip-wx.yml | 6 +- .github/workflows/test-with-pip.yml | 76 ----------------- ets-demo/etstool.py | 20 ++--- etstool.py | 16 +--- pyproject.toml | 6 +- traitsui/__init__.py | 17 +++- 15 files changed, 236 insertions(+), 220 deletions(-) rename .github/workflows/{run-tests.yml => basic-tests.yml} (79%) create mode 100644 .github/workflows/bleeding-edge-tests.yml delete mode 100644 .github/workflows/bleeding-edge.yml create mode 100644 .github/workflows/full-qt-tests.yml rename .github/workflows/{minimal-deps.yml => minimal-deps-tests.yml} (89%) delete mode 100644 .github/workflows/test-with-pip.yml diff --git a/.github/workflows/run-tests.yml b/.github/workflows/basic-tests.yml similarity index 79% rename from .github/workflows/run-tests.yml rename to .github/workflows/basic-tests.yml index 8f27bfc2f..9e0653022 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/basic-tests.yml @@ -10,11 +10,14 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.8', '3.10', '3.11'] + python-version: ['3.8', '3.11'] qt-api: ['pyqt5', 'pyside2', 'pyside6'] exclude: - python-version: '3.11' qt-api: 'pyside2' + - python-version: '3.8' + qt-api: 'pyside6' + os: macos-latest fail-fast: false env: @@ -39,17 +42,19 @@ jobs: run: | mkdir testdir - name: Run the test suite (Linux) - run: cd testdir && xvfb-run -a python -X faulthandler -m unittest discover -v traitsui + run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui + working-directory: testdir if: matrix.os == 'ubuntu-latest' - name: Run the test suite (Windows/macOS) - run: cd testdir && python -X faulthandler -m unittest discover -v traitsui + run: python -X faulthandler -m unittest discover -v traitsui + working-directory: testdir if: matrix.os != 'ubuntu-latest' tests-wx: strategy: matrix: os: [windows-latest] - python-version: ['3.8', '3.10'] + python-version: ['3.10'] fail-fast: false env: @@ -71,4 +76,5 @@ jobs: run: | mkdir testdir - name: Run the test suite (Windows/macOS) - run: cd testdir && python -X faulthandler -m unittest discover -v traitsui + run: python -X faulthandler -m unittest discover -v traitsui + working-directory: testdir diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml new file mode 100644 index 000000000..560a240c4 --- /dev/null +++ b/.github/workflows/bleeding-edge-tests.yml @@ -0,0 +1,84 @@ +name: Run test suite for Qt on bleeding-edge dependencies weekly + + schedule: + - cron: '0 4 * * 4' + # Make it possible to manually trigger the workflow + workflow_dispatch: + +env: + PYTHONUNBUFFERED: 1 + +jobs: + weekly-qt: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.11'] + qt-api: ['pyside6'] + exclude: + - python-version: '3.8' + qt-api: 'pyside6' + os: macos-latest + fail-fast: false + + env: + ETS_TOOLKIT: qt + + runs-on: ${{ matrix.os }} + timeout-minutes: 20 # should be plenty, it's usually < 5 + + steps: + - name: Check out the target commit + uses: actions/checkout@v3 + - name: Install Qt dependencies + uses: ./.github/actions/install-qt-support + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies and local packages + run: | + python -m pip install ".[${{ matrix.qt-api }},editors,examples,test]" + - name: Install source dependencies + run: | + python -m pip install --force-reinstall git+http://github.com/enthought/pyface.git#egg=pyface + python -m pip install --force-reinstall git+http://github.com/enthought/traits.git#egg=traits + - name: Create clean test directory + run: | + mkdir testdir + - name: Run the test suite (Linux) + run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui + working-directory: testdir + if: matrix.os == 'ubuntu-latest' + - name: Run the test suite (Windows/macOS) + run: python -X faulthandler -m unittest discover -v traitsui + working-directory: testdir + if: matrix.os != 'ubuntu-latest' + + notify-on-failure: + needs: weekly-qt + if: failure() + runs-on: ubuntu-latest + steps: + - name: Notify Slack channel on failure + uses: voxmedia/github-action-slack-notify-build@v1 + with: + channel_id: ${{ secrets.ETS_SLACK_CHANNEL_ID }} + status: FAILED + color: danger + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} + + notify-on-success: + needs: weekly-qt + if: success() + runs-on: ubuntu-latest + steps: + - name: Notify Slack channel on success + uses: voxmedia/github-action-slack-notify-build@v1 + with: + channel_id: ${{ secrets.ETS_BOTS_SLACK_CHANNEL_ID }} + status: SUCCESS + color: good + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} diff --git a/.github/workflows/bleeding-edge.yml b/.github/workflows/bleeding-edge.yml deleted file mode 100644 index 69c9f7a76..000000000 --- a/.github/workflows/bleeding-edge.yml +++ /dev/null @@ -1,74 +0,0 @@ -# This workflow installs dependencies from main branch - -name: ETS from source - -on: - schedule: - - cron: '0 0 * * 4' - # Make it possible to manually trigger the workflow - workflow_dispatch: - -jobs: - test: - if: github.repository == 'enthought/traitsui' - env: - # Enforce selection of toolkit - ETS_TOOLKIT: qt - QT_MAC_WANTS_LAYER: 1 - strategy: - matrix: - os: [ubuntu-20.04, macos-latest, windows-latest] - toolkit: ['pyside2'] - python-version: [3.9] - runs-on: ${{ matrix.os }} - steps: - - name: Check out - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install Qt dependencies for Linux - uses: ./.github/actions/install-qt-support - if: startsWith(matrix.os, 'ubuntu') - - name: Install local packages - run: python -m pip install .[${{ matrix.toolkit }},editors,test] - - name: Install source dependencies - run: | - python -m pip install --force-reinstall git+http://github.com/enthought/pyface.git#egg=pyface - python -m pip install --force-reinstall git+http://github.com/enthought/traits.git#egg=traits - - name: Sanity check dependencies - run: python -m pip list - - name: Run test suite - uses: GabrielBB/xvfb-action@v1 - with: - run: python -m unittest discover -v traitsui - working-directory: ${{ runner.temp }} - - notify-on-failure: - needs: test - if: failure() - runs-on: ubuntu-20.04 - steps: - - name: Notify Slack channel on failure - uses: voxmedia/github-action-slack-notify-build@v1 - with: - channel_id: ${{ secrets.ETS_SLACK_CHANNEL_ID }} - status: FAILED - color: danger - env: - SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} - - notify-on-success: - needs: test - if: success() - runs-on: ubuntu-20.04 - steps: - - name: Notify Slack channel on success - uses: voxmedia/github-action-slack-notify-build@v1 - with: - channel_id: ${{ secrets.ETS_BOTS_SLACK_CHANNEL_ID }} - status: SUCCESS - color: good - env: - SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml new file mode 100644 index 000000000..e2e33bbf6 --- /dev/null +++ b/.github/workflows/full-qt-tests.yml @@ -0,0 +1,85 @@ +name: Run test suite for Qt across all supported versions and OS weekly + + schedule: + - cron: '0 3 * * 4' + # Make it possible to manually trigger the workflow + workflow_dispatch: + +env: + PYTHONUNBUFFERED: 1 + +jobs: + weekly-qt: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.7', '3.8', '3.9', '3.10' '3.11'] + qt-api: ['pyqt5', 'pyside2', 'pyside6'] + exclude: + - python-version: '3.11' + qt-api: 'pyside2' + - python-version: '3.8' + qt-api: 'pyside6' + os: macos-latest + - python-version: '3.10' + qt-api: 'pyside6' + os: macos-latest + fail-fast: false + + env: + ETS_TOOLKIT: qt + + runs-on: ${{ matrix.os }} + timeout-minutes: 20 # should be plenty, it's usually < 5 + + steps: + - name: Check out the target commit + uses: actions/checkout@v3 + - name: Install Qt dependencies + uses: ./.github/actions/install-qt-support + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies and local packages + run: | + python -m pip install ".[${{ matrix.qt-api }},editors,examples,test]" + - name: Create clean test directory + run: | + mkdir testdir + - name: Run the test suite (Linux) + run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui + working-directory: testdir + if: matrix.os == 'ubuntu-latest' + - name: Run the test suite (Windows/macOS) + run: python -X faulthandler -m unittest discover -v traitsui + working-directory: testdir + if: matrix.os != 'ubuntu-latest' + + notify-on-failure: + needs: weekly-qt + if: failure() + runs-on: ubuntu-latest + steps: + - name: Notify Slack channel on failure + uses: voxmedia/github-action-slack-notify-build@v1 + with: + channel_id: ${{ secrets.ETS_SLACK_CHANNEL_ID }} + status: FAILED + color: danger + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} + + notify-on-success: + needs: weekly-qt + if: success() + runs-on: ubuntu-latest + steps: + - name: Notify Slack channel on success + uses: voxmedia/github-action-slack-notify-build@v1 + with: + channel_id: ${{ secrets.ETS_BOTS_SLACK_CHANNEL_ID }} + status: SUCCESS + color: good + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index af6e7d22f..b62134370 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -15,15 +15,15 @@ jobs: if: github.repository == 'enthought/traitsui' strategy: matrix: - os: [ubuntu-20.04] - toolkit: ['pyside2'] - python-version: [3.6, 3.8, 3.9] + os: [ubuntu-latest] + toolkit: ['pyside6'] + python-version: [3.8, 3.11] runs-on: ${{ matrix.os }} steps: - name: Check out - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install Qt dependencies for Linux @@ -38,15 +38,14 @@ jobs: python -m pip install .[${{ matrix.toolkit }},test,editors] python -m pip install .[examples] - name: Run integration tests - uses: GabrielBB/xvfb-action@v1 with: - run: python -m unittest discover -v ${{ github.workspace }}/integrationtests + run: xvfb-run -a python -X faulthandler -m unittest discover -v ${{ github.workspace }}/integrationtests working-directory: ${{ runner.temp }} notify-on-failure: needs: test if: failure() - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Notify Slack channel on failure uses: voxmedia/github-action-slack-notify-build@v1 @@ -60,7 +59,7 @@ jobs: notify-on-success: needs: test if: success() - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Notify Slack channel on success uses: voxmedia/github-action-slack-notify-build@v1 diff --git a/.github/workflows/minimal-deps.yml b/.github/workflows/minimal-deps-tests.yml similarity index 89% rename from .github/workflows/minimal-deps.yml rename to .github/workflows/minimal-deps-tests.yml index 3efbaecaa..3846bb096 100644 --- a/.github/workflows/minimal-deps.yml +++ b/.github/workflows/minimal-deps-tests.yml @@ -14,9 +14,9 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Check out - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install Python packages diff --git a/.github/workflows/style-checks.yml b/.github/workflows/style-checks.yml index 079cc9cd5..9bd7aa9f4 100644 --- a/.github/workflows/style-checks.yml +++ b/.github/workflows/style-checks.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: [3.8, 3.9] + python-version: [3.8, 3.11] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/test-etsdemo.yml b/.github/workflows/test-etsdemo.yml index 5f36aafe8..aafcd63ea 100644 --- a/.github/workflows/test-etsdemo.yml +++ b/.github/workflows/test-etsdemo.yml @@ -16,21 +16,21 @@ jobs: test-etsdemo: strategy: matrix: - os: [ubuntu-20.04] - toolkit: ['pyqt5', 'pyside2'] + os: [ubuntu-latest] + toolkit: ['pyside6'] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Qt dependencies for Linux uses: ./.github/actions/install-qt-support if: startsWith(matrix.os, 'ubuntu') - name: Cache EDM packages - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.cache key: ${{ runner.os }}-${{ matrix.toolkit }}-${{ hashFiles('ets-demo/etstool.py') }} - name: Setup EDM - uses: enthought/setup-edm-action@v1 + uses: enthought/setup-edm-action@v2 with: edm-version: ${{ env.INSTALL_EDM_VERSION }} - name: Install click to the default EDM environment @@ -39,7 +39,5 @@ jobs: run: edm run -- python etstool.py install --toolkit=${{ matrix.toolkit }} working-directory: ets-demo - name: Run tests - uses: GabrielBB/xvfb-action@v1 - with: - run: edm run -- python etstool.py test --toolkit=${{ matrix.toolkit }} - working-directory: ets-demo + run: xvfb-run -a edm run -- python etstool.py test --toolkit=${{ matrix.toolkit }} + working-directory: ets-demo diff --git a/.github/workflows/test-with-edm.yml b/.github/workflows/test-with-edm.yml index ad78dfa9e..9c257bba4 100644 --- a/.github/workflows/test-with-edm.yml +++ b/.github/workflows/test-with-edm.yml @@ -22,11 +22,8 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] toolkit: ['pyqt5', 'pyside2', 'pyside6'] - python-version: ['3.6', '3.8'] + python-version: ['3.8'] include: - - os: ubuntu-latest - toolkit: 'null' - python-version: '3.6' - os: ubuntu-latest toolkit: 'null' python-version: '3.8' @@ -37,8 +34,6 @@ jobs: python-version: '3.8' - toolkit: 'pyside2' python-version: '3.8' - - toolkit: 'pyside6' - python-version: '3.6' runs-on: ${{ matrix.os }} env: # Set root directory, mainly for Windows, so that the EDM Python @@ -49,17 +44,17 @@ jobs: # set the font config path for linux FONTCONFIG_PATH: /etc/fonts steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Qt dependencies for Linux uses: ./.github/actions/install-qt-support if: startsWith(matrix.os, 'ubuntu') && matrix.toolkit != 'wx' && matrix.toolkit != 'null' - name: Cache EDM packages - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.cache key: ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.toolkit }}-${{ hashFiles('etstool.py') }} - name: Setup EDM - uses: enthought/setup-edm-action@v1 + uses: enthought/setup-edm-action@v2 with: edm-version: ${{ env.INSTALL_EDM_VERSION }} - name: Install click to the default EDM environment @@ -67,6 +62,4 @@ jobs: - name: Install test environment run: edm run -- python etstool.py install --toolkit=${{ matrix.toolkit }} --runtime=${{ matrix.python-version }} - name: Run tests - uses: GabrielBB/xvfb-action@v1 - with: - run: edm run -- python etstool.py test --toolkit=${{ matrix.toolkit }} --runtime=${{ matrix.python-version }} + run: xvfb-run -a edm run -- python etstool.py test --toolkit=${{ matrix.toolkit }} --runtime=${{ matrix.python-version }} diff --git a/.github/workflows/test-with-pip-wx.yml b/.github/workflows/test-with-pip-wx.yml index e79a74d71..4565aef74 100644 --- a/.github/workflows/test-with-pip-wx.yml +++ b/.github/workflows/test-with-pip-wx.yml @@ -23,13 +23,13 @@ jobs: fail-fast: false matrix: os: [windows-latest] - python-version: [3.6, 3.8] + python-version: [3.8] runs-on: ${{ matrix.os }} steps: - name: Check out - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Update pip, setuptools and wheel diff --git a/.github/workflows/test-with-pip.yml b/.github/workflows/test-with-pip.yml deleted file mode 100644 index 5782d6cc3..000000000 --- a/.github/workflows/test-with-pip.yml +++ /dev/null @@ -1,76 +0,0 @@ -# This workflow targets stable released dependencies from PyPI -# The matrix is conservative to avoid using too much public resources. - -# We test only Qt support in this workflow; the test suite is currently not -# maintained for wxPython. See test-with-pip-wx.yml for a separate -# wxPython-only workflow. - -name: Test with PyPI and Qt - -on: - schedule: - - cron: '0 3 * * 4' - # Make it possible to manually trigger the workflow - workflow_dispatch: - -jobs: - # Tests against Qt/Python packages from PyPI - pip-qt: - if: github.repository == 'enthought/traitsui' - env: - # Enforce selection of toolkit - ETS_TOOLKIT: qt - QT_MAC_WANTS_LAYER: 1 - strategy: - matrix: - os: [ubuntu-20.04, macos-latest, windows-latest] - toolkit: ['pyside2', 'pyside6'] - python-version: [3.6] - runs-on: ${{ matrix.os }} - steps: - - name: Check out - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install Qt dependencies for Linux - uses: ./.github/actions/install-qt-support - if: startsWith(matrix.os, 'ubuntu') - - name: Update pip, setuptools and wheel - run: python -m pip install --upgrade pip setuptools wheel - - name: Install local packages - run: python -m pip install .[${{ matrix.toolkit }},editors,test] - - name: Run test suite - uses: GabrielBB/xvfb-action@v1 - with: - run: python -m unittest discover -v traitsui - working-directory: ${{ runner.temp }} - - notify-on-failure: - needs: pip-qt - if: failure() - runs-on: ubuntu-20.04 - steps: - - name: Notify Slack channel on failure - uses: voxmedia/github-action-slack-notify-build@v1 - with: - channel_id: ${{ secrets.ETS_SLACK_CHANNEL_ID }} - status: FAILED - color: danger - env: - SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} - - notify-on-success: - needs: pip-qt - if: success() - runs-on: ubuntu-20.04 - steps: - - name: Notify Slack channel on success - uses: voxmedia/github-action-slack-notify-build@v1 - with: - channel_id: ${{ secrets.ETS_BOTS_SLACK_CHANNEL_ID }} - status: SUCCESS - color: good - env: - SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} diff --git a/ets-demo/etstool.py b/ets-demo/etstool.py index ef41a5eab..c64bfec9c 100644 --- a/ets-demo/etstool.py +++ b/ets-demo/etstool.py @@ -91,10 +91,11 @@ supported_combinations = { '3.6': {'pyside2', 'pyqt5', 'wx', 'null'}, + '3.8': {'pyside6', 'pyqt6', 'null'}, } # Default Python version to use in the comamnds below if none is specified. -DEFAULT_RUNTIME = '3.6' +DEFAULT_RUNTIME = '3.8' # Default toolkit to use if none specified. DEFAULT_TOOLKIT = 'null' @@ -122,6 +123,10 @@ 'pyside2': { "pygments", }, + 'pyside6': { + 'pyside6', + 'pygments', + }, 'pyqt5': { 'pyqt5', 'pygments', @@ -157,6 +162,7 @@ environment_vars = { 'pyside2': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyside2'}, + 'pyside6': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyside6'}, 'pyqt5': {"ETS_TOOLKIT": "qt4", "QT_API": "pyqt5"}, 'wx': {'ETS_TOOLKIT': 'wx'}, 'null': {'ETS_TOOLKIT': 'null'}, @@ -204,14 +210,9 @@ def install(runtime, toolkit, environment, editable): install_here += "." # edm commands to setup the development environment - if sys.platform == 'linux': - commands = [ - "edm environments create {environment} --platform=rh6-x86_64 --force --version={runtime}" - ] # noqa: E501 - else: - commands = [ - "edm environments create {environment} --force --version={runtime}" - ] # noqa: E501 + commands = [ + "edm environments create {environment} --force --version={runtime}" + ] # noqa: E501 commands.extend( [ @@ -245,7 +246,6 @@ def install(runtime, toolkit, environment, editable): def shell(runtime, toolkit, environment): """Create a shell into the EDM development environment (aka 'activate' it). - """ parameters = get_parameters(runtime, toolkit, environment) commands = [ diff --git a/etstool.py b/etstool.py index c6a4e7d11..5537c0174 100644 --- a/etstool.py +++ b/etstool.py @@ -108,7 +108,6 @@ )) supported_combinations = { - '3.6': {'pyside2', 'pyside6', 'pyqt5', 'pyqt6', 'wx', 'null'}, '3.8': {'pyside2', 'pyside6', 'pyqt5', 'pyqt6', 'wx', 'null'}, } @@ -123,6 +122,7 @@ # temporarily get pyface from pip until EDM release # "pyface>=7.4.1", "traits", + "setuptools", } # Dependencies we install from source for cron tests @@ -174,7 +174,6 @@ # Extra runtime dependencies runtime_dependencies = { - "3.6": {"pillow", "pytables"}, "3.8": {"pillow_simd", "tables"}, } @@ -209,8 +208,6 @@ # toolkit versions in EDM edm_versions = { - ('3.6', 'pyside2'), - ('3.6', 'pyqt5'), ('3.8', 'pyside6'), ('3.8', 'pyqt6'), } @@ -284,16 +281,7 @@ def install(runtime, toolkit, environment, editable, source): "edm -c {config} run -e {environment} -- pip install -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-16.04/ wxPython" ) elif toolkit == 'pyside6': - # On Linux and macOS, some versions of PySide6 between 6.2.2 and 6.3.0 - # are unimportable on Python 3.6 and Python 3.7. See - # https://bugreports.qt.io/browse/PYSIDE-1797. It may be possible to - # remove this workaround once PySide6 6.3.1 or later is released. - # Also there are currently issues with PySide 6.4 - if sys.platform in {'darwin', 'linux'}: - commands.append( - "edm -c {config} run -e {environment} -- pip install pyside6<6.2.2") - else: - commands.append('edm run -e {environment} -- pip install "pyside6<6.4.0"') + commands.append('edm run -e {environment} -- pip install "pyside6"') elif toolkit != "null": commands.append("edm -c {config} run -e {environment} -- pip install {toolkit}") diff --git a/pyproject.toml b/pyproject.toml index b4e2ee5e7..f0284811e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,9 +15,10 @@ classifiers = [ dependencies = [ 'traits>=6.2', 'pyface>=7.4.1', + 'importlib_metadata ; python < "3.8"', ] license = {file = "LICENSE.txt"} -dynamic = ["version"] +version = 8.0.0.dev0 [project.entry-points.'traitsui.toolkits'] qt = 'traitsui.qt4:toolkit' @@ -62,9 +63,6 @@ order_by_type = false [tool.setuptools] packages = ['traitsui'] -[tool.setuptools.dynamic] -version = {attr = "traitsui.__version__"} - [tool.setuptools.package-data] traitsui = [ 'examples/demo/*', diff --git a/traitsui/__init__.py b/traitsui/__init__.py index 230450db3..4519d6a63 100644 --- a/traitsui/__init__.py +++ b/traitsui/__init__.py @@ -8,7 +8,22 @@ # # Thanks for using Enthought open source! -__version__ = "8.0.0.dev0" +def __getattr__(name): + """Handle deprecated attributes.""" + if name == "__version__": + try: + from importlib.metadata import version + except ImportError: + from importlib_metadata import version + from warnings import warn + + warn( + f"traitsui.{name} is deprecated, " + f"use impportlib.metadata.version('traitsui') ", + DeprecationWarning, + ) + return version('traitsui') + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") # ============================= Test Loader ================================== From 8afe91bbc4dc83e848d2e020fb400f3e157f8a93 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 09:10:02 +0000 Subject: [PATCH 06/30] Fix up pyproject.toml dependencies. --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f0284811e..5c7a74351 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,10 +15,10 @@ classifiers = [ dependencies = [ 'traits>=6.2', 'pyface>=7.4.1', - 'importlib_metadata ; python < "3.8"', + 'importlib-metadata>=3.6; python_version<"3.8"', ] license = {file = "LICENSE.txt"} -version = 8.0.0.dev0 +version = "8.0.0.dev0" [project.entry-points.'traitsui.toolkits'] qt = 'traitsui.qt4:toolkit' From bc74325478efcf115126a25fbc9c6f04defed319 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 11:06:04 +0000 Subject: [PATCH 07/30] Fix missing "on:" in CH workflows --- .github/workflows/bleeding-edge-tests.yml | 1 + .github/workflows/full-qt-tests.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 560a240c4..9cc4509dc 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -1,5 +1,6 @@ name: Run test suite for Qt on bleeding-edge dependencies weekly +on: schedule: - cron: '0 4 * * 4' # Make it possible to manually trigger the workflow diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml index e2e33bbf6..432cab7eb 100644 --- a/.github/workflows/full-qt-tests.yml +++ b/.github/workflows/full-qt-tests.yml @@ -1,5 +1,6 @@ name: Run test suite for Qt across all supported versions and OS weekly +on: schedule: - cron: '0 3 * * 4' # Make it possible to manually trigger the workflow From 17b5565ba6ef19d8c5bc81317018889d3f62e3d6 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 11:09:57 +0000 Subject: [PATCH 08/30] Fix use of xvfb-run --- .github/workflows/test-with-edm.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-with-edm.yml b/.github/workflows/test-with-edm.yml index 9c257bba4..bb9033287 100644 --- a/.github/workflows/test-with-edm.yml +++ b/.github/workflows/test-with-edm.yml @@ -61,5 +61,9 @@ jobs: run: edm install -y wheel click coverage - name: Install test environment run: edm run -- python etstool.py install --toolkit=${{ matrix.toolkit }} --runtime=${{ matrix.python-version }} - - name: Run tests + - name: Run the test suite (Linux) run: xvfb-run -a edm run -- python etstool.py test --toolkit=${{ matrix.toolkit }} --runtime=${{ matrix.python-version }} + if: matrix.os == 'ubuntu-latest' + - name: Run the test suite (Windows/macOS) + run: edm run -- python etstool.py test --toolkit=${{ matrix.toolkit }} --runtime=${{ matrix.python-version }} + if: matrix.os != 'ubuntu-latest' From f7c66284e057ea1cbe6de74721b90ba122894c27 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 11:20:17 +0000 Subject: [PATCH 09/30] Fixes for etstool runners. --- .github/workflows/test-etsdemo.yml | 2 +- .github/workflows/test-with-edm.yml | 2 +- ets-demo/etstool.py | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-etsdemo.yml b/.github/workflows/test-etsdemo.yml index aafcd63ea..f99749158 100644 --- a/.github/workflows/test-etsdemo.yml +++ b/.github/workflows/test-etsdemo.yml @@ -9,7 +9,7 @@ on: env: QT_MAC_WANTS_LAYER: 1 - INSTALL_EDM_VERSION: 3.3.1 + INSTALL_EDM_VERSION: 3.5.0 jobs: diff --git a/.github/workflows/test-with-edm.yml b/.github/workflows/test-with-edm.yml index bb9033287..3a9921bbd 100644 --- a/.github/workflows/test-with-edm.yml +++ b/.github/workflows/test-with-edm.yml @@ -11,7 +11,7 @@ name: Test with EDM on: [pull_request, workflow_dispatch] env: - INSTALL_EDM_VERSION: 3.3.1 + INSTALL_EDM_VERSION: 3.5.0 QT_MAC_WANTS_LAYER: 1 jobs: diff --git a/ets-demo/etstool.py b/ets-demo/etstool.py index c64bfec9c..437bc967c 100644 --- a/ets-demo/etstool.py +++ b/ets-demo/etstool.py @@ -216,8 +216,11 @@ def install(runtime, toolkit, environment, editable): commands.extend( [ - "edm install -y -e {environment} " + packages, - "edm run -e {environment} -- python setup.py clean --all", + ( + "edm install -y -e {environment} " + "--add-repository enthought/lgpl --add-repository enthought/gpl " + ) + + packages, install_here, ] ) From b20a2b40b4700aec2fc5d1ddca3e0adbd4ba32e8 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 12:05:53 +0000 Subject: [PATCH 10/30] More messing with workflows. --- .github/workflows/bleeding-edge-tests.yml | 6 ++++-- .github/workflows/full-qt-tests.yml | 6 ++++-- .github/workflows/integration-tests.yml | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 9cc4509dc..eafa13fa5 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -49,11 +49,13 @@ jobs: mkdir testdir - name: Run the test suite (Linux) run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui - working-directory: testdir + with: + working-directory: testdir if: matrix.os == 'ubuntu-latest' - name: Run the test suite (Windows/macOS) run: python -X faulthandler -m unittest discover -v traitsui - working-directory: testdir + with: + working-directory: testdir if: matrix.os != 'ubuntu-latest' notify-on-failure: diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml index 432cab7eb..13fdbd0e6 100644 --- a/.github/workflows/full-qt-tests.yml +++ b/.github/workflows/full-qt-tests.yml @@ -50,11 +50,13 @@ jobs: mkdir testdir - name: Run the test suite (Linux) run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui - working-directory: testdir + with: + working-directory: testdir if: matrix.os == 'ubuntu-latest' - name: Run the test suite (Windows/macOS) run: python -X faulthandler -m unittest discover -v traitsui - working-directory: testdir + with: + working-directory: testdir if: matrix.os != 'ubuntu-latest' notify-on-failure: diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index b62134370..feb58f53b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -38,8 +38,8 @@ jobs: python -m pip install .[${{ matrix.toolkit }},test,editors] python -m pip install .[examples] - name: Run integration tests + run: xvfb-run -a python -X faulthandler -m unittest discover -v ${{ github.workspace }}/integrationtests with: - run: xvfb-run -a python -X faulthandler -m unittest discover -v ${{ github.workspace }}/integrationtests working-directory: ${{ runner.temp }} notify-on-failure: From 8b49a689dcf419bfb2d93df146d42b1edf694901 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 12:56:24 +0000 Subject: [PATCH 11/30] Fixes for workflows --- .github/workflows/bleeding-edge-tests.yml | 6 +++--- .github/workflows/full-qt-tests.yml | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index eafa13fa5..885922104 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -10,7 +10,7 @@ env: PYTHONUNBUFFERED: 1 jobs: - weekly-qt: + test: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] @@ -59,7 +59,7 @@ jobs: if: matrix.os != 'ubuntu-latest' notify-on-failure: - needs: weekly-qt + needs: test if: failure() runs-on: ubuntu-latest steps: @@ -73,7 +73,7 @@ jobs: SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} notify-on-success: - needs: weekly-qt + needs: test if: success() runs-on: ubuntu-latest steps: diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml index 13fdbd0e6..ad66740b1 100644 --- a/.github/workflows/full-qt-tests.yml +++ b/.github/workflows/full-qt-tests.yml @@ -10,11 +10,11 @@ env: PYTHONUNBUFFERED: 1 jobs: - weekly-qt: + test: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.7', '3.8', '3.9', '3.10' '3.11'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] qt-api: ['pyqt5', 'pyside2', 'pyside6'] exclude: - python-version: '3.11' @@ -60,7 +60,7 @@ jobs: if: matrix.os != 'ubuntu-latest' notify-on-failure: - needs: weekly-qt + needs: test if: failure() runs-on: ubuntu-latest steps: @@ -74,7 +74,7 @@ jobs: SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} notify-on-success: - needs: weekly-qt + needs: test if: success() runs-on: ubuntu-latest steps: From c884bfafce6c7897e4649e267eb25a433d4e7c72 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 13:39:42 +0000 Subject: [PATCH 12/30] Fixes for video editor tests when Metal API not available. --- .github/workflows/basic-tests.yml | 9 ++++----- .github/workflows/bleeding-edge-tests.yml | 4 ---- .github/workflows/full-qt-tests.yml | 6 ------ traitsui/tests/editors/test_video_editor.py | 7 +++++++ 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/.github/workflows/basic-tests.yml b/.github/workflows/basic-tests.yml index 9e0653022..c0c73ab1e 100644 --- a/.github/workflows/basic-tests.yml +++ b/.github/workflows/basic-tests.yml @@ -15,9 +15,6 @@ jobs: exclude: - python-version: '3.11' qt-api: 'pyside2' - - python-version: '3.8' - qt-api: 'pyside6' - os: macos-latest fail-fast: false env: @@ -43,11 +40,13 @@ jobs: mkdir testdir - name: Run the test suite (Linux) run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui - working-directory: testdir + with: + working-directory: testdir if: matrix.os == 'ubuntu-latest' - name: Run the test suite (Windows/macOS) run: python -X faulthandler -m unittest discover -v traitsui - working-directory: testdir + with: + working-directory: testdir if: matrix.os != 'ubuntu-latest' tests-wx: diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 885922104..2dd5f16d7 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -16,10 +16,6 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ['3.11'] qt-api: ['pyside6'] - exclude: - - python-version: '3.8' - qt-api: 'pyside6' - os: macos-latest fail-fast: false env: diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml index ad66740b1..a87abf02d 100644 --- a/.github/workflows/full-qt-tests.yml +++ b/.github/workflows/full-qt-tests.yml @@ -19,12 +19,6 @@ jobs: exclude: - python-version: '3.11' qt-api: 'pyside2' - - python-version: '3.8' - qt-api: 'pyside6' - os: macos-latest - - python-version: '3.10' - qt-api: 'pyside6' - os: macos-latest fail-fast: false env: diff --git a/traitsui/tests/editors/test_video_editor.py b/traitsui/tests/editors/test_video_editor.py index 6be823cd3..321115f80 100644 --- a/traitsui/tests/editors/test_video_editor.py +++ b/traitsui/tests/editors/test_video_editor.py @@ -7,7 +7,10 @@ # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! + +import os import unittest +import sys try: import numpy as np # noqa: F401 @@ -39,6 +42,10 @@ class MovieTheater(HasTraits): @unittest.skipIf(not is_qt5() and not is_qt6(), 'Requires Qt5 or 6') +@unittest.skipIf( + sys.platform == 'darwin' and is_qt6 and os.environ.get('GITHUB_ACTIONS'), + "Mac Qt6 video editor requires Metal APIs, GitHub runners don't have them" +) class TestVideoEditor(BaseTestMixin, unittest.TestCase): def setUp(self): BaseTestMixin.setUp(self) From d6726bbb035f0feb1baf611350350a5ac069c71e Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 13:50:07 +0000 Subject: [PATCH 13/30] Go back to explicit cd. --- .github/workflows/basic-tests.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/basic-tests.yml b/.github/workflows/basic-tests.yml index c0c73ab1e..4949ebcfb 100644 --- a/.github/workflows/basic-tests.yml +++ b/.github/workflows/basic-tests.yml @@ -39,14 +39,10 @@ jobs: run: | mkdir testdir - name: Run the test suite (Linux) - run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui - with: - working-directory: testdir + run: cd testdir && xvfb-run -a python -X faulthandler -m unittest discover -v traitsui if: matrix.os == 'ubuntu-latest' - name: Run the test suite (Windows/macOS) - run: python -X faulthandler -m unittest discover -v traitsui - with: - working-directory: testdir + run: cd testdir && python -X faulthandler -m unittest discover -v traitsui if: matrix.os != 'ubuntu-latest' tests-wx: @@ -75,5 +71,4 @@ jobs: run: | mkdir testdir - name: Run the test suite (Windows/macOS) - run: python -X faulthandler -m unittest discover -v traitsui - working-directory: testdir + run: cd testdir && python -X faulthandler -m unittest discover -v traitsui From 67790195ff123ee6cc0698f3f2db0f848f91f83b Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 14:04:15 +0000 Subject: [PATCH 14/30] Test for metal APIs explicitly. --- .github/workflows/bleeding-edge-tests.yml | 8 ++------ .github/workflows/full-qt-tests.yml | 8 ++------ .github/workflows/integration-tests.yml | 4 +--- traitsui/tests/editors/test_video_editor.py | 18 ++++++++++++++---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 2dd5f16d7..35bab7409 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -44,14 +44,10 @@ jobs: run: | mkdir testdir - name: Run the test suite (Linux) - run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui - with: - working-directory: testdir + run: cd testdir && xvfb-run -a python -X faulthandler -m unittest discover -v traitsui if: matrix.os == 'ubuntu-latest' - name: Run the test suite (Windows/macOS) - run: python -X faulthandler -m unittest discover -v traitsui - with: - working-directory: testdir + run: cd testdir && python -X faulthandler -m unittest discover -v traitsui if: matrix.os != 'ubuntu-latest' notify-on-failure: diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml index a87abf02d..6ae2637d3 100644 --- a/.github/workflows/full-qt-tests.yml +++ b/.github/workflows/full-qt-tests.yml @@ -43,14 +43,10 @@ jobs: run: | mkdir testdir - name: Run the test suite (Linux) - run: xvfb-run -a python -X faulthandler -m unittest discover -v traitsui - with: - working-directory: testdir + run: cd testdir && xvfb-run -a python -X faulthandler -m unittest discover -v traitsui if: matrix.os == 'ubuntu-latest' - name: Run the test suite (Windows/macOS) - run: python -X faulthandler -m unittest discover -v traitsui - with: - working-directory: testdir + run: cd testdir && python -X faulthandler -m unittest discover -v traitsui if: matrix.os != 'ubuntu-latest' notify-on-failure: diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index feb58f53b..3c664a84a 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -38,9 +38,7 @@ jobs: python -m pip install .[${{ matrix.toolkit }},test,editors] python -m pip install .[examples] - name: Run integration tests - run: xvfb-run -a python -X faulthandler -m unittest discover -v ${{ github.workspace }}/integrationtests - with: - working-directory: ${{ runner.temp }} + run: cd testdir && xvfb-run -a python -X faulthandler -m unittest discover -v ${{ github.workspace }}/integrationtests notify-on-failure: needs: test diff --git a/traitsui/tests/editors/test_video_editor.py b/traitsui/tests/editors/test_video_editor.py index 321115f80..24a775be3 100644 --- a/traitsui/tests/editors/test_video_editor.py +++ b/traitsui/tests/editors/test_video_editor.py @@ -10,6 +10,7 @@ import os import unittest +import subprocess import sys try: @@ -26,6 +27,18 @@ filename = pkg_resources.resource_filename('traitsui.testing', 'data/test.mp4') +# Is a MacOS machine lacking the standard Metal APIs? +metal_api_missing = False +if sys.platform == 'darwin' and is_qt6: + # TODO: would be nice to detect if Qt build _uses_ Metal + result = subprocess.run( + ["system_profiler", "SPDisplaysDataType"], + capture_output=True, + check=True, + ) + metal_api_missing = (b'Metal Family: Supported' not in result.stdout) + + class MovieTheater(HasTraits): url = File(filename) @@ -42,10 +55,7 @@ class MovieTheater(HasTraits): @unittest.skipIf(not is_qt5() and not is_qt6(), 'Requires Qt5 or 6') -@unittest.skipIf( - sys.platform == 'darwin' and is_qt6 and os.environ.get('GITHUB_ACTIONS'), - "Mac Qt6 video editor requires Metal APIs, GitHub runners don't have them" -) +@unittest.skipIf(metal_api_missing, "Mac Qt6 video editor requires Metal API") class TestVideoEditor(BaseTestMixin, unittest.TestCase): def setUp(self): BaseTestMixin.setUp(self) From 53779b00ae0baea7f6dec74187a685ecc7f8a81f Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 14:18:29 +0000 Subject: [PATCH 15/30] One more try at fixing worflows --- .github/workflows/bleeding-edge-tests.yml | 6 +++--- .github/workflows/full-qt-tests.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 35bab7409..5f5630fc7 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -1,10 +1,10 @@ name: Run test suite for Qt on bleeding-edge dependencies weekly on: - schedule: - - cron: '0 4 * * 4' - # Make it possible to manually trigger the workflow + # Allows you to run this workflow manually from the Actions tab workflow_dispatch: + schedule: + - cron: '0 0 * * 4' env: PYTHONUNBUFFERED: 1 diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml index 6ae2637d3..598d02055 100644 --- a/.github/workflows/full-qt-tests.yml +++ b/.github/workflows/full-qt-tests.yml @@ -1,10 +1,10 @@ name: Run test suite for Qt across all supported versions and OS weekly on: - schedule: - - cron: '0 3 * * 4' - # Make it possible to manually trigger the workflow + # Allows you to run this workflow manually from the Actions tab workflow_dispatch: + schedule: + - cron: '0 0 * * 4' env: PYTHONUNBUFFERED: 1 From b991548a7bb864a778590dce69c9744c8e55305a Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 14:53:16 +0000 Subject: [PATCH 16/30] Prefer imports from pyface.ui.qt instead of pyface.ui.qt4 --- .github/workflows/integration-tests.yml | 3 ++ .../testing/substitutions.rst | 4 +-- traitsui/qt4/clipboard.py | 5 +++- traitsui/qt4/code_editor.py | 5 +++- traitsui/qt4/progress_editor.py | 5 +++- .../editors/test_liststr_editor_selection.py | 5 +++- traitsui/tests/test_actions.py | 30 ++++++++++++------- traitsui/tests/test_view_application.py | 5 +++- 8 files changed, 45 insertions(+), 17 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 3c664a84a..27e888018 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -37,6 +37,9 @@ jobs: python -m pip install --upgrade pip setuptools wheel python -m pip install .[${{ matrix.toolkit }},test,editors] python -m pip install .[examples] + - name: Create clean test directory + run: | + mkdir testdir - name: Run integration tests run: cd testdir && xvfb-run -a python -X faulthandler -m unittest discover -v ${{ github.workspace }}/integrationtests diff --git a/docs/source/traitsui_user_manual/testing/substitutions.rst b/docs/source/traitsui_user_manual/testing/substitutions.rst index a07c288e0..648cb8446 100644 --- a/docs/source/traitsui_user_manual/testing/substitutions.rst +++ b/docs/source/traitsui_user_manual/testing/substitutions.rst @@ -34,5 +34,5 @@ .. |UIWrapper.perform| replace:: :func:`~traitsui.testing.tester.ui_wrapper.UIWrapper.perform` .. |UIWrapper._target| replace:: :attr:`~traitsui.testing.tester.ui_wrapper.UIWrapper._target` -.. |ModalDialogTester| replace:: :class:`~pyface.ui.qt4.util.modal_dialog_tester.ModalDialogTester` -.. |GuiTestAssistant| replace:: :class:`~pyface.ui.qt4.util.gui_test_assistant.GuiTestAssistant` +.. |ModalDialogTester| replace:: :class:`~pyface.ui.qt.util.modal_dialog_tester.ModalDialogTester` +.. |GuiTestAssistant| replace:: :class:`~pyface.ui.qt.util.gui_test_assistant.GuiTestAssistant` diff --git a/traitsui/qt4/clipboard.py b/traitsui/qt4/clipboard.py index f07d670a1..fad4f7635 100644 --- a/traitsui/qt4/clipboard.py +++ b/traitsui/qt4/clipboard.py @@ -25,7 +25,10 @@ """ from pyface.qt import QtGui -from pyface.ui.qt4.mimedata import PyMimeData, str2bytes +try: + from pyface.ui.qt.mimedata import PyMimeData, str2bytes +except ModuleNotFoundError: + from pyface.ui.qt4.mimedata import PyMimeData, str2bytes from traits.api import HasTraits, Instance, Property diff --git a/traitsui/qt4/code_editor.py b/traitsui/qt4/code_editor.py index ed1eb564c..06dc4afc1 100644 --- a/traitsui/qt4/code_editor.py +++ b/traitsui/qt4/code_editor.py @@ -27,7 +27,10 @@ from pyface.qt import QtCore, QtGui -from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget +try: + from pyface.ui.qt.code_editor.code_widget import AdvancedCodeWidget +except ModuleNotFoundError: + from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget from traits.api import ( Str, List, diff --git a/traitsui/qt4/progress_editor.py b/traitsui/qt4/progress_editor.py index 803945592..2ccaaf9a7 100644 --- a/traitsui/qt4/progress_editor.py +++ b/traitsui/qt4/progress_editor.py @@ -13,8 +13,11 @@ from pyface.qt import QtGui, QtCore from traits.api import Instance, Int, Str +try: + from pyface.ui.qt.progress_dialog import ProgressDialog +except ModuleNotFoundError: + from pyface.ui.qt4.progress_dialog import ProgressDialog from traitsui.qt4.editor import Editor -from pyface.ui.qt4.progress_dialog import ProgressDialog class _ProgressDialog(ProgressDialog): diff --git a/traitsui/tests/editors/test_liststr_editor_selection.py b/traitsui/tests/editors/test_liststr_editor_selection.py index 2a19757d9..e8472824f 100644 --- a/traitsui/tests/editors/test_liststr_editor_selection.py +++ b/traitsui/tests/editors/test_liststr_editor_selection.py @@ -744,7 +744,10 @@ def test_wx_list_str_multi_selected_index(self): def test_selection_listener_disconnected(self): """Check that selection listeners get correctly disconnected""" from pyface.qt.QtGui import QApplication, QItemSelectionModel - from pyface.ui.qt4.util.testing import event_loop + try: + from pyface.ui.qt.util.testing import event_loop + except ModuleNotFoundError: + from pyface.ui.qt4.util.testing import event_loop obj = ListStrEditorWithSelectedIndex(values=["value1", "value2"]) diff --git a/traitsui/tests/test_actions.py b/traitsui/tests/test_actions.py index 49e88939f..54462028d 100644 --- a/traitsui/tests/test_actions.py +++ b/traitsui/tests/test_actions.py @@ -149,10 +149,12 @@ def test_qt_toolbar_action(self): # Bug: in the Qt4 backend, a # TypeError: perform() takes exactly 2 arguments (1 given) was raised # instead + try: + from pyface.ui.qt.action.tool_bar_manager import _ToolBar + except ModuleNotFoundError: + from pyface.ui.qt4.action.tool_bar_manager import _ToolBar - qt_trigger_toolbar_action = partial( - _qt_trigger_action, pyface.ui.qt4.action.tool_bar_manager._ToolBar - ) + qt_trigger_toolbar_action = partial(_qt_trigger_action, _ToolBar) self._test_actions(qt_trigger_toolbar_action) @@ -164,9 +166,13 @@ def test_qt_menu_action(self): # Bug: in the Qt4 backend, a # TypeError: perform() takes exactly 2 arguments (1 given) was raised # instead + try: + from pyface.ui.qt.action.menu_manager import _Menu + except ModuleNotFoundError: + from pyface.ui.qt4.action.menu_manager import _Menu qt_trigger_menu_action = partial( - _qt_trigger_action, pyface.ui.qt4.action.menu_manager._Menu + _qt_trigger_action, _Menu ) self._test_actions(qt_trigger_menu_action) @@ -270,10 +276,12 @@ def test_qt_toolbar_action(self): # Bug: in the Qt4 backend, a # TypeError: perform() takes exactly 2 arguments (1 given) was raised # instead + try: + from pyface.ui.qt.action.tool_bar_manager import _ToolBar + except ModuleNotFoundError: + from pyface.ui.qt4.action.tool_bar_manager import _ToolBar - qt_trigger_toolbar_action = partial( - _qt_trigger_action, pyface.ui.qt4.action.tool_bar_manager._ToolBar - ) + qt_trigger_toolbar_action = partial(_qt_trigger_action, _ToolBar) self._test_actions(qt_trigger_toolbar_action) @@ -285,10 +293,12 @@ def test_qt_menu_action(self): # Bug: in the Qt4 backend, a # TypeError: perform() takes exactly 2 arguments (1 given) was raised # instead + try: + from pyface.ui.qt.action.menu_manager import _Menu + except ModuleNotFoundError: + from pyface.ui.qt4.action.menu_manager import _Menu - qt_trigger_menu_action = partial( - _qt_trigger_action, pyface.ui.qt4.action.menu_manager._Menu - ) + qt_trigger_menu_action = partial(_qt_trigger_action, _Menu) self._test_actions(qt_trigger_menu_action) diff --git a/traitsui/tests/test_view_application.py b/traitsui/tests/test_view_application.py index 4317651a3..fd2a21689 100644 --- a/traitsui/tests/test_view_application.py +++ b/traitsui/tests/test_view_application.py @@ -102,7 +102,10 @@ def close_dialog(self): def click_button(self, text): if is_qt(): from pyface.qt.QtGui import QPushButton - from pyface.ui.qt4.util.testing import find_qt_widget + try: + from pyface.ui.qt.util.testing import find_qt_widget + except ModuleNotFoundError: + from pyface.ui.qt4.util.testing import find_qt_widget button = find_qt_widget( self.handler.info.ui.control, From 2f15efec0b93e4797ab9fc03cd1054630924d00a Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 15:26:41 +0000 Subject: [PATCH 17/30] Fix Wx font tests --- traitsui/wx/tests/test_font_trait.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/traitsui/wx/tests/test_font_trait.py b/traitsui/wx/tests/test_font_trait.py index 975eeb48d..bb91282e7 100644 --- a/traitsui/wx/tests/test_font_trait.py +++ b/traitsui/wx/tests/test_font_trait.py @@ -27,7 +27,7 @@ class FontExample(HasTraits): font = WxFont() -class TestPyQtFont(unittest.TestCase): +class TestWxFont(unittest.TestCase): def test_create_traitsfont(self): expected_outcomes = {} @@ -75,11 +75,11 @@ def test_create_traitsfont(self): # test we get expected font self.assertIsInstance(result, TraitsFont) - self.assert_qfont_equal(result, expected) + self.assert_wxfont_equal(result, expected) # round-trip trhough font_to_str result_2 = create_traitsfont(font_to_str(result)) - self.assert_qfont_equal(result, result_2) + self.assert_wxfont_equal(result, result_2) def test_create_traitsfont_wx_font(self): font = wx.Font( @@ -88,14 +88,14 @@ def test_create_traitsfont_wx_font(self): traits_font = create_traitsfont(font) self.assertIsInstance(traits_font, TraitsFont) - self.assert_qfont_equal(traits_font, font) + self.assert_wxfont_equal(traits_font, font) def test_create_traitsfont_system_default(self): font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) traits_font = create_traitsfont(font) self.assertIsInstance(traits_font, TraitsFont) - self.assert_qfont_equal(traits_font, font) + self.assert_wxfont_equal(traits_font, font) def test_create_traitsfont_pyface_font(self): args = simple_parser("18 pt Bold Oblique Underline Courier") @@ -103,13 +103,13 @@ def test_create_traitsfont_pyface_font(self): traits_font = create_traitsfont(font) self.assertIsInstance(traits_font, TraitsFont) - self.assert_qfont_equal(traits_font, font.to_toolkit()) + self.assert_wxfont_equal(traits_font, font.to_toolkit()) def test_font_trait_default(self): obj = FontExample() self.assertIsInstance(obj.font, TraitsFont) - self.assert_qfont_equal(obj.font, wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)) + self.assert_wxfont_equal(obj.font, wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)) def test_font_trait_str(self): obj = FontExample(font="18 pt Bold Oblique Underline Comic Sans script") @@ -118,7 +118,7 @@ def test_font_trait_str(self): ) self.assertIsInstance(obj.font, TraitsFont) - self.assert_qfont_equal(obj.font, wx_font) + self.assert_wxfont_equal(obj.font, wx_font) def test_font_trait_wx_font(self): wx_font = TraitsFont( @@ -127,7 +127,7 @@ def test_font_trait_wx_font(self): obj = FontExample(font=wx_font) self.assertIsInstance(obj.font, TraitsFont) - self.assert_qfont_equal(obj.font, wx_font) + self.assert_wxfont_equal(obj.font, wx_font) def test_font_trait_pyface_font(self): args = simple_parser("18 pt Bold Oblique Underline Courier typewriter") @@ -135,7 +135,7 @@ def test_font_trait_pyface_font(self): obj = FontExample(font=font) self.assertIsInstance(obj.font, TraitsFont) - self.assert_qfont_equal(obj.font, font.to_toolkit()) + self.assert_wxfont_equal(obj.font, font.to_toolkit()) def test_font_trait_none(self): obj = FontExample(font=None) From 5bd2dfe33adf88d8a1a708e8901b94a71c6841aa Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 15:40:49 +0000 Subject: [PATCH 18/30] Drive-by cleanup of the Qt CodeEditor --- traitsui/qt4/code_editor.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/traitsui/qt4/code_editor.py b/traitsui/qt4/code_editor.py index 06dc4afc1..801ef9c89 100644 --- a/traitsui/qt4/code_editor.py +++ b/traitsui/qt4/code_editor.py @@ -25,10 +25,10 @@ """ -from pyface.qt import QtCore, QtGui - +from pyface.qt import QtGui +from pyface.key_pressed_event import KeyPressedEvent try: - from pyface.ui.qt.code_editor.code_widget import AdvancedCodeWidget + from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget except ModuleNotFoundError: from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget from traits.api import ( @@ -42,8 +42,6 @@ ) from traits.trait_base import SequenceTypes -from pyface.key_pressed_event import KeyPressedEvent - from .constants import OKColor, ErrorColor from .editor import Editor from .helper import pixmap_cache From d373ecc576b79187edd282a4b0dc415fe6e82dcb Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 15:59:46 +0000 Subject: [PATCH 19/30] Fix signature of the wx FileEditor.show_file_dialog --- traitsui/wx/file_editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traitsui/wx/file_editor.py b/traitsui/wx/file_editor.py index e387e3e98..396a08b34 100644 --- a/traitsui/wx/file_editor.py +++ b/traitsui/wx/file_editor.py @@ -139,7 +139,7 @@ def update_editor(self): else: self._file_name.SetValue(self.str_value) - def show_file_dialog(self, event): + def show_file_dialog(self, event=None): """Displays the pop-up file dialog.""" if self.history is not None: self.popup = self._create_file_popup() From f70e2d3417e66ac624bcbfe3ce08a57b794ee060 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Mon, 20 Mar 2023 16:38:01 +0000 Subject: [PATCH 20/30] Fixes to font string representation. --- traitsui/wx/font_trait.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/traitsui/wx/font_trait.py b/traitsui/wx/font_trait.py index 2a424210a..db98825db 100644 --- a/traitsui/wx/font_trait.py +++ b/traitsui/wx/font_trait.py @@ -49,12 +49,12 @@ def font_to_str(font): """Converts a wx.Font into a string description of itself.""" family = { - wx.FONTFAMILY_DECORATIVE: "decorative family", - wx.FONTFAMILY_ROMAN: "roman family", - wx.FONTFAMILY_SCRIPT: "script family", - wx.FONTFAMILY_SWISS: "swiss family", - wx.FONTFAMILY_MODERN: "modern family", - wx.FONTFAMILY_TELETYPE: "typewriter family", + wx.FONTFAMILY_DECORATIVE: "decorative ", + wx.FONTFAMILY_ROMAN: "roman ", + wx.FONTFAMILY_SCRIPT: "script ", + wx.FONTFAMILY_SWISS: "swiss ", + wx.FONTFAMILY_MODERN: "modern ", + wx.FONTFAMILY_TELETYPE: "typewriter ", }.get(font.GetFamily(), "") weight = {wx.FONTWEIGHT_LIGHT: " Light", wx.FONTWEIGHT_BOLD: " Bold"}.get( font.GetWeight(), "" From 94261ea1d67efb1162c0ee409b908da2419715b7 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Tue, 21 Mar 2023 12:37:25 +0000 Subject: [PATCH 21/30] Remove WxPython from basic test set. --- .github/workflows/basic-tests.yml | 50 ++++++++++++++++--------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/.github/workflows/basic-tests.yml b/.github/workflows/basic-tests.yml index 4949ebcfb..374d5c0e7 100644 --- a/.github/workflows/basic-tests.yml +++ b/.github/workflows/basic-tests.yml @@ -45,30 +45,32 @@ jobs: run: cd testdir && python -X faulthandler -m unittest discover -v traitsui if: matrix.os != 'ubuntu-latest' - tests-wx: - strategy: - matrix: - os: [windows-latest] - python-version: ['3.10'] - fail-fast: false + # Wx Tests are turned off for now - env: - ETS_TOOLKIT: wx + # tests-wx: + # strategy: + # matrix: + # os: [windows-latest] + # python-version: ['3.10'] + # fail-fast: false - runs-on: ${{ matrix.os }} + # env: + # ETS_TOOLKIT: wx - steps: - - name: Check out the target commit - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies and local packages - run: | - python -m pip install ".[wx,editors,examples,test]" - - name: Create clean test directory - run: | - mkdir testdir - - name: Run the test suite (Windows/macOS) - run: cd testdir && python -X faulthandler -m unittest discover -v traitsui + # runs-on: ${{ matrix.os }} + + # steps: + # - name: Check out the target commit + # uses: actions/checkout@v3 + # - name: Set up Python ${{ matrix.python-version }} + # uses: actions/setup-python@v4 + # with: + # python-version: ${{ matrix.python-version }} + # - name: Install dependencies and local packages + # run: | + # python -m pip install ".[wx,editors,examples,test]" + # - name: Create clean test directory + # run: | + # mkdir testdir + # - name: Run the test suite (Windows/macOS) + # run: cd testdir && python -X faulthandler -m unittest discover -v traitsui From cb9b0de998a0fef3a208b08c0f60819fe6a22b13 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Tue, 21 Mar 2023 13:00:38 +0000 Subject: [PATCH 22/30] Add bleedign edge tests as PR tests because can't seem to run independently. --- .github/workflows/bleeding-edge-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 5f5630fc7..1eee17c4b 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -3,6 +3,7 @@ name: Run test suite for Qt on bleeding-edge dependencies weekly on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: + pull_request: schedule: - cron: '0 0 * * 4' From 8d69a7a472ee907c1867d3e4449af9eddd003bdc Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Tue, 21 Mar 2023 13:33:35 +0000 Subject: [PATCH 23/30] Fix Pyface8 imports; two-stage creation of Pyface Widgets --- traitsui/editors/shell_editor.py | 1 + traitsui/qt4/code_editor.py | 2 +- traitsui/tests/editors/test_code_editor.py | 1 + traitsui/tests/editors/test_shell_editor.py | 1 + traitsui/wx/code_editor.py | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/traitsui/editors/shell_editor.py b/traitsui/editors/shell_editor.py index 906c5d575..92222be04 100644 --- a/traitsui/editors/shell_editor.py +++ b/traitsui/editors/shell_editor.py @@ -50,6 +50,7 @@ def init(self, parent): if self.factory.share and isinstance(value, dict): locals = value self._shell = shell = PythonShell(parent) + shell.create() self.control = shell.control if locals: for item in locals.items(): diff --git a/traitsui/qt4/code_editor.py b/traitsui/qt4/code_editor.py index 801ef9c89..c835801c7 100644 --- a/traitsui/qt4/code_editor.py +++ b/traitsui/qt4/code_editor.py @@ -28,7 +28,7 @@ from pyface.qt import QtGui from pyface.key_pressed_event import KeyPressedEvent try: - from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget + from pyface.ui.qt.code_editor.code_widget import AdvancedCodeWidget except ModuleNotFoundError: from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget from traits.api import ( diff --git a/traitsui/tests/editors/test_code_editor.py b/traitsui/tests/editors/test_code_editor.py index 3b943b2c0..be599955b 100644 --- a/traitsui/tests/editors/test_code_editor.py +++ b/traitsui/tests/editors/test_code_editor.py @@ -48,6 +48,7 @@ def default_traits_view(self): class TestCodeEditor(BaseTestMixin, unittest.TestCase): + def setUp(self): BaseTestMixin.setUp(self) diff --git a/traitsui/tests/editors/test_shell_editor.py b/traitsui/tests/editors/test_shell_editor.py index 0b2f25202..ab7c430a8 100644 --- a/traitsui/tests/editors/test_shell_editor.py +++ b/traitsui/tests/editors/test_shell_editor.py @@ -45,6 +45,7 @@ def get_dict_view(share=False): @requires_toolkit([ToolkitName.qt, ToolkitName.wx]) class TestShellEditor(BaseTestMixin, unittest.TestCase): + def setUp(self): BaseTestMixin.setUp(self) diff --git a/traitsui/wx/code_editor.py b/traitsui/wx/code_editor.py index 4446f271c..7fc8d00be 100644 --- a/traitsui/wx/code_editor.py +++ b/traitsui/wx/code_editor.py @@ -96,6 +96,7 @@ def init(self, parent): self._editor = editor = PythonEditor( parent, show_line_numbers=factory.show_line_numbers ) + editor.create() self.control = control = editor.control # There are a number of events which aren't well documented that look From 4ed62ea198343e6357fd579a2d5e53934ddcbb0a Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Tue, 21 Mar 2023 16:18:03 +0000 Subject: [PATCH 24/30] Witch out conditions for running workflows; try to get full qt test running --- .github/workflows/bleeding-edge-tests.yml | 1 - .github/workflows/full-qt-tests.yml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 1eee17c4b..5f5630fc7 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -3,7 +3,6 @@ name: Run test suite for Qt on bleeding-edge dependencies weekly on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: - pull_request: schedule: - cron: '0 0 * * 4' diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml index 598d02055..eb3ee5cfb 100644 --- a/.github/workflows/full-qt-tests.yml +++ b/.github/workflows/full-qt-tests.yml @@ -3,6 +3,7 @@ name: Run test suite for Qt across all supported versions and OS weekly on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: + pull_request: schedule: - cron: '0 0 * * 4' From dc1fad599cf9478e4d344165fd32a4df2a4b96ea Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Tue, 21 Mar 2023 16:44:11 +0000 Subject: [PATCH 25/30] Turn off PR runs for full workflow. --- .github/workflows/full-qt-tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/full-qt-tests.yml b/.github/workflows/full-qt-tests.yml index eb3ee5cfb..598d02055 100644 --- a/.github/workflows/full-qt-tests.yml +++ b/.github/workflows/full-qt-tests.yml @@ -3,7 +3,6 @@ name: Run test suite for Qt across all supported versions and OS weekly on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: - pull_request: schedule: - cron: '0 0 * * 4' From 08b9e5292e923a854cf4311834b0284717022641 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 24 Mar 2023 13:24:25 +0000 Subject: [PATCH 26/30] Update settings; break out Wx checks into separate workflow --- .github/workflows/basic-tests.yml | 30 ----------------------- .github/workflows/full-wx-tests.yml | 37 +++++++++++++++++++++++++++++ pyproject.toml | 4 +--- 3 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 .github/workflows/full-wx-tests.yml diff --git a/.github/workflows/basic-tests.yml b/.github/workflows/basic-tests.yml index 374d5c0e7..0ade97711 100644 --- a/.github/workflows/basic-tests.yml +++ b/.github/workflows/basic-tests.yml @@ -44,33 +44,3 @@ jobs: - name: Run the test suite (Windows/macOS) run: cd testdir && python -X faulthandler -m unittest discover -v traitsui if: matrix.os != 'ubuntu-latest' - - # Wx Tests are turned off for now - - # tests-wx: - # strategy: - # matrix: - # os: [windows-latest] - # python-version: ['3.10'] - # fail-fast: false - - # env: - # ETS_TOOLKIT: wx - - # runs-on: ${{ matrix.os }} - - # steps: - # - name: Check out the target commit - # uses: actions/checkout@v3 - # - name: Set up Python ${{ matrix.python-version }} - # uses: actions/setup-python@v4 - # with: - # python-version: ${{ matrix.python-version }} - # - name: Install dependencies and local packages - # run: | - # python -m pip install ".[wx,editors,examples,test]" - # - name: Create clean test directory - # run: | - # mkdir testdir - # - name: Run the test suite (Windows/macOS) - # run: cd testdir && python -X faulthandler -m unittest discover -v traitsui diff --git a/.github/workflows/full-wx-tests.yml b/.github/workflows/full-wx-tests.yml new file mode 100644 index 000000000..16f911fe2 --- /dev/null +++ b/.github/workflows/full-wx-tests.yml @@ -0,0 +1,37 @@ +name: Run test suite for Wx across all supported versions and OS weekly + +# This is currently failing for various reasons, so set to workflow dispatch +on: [workflow_dispatch] + +env: + PYTHONUNBUFFERED: 1 + +jobs: + test: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + fail-fast: false + + env: + ETS_TOOLKIT: wx + + runs-on: ${{ matrix.os }} + timeout-minutes: 20 # should be plenty, it's usually < 5 + + steps: + - name: Check out the target commit + uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies and local packages + run: | + python -m pip install ".[wx,editors,examples,test]" + - name: Create clean test directory + run: | + mkdir testdir + - name: Run the test suite (Windows/macOS) + run: cd testdir && python -X faulthandler -m unittest discover -v traitsui diff --git a/pyproject.toml b/pyproject.toml index 5c7a74351..450fbc282 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,13 +50,11 @@ build-backend = 'setuptools.build_meta' [tool.black] line-length = 79 -target-version = ['py38'] [tool.isort] profile = 'black' sections = ['FUTURE', 'STDLIB', 'THIRDPARTY', 'ENTHOUGHT', 'FIRSTPARTY', 'LOCALFOLDER'] -known_third_party = ['wx', 'PyQt5', 'PyQt6', 'PySide2', 'PySide6', 'PIL', 'pygments', 'numpy'] -known_enthought = ['apptools', 'pyface', 'traits'] +known_enthought = ['apptools', 'pyface', 'traits', 'traitsui'] line_length = 79 order_by_type = false From ca69e89fe32a9817e2ea7b29e91919d114412558 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 24 Mar 2023 13:30:45 +0000 Subject: [PATCH 27/30] Accidentally added traitsui to wrong isort group - thought I was in pyface. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 450fbc282..a3cdb66a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ line-length = 79 [tool.isort] profile = 'black' sections = ['FUTURE', 'STDLIB', 'THIRDPARTY', 'ENTHOUGHT', 'FIRSTPARTY', 'LOCALFOLDER'] -known_enthought = ['apptools', 'pyface', 'traits', 'traitsui'] +known_enthought = ['apptools', 'pyface', 'traits'] line_length = 79 order_by_type = false From 3101dbd44a779595e765659ecff9ebf1ea70c83d Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 24 Mar 2023 16:08:51 +0000 Subject: [PATCH 28/30] run bleeding-edge tests to see if tests are fixed on main Pyface --- .github/workflows/bleeding-edge-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 5f5630fc7..1eee17c4b 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -3,6 +3,7 @@ name: Run test suite for Qt on bleeding-edge dependencies weekly on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: + pull_request: schedule: - cron: '0 0 * * 4' From 7649f9048d1f3dfaa8ac491fbda07ac2e2487e72 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 24 Mar 2023 16:22:21 +0000 Subject: [PATCH 29/30] Don't use process events, but properly invoke the event loop and stop it. --- traitsui/testing/tests/test_exception_handling.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/traitsui/testing/tests/test_exception_handling.py b/traitsui/testing/tests/test_exception_handling.py index 28018c201..f47b01d1b 100644 --- a/traitsui/testing/tests/test_exception_handling.py +++ b/traitsui/testing/tests/test_exception_handling.py @@ -42,7 +42,8 @@ def raise_error_2(): with reraise_exceptions(): gui.invoke_later(raise_error_1) gui.invoke_later(raise_error_2) - gui.process_events() + gui.invoke_after(100, gui.stop_event_loop) + gui.start_event_loop() error_msg = str(exception_context.exception) self.assertIn("ZeroDivisionError", error_msg) From 55d01818d1ea3fd79252646f0647246f7a656ed8 Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Fri, 24 Mar 2023 16:48:58 +0000 Subject: [PATCH 30/30] Revert bleeding edge to not run on PRs. --- .github/workflows/bleeding-edge-tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/bleeding-edge-tests.yml b/.github/workflows/bleeding-edge-tests.yml index 1eee17c4b..5f5630fc7 100644 --- a/.github/workflows/bleeding-edge-tests.yml +++ b/.github/workflows/bleeding-edge-tests.yml @@ -3,7 +3,6 @@ name: Run test suite for Qt on bleeding-edge dependencies weekly on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: - pull_request: schedule: - cron: '0 0 * * 4'