Changed how postexecution errors are handled in algorithms caling external apps

Improved R error messages
This commit is contained in:
Victor Olaya 2013-07-18 17:16:16 +02:00
parent 765ac75f78
commit 7a73307a2b
10 changed files with 117 additions and 83 deletions

View File

@ -83,23 +83,7 @@ class AlgorithmProvider():
def getDescription(self):
'''Returns the full name of the provider'''
return "Generic algorithm provider"
def getPostProcessingErrorMessage(self, wrongLayers):
'''Returns the message to be shown to the user when after running an algorithm for this provider,
there is a problem loading the resulting layer.
This method should analyze if the problem is caused by wrong entry data, a wrong or missing
installation of a required 3rd party app, or any other cause, and create an error response accordingly.
Message is provided as an HTML code that will be displayed to the user, and which might contains
links to installation paths for missing 3rd party apps.
- wrongLayers: a list of Output objects that could not be loaded.'''
html ="<p>Oooops! SEXTANTE could not open the following output layers</p><ul>\n"
for layer in wrongLayers:
html += '<li>' + layer.description + ': <font size=3 face="Courier New" color="ff0000">' + layer.value + "</font></li>\n"
html +="</ul><p>The above files could not be opened, which probably indicates that they were not correctly produced by the executed algorithm</p>"
html +="<p>Checking the log information might help you see why those layers were not created as expected</p>"
return html
return "Generic algorithm provider"
def getIcon(self):
return QtGui.QIcon(os.path.dirname(__file__) + "/../images/alg.png")

View File

@ -408,5 +408,21 @@ class GeoAlgorithm:
s+=out.getValueAsCommandLineParameter() + ","
s= s[:-1] + ")"
return s
def getPostProcessingErrorMessage(self, wrongLayers):
'''Returns the message to be shown to the user when, after running this algorithm,
there is a problem loading the resulting layer.
This method should analyze if the problem is caused by wrong entry data, a wrong or missing
installation of a required 3rd party app, or any other cause, and create an error response accordingly.
Message is provided as an HTML code that will be displayed to the user, and which might contains
links to installation paths for missing 3rd party apps.
- wrongLayers: a list of Output objects that could not be loaded.'''
html ="<p>Oooops! SEXTANTE could not open the following output layers</p><ul>\n"
for layer in wrongLayers:
html += '<li>' + layer.description + ': <font size=3 face="Courier New" color="ff0000">' + layer.value + "</font></li>\n"
html +="</ul><p>The above files could not be opened, which probably indicates that they were not correctly produced by the executed algorithm</p>"
html +="<p>Checking the log information might help you see why those layers were not created as expected</p>"
return html

View File

@ -449,7 +449,7 @@ class GrassAlgorithm(GeoAlgorithm):
if msg is not None:
html = ("<p>This algorithm requires GRASS to be run."
"Unfortunately, it seems that GRASS is not installed in your system, or it is not correctly configured to be used from QGIS</p>")
html += '<p><a href= "http://docs.qgis.org/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure GRASS to be used with SEXTANTE</p>'
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure GRASS to be used with SEXTANTE</p>'
return html
@ -463,3 +463,16 @@ class GrassAlgorithm(GeoAlgorithm):
func = getattr(module,'checkParameterValuesBeforeExecuting')
return func(self)
def getPostProcessingErrorMessage(self, wrongLayers):
html = GeoAlgorithm.getPostProcessingErrorMessage(self, wrongLayers)
msg = GrassUtils.checkGrassIsInstalled(True)
html += ("<p>This algorithm requires GRASS to be run. A test to check if GRASS is correctly installed "
"and configured in your system has been performed, with the following result:</p><ul><i>")
if msg is None:
html += "GRASS seems to be correctly installed and configured</i></li></ul>"
else:
html += msg + "</i></li></ul>"
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure GRASS to be used with SEXTANTE</p>'
return html

View File

@ -83,19 +83,6 @@ class GrassAlgorithmProvider(AlgorithmProvider):
def getIcon(self):
return QIcon(os.path.dirname(__file__) + "/../images/grass.png")
def getPostProcessingErrorMessage(self, wrongLayers):
html = AlgorithmProvider.getPostProcessingErrorMessage(self, wrongLayers)
msg = GrassUtils.checkGrassIsInstalled(True)
html += ("<p>This algorithm requires GRASS to be run. A test to check if GRASS is correctly installed "
"and configured in your system has been performed, with the following result:</p><ul><i>")
if msg is None:
html += "GRASS seems to be correctly installed and configured</li></ul>"
else:
html += msg + "</i></li></ul>"
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure GRASS to be used with SEXTANTE</p>'
return html
def getSupportedOutputVectorLayerExtensions(self):
return ["shp"]

