[PyQt] Class woes - QtCore.QAbstractItemModel.__init__(self)

C C coastalchaos at hotmail.co.uk
Fri May 29 18:11:04 BST 2015


I've managed to get a sample of the code together to show all the class inheritance which produces exactly the same error as in the application with PyQt5.  They PyQt4 version doesn't error.

The red line is the one throwing the error.



from __future__ import division, print_function, unicode_literals
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt, pyqtSignal
import weakref
#from PyQt4 import  QtCore, QtGui 
#from PyQt4.QtCore import pyqtSignal, Qt

class IViewModel(object):
    """
    Interface for a generic model in a model/view pattern
    """

    def __init__(self, session, data):
        """
        Constructor accepts the database session to be used to update the items
        in case of a database's change received by the ``databaseChanged()``
        signal and the user defined initial data.

        :param data: The view model data to display
        :param session: The database' session

        :type session: sqlalchemy.orm.session.Session
        :type data: object
        """
        raise NotImplementedError(self)

    def indentation(self):
        """
        Return the current indentation value

        :rtype: int
        """
        raise NotImplementedError(self)


class BaseViewModel(QtCore.QAbstractItemModel, IViewModel):
    """
    Base view model implementation.

    In the concrete implementation of this class you can define a custom size
    and resize mode for every column of the model but only in x* controls.

    Also set the :py:attr:`.BaseViewModel.orm_classes` static attribute to a
    tuple of classed to be used to filter incoming `databaseChanged` signals.

    To do that you just need to re-implement the
    :py:meth:`.BaseViewModel.columnWidth()` and
    :py:meth:`.BaseViewModel.columnWidthMode()` methods with your custom column
    sizes and resize modes.

    Custom signals:

    * databaseChanged(PyQt_PyObject)
      Emitted from the QCoreApplication's instance after changes in the
      database, an instance of :py:class:`.SessionStatusVO` will be sent within
      the signal
    """

    INDENTATION_CHAR = "  "
    """
    Character to be used during indentation indentation

    :type: string
    """  # pylint: disable=W0105

    INDENTATION_LEVEL = -1
    """
    Number of columns starting from the left side which will be indented.

    A value of -1 means all values in every column will be indented; a value of
    0 (zero) means no indentation will be applied.

    :type: int
    """  # pylint: disable=W0105

    orm_classes = ()
    """
    Class level variable which stores the list of ORM classes to be used as a
    filter when a databaseChanged() signal is received.

    Only the changes on the classes listed in this variable will be forwarded
    to the update/add/remove item's code.

    :type: list
    """  # pylint: disable=W0105

    def __init__(self, session, data):
        """
        See :py:class:`.IViewModel`
        """
        # Call superclass
        QtCore.QAbstractItemModel.__init__(self)      
        
        #super(BaseViewModel, self).__init__(session, data)
        
        # Protected attributes
        self._indentation = self.INDENTATION_LEVEL
        self._data = data

        # Public attributes
        self.session = session    
        
class ContextHelpMixin(object):
    """
    Mixin class to add support for a context help activated by pressing the F1
    key
    """

    DEFAULT = "<not_set>"
    trigger = pyqtSignal()
    helpIdentifierVisible = pyqtSignal(bool)
    
    def __init__(self, *args, **kwds):
        """
        Empty constructor
        """
        # Public attributes
        self._context_help_name = self.DEFAULT
        self._overlay = None

        # Connect signals
#         self.trigger.connect(
#             QtWidgets.QApplication.instance(),
#             QtCore.pyqtSignal(b"helpIdentifierVisible(bool)"),
#             self._on_identifier_visible_signal
#         )
        self.trigger.connect(self._on_identifier_visible_signal)
        
        
class xDialog(ContextHelpMixin, QtWidgets.QDialog):
    """
    Custom dialog class which supports the contextual help and display it as
    window modal, which blocks the interaction only on the dialog's parent and
    its ancestors but not to other windows in the same Qt application's loop.
    """

    def __init__(self, *args, **kwds):
        """
        See QDialog
        """
        # Call superclasses
        QtWidgets.QDialog.__init__(self, *args, **kwds)
        ContextHelpMixin.__init__(self)

        # Set up dialog
        self.setWindowModality(Qt.WindowModal)


class BaseViewMixin(object):
    """
    Mixin implementation for a base view class.

    Protected attributes are added to the class only if they are set.
    """

    def data(self):
        """
        Return current window data

        :rtype: object
        """
        return self._data if hasattr(self, "_data") else None

    def setData(self, value):
        """
        Set current window data

        :param value: The per view data
        :type value: object
        """
        self._data = value  # pylint: disable=W0201

    def delegate(self):
        """
        Returns the view's delegate

        :rtype: puremvc.interfaces.IMediator
        """
        if hasattr(self, "_delegate") and self._delegate is not None:
            return self._delegate()

        return None

    def setDelegate(self, value):
        """
        Keeps a weak reference of the view's delegate

        :param mediator: The view's mediator
        :type mediator: puremvc.interfaces.IMediator
        """
        # pylint: disable=W0201
        self._delegate = weakref.ref(value) if value is not None else None
        # pylint: enable=W0201


