How to fix missing resource imports when using pyside2-uic

1.3k views Asked by At

The tool offers no help whatsoever what the argument does and a colleague of mine is facing the issue of having to add the Python module generated by processing a QRC file (pyside2-rcc) to the Python module generated by processing the UI file (pyside2-uic) that includes items from the QRC file.

In C++ with CMake I don't have such an issue so I'm confused as to what needs to be done. The unknown --from-imports appears to be promising but I can't find information on how to use it.

Here is the Python code generated for the UI file:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file '.\VideoPreview.ui',
# licensing of '.\VideoPreview.ui' applies.
#
# Created: Mon May 23 10:19:15 2022
#      by: pyside2-uic  running on PySide2 5.13.2
#
# WARNING! All changes made in this file will be lost!

from PySide2 import QtCore, QtGui, QtWidgets

class Ui_w_video_preview(object):
    def setupUi(self, w_video_preview):
        w_video_preview.setObjectName("w_video_preview")
        w_video_preview.resize(614, 406)

        ...

        self.btn_open = QtWidgets.QPushButton(w_video_preview)
        self.btn_open.setText("")
        icon4 = QtGui.QIcon()
        icon4.addPixmap(QtGui.QPixmap(":/images/VideoPreviewButtons/open_button.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.btn_open.setIcon(icon4)
        ...

        self.retranslateUi(w_video_preview)
        QtCore.QMetaObject.connectSlotsByName(w_video_preview)

    def retranslateUi(self, w_video_preview):
        ...

from PySide2.QtMultimediaWidgets import QVideoWidget

# FOLLOWING WAS ADDED MANUALLY
from resources.icons import buttons_rc

I've excluded most of the code (since it's pretty generic) and left one example for a QPushButton that uses an icon provided by a QRC file. The code above reported missing buttons_rc when used like this

...
from widgets.views.VideoPreviewGenerated import Ui_w_video_preview
...

class VideoPreview(QWidget):

    def __init__(self):
        super(VideoPreview, self).__init__()
        self.ui = Ui_w_video_preview()
        self.ui.setupUi(self)
        ...

so the line

from resources.icons import buttons_rc

was added manually to the end of the UI generated Python code.

The generated Python code for the QRC file respectively looks like this:

# -*- coding: utf-8 -*-

# Resource object code
#
# Created: Mo Mai 23 10:18:59 2022
#      by: The Resource Compiler for PySide2 (Qt v5.12.9)
#
# WARNING! All changes made in this file will be lost!

from PySide2 import QtCore

qt_resource_data = b"\
...
"

def qInitResources():
    QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)

def qCleanupResources():
    QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)

qInitResources()

The UI form file contains the reference to the QRC item like this:

 <widget class="QPushButton" name="btn_open">
  <property name="text">
  <string/>
  </property>
  <property name="icon">
  <iconset resource="../../resources/icons/buttons.qrc">
    <normaloff>:/images/VideoPreviewButtons/open_button.png</normaloff>:/images/VideoPreviewButtons/open_button.png</iconset>
  </property>
  <property name="iconSize">
  <size>
    <width>100</width>
    <height>10</height>
  </size>
  </property>
</widget>

The QRC file is also referenced by the UI form file:

<resources>
  <include location="../../resources/icons/buttons.qrc"/>
</resources>

Is this intentional that I need to manually add QRC sources as imports or is there a way to automate it?


NOTE: uic at least for PySide2 (Qt5.x) does not offer a Python generator. I'm using the latest conda package (from Anaconda's code-forge channel).

1

There are 1 answers

0
ekhumoro On

As stated in the comments, pyside2-uic and pyside2-rcc were removed in version 5.14 when Python support was added to the Qt5 uic and rcc tools. However, this won't help anyone developing on a platform where the latest versions of Qt5/PySide2 aren't available.

From the output shown in the question, the generated modules were produced using version 5.13.2 of PySide2 and version 5.12.9 of Qt5. Looking at the conda-forge packages, it would seem the testing was done on Windows, since that is the most recent Qt version available for that platform. Needless to say, the Qt-5.12.9 uic/rcc tools don't have support for Python, so another solution will be required.

After setting up a venv with Python-3.9 and PySide-5.13.2, and then attempting to compile a ui file with resources, I see this output (when using the --debug option):

$ pyside2-uic --debug test.ui
Traceback (most recent call last):
  File "/home/foo/.venv/pyside513/lib/python3.9/site-packages/pyside2uic/port_v3/invoke.py", line 34, in invoke
    exit_status = driver.invoke()
  File "/home/foo/.venv/pyside513/lib/python3.9/site-packages/pyside2uic/driver.py", line 60, in invoke
    self._generate()
  File "/home/foo/.venv/pyside513/lib/python3.9/site-packages/pyside2uic/driver.py", line 95, in _generate
    compileUi(self._ui_file, pyfile, self._opts.execute, self._opts.indent, self._opts.from_imports)
  File "/home/foo/.venv/pyside513/lib/python3.9/site-packages/pyside2uic/__init__.py", line 144, in compileUi
    winfo = ui_comp.compileUi(uifile, pyfile, from_imports)
  File "/home/foo/.venv/pyside513/lib/python3.9/site-packages/pyside2uic/Compiler/compiler.py", line 91, in compileUi
    w = self.parse(input_stream)
  File "/home/foo/.venv/pyside513/lib/python3.9/site-packages/pyside2uic/uiparser.py", line 882, in parse
    actor(elem)
  File "/home/foo/.venv/pyside513/lib/python3.9/site-packages/pyside2uic/uiparser.py", line 797, in readResources
    for include in elem.getiterator("include"):
AttributeError: 'xml.etree.ElementTree.Element' object has no attribute 'getiterator'
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'test.ui',
# licensing of 'test.ui' applies.
#
# Created: Sat Jun  4 13:13:37 2022
#      by: pyside2-uic  running on PySide2 5.13.2
#
# WARNING! All changes made in this file will be lost!

from PySide2 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.toolButton = QtWidgets.QToolButton(Form)
        self.toolButton.setGeometry(QtCore.QRect(101, 82, 28, 25))
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/python.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.toolButton.setIcon(icon)
        self.toolButton.setObjectName("toolButton")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

So the required import line is missing due to an error resulting from the use of getiterator (which was deprecated and then removed in Python-3.9). This suggests a couple of solutions:

  1. Downgrade to Python-3.8. I tried this in a venv, and it produces the correct output without error (i.e. the relevant import line is appended to the end of the generated module).

  2. Keep the existing setup, but patch the currently installed PySide uic tool. Fortunately, there's only a single use of the deprecated method, so it's simply a matter of locating the file site-packages/pyside2uic/uiparser.py on your system, and then replacing line 797:

    for include in elem.getiterator("include"):
    

    with this:

    for include in elem.iter("include"):
    

    This change is enough to ensure the correct output is generated.