Uploaded image for project: 'Qt for Python'
  1. Qt for Python
  2. PYSIDE-239

Unable to use Python Enum type as parameters for Signal declaration

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 6.0
    • 1.2.x, 5.11.0
    • PySide
    • Ubuntu 12.04 x64 with Python 3.4.0 x64 running PySide 1.2.2 installed via pip 1.5.6. I had previously seen the problem with Python 3.3.5 and PySide 1.2.1 using the attached "enum.py" and upgraded in hopes that it would be fixed.
    • 4f1739e062623d3ab8aebe9540e945464734a75b (pyside/pyside-setup/5.14)

    Description

      When attempting to use the new Python 3.4.0 "enum.Enum", I encounter multiple problems.

      Consider the following PY file:

      pysideEnumBug.py
      from enum import Enum
      from PySide import QtCore, QtGui
      import sys
      import traceback
      
      class MYENUM(Enum):
        A = 1
        B = 2
        C = 3
      
      def work(val):
        print("'work' called with val {}".format(repr(val)))
      
      class TwoButton(QtGui.QWidget):
      
        works = QtCore.Signal(str)
      
        import pdb; pdb.set_trace()
        worksNot = QtCore.Signal(MYENUM)
      
        def __init__(self):
          super().__init__()
          layout = QtGui.QHBoxLayout()
          btn = QtGui.QPushButton('Works', self)
          layout.addWidget(btn)
          btn.clicked.connect(self.onWorks)
          btn = QtGui.QPushButton('Doesn\'t Work', self)
          layout.addWidget(btn)
          btn.clicked.connect(self.onDoesntWork)
          self.setWindowTitle('Enum Signal Bug Demo')
          self.setLayout(layout)
          self.show()
      
        def onWorks(self):
          self.works.emit("hello123")
        
        def onDoesntWork(self):
          try:
            self.worksNot.emit(MYENUM.A)
          except:
            traceback.print_exc()
      
      if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        wgt = TwoButton()
        wgt.works.connect(work)
        wgt.worksNot.connect(work)
        sys.exit(app.exec_())
      
      shell
      USER@USER-PC:~/scripts$ python3.4 pysideEnumBug.py 
      Segmentation fault (core dumped)
      USER@USER-PC:~/scripts$ python3.4 pysideEnumBug.py 
      > /home/USER/scripts/pysideEnumBug.py(18)TwoButton()
      -> worksNot = QtCore.Signal(MYENUM)
      (Pdb) s
      --Call--
      > /usr/lib/python3.4/enum.py(263)__len__()
      -> def __len__(cls):
      (Pdb) n
      > /usr/lib/python3.4/enum.py(264)__len__()
      -> return len(cls._member_names_)
      (Pdb) s
      --Return--
      > /usr/lib/python3.4/enum.py(264)__len__()->3
      -> return len(cls._member_names_)
      (Pdb) s
      --Call--
      > /usr/lib/python3.4/enum.py(257)__getitem__()
      -> def __getitem__(cls, name):
      (Pdb) n
      > /usr/lib/python3.4/enum.py(258)__getitem__()
      -> return cls._member_map_[name]
      (Pdb) s
      KeyError: 0
      > /usr/lib/python3.4/enum.py(258)__getitem__()
      -> return cls._member_map_[name]
      (Pdb) s
      --Return--
      > /usr/lib/python3.4/enum.py(258)__getitem__()->None
      -> return cls._member_map_[name]
      (Pdb) s
      Segmentation fault (core dumped)
      USER@USER-PC:~/scripts$ 
      

      "name" in this case is an integer, and PySide uses the length reported by "_len_" to query the various indexes of the MYENUM object. Since Enum doesn't support indexing, it raises a KeyError and this causes the segmentation fault.

      If I modify the source code for "enum.Enum._getitem" to accept integers and return the proper item from its internal OrderedDict (e.g. ".getitem_(1)" would return MYENUM.A), the code will compile, but then I'll get "TypeError: worksNot() only accepts 0 arguments, 2 given!" when I try to do "worksNot.emit(MYENUM.A)". I've attached the modified "enum.py" to this bug report.

      shell
      USER@USER-PC:~/scripts$ python3.4 pysideEnumBug.py 
      > /home/USER/scripts/pysideEnumBug.py(19)TwoButton()
      -> worksNot = QtCore.Signal(MYENUM)
      (Pdb) c
      #Click the "Works" button.
      'work' called with val 'hello123'
      #Click the "Doesn't Work" button.
      Traceback (most recent call last):
        File "pysideEnumBug.py", line 39, in onDoesntWork
          self.worksNot.emit(MYENUM.A)
      TypeError: worksNot() only accepts 0 arguments, 2 given!
      

      Such an error message is typically a symptom of the target class not deriving from the new Python class type. However, this is Python 3.x; all classes are the new type. For the sake of completeness, I tried modifying the enum.Enum source code to explicitly derive from "object" ("class Enum(object, metaclass=EnumMeta)"), but this did not change the outcome.

      Attachments

        For Gerrit Dashboard: PYSIDE-239
        # Subject Branch Project Status CR V

        Activity

          People

            crmaurei Cristian Maureira-Fredes
            defcello John Crawford
            Votes:
            2 Vote for this issue
            Watchers:
            8 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes