Hi Moritz,
i can reproduce this bug using the SVN revision 63. I have applied a
patch which should solve the problem and which will add new shiny
features (i was to lazy to remove the features from the patch).
Please apply the patch to the latest svn version of the plugin.
Best regards
Soeren
2011/4/15 Moritz Lennert <[email protected]>:
> On 15/04/11 09:20, Soeren Gebbert wrote:
>>
>> Hi Moritz,
>> the problem may be related to the QGIS WPS plugin version. The plugin
>> is still in an experimental state and under active development, but
>> the latest SVN version should be usable. Which version of the plugin
>> do you use?
>
> 0.5.
>
> Moritz
>
>>
>> Best regards
>> Soeren
>>
>> 2011/4/14 Moritz Lennert<[email protected]>:
>>>
>>> Soeren,
>>>
>>> Thanks for the great work on WPS integration !
>>>
>>> On 28/01/11 11:44, Soeren Gebbert wrote:
>>>>
>>>> How to attach GRASS modules to PyWPS using the wps-grass-bridge is
>>>> documented here:
>>>> http://code.google.com/p/wps-grass-bridge/wiki/PyWPS_Integration
>>>>
>>>> Well, the code isn't stable yet but it demonstrates the possibilities
>>>> of this approach.
>>>
>>> I've tried following the above instructions, and the server does give a
>>> correct answer for GetCapabilities. I can also see the list of modules in
>>> the QGIS WPS plugin and get the GUI of a module. However, once I run the
>>> module I always get the following error, whatever the module I try:
>>>
>>> <wps:ProcessFailed>
>>> <wps:ExceptionReport>
>>> <ows:Exception exceptionCode="NoApplicableCode">
>>> <ows:ExceptionText>argument 1 must be string or
>>> buffer,
>>> not None</ows:ExceptionText>
>>> </ows:Exception>
>>> </wps:ExceptionReport>
>>> </wps:ProcessFailed>
>>>
>>>
>>> Any idea what could be wrong ? I can't find a way to see what URL the
>>> QGIS
>>> plugin sends to the server.
>>>
>>> Moritz
>>>
>>>
>
>
>
Index: qgswpstools.py
===================================================================
--- qgswpstools.py (Revision 63)
+++ qgswpstools.py (Arbeitskopie)
@@ -211,14 +211,16 @@
##############################################################################
- def decodeBase64(self, infileName, mimeType="image/tiff"):
+ def decodeBase64(self, infileName, mimeType="image/tiff", outfileName=None):
# This is till untested
# TODO: test it
try:
# User project dir
- #filename = QFileDialog.getSaveFileName(None, "Chose filename for output file", "/home/soeren");
- filename = tempfile.mktemp(prefix="base64")
+ if outfileName == None:
+ filename = tempfile.mktemp(prefix="base64")
+ else:
+ filename = outfileName
infile = open(infileName)
outfile = open(filename, 'w')
base64.decode(infile,outfile)
@@ -264,9 +266,15 @@
writer.addFeature(feat)
del writer
-
+
+ # Check in case a ".g" was attached to the tempfile
+ if os.path.isfile(tmpFile + ".g") == True:
+ # The gdal creator attached a .g to the temp file
+ tmpFile = tmpFile + ".g"
+
myFile = QFile(tmpFile)
if (not myFile.open(QIODevice.ReadOnly | QIODevice.Text)):
+ print "Unable to open file " + tmpFile
pass
myGML = QTextStream(myFile)
Index: qgswps.py
===================================================================
--- qgswps.py (Revision 63)
+++ qgswps.py (Arbeitskopie)
@@ -30,10 +30,12 @@
from httplib import *
from urlparse import urlparse
import os, sys, string, tempfile, urllib2, urllib, mimetypes
+import time
# initialize Qt resources from file resources.py
import resources
+# Set this FLAG true to have Debug output, The request and the response will be saved in /tmp
DEBUG = False
# Our main class for the plugin
@@ -44,6 +46,8 @@
self.iface = iface
self.minimumRevision = 12026
self.localePath = ""
+ # Switch between downloading the data via a reference or to have embedded data in the WPS responce.
+ self.asReference = True
#Initialise the translation environment
userPluginPath = QFileInfo(QgsApplication.qgisUserDbFilePath()).path()+"/python/plugins/wps"
@@ -171,7 +175,8 @@
self.complexInputTextBoxList = [] # complex inpt of type text/plain
self.literalInputComboBoxList = [] # literal value list with selectable answers
self.literalInputLineEditList = [] # literal value list with single text line input
- self.complexOutputComboBoxList = [] # list combo box
+ self.complexOutputComboBoxList = [] # list combo box with output layer names
+ self.complexOutputNameList = {} # list output names in the file system
self.inputDataTypeList = {}
self.inputsMetaInfo = {} # dictionary for input metainfo, key is the input identifier
self.outputsMetaInfo = {} # dictionary for output metainfo, key is the output identifier
@@ -362,8 +367,10 @@
self.outputsMetaInfo[outputIdentifier] = supportedcomplexOutputFormat
self.outputDataTypeList[outputIdentifier] = complexOutputFormat
- widget, comboBox = self.addComplexOutputComboBox(groupbox, outputIdentifier, title, str(complexOutputFormat))
- self.complexOutputComboBoxList.append(comboBox)
+ widget, comboBox1, comboBox2 = self.addComplexOutputComboBox(groupbox, outputIdentifier, title, str(complexOutputFormat))
+ self.complexOutputComboBoxList.append(comboBox1)
+ # Store the file name of the output
+ self.complexOutputNameList[comboBox2.objectName()] = comboBox2
layout.addWidget(widget)
# Set the layout
@@ -422,40 +429,65 @@
def addComplexOutputComboBox(self, widget, name, title, mimeType):
"""Adds a combobox to select a raster or vector map as input to the process tab"""
+ # Horizontal
groupbox = QGroupBox(widget)
- groupbox.setMinimumHeight(25)
- layout = QHBoxLayout()
+ groupbox.setMinimumHeight(50)
+ hlayout = QHBoxLayout()
+ # Vertical
+ vgroupbox = QGroupBox(groupbox)
+ vgroupbox.setMinimumHeight(50)
+ vlayout = QVBoxLayout()
namesList = []
# Generate a unique name for the layer
namesList.append(self.tools.uniqueLayerName(self.processIdentifier + "_" + name + "_"))
- namesList.append("<None>")
+ namesList.append("<None>") # In case of none the output is not requested
- comboBox = QComboBox(groupbox)
- comboBox.setEditable(True)
- comboBox.addItems(namesList)
- comboBox.setObjectName(name)
- comboBox.setMinimumWidth(250)
- comboBox.setMaximumWidth(250)
- comboBox.setMinimumHeight(25)
+ # Set the combo box for output layer name selection
+ comboBox1 = QComboBox(groupbox)
+ comboBox1.setEditable(True)
+ comboBox1.addItems(namesList)
+ comboBox1.setObjectName(name)
+ comboBox1.setMinimumWidth(250)
+ comboBox1.setMaximumWidth(250)
+ comboBox1.setMinimumHeight(25)
+ # Set the combo box for output layer name selection and output path
+ fileName = self.processIdentifier + "_" + name + "_" + str(int(time.time()))
+ fileName = os.path.expanduser("~/" + str(fileName))
+ namesList = []
+ namesList.append(fileName)
+
+ comboBox2 = QComboBox(groupbox)
+ comboBox2.setEditable(True)
+ comboBox2.addItems(namesList)
+ comboBox2.setObjectName(name)
+ comboBox2.setMinimumWidth(250)
+ comboBox2.setMaximumWidth(250)
+ comboBox2.setMinimumHeight(25)
+
myLabel = QLabel(widget)
myLabel.setObjectName("qLabel"+name)
- string = "[" + name + "] <br>" + title
+ string = "[" + name + "] <br>" + title + "<br> Output file path"
myLabel.setText("<font color='Green'>" + string + "</font>" + " <br>(" + mimeType + ")")
myLabel.setWordWrap(True)
myLabel.setMinimumWidth(400)
myLabel.setMinimumHeight(25)
- layout.addWidget(myLabel)
- layout.addStretch(1)
- layout.addWidget(comboBox)
+ vlayout.addWidget(comboBox1)
+ vlayout.addWidget(comboBox2)
- groupbox.setLayout(layout)
+ vgroupbox.setLayout(vlayout)
+
+ hlayout.addWidget(myLabel)
+ hlayout.addStretch(1)
+ hlayout.addWidget(vgroupbox)
+
+ groupbox.setLayout(hlayout)
- return groupbox, comboBox
+ return groupbox, comboBox1, comboBox2
##############################################################################
@@ -774,7 +806,7 @@
elif self.tools.isMimeTypeVector(mimeType) != None or self.tools.isMimeTypeRaster(mimeType) != None:
postString += "<wps:ComplexData mimeType=\"" + mimeType + "\" encoding=\"base64\">\n"
postString += self.tools.createTmpBase64(comboBox.currentText())
-
+
postString += "</wps:ComplexData>\n"
postString += self.tools.xmlExecuteRequestInputEnd()
@@ -856,7 +888,11 @@
schema = self.outputDataTypeList[outputIdentifier]["Schema"]
encoding = self.outputDataTypeList[outputIdentifier]["Encoding"]
- postString += "<wps:Output asReference=\"true\" mimeType=\"" + mimeType + "\" schema=\"" + schema + "\">"
+ # We support as reference and as embedded
+ if self.asReference:
+ postString += "<wps:Output asReference=\"true\" mimeType=\"" + mimeType + "\" schema=\"" + schema + "\">"
+ else:
+ postString += "<wps:Output asReference=\"false\" mimeType=\"" + mimeType + "\" schema=\"" + schema + "\">"
postString += "<ows:Identifier>" + outputIdentifier + "</ows:Identifier>\n"
postString += "</wps:Output>\n"
@@ -873,7 +909,7 @@
outFile.write(postString)
outFile.close()
- f = urllib.urlopen( str(scheme)+"://"+str(server)+""+str(path), unicode(postString, "latin1").replace('<wps:ComplexData>\n','<wps:ComplexData>'))
+ f = urllib.urlopen( str(scheme)+"://"+str(server)+""+str(path), unicode(postString, "latin1"))
# Read the results back.
wpsRequestResult = f.read()
@@ -918,9 +954,13 @@
if fileLink == '0':
QMessageBox.warning(None, '', str(QCoreApplication.translate("WPS Error: Unable to download the result of reference: ")) + str(fileLink))
return
-
- # Get the mime type of the result
+
+ print "Download file " + str(fileLink)
+
+ ####################################################################
+ # Get the mime type of the result #################################
mimeType = str(reference.attribute("mimeType", "0").toLower())
+ outputName = self.complexOutputNameList[identifier].currentText()
if fileLink != '0':
# Set a valid layerName
@@ -930,8 +970,11 @@
if comboBox.objectName() == identifier:
layerName = comboBox.currentText()
- resultFileConnector = urllib.urlretrieve(unicode(fileLink,'latin1'))
+ resultFileConnector = urllib.urlretrieve(unicode(fileLink,'latin1'), outputName)
resultFile = resultFileConnector[0]
+
+ print "Saved file " + str(resultFile)
+
# Vector data
# TODO: Check for schema GML and KML
if self.tools.isMimeTypeVector(mimeType) != None:
@@ -956,13 +999,85 @@
content = open(resultFile, 'r').read()
# TODO: This should have a safe option
self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps", 'Process result (unsupported mime type)'), content)
-
+
+ ######################################################################
+ # Fetch the embedded complex data ###################################
+ elif f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0", "ComplexData").size() > 0:
+ identifier = f_element.elementsByTagNameNS("http://www.opengis.net/ows/1.1","Identifier").at(0).toElement().text().simplified()
+ ComplexData = f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0","ComplexData").at(0).toElement()
+
+ # Get the mime type of the result
+ mimeType = str(ComplexData.attribute("mimeType", "0").toLower())
+ resultFile = self.complexOutputNameList[identifier].currentText()
+
+ # Set a valid layerName
+ layerName = self.tools.uniqueLayerName(self.processIdentifier + "_" + identifier)
+ # The layername is normally defined in the comboBox
+ for comboBox in self.complexOutputComboBoxList:
+ if comboBox.objectName() == identifier:
+ layerName = comboBox.currentText()
+
+ # Vector data
+ # TODO: Check for schema GML and KML and implement lower memory consumption
+ if self.tools.isMimeTypeVector(mimeType) != None:
+ # Write the XML content to the disk, this is very memory consuming!
+ content = f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0","ComplexData").at(0).toElement().firstChild()
+ text = QString()
+ ts = QTextStream(text)
+ content.save(ts, 1)
+ f = open(resultFile, 'w')
+ f.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>")
+ f.write(text)
+ f.close()
+ del ts
+ del text
+ print "Attaching vector file " + resultFile + " to qgis "
+ vlayer = QgsVectorLayer(resultFile, layerName, "ogr")
+ QgsMapLayerRegistry.instance().addMapLayer(vlayer)
+ # Raster data
+ elif self.tools.isMimeTypeRaster(mimeType) != None:
+ # We need a temporal file first
+ myQTempFile = QTemporaryFile()
+ myQTempFile.open()
+ tmpFile = unicode(myQTempFile.fileName(),'latin1')
+ data = ComplexData.text().simplified()
+ f = open(tmpFile, 'w')
+ f.write(data)
+ f.close()
+ # We need to convert the base64 content
+ resultFile = self.tools.decodeBase64(tmpFile, mimeType, resultFile)
+ print "Attaching raster file " + resultFile + " to qgis "
+ rLayer = QgsRasterLayer(resultFile, layerName)
+ QgsMapLayerRegistry.instance().addMapLayer(rLayer)
+ myQTempFile.close()
+ # Text data
+ elif self.tools.isMimeTypeText(mimeType) != None:
+ #TODO: this should be handled in a separate dialog to save the text output as file'
+ QApplication.restoreOverrideCursor()
+ content = ComplexData.text().simplified()
+ print "Save text content to file " + resultFile
+ f = open(resultFile, 'w')
+ f.write(content)
+ f.close()
+ # TODO: This should be a text dialog with safe option
+ self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps",'Process result (text/plain)'), content)
+ # Everything else
+ else:
+ # For unsupported mime types we assume text
+ QApplication.restoreOverrideCursor()
+ content = ComplexData.text().simplified()
+ f = open(resultFile, 'w')
+ f.write(content)
+ f.close()
+ # TODO: This should have a safe option
+ self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps", 'Process result (unsupported mime type)'), content)
+
elif f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0", "LiteralData").size() > 0:
QApplication.restoreOverrideCursor()
literalText = f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0", "LiteralData").at(0).toElement().text()
self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps",'Result'),literalText)
else:
- QMessageBox.warning(None, '', str(QCoreApplication.translate("WPS Error: Missing reference or literal data in response")))
+ QMessageBox.warning(None, '', str(QCoreApplication.translate("WPS Error: Missing reference, embedded or literal data in response")))
QMessageBox.information(None, QCoreApplication.translate("QgsWps",'Process result'), QCoreApplication.translate("QgsWps",'The process finished successful'))
else:
_______________________________________________
grass-dev mailing list
[email protected]
http://lists.osgeo.org/mailman/listinfo/grass-dev