PyQGIS Plugin – Fix ‘ModuleNotFoundError: No Module Named…’ in Python GUI for QGIS Plugin

pyqgisqt-designer

I am overhauling my QGIS plugin to work with QGIS 3.0.

I have hit a problem relating to the importing of custom forms created using the Qt Designer. In the old version (which worked, with QGIS 2.x) I had imports like this at the top of the main module:

import resources
from xyz_dialog import XYZDialog

Now, in both of the above cases, I get a ModuleNotFoundError (for instance "ModuleNotFoundError: No module named 'resources'").

The specific case of the 'resources' import is discussed in ModuleNotFoundError: No module named 'resources', although this does not reach much of a conclusion. The suggested workaround of using 'from resources import *' does not work for me (and I believe that the use of 'import *' is generally discouraged?).

As far as my form is concerned, I don't think I am doing anything differently from my previous implementation, which worked. There is a file called xyz_dialog.py in the plugin folder and it does contain a class called XYZDialog. So I am not sure why it should not be found.

Further specifics (referring to a different form, but the issues are exactly the same as above):

In the main .py module I have this:

from ais import AISForm

I have got a corresponding form, with these files:
ais.py
ais.ui

ais.py contains the following:

import os

from PyQt5 import uic
from PyQt5 import QtWidgets

FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'ais.ui'))


class AISForm(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(AISForm, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)

If I take out the line 'from ais import AISForm' from the plugin code, it loads.

If I leave it in, it does not load due to the error "ModuleNotFoundError: No module named 'ais'"

(I have taken out, for now, 'import resources'. I don't see that I need it, and it causes the same ModuleNotFoundError as the form imports.)

Best Answer

Is there a file called resources.py? This is probably generated from a resources.qrc file by a rule in your Makefile, if that tries to use pyrcc4 it will fail on QGIS 3 because it uses Qt 5.

https://github.com/webgeodatavore/bivariate_legend/blob/master/Makefile uses pyrcc5 to build its resources.py (I just picked a random QGIS 3 plugin - perhaps you should see what the QGIS 3 plugin builder template does).

I think you might do best to start with a fresh QGIS3 plugin created by the plugin builder and then add your Q2 plugin code to it, fixing breaks as they happen.

So the plugin builder creates fnord_dialog.py, which looks like this:

import os

from PyQt5 import uic
from PyQt5 import QtWidgets

FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'fnord_dialog_base.ui'))


class FnordDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(FnordDialog, self).__init__(parent)
        self.setupUi(self)

and that loads the .ui file from the designer. No need to build the python version of the ui file with this method.

Related Question