Skip to content

Commit 422d804

Browse files
committed
[processing] update script provider to use QgsProcessingAlgorithm
subclasses instead of custom script code
1 parent aee3b44 commit 422d804

File tree

6 files changed

+92
-89
lines changed

6 files changed

+92
-89
lines changed

python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from qgis.core import (QgsApplication,
3737
QgsProcessingProvider)
3838

39-
from processing.script.ScriptUtils import ScriptUtils
39+
from processing.script import ScriptUtils
4040

4141
from .QgisAlgorithm import QgisAlgorithm
4242

@@ -288,11 +288,11 @@ def getAlgs(self):
288288
VectorLayerScatterplot3D()])
289289

290290
# to store algs added by 3rd party plugins as scripts
291-
folder = os.path.join(os.path.dirname(__file__), 'scripts')
292-
scripts = ScriptUtils.loadFromFolder(folder)
293-
for script in scripts:
294-
script.allowEdit = False
295-
algs.extend(scripts)
291+
#folder = os.path.join(os.path.dirname(__file__), 'scripts')
292+
#scripts = ScriptUtils.loadFromFolder(folder)
293+
#for script in scripts:
294+
# script.allowEdit = False
295+
#algs.extend(scripts)
296296

297297
return algs
298298

python/plugins/processing/core/Processing.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@
4545
QgsProcessingOutputMapLayer)
4646

4747
import processing
48-
from processing.script.ScriptUtils import ScriptUtils
4948
from processing.core.ProcessingConfig import ProcessingConfig
5049
from processing.gui.MessageBarProgress import MessageBarProgress
5150
from processing.gui.RenderingStyles import RenderingStyles
5251
from processing.gui.Postprocessing import handleAlgorithmResults
5352
from processing.gui.AlgorithmExecutor import execute
53+
from processing.script import ScriptUtils
5454
from processing.tools import dataobjects
5555

5656
from processing.algs.qgis.QgisAlgorithmProvider import QgisAlgorithmProvider # NOQA
@@ -105,25 +105,25 @@ def deinitialize():
105105

106106
@staticmethod
107107
def addScripts(folder):
108-
Processing.initialize()
109-
provider = QgsApplication.processingRegistry().providerById("qgis")
110-
scripts = ScriptUtils.loadFromFolder(folder)
111-
# fix_print_with_import
112-
print(scripts)
113-
for script in scripts:
114-
script.allowEdit = False
115-
script._icon = provider.icon()
116-
provider.externalAlgs.extend(scripts)
117-
provider.refreshAlgorithms()
108+
#Processing.initialize()
109+
#provider = QgsApplication.processingRegistry().providerById("qgis")
110+
#scripts = ScriptUtils.loadFromFolder(folder)
111+
#for script in scripts:
112+
# script.allowEdit = False
113+
# script._icon = provider.icon()
114+
#provider.externalAlgs.extend(scripts)
115+
#provider.refreshAlgorithms()
116+
pass
118117

119118
@staticmethod
120119
def removeScripts(folder):
121-
provider = QgsApplication.processingRegistry().providerById("qgis")
122-
for alg in provider.externalAlgs[::-1]:
123-
path = os.path.dirname(alg.descriptionFile)
124-
if path == folder:
125-
provider.externalAlgs.remove(alg)
126-
provider.refreshAlgorithms()
120+
#provider = QgsApplication.processingRegistry().providerById("qgis")
121+
#for alg in provider.externalAlgs[::-1]:
122+
# path = os.path.dirname(alg.descriptionFile)
123+
# if path == folder:
124+
# provider.externalAlgs.remove(alg)
125+
#provider.refreshAlgorithms()
126+
pass
127127

128128
@staticmethod
129129
def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=None):

python/plugins/processing/script/AddScriptFromFileAction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
from processing.script.ScriptAlgorithm import ScriptAlgorithm
3838
from processing.script.WrongScriptException import WrongScriptException
39-
from processing.script.ScriptUtils import ScriptUtils
39+
from processing.script import ScriptUtils
4040

4141
pluginPath = os.path.split(os.path.dirname(__file__))[0]
4242

python/plugins/processing/script/ScriptAlgorithmProvider.py

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
QgsProcessingProvider)
3232

