Skip to content

MNT: deal with large number of warnings when running tests on pyside6 #1228

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 93 additions & 89 deletions pydm/data_plugins/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import numpy as np
import weakref
import threading
import warnings

from typing import Optional, Callable
from urllib.parse import ParseResult
Expand Down Expand Up @@ -105,103 +106,106 @@ def remove_listener(self, channel, destroying: Optional[bool] = False) -> None:
QObject is destroyed, setting this to True ensures we do not try to do the disconnection a second time.
If set to False, any active signals/slots on the channel will be manually disconnected here.
"""
if self._should_disconnect(channel.connection_slot, destroying):
try:
self.connection_state_signal.disconnect(channel.connection_slot)
except TypeError:
pass
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)

if self._should_disconnect(channel.value_slot, destroying):
for signal_type in (int, float, str, bool, object):
if self._should_disconnect(channel.connection_slot, destroying):
try:
self.new_value_signal[signal_type].disconnect(channel.value_slot)
# If the signal exists (always does in this case since we define it for all 'signal_type' earlier)
# but doesn't match slot, TypeError is thrown. We also don't need to catch KeyError/IndexError here,
# since those are only thrown when signal type doesn't exist.
self.connection_state_signal.disconnect(channel.connection_slot)
except TypeError:
pass

if self._should_disconnect(channel.severity_slot, destroying):
try:
self.new_severity_signal.disconnect(channel.severity_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.write_access_slot, destroying):
try:
self.write_access_signal.disconnect(channel.write_access_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.enum_strings_slot, destroying):
try:
self.enum_strings_signal.disconnect(channel.enum_strings_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.unit_slot, destroying):
try:
self.unit_signal.disconnect(channel.unit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.upper_ctrl_limit_slot, destroying):
try:
self.upper_ctrl_limit_signal.disconnect(channel.upper_ctrl_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.lower_ctrl_limit_slot, destroying):
try:
self.lower_ctrl_limit_signal.disconnect(channel.lower_ctrl_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.upper_alarm_limit_slot, destroying):
try:
self.upper_alarm_limit_signal.disconnect(channel.upper_alarm_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.lower_alarm_limit_slot, destroying):
try:
self.lower_alarm_limit_signal.disconnect(channel.lower_alarm_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.upper_warning_limit_slot, destroying):
try:
self.upper_warning_limit_signal.disconnect(channel.upper_warning_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.lower_warning_limit_slot, destroying):
try:
self.lower_warning_limit_signal.disconnect(channel.lower_warning_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.prec_slot, destroying):
try:
self.prec_signal.disconnect(channel.prec_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.timestamp_slot, destroying):
try:
self.timestamp_signal.disconnect(channel.timestamp_slot)
except (KeyError, TypeError):
pass

if not destroying and channel.value_signal is not None and hasattr(self, "put_value"):
for signal_type in (str, int, float, np.ndarray, dict):
if self._should_disconnect(channel.value_slot, destroying):
for signal_type in (int, float, str, bool, object):
try:
self.new_value_signal[signal_type].disconnect(channel.value_slot)
# If the signal exists (always does in this case since we define it for all 'signal_type' earlier)
# but doesn't match slot, TypeError is thrown. We also don't need to catch KeyError/IndexError here,
# since those are only thrown when signal type doesn't exist.
except TypeError:
pass

if self._should_disconnect(channel.severity_slot, destroying):
try:
self.new_severity_signal.disconnect(channel.severity_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.write_access_slot, destroying):
try:
channel.value_signal[signal_type].disconnect(self.put_value)
# When signal type can't be found, PyQt5 throws KeyError here, but PySide6 index error.
# If signal type exists but doesn't match the slot, TypeError gets thrown.
except (KeyError, IndexError, TypeError):
self.write_access_signal.disconnect(channel.write_access_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.enum_strings_slot, destroying):
try:
self.enum_strings_signal.disconnect(channel.enum_strings_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.unit_slot, destroying):
try:
self.unit_signal.disconnect(channel.unit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.upper_ctrl_limit_slot, destroying):
try:
self.upper_ctrl_limit_signal.disconnect(channel.upper_ctrl_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.lower_ctrl_limit_slot, destroying):
try:
self.lower_ctrl_limit_signal.disconnect(channel.lower_ctrl_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.upper_alarm_limit_slot, destroying):
try:
self.upper_alarm_limit_signal.disconnect(channel.upper_alarm_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.lower_alarm_limit_slot, destroying):
try:
self.lower_alarm_limit_signal.disconnect(channel.lower_alarm_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.upper_warning_limit_slot, destroying):
try:
self.upper_warning_limit_signal.disconnect(channel.upper_warning_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.lower_warning_limit_slot, destroying):
try:
self.lower_warning_limit_signal.disconnect(channel.lower_warning_limit_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.prec_slot, destroying):
try:
self.prec_signal.disconnect(channel.prec_slot)
except (KeyError, TypeError):
pass

if self._should_disconnect(channel.timestamp_slot, destroying):
try:
self.timestamp_signal.disconnect(channel.timestamp_slot)
except (KeyError, TypeError):
pass

if not destroying and channel.value_signal is not None and hasattr(self, "put_value"):
for signal_type in (str, int, float, np.ndarray, dict):
try:
channel.value_signal[signal_type].disconnect(self.put_value)
# When signal type can't be found, PyQt5 throws KeyError here, but PySide6 index error.
# If signal type exists but doesn't match the slot, TypeError gets thrown.
except (KeyError, IndexError, TypeError):
pass

self.listener_count = self.listener_count - 1
if self.listener_count < 1:
self.close()
Expand Down
7 changes: 6 additions & 1 deletion pydm/tests/widgets/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,12 @@ def mock_exec_(*args):
monkeypatch.setattr(QMenu, "exec_", mock_exec_)

mouse_event = QMouseEvent(
QMouseEvent.MouseButtonRelease, pydm_label.rect().center(), Qt.RightButton, Qt.RightButton, Qt.ShiftModifier
QMouseEvent.MouseButtonRelease,
pydm_label.rect().center(), # localPos
pydm_label.rect().center(), # globalPos
Qt.RightButton, # button
Qt.RightButton, # buttons
Qt.ShiftModifier # modifiers
)
pydm_label.open_context_menu(mouse_event)
assert "Context Menu displayed." in caplog.text
Expand Down
94 changes: 50 additions & 44 deletions pydm/tests/widgets/test_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest
import numpy as np
import logging
import warnings

from ...utilities import is_pydm_app
from ...widgets.label import PyDMLabel
Expand Down Expand Up @@ -480,50 +481,55 @@ def test_label_connection_changes_with_alarm_and_no_channel(
tooltip : str
The tooltip for the widget. This can be an empty string
"""
pydm_label = PyDMLabel()
qtbot.addWidget(pydm_label)

