Skip to content

Commit

Permalink
qt brain: Make slot argument optional for disconnect() (#1550)
Browse files Browse the repository at this point in the history
* qt brain: Make slot argument optional for disconnect()

Discussed here:
#1531 (comment)

PyQt supports calling .disconnect() without any arguments in order to
disconnect all slots:
https://www.riverbankcomputing.com/static/Docs/PyQt6/signals_slots.html#disconnect

Strictly speaking, slot=None is a wrong call, as actually passing None
does not work:
python-qt-tools/PyQt5-stubs#103

However, pylint/astroid does not support overloads needed to properly
express this: pylint-dev/pylint#5264

So, while this is "wrong", it's less wrong than before - without this
change, pylint expects a mandatory argument, thus raising a
false-positive here:

    from PyQt5.QtCore import QTimer
    t = QTimer()
    t.timeout.connect(lambda: None)
    t.timeout.disconnect()

despite running fine, pylint complains:

    test.py:4:0: E1120: No value for argument 'slot' in method call (no-value-for-parameter)

while with this change, things work fine.
  • Loading branch information
The-Compiler authored and Pierre-Sassoulas committed Jun 13, 2022
1 parent 218ed2b commit b30977e
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 1 deletion.
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ What's New in astroid 2.11.6?
=============================
Release date: TBA

* The Qt brain now correctly treats calling ``.disconnect()`` (with no
arguments) on a slot as valid.


What's New in astroid 2.11.5?
Expand Down
4 changes: 3 additions & 1 deletion astroid/brain/brain_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ def _looks_like_signal(node, signal_name="pyqtSignal"):
def transform_pyqt_signal(node: nodes.FunctionDef) -> None:
module = parse(
"""
_UNSET = object()
class pyqtSignal(object):
def connect(self, slot, type=None, no_receiver_check=False):
pass
def disconnect(self, slot):
def disconnect(self, slot=_UNSET):
pass
def emit(self, *args):
pass
Expand Down
18 changes: 18 additions & 0 deletions tests/unittest_brain_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,21 @@ def test_implicit_parameters() -> None:
pytest.skip("PyQt6 C bindings may not be installed?")
assert isinstance(attribute_node, FunctionDef)
assert attribute_node.implicit_parameters() == 1

@staticmethod
def test_slot_disconnect_no_args() -> None:
"""Test calling .disconnect() on a signal.
See https://github.com/PyCQA/astroid/pull/1531#issuecomment-1111963792
"""
src = """
from PyQt6.QtCore import QTimer
timer = QTimer()
timer.timeout.disconnect #@
"""
node = extract_node(src)
attribute_node = node.inferred()[0]
if attribute_node is Uninferable:
pytest.skip("PyQt6 C bindings may not be installed?")
assert isinstance(attribute_node, FunctionDef)
assert attribute_node.args.defaults

0 comments on commit b30977e

Please sign in to comment.