Skip to content
14 changes: 10 additions & 4 deletions python/plugins/grassprovider/Grass7Algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import uuid
import math
import importlib
from pathlib import Path

from qgis.PyQt.QtCore import QCoreApplication, QUrl

Expand Down Expand Up @@ -139,11 +140,16 @@ def __init__(self, descriptionfile):

# Use the ext mechanism
name = self.name().replace('.', '_')
self.module = None
try:
self.module = importlib.import_module(
'grassprovider.ext.{}'.format(name))
except ImportError:
self.module = None
extpath = Path(self.descriptionFile).parents[1].joinpath('ext', name + '.py')
# this check makes it a bit faster
if extpath.exists():
spec = importlib.util.spec_from_file_location('grassprovider.ext.' + name, extpath)
self.module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(self.module)
except Exception:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we avoid the broad exception here and catch specific ones instead?

Copy link
Contributor Author

@AlisterH AlisterH May 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any advice on what to catch, given that we're loading code written by the user?

  1. Maybe we just need to be more informative?:
        except Exception as e:
            QgsMessageLog.logMessage(self.tr('Failed to load: {0}\n{1}').format(extpath, str(e)), 'Processing', Qgis.Critical)
            pass
  1. Are you happy with pass rather than raise e? This means if someone has written a working algorithm description, in most cases it will be useable even if they are struggling with getting an ext module module they're writing to work.
  2. Should Qgis.Critical be downgraded? With the current pull request we get a Qgis.Critical Could not open GRASS GIS 7 algorithm:, with the exception, so I presume we should stick with Qgis.Critical

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with a QgsMessage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added that to the pull request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did wonder if we should add something like this, but it didn't seem right when we don't show a message even when we fail to load an algorithm:

            iface.messageBar().pushMessage("Warning", "GRASS algorithm " + self.name() + " failed to load ext module - see Processing log messages", 1)

pass

def createInstance(self):
return self.__class__(self.descriptionFile)
Expand Down
30 changes: 16 additions & 14 deletions python/plugins/grassprovider/Grass7AlgorithmProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@
from processing.core.ProcessingConfig import (ProcessingConfig, Setting)
from grassprovider.Grass7Utils import Grass7Utils
from grassprovider.Grass7Algorithm import Grass7Algorithm
from processing.tools.system import isWindows, isMac
from processing.tools.system import isWindows, isMac, mkdir


class Grass7AlgorithmProvider(QgsProcessingProvider):
descriptionFolder = Grass7Utils.grassDescriptionPath()
descriptionFolders = Grass7Utils.grassDescriptionFolders()
mkdir(descriptionFolders[0])

def __init__(self):
super().__init__()
Expand Down Expand Up @@ -86,18 +87,19 @@ def unload(self):

def createAlgsList(self):
algs = []
folder = self.descriptionFolder
for descriptionFile in os.listdir(folder):
if descriptionFile.endswith('txt'):
try:
alg = Grass7Algorithm(os.path.join(folder, descriptionFile))
if alg.name().strip() != '':
algs.append(alg)
else:
QgsMessageLog.logMessage(self.tr('Could not open GRASS GIS 7 algorithm: {0}').format(descriptionFile), self.tr('Processing'), Qgis.Critical)
except Exception as e:
QgsMessageLog.logMessage(
self.tr('Could not open GRASS GIS 7 algorithm: {0}\n{1}').format(descriptionFile, str(e)), self.tr('Processing'), Qgis.Critical)
folders = self.descriptionFolders
for folder in folders:
for descriptionFile in os.listdir(folder):
if descriptionFile.endswith('txt'):
try:
alg = Grass7Algorithm(os.path.join(folder, descriptionFile))
if alg.name().strip() != '':
algs.append(alg)
else:
QgsMessageLog.logMessage(self.tr('Could not open GRASS GIS 7 algorithm: {0}').format(descriptionFile), self.tr('Processing'), Qgis.Critical)
except Exception as e:
QgsMessageLog.logMessage(
self.tr('Could not open GRASS GIS 7 algorithm: {0}\n{1}').format(descriptionFile, str(e)), self.tr('Processing'), Qgis.Critical)
return algs

def loadAlgorithms(self):
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/grassprovider/Grass7Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,8 @@ def grassPath():
return folder or ''

@staticmethod
def grassDescriptionPath():
return os.path.join(os.path.dirname(__file__), 'description')
def grassDescriptionFolders():
return [os.path.join(userFolder(), 'grassaddons', 'description'), os.path.join(os.path.dirname(__file__), 'description')]

@staticmethod
def getWindowsCodePage():
Expand Down