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_()
The problem is caused by the C++ signatures of
fixup
andvalidate
requiring that thetext
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:
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:To work around this, you can do an explict in-place mutation: