Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding ci test #12

Merged
merged 20 commits into from
Aug 21, 2024
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: Python application

on:
push:
branches: ["main"]
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"
81 changes: 48 additions & 33 deletions a00_qpip/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import platform
import subprocess
import sys
from typing import List
from collections import defaultdict, namedtuple
from importlib import metadata

Expand All @@ -20,15 +21,18 @@
class Plugin:
"""QGIS Plugin Implementation."""

def __init__(self, iface):
def __init__(self, iface, test_path=None):
axelande marked this conversation as resolved.
Show resolved Hide resolved
self.iface = iface
self._defered_packages = []
self.settings = QgsSettings()
self.settings.beginGroup("QPIP")

self.plugins_path = os.path.join(
QgsApplication.qgisSettingsDirPath(), "python", "plugins"
)

if test_path is None:
self.plugins_path = os.path.join(
QgsApplication.qgisSettingsDirPath(), "python", "plugins"
)
else:
self.plugins_path = test_path
self.prefix_path = os.path.join(
QgsApplication.qgisSettingsDirPath().replace("/", os.path.sep),
"python",
Expand Down Expand Up @@ -70,9 +74,12 @@ def initGui(self):
def initComplete(self):
if self._defered_packages:
log(f"Initialization complete. Loading deferred packages")
self.check_deps_and_prompt_install(
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 Down Expand Up @@ -118,11 +125,14 @@ 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=[]) -> List[MainDialog, bool]:
m-kuhn marked this conversation as resolved.
Show resolved Hide resolved
"""
This checks dependencies for installed plugins and to-be installed plugins. If
anything is missing, shows a GUI to install them.
Expand Down Expand Up @@ -165,31 +175,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 +262,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
40 changes: 40 additions & 0 deletions tests/test_finding_req.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import os

import pytest
from pytest_qgis import qgis_iface

from PyQt5.QtCore import QSettings, QDate

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 = plugin.check_deps([plugin_a])
libs = dialog.reqs_to_install
assert len(libs) == 2
assert libs[0] == 'cowsay==4.0'


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