Skip to content

Commit

Permalink
[FEATURE][needs-docs] Add new @alg decorator for nicer python process…
Browse files Browse the repository at this point in the history
…ing scripts. (#8586)

@alg()
@alg.help()
@alg.input()
@alg.output()
  • Loading branch information
NathanW2 committed Dec 10, 2018
1 parent d136e92 commit 87d2da1
Show file tree
Hide file tree
Showing 12 changed files with 778 additions and 40 deletions.
1 change: 1 addition & 0 deletions python/CMakeLists.txt
Expand Up @@ -66,6 +66,7 @@ ENDIF ()
ADD_SUBDIRECTORY(PyQt)
ADD_SUBDIRECTORY(ext-libs)
ADD_SUBDIRECTORY(testing)
ADD_SUBDIRECTORY(processing)

INCLUDE_DIRECTORIES(SYSTEM
${PYTHON_INCLUDE_PATH}
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/script/DeleteScriptAction.py
Expand Up @@ -52,7 +52,7 @@ def execute(self):
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
filePath = ScriptUtils.findAlgorithmSource(self.itemData.__class__.__name__)
filePath = ScriptUtils.findAlgorithmSource(self.itemData.name())
if filePath is not None:
os.remove(filePath)
QgsApplication.processingRegistry().providerById("script").refreshAlgorithms()
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/script/EditScriptAction.py
Expand Up @@ -27,7 +27,7 @@

import inspect

from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingAlgorithm, QgsMessageLog
from qgis.utils import iface
from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtWidgets import QMessageBox
Expand All @@ -47,7 +47,7 @@ def isEnabled(self):
return isinstance(self.itemData, QgsProcessingAlgorithm) and self.itemData.provider().id() == "script"

def execute(self):
filePath = ScriptUtils.findAlgorithmSource(self.itemData.__class__.__name__)
filePath = ScriptUtils.findAlgorithmSource(self.itemData.name())
if filePath is not None:
dlg = ScriptEditorDialog(filePath, iface.mainWindow())
dlg.show()
Expand Down
16 changes: 10 additions & 6 deletions python/plugins/processing/script/ScriptEditorDialog.py
Expand Up @@ -44,6 +44,7 @@
QgsProcessingAlgorithm,
QgsProcessingFeatureBasedAlgorithm)
from qgis.utils import iface, OverrideCursor
from qgis.processing import alg as algfactory

from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.script import ScriptUtils
Expand Down Expand Up @@ -222,9 +223,9 @@ def setHasChanged(self, hasChanged):
self.update_dialog_title()

def runAlgorithm(self):
d = {}
_locals = {}
try:
exec(self.editor.text(), d)
exec(self.editor.text(), _locals)
except Exception as e:
error = QgsError(traceback.format_exc(), "Processing")
QgsErrorDialog.show(error,
Expand All @@ -233,10 +234,13 @@ def runAlgorithm(self):
return

alg = None
for k, v in d.items():
if inspect.isclass(v) and issubclass(v, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and v.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"):
alg = v()
break
try:
alg = algfactory.instances.pop().createInstance()
except IndexError:
for name, attr in _locals.items():
if inspect.isclass(attr) and issubclass(attr, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and attr.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"):
alg = attr()
break

if alg is None:
QMessageBox.warning(self,
Expand Down
21 changes: 14 additions & 7 deletions python/plugins/processing/script/ScriptUtils.py
Expand Up @@ -25,6 +25,7 @@

__revision__ = '$Format:%H$'

from qgis.processing import alg as algfactory
import os
import inspect
import importlib
Expand Down Expand Up @@ -66,20 +67,26 @@ def loadAlgorithm(moduleName, filePath):
spec = importlib.util.spec_from_file_location(moduleName, filePath)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
for x in dir(module):
obj = getattr(module, x)
if inspect.isclass(obj) and issubclass(obj, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and obj.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"):
scriptsRegistry[x] = filePath
return obj()
try:
alg = algfactory.instances.pop().createInstance()
scriptsRegistry[alg.name()] = filePath
return alg
except IndexError:
for x in dir(module):
obj = getattr(module, x)
if inspect.isclass(obj) and issubclass(obj, (QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm)) and obj.__name__ not in ("QgsProcessingAlgorithm", "QgsProcessingFeatureBasedAlgorithm"):
o = obj()
scriptsRegistry[o.name()] = filePath
return o
except ImportError as e:
QgsMessageLog.logMessage(QCoreApplication.translate("ScriptUtils", "Could not import script algorithm '{}' from '{}'\n{}").format(moduleName, filePath, str(e)),
QCoreApplication.translate("ScriptUtils", "Processing"),
Qgis.Critical)


def findAlgorithmSource(className):
def findAlgorithmSource(name):
global scriptsRegistry
try:
return scriptsRegistry[className]
return scriptsRegistry[name]
except:
return None
25 changes: 25 additions & 0 deletions python/processing/CMakeLists.txt
@@ -0,0 +1,25 @@
# See ../CMakeLists.txt for info on staged-plugins* and clean-staged-plugins targets

SET(QGIS_PYTHON_DIR ${PYTHON_SITE_PACKAGES_DIR}/qgis)
SET (PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python)
SET (NAME processing)

SET(PY_FILES
__init__.py
algfactory.py
)

FILE (MAKE_DIRECTORY ${QGIS_PYTHON_OUTPUT_DIRECTORY}/${NAME})
INSTALL(FILES ${PY_FILES} DESTINATION "${QGIS_PYTHON_DIR}/${NAME}")

ADD_CUSTOM_TARGET(py${NAME} ALL)
# stage to output to make available when QGIS is run from build directory
FOREACH(pyfile ${PY_FILES})
ADD_CUSTOM_COMMAND(TARGET py${NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${pyfile} "${QGIS_PYTHON_OUTPUT_DIRECTORY}/${NAME}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${pyfile}
)
PY_COMPILE(pyutils "${QGIS_PYTHON_OUTPUT_DIRECTORY}/${NAME}/${pyfile}")
ENDFOREACH(pyfile)
28 changes: 28 additions & 0 deletions python/processing/__init__.py
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
__init__.py
---------------------
Date : November 2018
Copyright : (C) 2018 by Nathan Woodrow
Email : woodrow dot nathan at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""

__author__ = 'Nathan Woodrow'
__date__ = 'November 2018'
__copyright__ = '(C) 2018, Nathan Woodrow'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

from .algfactory import ProcessingAlgFactory

alg = ProcessingAlgFactory()

0 comments on commit 87d2da1

Please sign in to comment.