Thank you for this bug report, the new release is uploaded to debian/unstable
-----------------8<------------
qr-tools (2.1-3) unstable; urgency=medium

  * applied Faidon Liambotis' patch, thanks!. Closes: #1129518
    (Patch to port to PyQt6)
-----------------8<------------

Best regards,                   Georges.

Faidon Liambotis a écrit :
> Source: qr-tools
> Version: 2.1-2
> Severity: minor
> Tags: upstream patch
> 
> Attached is a patch to port qr-tools from PyQt5 to PyQt6.
> 
> I noticed upstream is not active anymore, so I don't think there is
> anywhere to forward it. In the absence of an active upstream, I think
> it'd be meaningful to carry it to the Debian package.
> 
> Thank you for maintaining qr-tools! I've found it to be quite useful.
> It's one of the last Qt5 tools on my system, and I started getting
> worried about its inclusion in Debian, hence this patch :) HTH!
> 
> Regards,
> Faidon

> diff --git a/debian/control b/debian/control
> index eaf78ec..55f335e 100644
> --- a/debian/control
> +++ b/debian/control
> @@ -7,7 +7,7 @@ Build-Depends:
>   dh-python,
>   python3,
>   python3-setuptools,
> - qttools5-dev-tools,
> + qt6-tools-dev,
>  Standards-Version: 4.7.3
>  Rules-Requires-Root: no
>  Homepage: https://launchpad.net/qr-tools
> @@ -20,7 +20,7 @@ Depends:
>   python3-pil,
>   python3-zbar,
>   qrencode,
> - libqt5multimedia5-plugins,
> + libqt6multimedia6,
>   ${misc:Depends},
>   ${python3:Depends}
>  Description: high level library for reading and generating QR codes
> @@ -33,8 +33,8 @@ Architecture: all
>  Section: utils
>  Depends:
>   python3-qrtools,
> - python3-pyqt5,
> - python3-pyqt5.qtmultimedia,
> + python3-pyqt6,
> + python3-pyqt6.qtmultimedia,
>   ${misc:Depends},
>   ${python3:Depends}
>  Description: Qt frontend for QR code generator and decoder
> diff --git a/debian/patches/Port-from-PyQt5-to-PyQt6.patch 
> b/debian/patches/Port-from-PyQt5-to-PyQt6.patch
> new file mode 100644
> index 0000000..e73f3b5
> --- /dev/null
> +++ b/debian/patches/Port-from-PyQt5-to-PyQt6.patch
> @@ -0,0 +1,231 @@
> +From: Faidon Liambotis <[email protected]>
> +Date: Mon, 2 Mar 2026 11:14:01 +0200
> +Subject: Port from PyQt5 to PyQt6
> +
> +---
> + qtqr.py | 86 
> ++++++++++++++++++++++++++++++++++++-----------------------------
> + 1 file changed, 48 insertions(+), 38 deletions(-)
> +
> +diff --git a/qtqr.py b/qtqr.py
> +index 84f9c7c..0f8276e 100644
> +--- a/qtqr.py
> ++++ b/qtqr.py
> +@@ -11,11 +11,10 @@ uses python-zbar for decoding from files and webcam
> + 
> + import sys, os
> + from math import ceil
> +-from PyQt5 import QtCore, QtGui, QtNetwork, QtWidgets
> ++from PyQt6 import QtCore, QtGui, QtNetwork, QtWidgets
> + from qrtools import QR
> + from PIL import Image
> +-from PyQt5.QtMultimedia import QCameraInfo
> +-from PyQt5.QtWidgets import QDialog
> ++from PyQt6.QtMultimedia import QMediaDevices
> + 
> + __author__ = "Ramiro Algozino"
> + __email__ = "[email protected]"
> +@@ -233,7 +232,7 @@ class MainWindow(QtWidgets.QMainWindow):
> + 
> +         #QLabel for displaying the Generated QRCode
> +         self.qrcode = QtWidgets.QLabel(self.tr('Start typing to create QR 
> Code\n or  drop here image files for decoding.'))
> +-        self.qrcode.setAlignment(QtCore.Qt.AlignVCenter | 
> QtCore.Qt.AlignHCenter)
> ++        self.qrcode.setAlignment(QtCore.Qt.AlignmentFlag.AlignVCenter | 
> QtCore.Qt.AlignmentFlag.AlignHCenter)
> +         self.scroll = QtWidgets.QScrollArea()
> +         self.scroll.setWidgetResizable(True)
> +         self.scroll.setWidget(self.qrcode)
> +@@ -245,9 +244,9 @@ class MainWindow(QtWidgets.QMainWindow):
> +         self.decodeFileButton = 
> QtWidgets.QPushButton(QtGui.QIcon.fromTheme(u'document-open'), 
> self.tr('Decode from &File'))
> +         self.decodeWebcamButton = 
> QtWidgets.QPushButton(QtGui.QIcon.fromTheme(u'camera-web'), self.tr('Decode 
> from &Webcam'))
> + 
> +-        self.exitAction = 
> QtWidgets.QAction(QtGui.QIcon.fromTheme(u'application-exit'), 
> self.tr('E&xit'), self)
> ++        self.exitAction = 
> QtGui.QAction(QtGui.QIcon.fromTheme(u'application-exit'), self.tr('E&xit'), 
> self)
> +         self.addAction(self.exitAction)
> +-        self.aboutAction = 
> QtWidgets.QAction(QtGui.QIcon.fromTheme(u"help-about"), self.tr("&About"), 
> self)
> ++        self.aboutAction = 
> QtGui.QAction(QtGui.QIcon.fromTheme(u"help-about"), self.tr("&About"), self)
> +         self.addAction(self.aboutAction)
> + 
> +         # UI Tunning
> +@@ -689,7 +688,7 @@ class MainWindow(QtWidgets.QMainWindow):
> +                 u"Decode from file",
> +                 u"The file <b>%s</b> doesn't exist." %
> +                 os.path.abspath(fn),
> +-                QtWidgets.QMessageBox.Ok
> ++                QtWidgets.QMessageBox.StandardButton.Ok
> +             )
> +     
> +     def decodeFromMemory(self, image):
> +@@ -778,29 +777,29 @@ class MainWindow(QtWidgets.QMainWindow):
> +         }
> +         if action[qr.data_type] != u"":
> +             msgBox = QtWidgets.QMessageBox(
> +-                QtWidgets.QMessageBox.Question,
> ++                QtWidgets.QMessageBox.Icon.Question,
> +                 self.tr('Decode QRCode'),
> +                 msg[qr.data_type]() + action[qr.data_type],
> +-                QtWidgets.QMessageBox.No |
> +-                QtWidgets.QMessageBox.Yes,
> ++                QtWidgets.QMessageBox.StandardButton.No |
> ++                QtWidgets.QMessageBox.StandardButton.Yes,
> +                 self
> +                 )
> +-            msgBox.addButton(self.tr("&Edit"), 
> QtWidgets.QMessageBox.ApplyRole)
> +-            msgBox.setDefaultButton(QtWidgets.QMessageBox.Yes)
> +-            rsp = msgBox.exec_()
> ++            msgBox.addButton(self.tr("&Edit"), 
> QtWidgets.QMessageBox.ButtonRole.ApplyRole)
> ++            
> msgBox.setDefaultButton(QtWidgets.QMessageBox.StandardButton.Yes)
> ++            rsp = msgBox.exec()
> +         else:
> +             msgBox = QtWidgets.QMessageBox(
> +-                QtWidgets.QMessageBox.Information,
> ++                QtWidgets.QMessageBox.Icon.Information,
> +                 self.tr("Decode QRCode"),
> +                 msg[qr.data_type]() + action[qr.data_type],
> +-                QtWidgets.QMessageBox.Ok,
> ++                QtWidgets.QMessageBox.StandardButton.Ok,
> +                 self
> +                 )
> +-            msgBox.addButton(self.tr("&Edit"), 
> QtWidgets.QMessageBox.ApplyRole)
> +-            msgBox.setDefaultButton(QtWidgets.QMessageBox.Ok)
> +-            rsp = msgBox.exec_()
> ++            msgBox.addButton(self.tr("&Edit"), 
> QtWidgets.QMessageBox.ButtonRole.ApplyRole)
> ++            msgBox.setDefaultButton(QtWidgets.QMessageBox.StandardButton.Ok)
> ++            rsp = msgBox.exec()
> + 
> +-        if rsp == QtWidgets.QMessageBox.Yes:
> ++        if rsp == QtWidgets.QMessageBox.StandardButton.Yes:
> +             #Open Link
> +             if qr.data_type == 'email':
> +                 link = 'mailto:'+ data
> +@@ -814,7 +813,7 @@ class MainWindow(QtWidgets.QMainWindow):
> +                 link = qr.data_decode[qr.data_type](qr.data)
> +             print (u"Opening " + link)
> +             QtGui.QDesktopServices.openUrl(QtCore.QUrl(link))
> +-        elif rsp == 0:
> ++        elif rsp == 0 or rsp == 
> QtWidgets.QMessageBox.StandardButton.NoButton:
> +             #Edit the code
> +             data = qr.data_decode[qr.data_type](qr.data)
> +             try:
> +@@ -871,7 +870,7 @@ class MainWindow(QtWidgets.QMainWindow):
> +                 self.wifiSSIDEdit.setText(data[0] or "")
> +                 
> self.wifiEncryptionType.setCurrentIndex({u"WEP":0,u"WPA":1,u"nopass":2}.get(data[1])
>  or 0)
> +                 self.wifiPasswordEdit.setText(data[2] or "")
> +-                self.wifiHiddenNetwork.setCheckState(True if data[3] == 
> "true" else False)
> ++                self.wifiHiddenNetwork.setChecked(True if data[3] == "true" 
> else False)
> +                 self.tabs.setCurrentIndex(tabIndex)
> +             elif qr.data_type == 'sepa':
> +                 self.sepaNameEdit.setText(data.get('name')[0])
> +@@ -892,10 +891,18 @@ class MainWindow(QtWidgets.QMainWindow):
> +         vdDialog = VideoDevices()
> +         device_desc = vdDialog.videoDevice.currentText()
> +         if vdDialog.videoDevice.count() != 1:
> +-            d_res = vdDialog.exec_()
> +-            device_desc = {QDialog.Rejected: '', QDialog.Accepted: 
> vdDialog.videoDevice.currentText()}[d_res]
> +-        device = {device.description(): device.deviceName()
> +-                  for device in 
> QCameraInfo.availableCameras()}.get(device_desc, None)
> ++            d_res = vdDialog.exec()
> ++            device_desc = {
> ++                QtWidgets.QDialog.DialogCode.Rejected: '',
> ++                QtWidgets.QDialog.DialogCode.Accepted: 
> vdDialog.videoDevice.currentText(),
> ++            }[d_res]
> ++        device = {device.description(): device.id()
> ++                  for device in 
> QMediaDevices.videoInputs()}.get(device_desc, None)
> ++        if device and not isinstance(device, str):
> ++            try:
> ++                device = bytes(device).decode('utf-8', errors='ignore')
> ++            except Exception:
> ++                device = str(device)
> + 
> +         if device:
> +             qr = QR()
> +@@ -906,7 +913,7 @@ class MainWindow(QtWidgets.QMainWindow):
> +                         self,
> +                         self.tr("Webcam not availabled"),
> +                         self.tr("<p>Oops! failed to connect to the 
> webcam.<br /> Maybe your webcam is already busy in another application?</p>"),
> +-                        QtWidgets.QMessageBox.Ok
> ++                        QtWidgets.QMessageBox.StandardButton.Ok
> +                   )
> +                 return
> +             try:
> +@@ -916,7 +923,7 @@ class MainWindow(QtWidgets.QMainWindow):
> +                   self,
> +                   self.tr("Decoding Failed"),
> +                   self.tr(f"<p>oops! Your code seems to be of type 
> '{qr.data_type}', but no decoding for data '{qr.data}' could be found.</p>"),
> +-                  QtWidgets.QMessageBox.Ok
> ++                  QtWidgets.QMessageBox.StandardButton.Ok
> +                 )
> +             else:
> +                 if matchData == 'NULL':
> +@@ -924,7 +931,7 @@ class MainWindow(QtWidgets.QMainWindow):
> +                         self,
> +                         self.tr("Decoding Failed"),
> +                         self.tr("<p>Oops! no code was found.<br /> Maybe 
> your webcam didn't focus.</p>"),
> +-                        QtWidgets.QMessageBox.Ok
> ++                        QtWidgets.QMessageBox.StandardButton.Ok
> +                   )
> +                 else:
> +                     self.showInfo(qr)
> +@@ -966,9 +973,9 @@ class MainWindow(QtWidgets.QMainWindow):
> + 
> +     def toggleShowPassword(self, status):
> +         if status == 0:
> +-            self.wifiPasswordEdit.setEchoMode(QtWidgets.QLineEdit.Password)
> ++            
> self.wifiPasswordEdit.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
> +         elif status == 2:
> +-            self.wifiPasswordEdit.setEchoMode(QtWidgets.QLineEdit.Normal)
> ++            
> self.wifiPasswordEdit.setEchoMode(QtWidgets.QLineEdit.EchoMode.Normal)
> + 
> + 
> + class VideoDevices(QtWidgets.QDialog):
> +@@ -982,13 +989,16 @@ class VideoDevices(QtWidgets.QDialog):
> +         self.videoDevice = QtWidgets.QComboBox()
> +         self.label = QtWidgets.QLabel(self.tr("You are about to decode from 
> your webcam. Please put the code in front of your camera with a good light 
> source and keep it steady.\nQtQR will try to detect automatically the QR 
> Code.\n\nPlease select the video device you want to use for decoding:"))
> +         self.label.setWordWrap(True)
> +-        self.Buttons = 
> QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | 
> QtWidgets.QDialogButtonBox.Cancel)
> ++        self.Buttons = QtWidgets.QDialogButtonBox(
> ++            QtWidgets.QDialogButtonBox.StandardButton.Ok |
> ++            QtWidgets.QDialogButtonBox.StandardButton.Cancel
> ++        )
> +         self.Buttons.accepted.connect(self.accept)
> +         self.Buttons.rejected.connect(self.reject)
> +         self.layout = QtWidgets.QVBoxLayout()
> +         self.hlayout = QtWidgets.QHBoxLayout()
> +         self.vlayout = QtWidgets.QVBoxLayout()
> +-        self.hlayout.addWidget(self.icon, 0, QtCore.Qt.AlignTop)
> ++        self.hlayout.addWidget(self.icon, 0, 
> QtCore.Qt.AlignmentFlag.AlignTop)
> +         self.vlayout.addWidget(self.label)
> +         self.vlayout.addWidget(self.videoDevice)
> +         self.hlayout.addLayout(self.vlayout)
> +@@ -996,7 +1006,7 @@ class VideoDevices(QtWidgets.QDialog):
> +         self.layout.addStretch()
> +         self.layout.addWidget(self.Buttons)
> +         self.setLayout(self.layout)
> +-        self.videoDevice.addItems([info.description() for info in 
> QCameraInfo.availableCameras()])
> ++        self.videoDevice.addItems([info.description() for info in 
> QMediaDevices.videoInputs()])
> + 
> + 
> + if __name__ == '__main__':
> +@@ -1010,14 +1020,14 @@ if __name__ == '__main__':
> +         # "qtqr_" + locale))
> +     # We load from standard location the translations
> +     translator.load("qtqr_" + locale,
> +-                    QtCore.QLibraryInfo.location(
> +-                    QtCore.QLibraryInfo.TranslationsPath)
> ++                    QtCore.QLibraryInfo.path(
> ++                    QtCore.QLibraryInfo.LibraryPath.TranslationsPath)
> +                     )
> +     app.installTranslator(translator)    
> +     qtTranslator=QtCore.QTranslator()
> +     qtTranslator.load("qt_" + locale,
> +-                    QtCore.QLibraryInfo.location(
> +-                    QtCore.QLibraryInfo.TranslationsPath)
> ++                    QtCore.QLibraryInfo.path(
> ++                    QtCore.QLibraryInfo.LibraryPath.TranslationsPath)
> +                     )
> +     app.installTranslator(qtTranslator)
> + 
> +@@ -1031,4 +1041,4 @@ if __name__ == '__main__':
> +         for fn in sys.argv[1:]:
> +             # We should check if the file exists.
> +             mw.decodeFile(fn)
> +-    sys.exit(app.exec_())
> ++    sys.exit(app.exec())
> diff --git a/debian/patches/series b/debian/patches/series
> index 818836e..3f6fa6d 100644
> --- a/debian/patches/series
> +++ b/debian/patches/series
> @@ -1 +1,2 @@
>  fix-961503.patch
> +Port-from-PyQt5-to-PyQt6.patch
> diff --git a/debian/qtqr.install b/debian/qtqr.install
> index 40e08da..8193878 100644
> --- a/debian/qtqr.install
> +++ b/debian/qtqr.install
> @@ -1,2 +1,2 @@
> -*.qm usr/share/qt5/translations
> +*.qm usr/share/qt6/translations
>  debian/qtqr.desktop usr/share/applications
> diff --git a/debian/rules b/debian/rules
> index e760782..c62aa9a 100755
> --- a/debian/rules
> +++ b/debian/rules
> @@ -1,7 +1,5 @@
>  #!/usr/bin/make -f
>  
> -export QT_SELECT := 5
> -
>  %:
>       dh $@ --buildsystem=pybuild --with python3
>  
> @@ -9,7 +7,7 @@ ts = $(wildcard qtqr_*.ts)
>  qm = $(ts:ts=qm)
>  execute_after_dh_auto_build: $(qm)
>  $(qm): %.qm: %.ts
> -     lrelease -nounfinished $< -qm $@
> +     /usr/lib/qt6/bin/lrelease -nounfinished $< -qm $@
>  
>  execute_after_dh_auto_install:
>       install -m 644 qtqr.py  debian/qtqr/usr/bin/qtqr

Attachment: signature.asc
Description: PGP signature

Reply via email to