class Enumerator(object):
    """
    An enumerator class is a class which cannot be instantiated and offers only
    a set of static constants
    """

    @classmethod
    def members(cls):
        """
        Class method that returns a list with the enumerator members

        :rtype: list( object )
        """
        return [getattr(cls, member_name) for member_name in sorted(vars(cls))
                if not member_name.startswith("__")]

    def __init__(self):  # pylint: disable=W0231
        raise SyntaxError("You cannot create an instance of this class")


class CustomItemRoles(Enumerator):
    """
    Enumerates the custom item roles used by the application
    """

    IDENTIFIER_ROLE = Qt.UserRole + 1
    """
    Returns a unique identifier for the model index item

    :rtype: object
    """  # pylint: disable=W0105




class BaseViewModelItem(object):
    """
    Base view model item implementation
    """

    def __init__(self, value, parent=None):
        """
        Constructor accepts the user defined data and the optional item's
        parent

        :param value: The data displayed by this model item
        :param parent: The optional item's parent

        :type value: object
        :type parent: :py:class:`.BaseViewModelItem`
        """
        # Public attributes
        self.value = value
        self.parent = parent
        self.children = []

    def setData(self, index, value, role):
        """
        Sets data for the column index and role.

        See QAbstractItemModel.setData()

        :param index: The column index
        :param value: The value to be set
        :param role: The item's role

        :type index: int
        :type value: object
        :type role: Qt::ItemDataRole
        """
        pass

    def data(self, index, role):
        """
        Returns data for the column index and role.

        In details:

        * for Qt::UserRole returns the value referenced by the model view item
        * for :py:attr:`.CustomItemRoles.IDENTIFIER_ROLE` returns the
          ID of the object if any

        See QAbstractItemModel.data()

        :param index: The column index
        :param role: The requested role

        :type index: int
        :type role: Qt::ItemDataRole

        :rtype: object
        """
        if role == CustomItemRoles.IDENTIFIER_ROLE:
            return self.identifier()

        if role == Qt.UserRole:
            return self.value

class UsernameItem(BaseViewModelItem):
    """
    Single Username item
    """

    def data(self, index, role):
        """
        See QAbstractItemModel.data()
        """
        # Display role
        if role in (Qt.DisplayRole, Qt.EditRole) and index == 0:
            return self.value.username

        # Default
        return super(UsernameItem, self).data(index, role)
    
class UsernamesModel(BaseViewModel):
    """
    Model for usernames list view
    """

    COLUMNS = ("Username",)

    def __init__(self, session, users, current_user=None):
        """
        Constructor accepts the database session, the list of users and the
        optional current logged user

        :param session: The database session
        :param users: The list of users
        :param current_user: The current logged user

        :type session: sqlachemy.orm.session
        :type users: list( :py:class:`.User` )
        :type current_user: :py:class:`.User`
        """
        # Call superclass
        super(UsernamesModel, self).__init__(
            session, [UsernameItem(user) for user in users])

        # Protected attributes
        self._current_user = current_user
        

class LogonView(BaseViewMixin, xDialog): #, Ui_LogonDialog):
    """
    Logon dialog which let the user to choose the user name and input enter the
    password to logon into the application.

    If the Cancel button is pressed the application will be closed.

    If the logon fails an error message appears on the screen.

    The user cannot close the dialog unless press the Cancel button or logon
    into the application.
    """

    def __init__(self):  # pylint: disable=W0231
        """
        Empty constructor
        """
        # Call superclasses
        BaseViewMixin.__init__(self)
        xDialog.__init__(
            self, flags=(Qt.CustomizeWindowHint | Qt.WindowTitleHint
                         | Qt.WindowStaysOnTopHint)
        )

        # Setup UI
        self.setupUi(self)
        self.password.setFocus(Qt.OtherFocusReason)

    def setData(self, users):
        """
        Show the users by the current system location

        :param users: The list of current system location's users
        :type users: list( :py:class:`.User` )
        """
        # Call superclass
        super(LogonView, self).setData(users)

        # Set data
        self.username.setModel(
            SortViewModelProxy(UsernamesModel(self.delegate().session, users)))
        self.password.setText()
               
if __name__ == '__main__':
    users=[['1','a'],['2','b'],['3','c'],['4','d']]
    a = UsernamesModel(1, users)
    pass


The error message is:-

  File "/Users/CC/Documents/work/CC.code.trunk/splash_example.py", line 390, in <module>
    a = UsernamesModel(1, users)
  File "/Users/CC/Documents/work/CC.code.trunk/splash_example.py", line 337, in __init__
    session, [UsernameItem(user) for user in users])
  File "/Users/CC/Documents/work/CC.code.trunk/splash_example.py", line 95, in __init__
    QtCore.QAbstractItemModel.__init__(self)      
TypeError: __init__() takes exactly 3 arguments (1 given)



If you rem out the PyQt5 imports and unrem the PyQt4 imports then you'll see that there isn't a problem.

I have seen the post by 
Chris O'Halloran   - 28 May 00:47 [PyQt] Addition of parent argument when subclassing with super.

And wondered if he was also having a similar issue but managed to get around it.


I have tried the super() function but to no avail.

I've also looked at http://pyqt.sourceforge.net/Docs/PyQt5/pyqt4_differences.html#cooperative-multi-inheritance for clues


Many thanks in advance
Rob
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20150529/4f8e8257/attachment-0001.html>


More information about the PyQt mailing list