3333
from processing.core.ProcessingConfig import ProcessingConfig, Setting
34+
3435
from processing.gui.ProviderActions import (ProviderActions,
3536
ProviderContextMenuActions)
3637

@@ -39,9 +40,7 @@
3940
from processing.script.DeleteScriptAction import DeleteScriptAction
4041
from processing.script.EditScriptAction import EditScriptAction
4142
from processing.script.CreateScriptCollectionPluginAction import CreateScriptCollectionPluginAction
42-
from processing.script.ScriptUtils import ScriptUtils
43-
44-
pluginPath = os.path.split(os.path.dirname(__file__))[0]
43+
from processing.script import ScriptUtils
4544

4645

4746
class ScriptAlgorithmProvider(QgsProcessingProvider):
@@ -59,17 +58,22 @@ def __init__(self):
5958
def load(self):
6059
ProcessingConfig.settingIcons[self.name()] = self.icon()
6160
ProcessingConfig.addSetting(Setting(self.name(),
62-
ScriptUtils.SCRIPTS_FOLDER,
63-
self.tr('Scripts folder', 'ScriptAlgorithmProvider'),
64-
ScriptUtils.defaultScriptsFolder(), valuetype=Setting.MULTIPLE_FOLDERS))
61+
ScriptUtils.SCRIPTS_FOLDERS,
62+
self.tr("Scripts folder(s)"),
63+
ScriptUtils.defaultScriptsFolder(),
64+
valuetype=Setting.MULTIPLE_FOLDERS))
65+
6566
ProviderActions.registerProviderActions(self, self.actions)
6667
ProviderContextMenuActions.registerProviderContextMenuActions(self.contextMenuActions)
68+
6769
ProcessingConfig.readSettings()
6870
self.refreshAlgorithms()
71+
6972
return True
7073

7174
def unload(self):
72-
ProcessingConfig.removeSetting(ScriptUtils.SCRIPTS_FOLDER)
75+
ProcessingConfig.removeSetting(ScriptUtils.SCRIPTS_FOLDERS)
76+
7377
ProviderActions.deregisterProviderActions(self)
7478
ProviderContextMenuActions.deregisterProviderContextMenuActions(self.contextMenuActions)
7579

@@ -80,26 +84,30 @@ def svgIconPath(self):
8084
return QgsApplication.iconPath("processingScript.svg")
8185

8286
def id(self):
83-
return 'script'
87+
return "script"
8488

8589
def name(self):
86-
return self.tr('Scripts', 'ScriptAlgorithmProvider')
87-
88-
def loadAlgorithms(self):
89-
self.algs = []
90-
folders = ScriptUtils.scriptsFolders()
91-
for f in folders:
92-
self.algs.extend(ScriptUtils.loadFromFolder(f))
93-
self.algs.extend(self.folder_algorithms)
94-
for a in self.algs:
95-
self.addAlgorithm(a)
96-
97-
def addAlgorithmsFromFolder(self, folder):
98-
self.folder_algorithms.extend(ScriptUtils.loadFromFolder(folder))
90+
return self.tr("Scripts")
9991

10092
def supportsNonFileBasedOutput(self):
10193
# TODO - this may not be strictly true. We probably need a way for scripts
10294
# to indicate whether individual outputs support non-file based outputs,
10395
# but for now allow it. At best we expose nice features to users, at worst
10496
# they'll get an error if they use them with incompatible outputs...
10597
return True
98+
99+
def loadAlgorithms(self):
100+
self.algs = []
101+
folders = ScriptUtils.scriptsFolders()
102+
for folder in folders:
103+
items = os.scandir(folder)
104+
for entry in items:
105+
if entry.name.lower().endswith("py") and entry.is_file():
106+
algName = os.path.splitext(entry.name)[0]
107+
filePath = os.path.abspath(os.path.join(folder, entry.name))
108+
alg = ScriptUtils.loadAlgorithm(algName, filePath)
109+
if alg is not None:
110+
self.algs.append(alg)
111+
112+
for a in self.algs:
113+
self.addAlgorithm(a)

python/plugins/processing/script/ScriptEditorDialog.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
from processing.gui.HelpEditionDialog import HelpEditionDialog
4545

