Skip to content

Commit

Permalink
Merge pull request #12 from axelande/adding_ci_test
Browse files Browse the repository at this point in the history
Adding ci test
  • Loading branch information
m-kuhn authored Aug 21, 2024
2 parents b14b4ca + 88bdc06 commit 8b289b4
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 35 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/test_plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: Run tests

on:
push:
pull_request:
branches:
- 'main'

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Pull qgis image
run: docker pull qgis/qgis:stable

- name: Pip install
run: |
docker run --name qgis_container --volume $(pwd):/app -w=/app qgis/qgis:stable sh -c "python3 -m pip install pytest-qgis --break-system-packages"
docker commit qgis_container qgis_with_deps
- name: Run tests
run: docker run --volume $(pwd):/app -w=/app qgis_with_deps sh -c "xvfb-run -s '+extension GLX -screen 0 1024x768x24' python3 -m pytest tests -s"
88 changes: 53 additions & 35 deletions a00_qpip/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@
class Plugin:
"""QGIS Plugin Implementation."""

def __init__(self, iface):
def __init__(self, iface, plugin_path=None):
self.iface = iface
self._defered_packages = []
self.settings = QgsSettings()
self.settings.beginGroup("QPIP")

self.plugins_path = os.path.join(
QgsApplication.qgisSettingsDirPath(), "python", "plugins"
)
if plugin_path is None:
self.plugins_path = os.path.join(
QgsApplication.qgisSettingsDirPath(), "python", "plugins"
)
else:
self.plugins_path = plugin_path
self.prefix_path = os.path.join(
QgsApplication.qgisSettingsDirPath().replace("/", os.path.sep),
"python",
Expand Down Expand Up @@ -70,9 +73,10 @@ def initGui(self):
def initComplete(self):
if self._defered_packages:
log(f"Initialization complete. Loading deferred packages")
self.check_deps_and_prompt_install(
additional_plugins=self._defered_packages
)
dialog, run_gui = self.check_deps(additional_plugins=self._defered_packages)
if run_gui:
self.promt_install(dialog)
self.save_settings(dialog)
self.start_packages(self._defered_packages)
self._defered_packages = []

Expand All @@ -91,7 +95,9 @@ def unload(self):
os.environ["PYTHONPATH"] = os.environ["PYTHONPATH"].replace(
self.bin_path + os.pathsep, ""
)
os.environ["PATH"] = os.environ["PATH"].replace(self.bin_path + os.pathsep, "")
os.environ["PATH"] = os.environ["PATH"].replace(
self.bin_path + os.pathsep, ""
)

def patched_load_plugin(self, packageName):
"""
Expand All @@ -118,14 +124,21 @@ def patched_load_plugin(self, packageName):
return self._original_loadPlugin(packageName)
else:
log(f"Check on install enabled, we check {packageName}.")
self.check_deps_and_prompt_install(additional_plugins=[packageName])
dialog, run_gui = self.check_deps(additional_plugins=[packageName])
if run_gui:
self.promt_install(dialog)
self.save_settings(dialog)
self.start_packages([packageName])
return True

def check_deps_and_prompt_install(self, additional_plugins=[], force_gui=False):
def check_deps(self, additional_plugins=[]) -> MainDialog | bool:
"""
This checks dependencies for installed plugins and to-be installed plugins. If
anything is missing, shows a GUI to install them.
The function returns:
- MainDialog, the QDialog object (without opening it)
- A bool if the dialog needs to be opened or not
"""

plugin_names = [*qgis.utils.active_plugins, *additional_plugins]
Expand Down Expand Up @@ -165,31 +178,34 @@ def check_deps_and_prompt_install(self, additional_plugins=[], force_gui=False):
req = Req(plugin_name, str(requirement), error)
libs[requirement.key].name = requirement.key
libs[requirement.key].required_by.append(req)
dialog = MainDialog(
libs.values(), self._check_on_startup(), self._check_on_install()
)
return dialog, needs_gui

def promt_install(self, dialog: MainDialog):
"""Promts the install dialog and ask the user what to install"""
if dialog.exec_():
reqs_to_uninstall = dialog.reqs_to_uninstall
if reqs_to_uninstall:
log(f"Will uninstall selected dependencies : {reqs_to_uninstall}")
self.pip_uninstall_reqs(reqs_to_uninstall)

reqs_to_install = dialog.reqs_to_install
if reqs_to_install:
log(f"Will install selected dependencies : {reqs_to_install}")
self.pip_install_reqs(reqs_to_install)

def save_settings(self, dialog):
"""Stores the settings values"""
sys.path_importer_cache.clear()

if force_gui or needs_gui:
dialog = MainDialog(
libs.values(), self._check_on_startup(), self._check_on_install()
)
if dialog.exec_():
reqs_to_uninstall = dialog.reqs_to_uninstall
if reqs_to_uninstall:
log(f"Will uninstall selected dependencies : {reqs_to_uninstall}")
self.pip_uninstall_reqs(reqs_to_uninstall)

reqs_to_install = dialog.reqs_to_install
if reqs_to_install:
log(f"Will install selected dependencies : {reqs_to_install}")
self.pip_install_reqs(reqs_to_install)

sys.path_importer_cache.clear()

# Save these even if the dialog was closed
self.settings.setValue(
"check_on_startup", "yes" if dialog.check_on_startup else "no"
)
self.settings.setValue(
"check_on_install", "yes" if dialog.check_on_install else "no"
)
self.settings.setValue(
"check_on_startup", "yes" if dialog.check_on_startup else "no"
)
self.settings.setValue(
"check_on_install", "yes" if dialog.check_on_install else "no"
)

def start_packages(self, packageNames):
"""
Expand Down Expand Up @@ -249,7 +265,9 @@ def pip_install_reqs(self, reqs_to_install):
)

def check(self):
self.check_deps_and_prompt_install(force_gui=True)
dialog, _ = self.check_deps()
self.promt_install(dialog)
self.save_settings(dialog)

def show_folder(self):
if platform.system() == "Windows":
Expand Down
43 changes: 43 additions & 0 deletions tests/test_finding_req.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import os

import pytest

from a00_qpip.plugin import Plugin


class initializationCompleted:
def connect(self):
pass


def popWidget():
return True


THIS_DIR = os.path.dirname(__file__)


@pytest.fixture()
def plugin(qgis_iface):
qgis_iface.initializationCompleted = initializationCompleted
qgis_iface.messageBar().popWidget = popWidget
plugin = Plugin(qgis_iface, ".")
yield plugin


def test_plugin_a(plugin: Plugin):
plugin_a = os.path.join(THIS_DIR, "..", "test_plugins", "plugin_a")
dialog, needs_gui = plugin.check_deps([plugin_a])
libs = dialog.reqs_to_install
assert len(libs) == 2
assert libs[0] == "cowsay==4.0"
assert needs_gui


def test_plugin_b(plugin: Plugin):
plugin_b = os.path.join(THIS_DIR, "..", "test_plugins", "plugin_b")
dialog, needs_gui = plugin.check_deps([plugin_b])
libs = dialog.reqs_to_install
assert len(libs) == 2
assert libs[0] == "cowsay==5.0"
assert needs_gui

0 comments on commit 8b289b4

Please sign in to comment.