pydm_label.alarmSensitiveContent = alarm_sensitive_content
pydm_label.alarmSensitiveBorder = alarm_sensitive_border
pydm_label.setToolTip(tooltip)

# Do not the channel, but set the alarm severity to normal (NONE)
pydm_label.channel = None
signals.new_severity_signal.connect(pydm_label.alarmSeverityChanged)
signals.new_severity_signal.emit(PyDMWidget.ALARM_NONE)

# Set the connection as enabled (True)
signals.connection_state_signal.connect(pydm_label.connectionStateChanged)

blocker = qtbot.waitSignal(signals.connection_state_signal, timeout=1000)
signals.connection_state_signal.emit(True)
blocker.wait()

# Confirm alarm severity, style, connection state, enabling state, and tooltip
assert pydm_label._alarm_state == PyDMWidget.ALARM_NONE
assert pydm_label._connected is True
assert pydm_label.toolTip() == tooltip
assert pydm_label.isEnabled() is True

# Next, disconnect the alarm, and check for the alarm severity, style, connection state, enabling state, and
# tooltip
signals.connection_state_signal.emit(False)
blocker.wait()
assert pydm_label._alarm_state == PyDMWidget.ALARM_NONE

assert pydm_label._connected is False
assert pydm_label.toolTip() == tooltip
assert pydm_label.isEnabled() is True

# Finally, reconnect the alarm, and check for the same attributes
signals.connection_state_signal.emit(True)
blocker.wait()

# Confirm alarm severity, style, connection state, enabling state, and tooltip
assert pydm_label._alarm_state == PyDMWidget.ALARM_NONE
assert pydm_label._connected is True
assert pydm_label.toolTip() == tooltip
assert pydm_label.isEnabled() is True
# Ignore warnings on pyside6: 'RuntimeWarning: Failed to disconnect ... from signal "timeout()"', which seems to just be
# some odd issue related to pytest-qt's waitSignal().
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)

