Skip to content

Commit

Permalink
Backport bug fixes for 7.0.1 release (#562)
Browse files Browse the repository at this point in the history
* Fix errors from incorrect QImage memory management. (#546)

This should stop the sporadic test failures caused by referencing memory
which has been freed and used by something else.  The fix is to attach the
numpy array with the allocated memory to the QImage, so that the lifetime
of the array is at least as long as that of the QImage.

* Fix dock pane layout (#545)

* Provide sizeHint to QWidget

* REF : Restore qt4 conditional branch

	modified:   pyface/ui/qt4/tasks/main_window_layout.py

* TST: Test Qt dock widget has the correct size (#552)

Co-authored-by: Sai Rahul Poruri <rporuri@enthought.com>
Co-authored-by: Kit Choi <kitchoi@users.noreply.github.com>

* Update Changelog for 7.0.1

* Remove master only setting on Travis and Appveyor which prevent bug fix release PR from building

* Update .travis.yml for Qt (#529)

* Update .travis.yml to include libglu1-mesa-dev for Qt

* Restore libxkbcommon-x11 and move other dependencies up

* Fix package name for libsdl

* Add a debug flag

* Add libxcb-iccm4

* Continue the same exercise for pyside2, add libxcb-image

* Giving up - let's use the same packages

* Add libxml2 for osx image

* Use brew manually
See https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296/28

* Try a newer osx image

* Add a comment

* Is libdbus still needed?

* Remove debugging flag - it is noisy and is embedded in between tests

* Update install command for installing wx to match master (this is equivalent to a merge of a couple of PRs

Co-authored-by: Corran Webster <cwebster@enthought.com>
Co-authored-by: Pedro Rivotti <44579232+pedrorivotti@users.noreply.github.com>
Co-authored-by: Sai Rahul Poruri <rporuri@enthought.com>
  • Loading branch information
4 people committed Jul 8, 2020
1 parent ac89315 commit 99cb1f4
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 25 deletions.
24 changes: 18 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ dist: xenial
services:
- xvfb

addons:
apt:
packages:
# Qt dependencies
- libxkbcommon-x11-0
- libxcb-icccm4
- libxcb-image0
- libxcb-keysyms1
- libxcb-randr0
- libxcb-render-util0
- libxcb-xinerama0
- pulseaudio
- libpulse-mainloop-glib0
# Wx dependencies
- libsdl1.2debian

env:
global:
- INSTALL_EDM_VERSION=2.0.0
Expand All @@ -12,22 +28,18 @@ matrix:
include:
- env: RUNTIME=3.6 TOOLKITS="pyqt pyqt5 pyside2 wx"
- os: osx
# Obtain newer libxml2 for QtWebKit
osx_image: xcode11.5
env: RUNTIME=3.6 TOOLKITS="pyqt pyqt5 pyside2 wx"
fast_finish: true

branches:
only:
- master

cache:
directories:
- "~/.cache"

before_install:
- mkdir -p "${HOME}/.cache/download"
- if [[ ${TRAVIS_OS_NAME} == 'linux' ]]; then ./install-edm-linux.sh; export PATH="${HOME}/edm/bin:${PATH}"; fi
# libdbus, libxkb and pulseaudio for Pyside2, libsdl for wxpython
- if [[ ${TRAVIS_OS_NAME} == 'linux' ]]; then sudo apt-get install -y libdbus-1-3 libxkbcommon-x11-0 libsdl1.2debian pulseaudio libpulse-mainloop-glib0; fi
- if [[ ${TRAVIS_OS_NAME} == 'osx' ]]; then ./install-edm-osx.sh; export PATH="${PATH}:/usr/local/bin"; fi
- edm install -y wheel click coverage
install:
Expand Down
18 changes: 18 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@
Pyface Changelog
================

Release 7.0.1
=============

This is a bugfix release which fixes a number of minor issues with the 7.0.0
release.

Thanks to:

Kit Choi, Rahul Poruri, Pedro Rivotti, Corran Webster.

Change summary
--------------

Fixes

* Fix dock pane layout on Qt5. (#545)
* Fix errors from incorrect QImage memory management. (#546)

Release 7.0.0
=============

Expand Down
5 changes: 0 additions & 5 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ matrix:
- RUNTIME: '3.6'
TOOLKITS: "pyside2 pyqt5"


branches:
only:
- master

cache:
- C:\Users\appveyor\.cache -> appveyor-clean-cache.txt
- C:\Users\appveyor\AppData\Local\pip\Cache -> appveyor-clean-cache.txt
Expand Down
12 changes: 8 additions & 4 deletions etstool.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,18 @@ def install(edm, runtime, toolkit, environment):
]
)
elif toolkit == "wx":
if sys.platform != "linux":
if sys.platform == "darwin":
commands.append(
"{edm} run -e {environment} -- pip install wxPython"
"{edm} run -e {environment} -- python -m pip install wxPython<4.1"
)
else:
elif sys.platform == "linux":
# XXX this is mainly for TravisCI workers; need a generic solution
commands.append(
"{edm} run -e {environment} -- pip install -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-14.04 wxPython"
"{edm} run -e {environment} -- pip install -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-14.04/ wxPython<4.1"
)
else:
commands.append(
"{edm} run -e {environment} -- python -m pip install wxPython"
)

click.echo("Creating environment '{environment}'".format(**parameters))
Expand Down
26 changes: 16 additions & 10 deletions pyface/ui/qt4/tasks/main_window_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import logging


from pyface.qt import QtCore, QtGui
from pyface.qt import QtCore, QtGui, is_qt4


from traits.api import Any, HasTraits
Expand Down Expand Up @@ -154,8 +154,9 @@ def set_layout(self, layout):
sublayout, q_dock_area, _toplevel_call=False
)

# Remove the fixed sizes once Qt activates the layout.
QtCore.QTimer.singleShot(0, self._reset_fixed_sizes)
if is_qt4:
# Remove the fixed sizes once Qt activates the layout.
QtCore.QTimer.singleShot(0, self._reset_fixed_sizes)

def set_layout_for_area(
self, layout, q_dock_area, _toplevel_added=False, _toplevel_call=True
Expand Down Expand Up @@ -227,9 +228,10 @@ def set_layout_for_area(
else:
raise MainWindowLayoutError("Unknown layout item %r" % layout)

# Remove the fixed sizes once Qt activates the layout.
if _toplevel_call:
QtCore.QTimer.singleShot(0, self._reset_fixed_sizes)
if is_qt4:
# Remove the fixed sizes once Qt activates the layout.
if _toplevel_call:
QtCore.QTimer.singleShot(0, self._reset_fixed_sizes)

# ------------------------------------------------------------------------
# 'MainWindowLayout' abstract interface.
Expand Down Expand Up @@ -309,10 +311,14 @@ def _prepare_toplevel_for_item(self, layout):
"Cannot retrieve dock widget for pane %r" % layout.id
)
else:
if layout.width > 0:
dock_widget.widget().setFixedWidth(layout.width)
if layout.height > 0:
dock_widget.widget().setFixedHeight(layout.height)
if is_qt4:
if layout.width > 0:
dock_widget.widget().setFixedWidth(layout.width)
if layout.height > 0:
dock_widget.widget().setFixedHeight(layout.height)
else:
sizeHint = lambda : QtCore.QSize(layout.width, layout.height)
dock_widget.widget().sizeHint = sizeHint
return dock_widget

elif isinstance(layout, LayoutContainer):
Expand Down
128 changes: 128 additions & 0 deletions pyface/ui/qt4/tasks/tests/test_main_window_layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# (C) Copyright 2005-2020 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 unittest
from unittest import mock

from pyface.tasks.api import TaskLayout, PaneItem
from pyface.toolkit import toolkit_object
from pyface.window import Window

try:
from pyface.qt import QtGui
from pyface.ui.qt4.tasks.main_window_layout import MainWindowLayout
except ImportError:
if toolkit_object.toolkit == "qt4":
raise


GuiTestAssistant = toolkit_object("util.gui_test_assistant:GuiTestAssistant")


def create_dummy_dock_widget(parent):
""" Create a dummy QDockWidget with a dummy child widget for test.
Parameters
----------
parent : QObject
Returns
-------
dock_widget : QDockWidget
"""
dock_widget = QtGui.QDockWidget(parent)
content_widget = QtGui.QWidget(parent)
dock_widget.setWidget(content_widget)
return dock_widget


@unittest.skipIf(
toolkit_object.toolkit != "qt4",
"This test targets Qt specific MainWindowLayout. "
"Current toolkit is not Qt."
)
class TestMainWindowLayout(unittest.TestCase, GuiTestAssistant):
""" Test Qt specific MainWindowLayout.
Note that MainWindowLayout does not have a toolkit-agnostic interface
in the ``pyface.tasks`` package. Therefore this test is Qt-only.
"""

def setUp(self):
GuiTestAssistant.setUp(self)
self.window = Window(size=(500, 500))
self.window._create()

def tearDown(self):
if self.window.control is not None:
with self.delete_widget(self.window.control):
self.window.destroy()
del self.window
GuiTestAssistant.tearDown(self)

def setup_window_with_central_widget(self):
# Add a central widget to the main window.
# The main window takes ownership of the child widget.
central_widget = QtGui.QWidget(parent=self.window.control)
self.window.control.setCentralWidget(central_widget)

def test_set_pane_item_width_in_main_window_layout(self):
# Test the dock pane width is as expected.

self.setup_window_with_central_widget()

# Set the dock widget expected width to be smaller than the window
# for a meaningful test.
expected_width = self.window.size[0] // 2
window_layout = MainWindowLayout(control=self.window.control)
dock_layout = TaskLayout(
left=PaneItem(width=expected_width)
)
dock_widget = create_dummy_dock_widget(parent=self.window.control)
patch_get_dock_widget = mock.patch.object(
MainWindowLayout, "_get_dock_widget",
return_value=dock_widget,
)

# when
with self.event_loop():
with patch_get_dock_widget:
window_layout.set_layout(dock_layout)

# then
size = dock_widget.widget().size()
self.assertEqual(size.width(), expected_width)

def test_set_pane_item_height_in_main_window_layout(self):
# Test the dock pane height is as expected.

self.setup_window_with_central_widget()

# Set the dock widget expected height to be smaller than the window
# for a meaningful test.
expected_height = self.window.size[1] // 2
window_layout = MainWindowLayout(control=self.window.control)
dock_layout = TaskLayout(
bottom=PaneItem(height=expected_height)
)
dock_widget = create_dummy_dock_widget(parent=self.window.control)
patch_get_dock_widget = mock.patch.object(
MainWindowLayout, "_get_dock_widget",
return_value=dock_widget,
)

# when
with self.event_loop():
with patch_get_dock_widget:
window_layout.set_layout(dock_layout)

# then
size = dock_widget.widget().size()
self.assertEqual(size.height(), expected_height)
1 change: 1 addition & 0 deletions pyface/ui/qt4/util/image_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,6 @@ def array_to_QImage(array):
elif channels == 4:
image = QImage(data.data, width, height, bytes_per_line,
QImage.Format_ARGB32)
image._numpy_data = data
return image

0 comments on commit 99cb1f4

Please sign in to comment.