Updating PyQt signals that use lambda in QGIS with 2to3

Just for the sake of documenting things, when running qgis 2to3 on a plugin I encountered a tricky situation regarding signals.

MYQGISDIR/scripts/2to3 -f signals -w my/plugin/path

The original code:

extra_arg = "my test argument"
QObject.connect(
  action,
  SIGNAL( "triggered()"),
  lambda extra_arg=my_arg: show_extra_arg(extra_arg))
def do_load_project(extra_arg):
  print extra_arg # "my test argument"

The generated code:

extra_arg = "test_arg"
action.triggered.connect(
  lambda extra_arg=my_arg: show_extra_arg(extra_arg))
def do_load_project(extra_arg):
  print extra_arg # False

so in do_load_project we get False instead of “my test argument”, why?
well due to a subtle difference in the generated code. in the original code we had the signature triggered() which has no arguments, so in our lambda extra_arg gets passed my_arg.
in the generated code, triggered actually has an optional param checked [1] which if emitted gets passed to extra_arg causing the problem.
The correct code (note the additional argument in the lambda definition)

extra_arg = "test_arg"
action.triggered.connect(
  lambda checked, extra_arg=my_arg: show_extra_arg(extra_arg))
def do_load_project(extra_arg):
  print extra_arg # False

some reference:
[0] http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html
[1] http://doc.qt.io/qt-4.8/qaction.html#triggered

Leave a Reply