4646
from processing.script.ScriptAlgorithm import ScriptAlgorithm
47-
from processing.script.ScriptUtils import ScriptUtils
47+
from processing.script import ScriptUtils
4848

4949
pluginPath = os.path.split(os.path.dirname(__file__))[0]
5050
WIDGET, BASE = uic.loadUiType(

python/plugins/processing/script/ScriptUtils.py

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,53 +26,48 @@
2626
__revision__ = '$Format:%H$'
2727

2828
import os
29-
from qgis.core import (QgsProcessingUtils,
30-
QgsMessageLog)
29+
import inspect
30+
import importlib
31+
32+
from qgis.PyQt.QtCore import QCoreApplication
33+
34+
from qgis.core import QgsProcessingAlgorithm, QgsMessageLog
35+
3136
from processing.core.ProcessingConfig import ProcessingConfig
37+
3238
from processing.script.ScriptAlgorithm import ScriptAlgorithm
3339
from processing.script.WrongScriptException import WrongScriptException
40+
3441
from processing.tools.system import mkdir, userFolder
3542

36-
from qgis.PyQt.QtCore import QCoreApplication
43+
44+
SCRIPTS_FOLDERS = "SCRIPTS_FOLDERS"
45+
46+
47+
def defaultScriptsFolder():
48+
folder = str(os.path.join(userFolder(), "scripts"))
49+
mkdir(folder)
50+
return os.path.abspath(folder)
51+
52+
53+
def scriptsFolders():
54+
folder = ProcessingConfig.getSetting(SCRIPTS_FOLDERS)
55+
if folder is not None:
56+
return folder.split(";")
57+
else:
58+
return [ScriptUtils.defaultScriptsFolder()]
3759

3860

39-
class ScriptUtils:
40-
41-
SCRIPTS_FOLDER = 'SCRIPTS_FOLDER'
42-
43-
@staticmethod
44-
def defaultScriptsFolder():
45-
folder = str(os.path.join(userFolder(), 'scripts'))
46-
mkdir(folder)
47-
return os.path.abspath(folder)
48-
49-
@staticmethod
50-
def scriptsFolders():
51-
folder = ProcessingConfig.getSetting(ScriptUtils.SCRIPTS_FOLDER)
52-
if folder is not None:
53-
return folder.split(';')
54-
else:
55-
return [ScriptUtils.defaultScriptsFolder()]
56-
57-
@staticmethod
58-
def loadFromFolder(folder):
59-
if not os.path.exists(folder):
60-
return []
61-
algs = []
62-
for path, subdirs, files in os.walk(folder):
63-
for descriptionFile in files:
64-
if descriptionFile.endswith('py'):
65-
try:
66-
fullpath = os.path.join(path, descriptionFile)
67-
alg = ScriptAlgorithm(fullpath)
68-
if alg.name().strip() != '':
69-
algs.append(alg)
70-
except WrongScriptException as e:
71-
QgsMessageLog.logMessage(e.msg, QCoreApplication.translate('Processing', 'Processing'), QgsMessageLog.CRITICAL)
72-
except Exception as e:
73-
QgsMessageLog.logMessage(
74-
QCoreApplication.translate('Processing', 'Could not load script: {0}\n{1}').format(descriptionFile, str(e)),
75-
QCoreApplication.translate('Processing', 'Processing'),
76-
QgsMessageLog.CRITICAL
77-
)
78-
return algs
61+
def loadAlgorithm(moduleName, filePath):
62+
try:
63+
spec = importlib.util.spec_from_file_location(moduleName, filePath)
64+
module = importlib.util.module_from_spec(spec)
65+
spec.loader.exec_module(module)
66+
for x in dir(module):
67+
obj = getattr(module, x)
68+
if inspect.isclass(obj) and issubclass(obj, QgsProcessingAlgorithm) and obj.__name__ == moduleName:
69+
return obj()
70+
except ImportError as e:
71+
QgsMessageLog.logMessage("Could not import script algorithm '{}' from '{}'\n{}".format(moduleName, filePath, str(e)),
72+
"Processing",
73+
QgsMessageLog.CRITICAL)

0 commit comments

Comments
 (0)