View File

@ -325,7 +325,6 @@ class GrassUtils:
if not ignoreRegistrySettings:
if settings.contains(GRASS_INSTALLED):
return
try:
from sextante import runalg
result = runalg("grass:v.voronoi", points(),False,False,"270778.60198,270855.745301,4458921.97814,4458983.8488",-1,0.0001, 0, None)

View File

@ -42,7 +42,7 @@ class CouldNotLoadResultsDialog(QtGui.QDialog):
webView = QtWebKit.QWebView()
webView.page().setLinkDelegationPolicy(QtWebKit.QWebPage.DelegateAllLinks)
webView.connect(webView, SIGNAL("linkClicked(const QUrl&)"), self.linkClicked)
html = self.alg.provider.getPostProcessingErrorMessage(self.wrongLayers)
html = self.alg.getPostProcessingErrorMessage(self.wrongLayers)
webView.setHtml(html)
closeButton = QtGui.QPushButton()
closeButton.setText("Close")

View File

@ -270,22 +270,19 @@ class RAlgorithm(GeoAlgorithm):
def getImportCommands(self):
commands = []
# if rgdal is not available, try to install it
# just use main mirror
commands.append('options("repos"="http://cran.at.r-project.org/")')
rLibDir = "%s/rlibs" % SextanteUtils.userFolder().replace("\\","/")
if not os.path.isdir(rLibDir):
os.mkdir(rLibDir)
# .libPaths("%s") substitutes the personal libPath with "%s"! With '.libPaths(c("%s",deflibloc))' it is added without replacing and we can use all installed R packages!
commands.append('deflibloc <- .libPaths()[1]')
commands.append('.libPaths(c("%s",deflibloc))' % rLibDir )
commands.append(
'tryCatch(find.package("rgdal"), error=function(e) install.packages("rgdal", dependencies=TRUE, lib="%s"))' % rLibDir)
commands.append("library(\"rgdal\")");
#if not self.useRasterPackage or self.passFileNames:
commands.append(
'tryCatch(find.package("raster"), error=function(e) install.packages("raster", dependencies=TRUE, lib="%s"))' % rLibDir)
commands.append("library(\"raster\")");
# try to install packages if needed
packages = RUtils.getRequiredPackages(self.script)
packages.extend(['rgdal', 'raster'])
for p in packages:
commands.append(
'tryCatch(find.package("' + p +
'"), error=function(e) install.packages("' + p +'", dependencies=TRUE))')
commands.append('library("raster")')
commands.append('library("rgdal")')
for param in self.parameters:
if isinstance(param, ParameterRaster):
@ -386,28 +383,28 @@ class RAlgorithm(GeoAlgorithm):
return None
def checkBeforeOpeningParametersDialog(self):
if SextanteUtils.isWindows():
path = RUtils.RFolder()
if path == "":
return "R folder is not configured.\nPlease configure it before running R scripts."
msg = RUtils.checkRIsInstalled()
if msg is not None:
html = ("<p>This algorithm requires R to be run."
"Unfortunately, it seems that R is not installed in your system, or it is not correctly configured to be used from QGIS</p>")
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure R to be used with SEXTANTE</p>'
return html
R_INSTALLED = "R_INSTALLED"
settings = QSettings()
if settings.contains(R_INSTALLED):
return
if SextanteUtils.isWindows():
if SextanteConfig.getSetting(RUtils.R_USE64):
execDir = "x64"
else:
execDir = "i386"
command = [RUtils.RFolder() + os.sep + "bin" + os.sep + execDir + os.sep + "R.exe", "--version"]
def getPostProcessingErrorMessage(self, wrongLayers):
html = GeoAlgorithm.getPostProcessingErrorMessage(self, wrongLayers)
msg = RUtils.checkRIsInstalled(True)
html += ("<p>This algorithm requires R to be run. A test to check if R is correctly installed "
"and configured in your system has been performed, with the following result:</p><ul><i>")
if msg is None:
html += "GRASS seems to be correctly installed and configured</i></li></ul>"
html += "<p>The script you have executed needs the following packages:</p><ul>"
packages = RUtils.getRequiredPackages(self.script)
for p in packages:
html += '<li>' + p + '</li>'
html += "</ul><p>Make sure they are installed in your R environment before trying to execute this script.</p>"
else:
command = ["R --version"]
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.STDOUT, universal_newlines=True).stdout
for line in iter(proc.readline, ""):
if "R version" in line:
settings.setValue(R_INSTALLED, True)
return
return "It seems that R is not correctly installed in your system.\nPlease install it before running R Scripts."
html += msg + "</i></li></ul>"
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure R to be used with SEXTANTE</p>'
return html