pydm_label = PyDMLabel()
qtbot.addWidget(pydm_label)

pydm_label.alarmSensitiveContent = alarm_sensitive_content
pydm_label.alarmSensitiveBorder = alarm_sensitive_border
pydm_label.setToolTip(tooltip)

# Do not the channel, but set the alarm severity to normal (NONE)
pydm_label.channel = None
signals.new_severity_signal.connect(pydm_label.alarmSeverityChanged)
signals.new_severity_signal.emit(PyDMWidget.ALARM_NONE)

# Set the connection as enabled (True)
signals.connection_state_signal.connect(pydm_label.connectionStateChanged)

blocker = qtbot.waitSignal(signals.connection_state_signal, timeout=1000)
signals.connection_state_signal.emit(True)
blocker.wait()

# Confirm alarm severity, style, connection state, enabling state, and tooltip
assert pydm_label._alarm_state == PyDMWidget.ALARM_NONE
assert pydm_label._connected is True
assert pydm_label.toolTip() == tooltip
assert pydm_label.isEnabled() is True

# Next, disconnect the alarm, and check for the alarm severity, style, connection state, enabling state, and
# tooltip
signals.connection_state_signal.emit(False)
blocker.wait()
assert pydm_label._alarm_state == PyDMWidget.ALARM_NONE

assert pydm_label._connected is False
assert pydm_label.toolTip() == tooltip
assert pydm_label.isEnabled() is True

# Finally, reconnect the alarm, and check for the same attributes
signals.connection_state_signal.emit(True)
blocker.wait()

# Confirm alarm severity, style, connection state, enabling state, and tooltip
assert pydm_label._alarm_state == PyDMWidget.ALARM_NONE
assert pydm_label._connected is True
assert pydm_label.toolTip() == tooltip
assert pydm_label.isEnabled() is True


# --------------------
Expand Down
24 changes: 21 additions & 3 deletions pydm/tests/widgets/test_slider.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,33 @@ def test_mouseMoveEvent(slider_fixture, qtbot, request):

initial_value = test_slider.value()

press_event = QMouseEvent(QEvent.MouseButtonPress, start_pos, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
press_event = QMouseEvent(
QEvent.MouseButtonPress,
start_pos, # localPos
start_pos, # globalPos
Qt.LeftButton, # button
Qt.LeftButton, # buttons
Qt.NoModifier) # modifiers
QApplication.postEvent(test_slider, press_event)
QApplication.processEvents()

move_event = QMouseEvent(QEvent.MouseMove, end_pos, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
move_event = QMouseEvent(
QEvent.MouseMove,
end_pos, # localPos
end_pos, # globalPos
Qt.LeftButton, # button
Qt.LeftButton, # buttons
Qt.NoModifier) # modifiers
QApplication.postEvent(test_slider, move_event)
QApplication.processEvents()

release_event = QMouseEvent(QEvent.MouseButtonRelease, end_pos, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
release_event = QMouseEvent(
QEvent.MouseButtonRelease,
end_pos, # localPos
end_pos, # globalPos
Qt.LeftButton, # button
Qt.LeftButton, # buttons
Qt.NoModifier) # modifier
QApplication.postEvent(test_slider, release_event)
QApplication.processEvents()

Expand Down
8 changes: 6 additions & 2 deletions pydm/widgets/archiver_time_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import re
import time
import numpy as np
import warnings
from collections import OrderedDict
from typing import List, Optional, Union
from pyqtgraph import DateAxisItem, ErrorBarItem, PlotCurveItem
Expand Down Expand Up @@ -999,8 +1000,11 @@ def cache_data(self, enable: bool):
return
if enable:
try:
self.plotItem.sigXRangeChanged.disconnect(self.updateXAxis)
self.plotItem.sigXRangeChangedManually.disconnect(self.updateXAxis)
# Catch the warnings when sigXRangeChanged and sigXRangeChangedManually were not connected yet.
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)
self.plotItem.sigXRangeChanged.disconnect(self.updateXAxis)
self.plotItem.sigXRangeChangedManually.disconnect(self.updateXAxis)
except TypeError:
pass
else:
Expand Down