2

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.)

  • If you create a file foo.py with a Bar class definition in it, and in main.py do from foo import Bar (before the current failing import), does that fail also? Basically, is the UI code special or is this a module search path error that applies to anything? – Spacedman May 1 '18 at 11:09
  • Problem now resolved. Many thanks for your input. Seems that a relative path was required. – wotnot May 3 '18 at 13:08
2

In your case you need to use relative path instead of absolute path. Assuming that ais is present in same directory as main.py you need to change

from ais import AISForm

to

from .ais import AISForm

Hope this answers your question.

  • This does resolve the problem. :-) Thank you. (I don't understand the reason for the difference, though. Why was the dot required in the QGIS3 version but not in the QGIS2 version?? File names and locations are the same in both cases.) – wotnot May 3 '18 at 13:05
  • This has only to do with differences between python 2.x and python 3.x. – Asad Abbas May 4 '18 at 2:32
4

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.

  • There is, yes. I have used pyrcc5. I used 'pyrcc5 -o resources.py resources.qrc' in a batch file as per gis.stackexchange.com/questions/274548/… – wotnot Apr 30 '18 at 12:56
  • I don't think I need resources.py anyway. What I do need are my forms. – wotnot Apr 30 '18 at 13:15
  • Are your forms in a .ui file from the designer? Then you need to convert that to .py with uic foo.ui > foo.py or have a rule that does that in a Makefile. – Spacedman Apr 30 '18 at 17:56
  • Thanks for your help Spacedman, which is much appreciated. Your suggestion of starting with a fresh QGIS3 plugin is exactly what I am doing. I created a new plugin from scratch using the plugin builder, removed anything I didn't want and started adding content from my QGIS2 plugin. Now I am at the point of needing forms. Initially I just copied them across, but as you point out I need to modify some of the code in the form's .py file to be compatible for the new API. I have now done this, and my code matches your snippet above. However, result is still the same. ModuleNotFoundError. – wotnot Apr 30 '18 at 22:26
  • I'm not sure we can get any further without seeing your plugin code. Must be something subtle we're both missing. – Spacedman May 1 '18 at 7:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.