QValidator fixup issue

1.9k Views Asked by At

Following is my code to validate an account code, and add dashes at certain intervals. An example account code is 140-100-1000-6610-543. The code takes the regex: \d{3}-\d{3}-\d{4}-\d{4}-\d{3] and allows the user to type in numbers, and where there is a dash in the regex, it places the dash for the user. Or rather, it should. On our production server (('Qt version:', '4.8.1'), ('SIP version:', '4.13.2'), ('PyQt version:', '4.9.1')) it does work. Our dev server is upgraded to ('Qt version:', '4.8.6'), ('SIP version:', '4.15.5'), ('PyQt version:', '4.10.4') and it doesn't work there.

On each server, I type in 140. On the production (older version), the line edit value changes to 140-. On the newer version development server, it does not add the dash.

Please let me know if you see my issue, and let me know if this is a PyQt issue, or a Qt issue.

import sys
from PyQt4 import QtGui, QtCore

DEBUG = True

class acValidator(QtGui.QRegExpValidator):

    def __init__(self, regexp, widget):
        QtGui.QRegExpValidator.__init__(self, regexp, widget)
        self.widget = widget

    def validate(self, text, pos):
        '''function to decide if this account code is valid'''
        valid, _npos = QtGui.QRegExpValidator.validate(self, text, pos)

        if valid != QtGui.QValidator.Acceptable:
            self.fixup(text)
            print 'acWidget.validate result of fixup', text

            # move position to the end, if fixup just added a dash
            # to the end
            newstr = self.widget.text()
            newpos = len(str(newstr))
            if pos + 1 == newpos and newstr[pos:newpos] == '-':
                pos = newpos

        # return the valid variable, and the current position
        return (valid, pos)

    def fixup(self, text):
        '''place dashes, if we can'''
        # pylint: disable=no-member
        if DEBUG:
            print 'acWidget.py fixup'
        reParts = self.regExp().pattern().split('-')
        if DEBUG:
            print list(reParts)
        newreg = ''
        for i in range(len(reParts)):
            newreg += reParts[i]
            if DEBUG:
                print i, reParts[i]

            nr = QtCore.QRegExp(newreg)
            # pylint: disable=no-member
            if nr.exactMatch(text) and not self.regExp().exactMatch(text):
                if DEBUG:
                    print 'adding dash'
                text += '-'
                return

            newreg += '-'

    def isValid(self):
        '''return a true or false for the validity based on whether the
        widget is a lineEdit or a comboBox (acCB).  true only if the
        validator returns QtGui.QValidator.Acceptable
        '''
        valid, _npos = QtGui.QRegExpValidator.validate(self,
                        self.widget.text(),
                        self.widget.cursorPosition())
        if valid == QtGui.QValidator.Acceptable:
            return True

        return False


class acWidget(QtGui.QLineEdit):

    def __init__(self, parent=None):
        QtGui.QLineEdit.__init__(self, parent)

        self.regex = r'\d{3}-\d{3}-\d{4}-\d{4}-\d{3}'
        self.setMinimumWidth(200)
        self.setValidator(acValidator(QtCore.QRegExp(self.regex),
                    self))

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    form = QtGui.QDialog()
    layout = QtGui.QVBoxLayout(form)
    a = acWidget(form)
    layout.addWidget(a)
    form.setLayout(layout)
    form.setMinimumWidth(400)
    form.setMinimumHeight(200)
    form.show()
    app.exec_()
1

There are 1 best solutions below

1
On

The problem is caused by the C++ signatures of fixup and validate requiring that the text argument is modifiable. If you're using Python 2, this distinctly unpythonic way of doing things is honoured by PyQt; whereas with Python 3, the signatures have been changed so that the methods simply return the modified values.

The specific issue in your code can be found here:

    def fixup(self, text):
        ...

        text += '-'

It seems that, in earlier versions of PyQt, augmented assignment on a QString did an implicit in-place mutation. But in more recent versions, it works more like normal python augmented assignment and simply re-binds the local variable like this:

        text = text + '-'

To work around this, you can do an explict in-place mutation:

        text.append('-')