View File

@ -16,6 +16,7 @@
* *
***************************************************************************
"""
import re
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
@ -24,6 +25,7 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$'
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from sextante.core.SextanteConfig import SextanteConfig
import os
from sextante.core.SextanteUtils import mkdir, SextanteUtils
@ -123,3 +125,41 @@ class RUtils:
s+="</font>\n"
return s
@staticmethod
def checkRIsInstalled(ignoreRegistrySettings=False):
if SextanteUtils.isWindows():
path = RUtils.RFolder()
if path == "":
return "R folder is not configured.\nPlease configure it before running R scripts."
R_INSTALLED = "R_INSTALLED"
settings = QSettings()
if not ignoreRegistrySettings:
if settings.contains(R_INSTALLED):
return
if SextanteUtils.isWindows():
if SextanteConfig.getSetting(RUtils.R_USE64):
execDir = "x64"
else:
execDir = "i386"
command = [RUtils.RFolder() + os.sep + "bin" + os.sep + execDir + os.sep + "R.exe", "--version"]
else:
command = ["R --version"]
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.STDOUT, universal_newlines=True).stdout
for line in iter(proc.readline, ""):
if "R version" in line:
settings.setValue(R_INSTALLED, True)
return
html = ("<p>This algorithm requires R to be run."
"Unfortunately, it seems that R is not installed in your system, or it is not correctly configured to be used from QGIS</p>"
'<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a>'
'to know more about how to install and configure R to be used with SEXTANTE</p>')
return html
@staticmethod
def getRequiredPackages(code):
regex = re.compile('library\("?(.*?)"?\)')
return regex.findall(code)

View File

@ -362,7 +362,7 @@ class SagaAlgorithm(GeoAlgorithm):
if msg is not None:
html = ("<p>This algorithm requires SAGA to be run."
"Unfortunately, it seems that SAGA is not installed in your system, or it is not correctly configured to be used from QGIS</p>")
html += '<p><a href= "http://docs.qgis.org/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure SAGA to be used with SEXTANTE</p>'
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure SAGA to be used with SEXTANTE</p>'
return html
@ -379,7 +379,18 @@ class SagaAlgorithm(GeoAlgorithm):
def helpFile(self):
return os.path.join(os.path.dirname(__file__), "help", self.name.replace(" ", "") + ".html")
def getPostProcessingErrorMessage(self, wrongLayers):
html = GeoAlgorithm.getPostProcessingErrorMessage(self, wrongLayers)
msg = SagaUtils.checkSagaIsInstalled(True)
html += ("<p>This algorithm requires SAGA to be run. A test to check if SAGA is correctly installed "
"and configured in your system has been performed, with the following result:</p><ul><i>")
if msg is None:
html += "SAGA seems to be correctly installed and configured</li></ul>"
else:
html += msg + "</i></li></ul>"
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure SAGA to be used with SEXTANTE</p>'
return html
#===========================================================================
# def commandLineName(self):
# name = self.provider.getName().lower() + ":" + self.cmdname.lower()

View File

@ -99,19 +99,6 @@ class SagaAlgorithmProvider(AlgorithmProvider):
def getName(self):
return "saga"
def getPostProcessingErrorMessage(self, wrongLayers):
html = AlgorithmProvider.getPostProcessingErrorMessage(self, wrongLayers)
msg = SagaUtils.checkSagaIsInstalled(True)
html += ("<p>This algorithm requires SAGA to be run. A test to check if SAGA is correctly installed "
"and configured in your system has been performed, with the following result:</p><ul><i>")
if msg is None:
html += "SAGA seems to be correctly installed and configured</li></ul>"
else:
html += msg + "</i></li></ul>"
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html">Click here</a> to know more about how to install and configure SAGA to be used with SEXTANTE</p>'
return html
def getSupportedOutputVectorLayerExtensions(self):
return ["shp"]