I am writing a QGIS plugin. During early development, I wrote and tested the Qt GUI application independently of QGIS. I made use of absolute imports, and everything worked fine.
Then, I had to adapt everything to the quirks of QGIS. I can't explain why and haven't been able to find any supporting documentation, but nonetheless: apparently, QGIS needs or strongly prefers relative imports. The majority of other plugins I've looked at (completely anecdotal of course) have all used a flat plugin directory and relative imports.
My team decided to keep the hierarchical structure. The plugin now works in QGIS, with the same hierarchical structure, using relative imports.
My goal: I would like to still be able to run the GUI independently of QGIS, as it does not (yet) depend on any aspects of QGIS. With the relative imports, this is completely broken.
My project directory has the following hierarchy:
.
├── app
│ └── main.py
├── __init__.py
├── justfile
├── metadata.txt
├── plugin.py
├── README.md
├── resources
│ ├── name_resolver.py
│ └── response_codes.py
├── processing
│ ├── B_processor.py
│ ├── A_processor.py
│ ├── processor_core.py
│ ├── processor_interface.py
│ ├── processor_query_ui.py
│ └── processor_query_ui.ui
└── tests
├── __init__.py
├── test_A_processor.py
└── test_processor_core.py
The app directory and its main.py module are where I'm trying to run the GUI independently of QGIS. The GUI is in processing/processor_query_ui.py.
app/main.py is as follows:
if __name__ == "__main__":
import sys
from PyQt5 import QtWidgets
from processing.processor_query_ui import UI_DataFinderUI
app = QtWidgets.QApplication(sys.argv)
ui = UI_DataFinderUI()
ui.show()
sys.exit(app.exec_())
When running main from the top level, all imports within main.py work:
$ python app/main.py
What does NOT work are the subsequent imports:
Traceback (most recent call last):
File "/path/to/app/main.py", line 4, in <module>
from processing.processor_query_ui import UI_DataFinderUI
File "/path/to/processing/processor_query_ui.py", line 2, in <module>
from .A_processor import Aprocessor
File "/path/to/processing/A_processor.py", line 5, in <module>
from ..resources.response_codes import RESPONSE_CODES
ImportError: attempted relative import beyond top-level package
This shows that all imports in main.py are working correctly. But when processor_query_ui tries to do its imports, those ones fail.
I have tried adding __init__.py files to all first level directories as well (e.g. {app,resources,processing}/__init__.py) to no vail. Running python -m app/main{.py} doesn't work, though I didn't really expect it to.
For pytest to work, the tests directory must have an init.py file; then, pytest works as either pytest or python -m pytest.
My goal is to be able to run the GUI in processing/processor_query_ui.py as a standalone app, by writing some kind of adaptor such that I do not have to change the current directory structure or relative imports (which, as above, make QGIS happy).
Any advice is greatly appreciated.