2014-05-13 16:18:38 -04:00
############################################
#
# Author: Luca Cinquini
#
############################################
"""
Abstract
- - - - - - - -
The wps module of the OWSlib package provides client - side functionality for executing invocations to a remote Web Processing Server .
Disclaimer
- - - - - - - - - -
PLEASE NOTE : the owslib wps module should be considered in beta state : it has been tested versus only a handful of WPS services ( deployed by the USGS , BADC and PML ) .
More extensive testing is needed and feedback is appreciated .
Usage
- - - - -
2014-09-03 08:43:11 -04:00
The module can be used to execute three types of requests versus a remote WPS endpoint :
2014-05-13 16:18:38 -04:00
2014-09-03 08:43:11 -04:00
a ) " GetCapabilities "
2014-05-13 16:18:38 -04:00
- use the method wps . getcapabilities ( xml = None )
- the optional keyword argument " xml " may be used to avoid a real live request , and instead read the WPS capabilities document from a cached XML file
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
b ) " DescribeProcess "
- use the method wps . describeprocess ( identifier , xml = None )
- identifier is the process identifier , retrieved from the list obtained from a previous " GetCapabilities " invocation
- the optional keyword argument " xml " may be used to avoid a real live request , and instead read the WPS process description document from a cached XML file
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
c ) " Execute "
2014-09-03 08:43:11 -04:00
- use the method wps . execute ( identifier , inputs , output = None , request = None , response = None ) ,
which submits the job to the remote WPS server and returns a WPSExecution object that can be used to periodically check the job status until completion
2014-05-13 16:18:38 -04:00
( or error )
2014-09-03 08:43:11 -04:00
- the optional keyword argument " request " may be used to avoid re - building the request XML from input arguments , and instead submit a request from a
2014-05-13 16:18:38 -04:00
pre - made XML file
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
- alternatively , an " Execute " request can be built from input arguments by supplying the " identifier " , " inputs " and " output " arguments to the execute ( ) method .
- " identifier " is the mandatory process identifier
- " inputs " is a dictionary of ( key , value ) pairs where :
- key is a named input parameter
- value is either a string , or any python object that supports a getXml ( ) method
In particular , a few classes are included in the package to support a FeatuteCollection input :
- " WFSFeatureCollection " can be used in conjunction with " WFSQuery " to define a FEATURE_COLLECTION retrieved from a live WFS server .
- " GMLMultiPolygonFeatureCollection " can be used to define one or more polygons of ( latitude , longitude ) points .
- " output " is an optional output identifier to be included in the ResponseForm section of the request .
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
- the optional keyword argument " response " mey be used to avoid submitting a real live request , and instead reading the WPS execution response document
from a cached XML file ( for debugging or testing purposes )
- the convenience module function monitorExecution ( ) can be used to periodically check the status of a remote running job , and eventually download the output
either to a named file , or to a file specified by the server .
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
Examples
- - - - - - - -
2014-09-03 08:43:11 -04:00
The files examples / wps - usgs - script . py , examples / wps - pml - script - 1. py and examples / wps - pml - script - 2. py contain real - world usage examples
that submits a " GetCapabilities " , " DescribeProcess " and " Execute " requests to the live USGS and PML servers . To run :
2014-05-13 16:18:38 -04:00
cd examples
python wps - usgs - script . py
python wps - pml - script - 1. py
python wps - pml - script - 2. py
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
The file wps - client . py contains a command - line client that can be used to submit a " GetCapabilities " , " DescribeProcess " or " Execute "
request to an arbitratry WPS server . For example , you can run it as follows :
cd examples
To prints out usage and example invocations : wps - client - help
2014-09-03 08:43:11 -04:00
To execute a ( fake ) WPS invocation :
2014-05-13 16:18:38 -04:00
wps - client . py - v - u http : / / cida . usgs . gov / climate / gdp / process / WebProcessingService - r GetCapabilities - x . . / tests / USGSCapabilities . xml
2014-09-03 08:43:11 -04:00
The directory tests / includes several doctest - style files wps_ * . txt that show how to interactively submit a
2014-05-13 16:18:38 -04:00
" GetCapabilities " , " DescribeProcess " or " Execute " request , without making a live request but rather parsing the response of cached XML response documents . To run :
cd tests
python - m doctest wps_ * . txt
( or python - m doctest - v wps_ * . txt for verbose output )
Also , the directory tests / contains several examples of well - formed " Execute " requests :
- The files wps_USGSExecuteRequest * . xml contain requests that can be submitted to the live USGS WPS service .
- The files PMLExecuteRequest * . xml contain requests that can be submitted to the live PML WPS service .
"""
from owslib . etree import etree
from owslib . ows import DEFAULT_OWS_NAMESPACE , ServiceIdentification , ServiceProvider , OperationsMetadata
from time import sleep
2014-09-03 08:43:11 -04:00
from owslib . util import ( testXMLValue , build_get_url , dump , getTypedValue ,
getNamespace , element_to_string , nspath , openURL , nspath_eval )
2014-05-13 16:18:38 -04:00
from xml . dom . minidom import parseString
from owslib . namespaces import Namespaces
# namespace definition
n = Namespaces ( )
# These static namespaces are DEPRECIATED. Please don't use them.
# No great way of printing a message since there are at the file level
WPS_DEFAULT_NAMESPACE = n . get_namespace ( " wps " )
WFS_NAMESPACE = n . get_namespace ( " wfs " )
OGC_NAMESPACE = n . get_namespace ( " ogc " )
GML_NAMESPACE = n . get_namespace ( " gml " )
DRAW_NAMESPACE = n . get_namespace ( " draw " )
GML_SCHEMA_LOCATION = " http://schemas.opengis.net/gml/3.1.1/base/feature.xsd "
DRAW_SCHEMA_LOCATION = ' http://cida.usgs.gov/climate/derivative/xsd/draw.xsd '
WPS_DEFAULT_SCHEMA_LOCATION = ' http://schemas.opengis.net/wps/1.0.0/wpsExecute_request.xsd '
WPS_DEFAULT_VERSION = ' 1.0.0 '
def get_namespaces ( ) :
ns = n . get_namespaces ( [ " ogc " , " wfs " , " wps " , " gml " , " xsi " , " xlink " ] )
ns [ None ] = n . get_namespace ( " wps " )
ns [ " ows " ] = DEFAULT_OWS_NAMESPACE
return ns
namespaces = get_namespaces ( )
class IWebProcessingService ( ) :
"""
Abstract interface for an OGC Web Processing Service ( WPS ) .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
url = property ( """ URL for the remote WPS server (string). """ )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def getcapabilities ( * * kw ) :
"""
Makes a GetCapabilities request to the remote WPS server ,
returns an XML document wrapped in a python file - like object .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def describeprocess ( * * kw ) :
"""
Makes a DescribeProcess request to the remote WPS server ,
returns a Process object containing all the process metadata .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def execute ( * * kw ) :
"""
Submits an Execute request to the remote WPS server ,
returns a WPSExecution object , which can be used to monitor the status of the job , and ultimately retrieve the result .
"""
class IComplexData ( ) :
"""
Abstract interface representing complex input object for a WPS request .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def getXml ( self ) :
"""
2014-09-03 08:43:11 -04:00
Method that returns the object data as an XML snippet ,
2014-05-13 16:18:38 -04:00
to be inserted into the WPS request document sent to the server .
2014-09-03 08:43:11 -04:00
"""
2014-05-13 16:18:38 -04:00
class WebProcessingService ( object ) :
"""
Class that contains client - side functionality for invoking an OGC Web Processing Service ( WPS ) .
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
Implements IWebProcessingService .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , url , version = WPS_DEFAULT_VERSION , username = None , password = None , verbose = False , skip_caps = False ) :
"""
Initialization method resets the object status .
2014-09-03 08:43:11 -04:00
By default it will execute a GetCapabilities invocation to the remote service ,
2014-05-13 16:18:38 -04:00
which can be skipped by using skip_caps = True .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# fields passed in from object initializer
self . url = url
self . username = username
self . password = password
self . version = version
self . verbose = verbose
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# fields populated by method invocations
self . _capabilities = None
self . identification = None
self . provider = None
self . operations = [ ]
self . processes = [ ]
if not skip_caps :
self . getcapabilities ( )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def getcapabilities ( self , xml = None ) :
"""
Method that requests a capabilities document from the remote WPS server and populates this object ' s metadata.
keyword argument xml : local XML GetCapabilities document , prevents actual HTTP invocation .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# read capabilities document
reader = WPSCapabilitiesReader ( version = self . version , verbose = self . verbose )
if xml :
# read from stored XML file
self . _capabilities = reader . readFromString ( xml )
else :
self . _capabilities = reader . readFromUrl ( self . url , username = self . username , password = self . password )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
if self . verbose == True :
2014-09-03 08:43:11 -04:00
print element_to_string ( self . _capabilities )
2014-05-13 16:18:38 -04:00
# populate the capabilities metadata obects from the XML tree
self . _parseCapabilitiesMetadata ( self . _capabilities )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def describeprocess ( self , identifier , xml = None ) :
"""
Requests a process document from a WPS service and populates the process metadata .
Returns the process object .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# read capabilities document
reader = WPSDescribeProcessReader ( version = self . version , verbose = self . verbose )
if xml :
# read from stored XML file
rootElement = reader . readFromString ( xml )
else :
# read from server
rootElement = reader . readFromUrl ( self . url , identifier )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
if self . verbose == True :
2014-09-03 08:43:11 -04:00
print element_to_string ( rootElement )
2014-05-13 16:18:38 -04:00
# build metadata objects
return self . _parseProcessMetadata ( rootElement )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def execute ( self , identifier , inputs , output = None , request = None , response = None ) :
"""
2014-09-03 08:43:11 -04:00
Submits a WPS process execution request .
2014-05-13 16:18:38 -04:00
Returns a WPSExecution object , which can be used to monitor the status of the job , and ultimately retrieve the result .
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
identifier : the requested process identifier
inputs : list of process inputs as ( key , value ) tuples ( where value is either a string for LiteralData , or an object for ComplexData )
output : optional identifier for process output reference ( if not provided , output will be embedded in the response )
request : optional pre - built XML request document , prevents building of request from other arguments
response : optional pre - built XML response document , prevents submission of request to live WPS server
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# instantiate a WPSExecution object
print ' Executing WPS request... '
execution = WPSExecution ( version = self . version , url = self . url , username = self . username , password = self . password , verbose = self . verbose )
2014-09-03 08:43:11 -04:00
# build XML request from parameters
2014-05-13 16:18:38 -04:00
if request is None :
requestElement = execution . buildRequest ( identifier , inputs , output )
2014-09-03 08:43:11 -04:00
request = etree . tostring ( requestElement )
2014-05-13 16:18:38 -04:00
if self . verbose == True :
print request
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# submit the request to the live server
2014-09-03 08:43:11 -04:00
if response is None :
2014-05-13 16:18:38 -04:00
response = execution . submitRequest ( request )
else :
response = etree . fromstring ( response )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
if self . verbose == True :
print etree . tostring ( response )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# parse response
execution . parseResponse ( response )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
return execution
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def _parseProcessMetadata ( self , rootElement ) :
"""
Method to parse a < ProcessDescriptions > XML element and returned the constructed Process object
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
processDescriptionElement = rootElement . find ( ' ProcessDescription ' )
process = Process ( processDescriptionElement , verbose = self . verbose )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# override existing processes in object metadata, if existing already
found = False
for n , p in enumerate ( self . processes ) :
if p . identifier == process . identifier :
self . processes [ n ] = process
found = True
# otherwise add it
if not found :
self . processes . append ( process )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
return process
2014-09-03 08:43:11 -04:00
def _parseCapabilitiesMetadata ( self , root ) :
2014-05-13 16:18:38 -04:00
''' Sets up capabilities metadata objects '''
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# use the WPS namespace defined in the document root
wpsns = getNamespace ( root )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# loop over children WITHOUT requiring a specific namespace
for element in root :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# thie element's namespace
ns = getNamespace ( element )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:ServiceIdentification> metadata
if element . tag . endswith ( ' ServiceIdentification ' ) :
self . identification = ServiceIdentification ( element , namespace = ns )
if self . verbose == True :
dump ( self . identification )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:ServiceProvider> metadata
elif element . tag . endswith ( ' ServiceProvider ' ) :
2014-09-03 08:43:11 -04:00
self . provider = ServiceProvider ( element , namespace = ns )
2014-05-13 16:18:38 -04:00
if self . verbose == True :
dump ( self . provider )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ns0:OperationsMetadata xmlns:ns0="http://www.opengeospatial.net/ows">
# <ns0:Operation name="GetCapabilities">
# <ns0:DCP>
# <ns0:HTTP>
# <ns0:Get xlink:href="http://ceda-wps2.badc.rl.ac.uk/wps?" xmlns:xlink="http://www.w3.org/1999/xlink" />
# </ns0:HTTP>
# </ns0:DCP>
# </ns0:Operation>
# ........
# </ns0:OperationsMetadata>
elif element . tag . endswith ( ' OperationsMetadata ' ) :
for child in element . findall ( nspath ( ' Operation ' , ns = ns ) ) :
self . operations . append ( OperationsMetadata ( child , namespace = ns ) )
if self . verbose == True :
dump ( self . operations [ - 1 ] )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <wps:ProcessOfferings>
# <wps:Process ns0:processVersion="1.0.0">
# <ows:Identifier xmlns:ows="http://www.opengis.net/ows/1.1">gov.usgs.cida.gdp.wps.algorithm.filemanagement.ReceiveFiles</ows:Identifier>
# <ows:Title xmlns:ows="http://www.opengis.net/ows/1.1">gov.usgs.cida.gdp.wps.algorithm.filemanagement.ReceiveFiles</ows:Title>
# </wps:Process>
# ......
# </wps:ProcessOfferings>
elif element . tag . endswith ( ' ProcessOfferings ' ) :
for child in element . findall ( nspath ( ' Process ' , ns = ns ) ) :
p = Process ( child , verbose = self . verbose )
self . processes . append ( p )
if self . verbose == True :
dump ( self . processes [ - 1 ] )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class WPSReader ( object ) :
"""
Superclass for reading a WPS document into a lxml . etree infoset .
"""
2014-09-03 08:43:11 -04:00
def __init__ ( self , version = WPS_DEFAULT_VERSION , verbose = False ) :
2014-05-13 16:18:38 -04:00
self . version = version
self . verbose = verbose
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def _readFromUrl ( self , url , data , method = ' Get ' , username = None , password = None ) :
"""
Method to get and parse a WPS document , returning an elementtree instance .
url : WPS service base url .
data : GET : dictionary of HTTP ( key , value ) parameter pairs , POST : XML document to post
username , password : optional user credentials
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
if method == ' Get ' :
# full HTTP request url
request_url = build_get_url ( url , data )
if self . verbose == True :
print request_url
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# split URL into base url and query string to use utility function
spliturl = request_url . split ( ' ? ' )
u = openURL ( spliturl [ 0 ] , spliturl [ 1 ] , method = ' Get ' , username = username , password = password )
return etree . fromstring ( u . read ( ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
elif method == ' Post ' :
u = openURL ( url , data , method = ' Post ' , username = username , password = password )
return etree . fromstring ( u . read ( ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
else :
raise Exception ( " Unrecognized HTTP method: %s " % method )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def readFromString ( self , string ) :
"""
Method to read a WPS GetCapabilities document from an XML string .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
if not isinstance ( string , str ) :
raise ValueError ( " Input must be of type string, not %s " % type ( string ) )
2014-09-03 08:43:11 -04:00
return etree . fromstring ( string )
2014-05-13 16:18:38 -04:00
class WPSCapabilitiesReader ( WPSReader ) :
"""
Utility class that reads and parses a WPS GetCapabilities document into a lxml . etree infoset .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , version = WPS_DEFAULT_VERSION , verbose = False ) :
# superclass initializer
super ( WPSCapabilitiesReader , self ) . __init__ ( version = version , verbose = verbose )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def readFromUrl ( self , url , username = None , password = None ) :
"""
Method to get and parse a WPS capabilities document , returning an elementtree instance .
url : WPS service base url , to which is appended the HTTP parameters : service , version , and request .
username , password : optional user credentials
"""
2014-09-03 08:43:11 -04:00
return self . _readFromUrl ( url ,
{ ' service ' : ' WPS ' , ' request ' : ' GetCapabilities ' , ' version ' : self . version } ,
2014-05-13 16:18:38 -04:00
username = username , password = password )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class WPSDescribeProcessReader ( WPSReader ) :
"""
Class that reads and parses a WPS DescribeProcess document into a etree infoset
"""
def __init__ ( self , version = WPS_DEFAULT_VERSION , verbose = False ) :
# superclass initializer
super ( WPSDescribeProcessReader , self ) . __init__ ( version = version , verbose = verbose )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def readFromUrl ( self , url , identifier , username = None , password = None ) :
"""
Reads a WPS DescribeProcess document from a remote service and returns the XML etree object
url : WPS service base url , to which is appended the HTTP parameters : ' service ' , ' version ' , and ' request ' , and ' identifier ' .
"""
2014-09-03 08:43:11 -04:00
return self . _readFromUrl ( url ,
{ ' service ' : ' WPS ' , ' request ' : ' DescribeProcess ' , ' version ' : self . version , ' identifier ' : identifier } ,
2014-05-13 16:18:38 -04:00
username = username , password = password )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class WPSExecuteReader ( WPSReader ) :
"""
Class that reads and parses a WPS Execute response document into a etree infoset
"""
def __init__ ( self , verbose = False ) :
# superclass initializer
super ( WPSExecuteReader , self ) . __init__ ( verbose = verbose )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def readFromUrl ( self , url , data = { } , method = ' Get ' , username = None , password = None ) :
"""
Reads a WPS status document from a remote service and returns the XML etree object .
url : the URL to submit the GET / POST request to .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
return self . _readFromUrl ( url , data , method , username = username , password = password )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class WPSExecution ( ) :
"""
Class that represents a single WPS process executed on a remote WPS service .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , version = WPS_DEFAULT_VERSION , url = None , username = None , password = None , verbose = False ) :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# initialize fields
self . url = url
self . version = version
self . username = username
self . password = password
self . verbose = verbose
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# request document
self . request = None
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# last response document
self . response = None
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# status fields retrieved from the response documents
self . process = None
self . serviceInstance = None
self . status = None
self . percentCompleted = 0
self . statusMessage = None
self . errors = [ ]
self . statusLocation = None
self . dataInputs = [ ]
self . processOutputs = [ ]
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def buildRequest ( self , identifier , inputs = [ ] , output = None ) :
"""
Method to build a WPS process request .
identifier : the requested process identifier
inputs : array of input arguments for the process .
- LiteralData inputs are expressed as simple ( key , value ) tuples where key is the input identifier , value is the value
- ComplexData inputs are express as ( key , object ) tuples , where key is the input identifier ,
and the object must contain a ' getXml() ' method that returns an XML infoset to be included in the WPS request
output : optional identifier if process output is to be returned as a hyperlink reference
"""
2014-09-03 08:43:11 -04:00
#<wps:Execute xmlns:wps="http://www.opengis.net/wps/1.0.0"
# xmlns:ows="http://www.opengis.net/ows/1.1"
# xmlns:xlink="http://www.w3.org/1999/xlink"
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
# service="WPS"
# version="1.0.0"
# xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsExecute_request.xsd">
2014-05-13 16:18:38 -04:00
root = etree . Element ( nspath_eval ( ' wps:Execute ' , namespaces ) )
root . set ( ' service ' , ' WPS ' )
root . set ( ' version ' , WPS_DEFAULT_VERSION )
root . set ( nspath_eval ( ' xsi:schemaLocation ' , namespaces ) , ' %s %s ' % ( namespaces [ ' wps ' ] , WPS_DEFAULT_SCHEMA_LOCATION ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:Identifier>gov.usgs.cida.gdp.wps.algorithm.FeatureWeightedGridStatisticsAlgorithm</ows:Identifier>
identifierElement = etree . SubElement ( root , nspath_eval ( ' ows:Identifier ' , namespaces ) )
identifierElement . text = identifier
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <wps:DataInputs>
dataInputsElement = etree . SubElement ( root , nspath_eval ( ' wps:DataInputs ' , namespaces ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
for ( key , val ) in inputs :
inputElement = etree . SubElement ( dataInputsElement , nspath_eval ( ' wps:Input ' , namespaces ) )
identifierElement = etree . SubElement ( inputElement , nspath_eval ( ' ows:Identifier ' , namespaces ) )
identifierElement . text = key
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# Literal data
# <wps:Input>
# <ows:Identifier>DATASET_URI</ows:Identifier>
# <wps:Data>
# <wps:LiteralData>dods://igsarm-cida-thredds1.er.usgs.gov:8080/thredds/dodsC/dcp/conus_grid.w_meta.ncml</wps:LiteralData>
# </wps:Data>
# </wps:Input>
if isinstance ( val , str ) :
dataElement = etree . SubElement ( inputElement , nspath_eval ( ' wps:Data ' , namespaces ) )
literalDataElement = etree . SubElement ( dataElement , nspath_eval ( ' wps:LiteralData ' , namespaces ) )
literalDataElement . text = val
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# Complex data
# <wps:Input>
# <ows:Identifier>FEATURE_COLLECTION</ows:Identifier>
# <wps:Reference xlink:href="http://igsarm-cida-gdp2.er.usgs.gov:8082/geoserver/wfs">
# <wps:Body>
# <wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" service="WFS" version="1.1.0" outputFormat="text/xml; subtype=gml/3.1.1" xsi:schemaLocation="http://www.opengis.net/wfs ../wfs/1.1.0/WFS.xsd">
# <wfs:Query typeName="sample:CONUS_States">
# <wfs:PropertyName>the_geom</wfs:PropertyName>
# <wfs:PropertyName>STATE</wfs:PropertyName>
# <ogc:Filter>
# <ogc:GmlObjectId gml:id="CONUS_States.508"/>
# </ogc:Filter>
# </wfs:Query>
# </wfs:GetFeature>
# </wps:Body>
# </wps:Reference>
# </wps:Input>
else :
inputElement . append ( val . getXml ( ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <wps:ResponseForm>
# <wps:ResponseDocument storeExecuteResponse="true" status="true">
# <wps:Output asReference="true">
# <ows:Identifier>OUTPUT</ows:Identifier>
# </wps:Output>
# </wps:ResponseDocument>
# </wps:ResponseForm>
if output is not None :
responseFormElement = etree . SubElement ( root , nspath_eval ( ' wps:ResponseForm ' , namespaces ) )
2014-09-03 08:43:11 -04:00
responseDocumentElement = etree . SubElement ( responseFormElement , nspath_eval ( ' wps:ResponseDocument ' , namespaces ) ,
2014-05-13 16:18:38 -04:00
attrib = { ' storeExecuteResponse ' : ' true ' , ' status ' : ' true ' } )
if isinstance ( output , str ) :
self . _add_output ( responseDocumentElement , output , asReference = True )
elif isinstance ( output , list ) :
for ( identifier , as_reference ) in output :
self . _add_output ( responseDocumentElement , identifier , asReference = as_reference )
else :
raise Exception ( ' output parameter is neither string nor list. output= %s ' % output )
return root
def _add_output ( self , element , identifier , asReference = False ) :
2014-09-03 08:43:11 -04:00
outputElement = etree . SubElement ( element , nspath_eval ( ' wps:Output ' , namespaces ) ,
2014-05-13 16:18:38 -04:00
attrib = { ' asReference ' : str ( asReference ) . lower ( ) } )
outputIdentifierElement = etree . SubElement ( outputElement , nspath_eval ( ' ows:Identifier ' , namespaces ) ) . text = identifier
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# wait for 60 seconds by default
def checkStatus ( self , url = None , response = None , sleepSecs = 60 ) :
"""
Method to check the status of a job execution .
In the process , this method will upadte the object ' response ' attribute .
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
url : optional ' statusLocation ' URL retrieved from a previous WPS Execute response document .
If not provided , the current ' statusLocation ' URL will be used .
sleepSecs : number of seconds to sleep before returning control to the caller .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
reader = WPSExecuteReader ( verbose = self . verbose )
if response is None :
# override status location
if url is not None :
self . statusLocation = url
print ' \n Checking execution status... (location= %s ) ' % self . statusLocation
response = reader . readFromUrl ( self . statusLocation , username = self . username , password = self . password )
else :
response = reader . readFromString ( response )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# store latest response
self . response = etree . tostring ( response )
if self . verbose == True :
print self . response
self . parseResponse ( response )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# sleep given number of seconds
if self . isComplete ( ) == False :
print ' Sleeping %d seconds... ' % sleepSecs
sleep ( sleepSecs )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def getStatus ( self ) :
return self . status
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def isComplete ( self ) :
if ( self . status == ' ProcessSucceeded ' or self . status == ' ProcessFailed ' or self . status == ' Exception ' ) :
return True
elif ( self . status == ' ProcessStarted ' ) :
return False
elif ( self . status == ' ProcessAccepted ' or self . status == ' ProcessPaused ' ) :
return False
else :
raise Exception ( ' Unknown process execution status: %s ' % self . status )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def isSucceded ( self ) :
if self . status == ' ProcessSucceeded ' :
return True
else :
return False
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def isNotComplete ( self ) :
return not self . isComplete ( )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def getOutput ( self , filepath = None ) :
"""
2014-09-03 08:43:11 -04:00
Method to write the outputs of a WPS process to a file :
either retrieves the referenced files from the server , or writes out the content of response embedded output .
filepath : optional path to the output file , otherwise a file will be created in the local directory with the name assigned by the server ,
2014-05-13 16:18:38 -04:00
or default name ' wps.out ' for embedded output .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
if self . isSucceded ( ) :
content = ' '
for output in self . processOutputs :
2014-09-03 08:43:11 -04:00
output_content = output . retrieveData ( self . username , self . password )
2014-05-13 16:18:38 -04:00
# ExecuteResponse contains reference to server-side output
2014-09-03 08:43:11 -04:00
if output_content is not " " :
content = content + output_content
if filepath is None :
filepath = output . fileName
# ExecuteResponse contain embedded output
2014-05-13 16:18:38 -04:00
if len ( output . data ) > 0 :
if filepath is None :
filepath = ' wps.out '
for data in output . data :
content = content + data
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# write out content
if content is not ' ' :
out = open ( filepath , ' wb ' )
out . write ( content )
out . close ( )
print ' Output written to file: %s ' % filepath
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
else :
raise Exception ( " Execution not successfully completed: status= %s " % self . status )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def submitRequest ( self , request ) :
"""
Submits a WPS Execute document to a remote service , returns the XML response document from the server .
This method will save the request document and the first returned response document .
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
request : the XML request document to be submitted as POST to the server .
2014-09-03 08:43:11 -04:00
"""
2014-05-13 16:18:38 -04:00
self . request = request
reader = WPSExecuteReader ( verbose = self . verbose )
response = reader . readFromUrl ( self . url , request , method = ' Post ' , username = self . username , password = self . password )
self . response = response
return response
2014-09-03 08:43:11 -04:00
'''
2014-05-13 16:18:38 -04:00
if response is None :
# override status location
if url is not None :
self . statusLocation = url
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
else :
response = reader . readFromString ( response )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
'''
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def parseResponse ( self , response ) :
"""
Method to parse a WPS response document
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
rootTag = response . tag . split ( ' } ' ) [ 1 ]
# <ns0:ExecuteResponse>
if rootTag == ' ExecuteResponse ' :
self . _parseExecuteResponse ( response )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:ExceptionReport>
elif rootTag == ' ExceptionReport ' :
self . _parseExceptionReport ( response )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
else :
print ' Unknown Response '
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# print status, errors
print ' Execution status= %s ' % self . status
print ' Percent completed= %s ' % self . percentCompleted
print ' Status message= %s ' % self . statusMessage
for error in self . errors :
dump ( error )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def _parseExceptionReport ( self , root ) :
"""
Method to parse a WPS ExceptionReport document and populate this object ' s metadata.
"""
# set exception status, unless set already
if self . status is None :
self . status = " Exception "
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
for exceptionEl in root . findall ( nspath ( ' Exception ' , ns = namespaces [ ' ows ' ] ) ) :
self . errors . append ( WPSException ( exceptionEl ) )
2014-09-03 08:43:11 -04:00
def _parseExecuteResponse ( self , root ) :
2014-05-13 16:18:38 -04:00
"""
Method to parse a WPS ExecuteResponse response document and populate this object ' s metadata.
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# retrieve WPS namespace directly from root element
wpsns = getNamespace ( root )
self . serviceInstance = root . get ( ' serviceInstance ' )
self . statusLocation = root . get ( ' statusLocation ' )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ns0:Status creationTime="2011-11-09T14:19:50Z">
# <ns0:ProcessSucceeded>PyWPS Process v.net.path successfully calculated</ns0:ProcessSucceeded>
# </ns0:Status>
# OR
# <ns0:Status creationTime="2011-11-07T08:26:44.359-06:00">
# <ns0:ProcessFailed>
# <ows:ExceptionReport xmlns:ows="http://www.opengis.net/ows/1.1">
# <ows:Exception>
# <ows:ExceptionText>Attribute null not found in feature collection</ows:ExceptionText>
# </ows:Exception>
# </ows:ExceptionReport>
# </ns0:ProcessFailed>
# </ns0:Status>
statusEl = root . find ( nspath ( ' Status/* ' , ns = wpsns ) )
self . status = statusEl . tag . split ( ' } ' ) [ 1 ]
# get progress info
try :
percentCompleted = int ( statusEl . get ( ' percentCompleted ' ) )
self . percentCompleted = percentCompleted
except :
pass
# get status message
self . statusMessage = statusEl . text
# exceptions ?
for element in statusEl :
if element . tag . endswith ( ' ExceptionReport ' ) :
self . _parseExceptionReport ( element )
self . process = Process ( root . find ( nspath ( ' Process ' , ns = wpsns ) ) , verbose = self . verbose )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
#<wps:DataInputs xmlns:wps="http://www.opengis.net/wps/1.0.0"
# xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
for inputElement in root . findall ( nspath ( ' DataInputs/Input ' , ns = wpsns ) ) :
self . dataInputs . append ( Input ( inputElement ) )
if self . verbose == True :
dump ( self . dataInputs [ - 1 ] )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ns:ProcessOutputs>
2014-09-03 08:43:11 -04:00
# xmlns:ns="http://www.opengis.net/wps/1.0.0"
2014-05-13 16:18:38 -04:00
for outputElement in root . findall ( nspath ( ' ProcessOutputs/Output ' , ns = wpsns ) ) :
self . processOutputs . append ( Output ( outputElement ) )
if self . verbose == True :
dump ( self . processOutputs [ - 1 ] )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class ComplexData ( object ) :
"""
Class that represents a ComplexData element in a WPS document
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , mimeType = None , encoding = None , schema = None ) :
self . mimeType = mimeType
self . encoding = encoding
self . schema = schema
class InputOutput ( object ) :
"""
Superclass of a WPS input or output data object .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , element ) :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# loop over sub-elements without requiring a specific namespace
for subElement in element :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:Identifier xmlns:ows="http://www.opengis.net/ows/1.1">SUMMARIZE_TIMESTEP</ows:Identifier>
if subElement . tag . endswith ( ' Identifier ' ) :
self . identifier = testXMLValue ( subElement )
# <ows:Title xmlns:ows="http://www.opengis.net/ows/1.1">Summarize Timestep</ows:Title>
elif subElement . tag . endswith ( ' Title ' ) :
self . title = testXMLValue ( subElement )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:Abstract xmlns:ows="http://www.opengis.net/ows/1.1">If selected, processing output will include columns with summarized statistics for all feature attribute values for each timestep</ows:Abstract>
elif subElement . tag . endswith ( ' Abstract ' ) :
self . abstract = testXMLValue ( subElement )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
self . allowedValues = [ ]
self . supportedValues = [ ]
self . defaultValue = None
self . dataType = None
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def _parseData ( self , element ) :
"""
Method to parse a " Data " element
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ns0:Data>
# <ns0:ComplexData mimeType="text/plain">
2014-09-03 08:43:11 -04:00
# 7504912.93758151 -764109.175074507,7750849.82379226 -22141.8611641468,8561828.42371234 -897195.923493867,7724946.16844165 -602984.014261927
2014-05-13 16:18:38 -04:00
# </ns0:ComplexData>
# </ns0:Data>
#nspath('Data', ns=WPS_NAMESPACE)
complexDataElement = element . find ( nspath ( ' ComplexData ' , ns = getNamespace ( element ) ) )
if complexDataElement is not None :
self . dataType = " ComplexData "
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def _parseLiteralData ( self , element , literalElementName ) :
"""
Method to parse the LiteralData element .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <LiteralData>
# <ows:DataType ows:reference="xs:string" xmlns:ows="http://www.opengis.net/ows/1.1" />
# <ows:AllowedValues xmlns:ows="http://www.opengis.net/ows/1.1">
# <ows:Value>COMMA</ows:Value>
# <ows:Value>TAB</ows:Value>
# <ows:Value>SPACE</ows:Value>
# </ows:AllowedValues>
# <DefaultValue>COMMA</DefaultValue>
# </LiteralData>
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <LiteralData>
# <ows:DataType ows:reference="xs:anyURI" xmlns:ows="http://www.opengis.net/ows/1.1" />
# <ows:AnyValue xmlns:ows="http://www.opengis.net/ows/1.1" />
# </LiteralData>
literalDataElement = element . find ( literalElementName )
if literalDataElement is not None :
self . dataType = ' LiteralData '
for subElement in literalDataElement :
subns = getNamespace ( subElement )
if subElement . tag . endswith ( ' DataType ' ) :
self . dataType = subElement . get ( nspath ( " reference " , ns = subns ) ) . split ( ' : ' ) [ 1 ]
elif subElement . tag . endswith ( ' AllowedValues ' ) :
for value in subElement . findall ( nspath ( ' Value ' , ns = subns ) ) :
self . allowedValues . append ( getTypedValue ( self . dataType , value . text ) )
elif subElement . tag . endswith ( ' DefaultValue ' ) :
self . defaultValue = getTypedValue ( self . dataType , subElement . text )
elif subElement . tag . endswith ( ' AnyValue ' ) :
self . allowedValues . append ( getTypedValue ( self . dataType , ' AnyValue ' ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def _parseComplexData ( self , element , complexDataElementName ) :
"""
Method to parse a ComplexData or ComplexOutput element .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ComplexData>
# <Default>
# <Format>
# <MimeType>text/xml</MimeType>
# <Encoding>UTF-8</Encoding>
# <Schema>http://schemas.opengis.net/gml/2.0.0/feature.xsd</Schema>
# </Format>
# </Default>
# <Supported>
# <Format>
# <MimeType>text/xml</MimeType>
# <Encoding>UTF-8</Encoding>
# <Schema>http://schemas.opengis.net/gml/2.0.0/feature.xsd</Schema>
# </Format>
# <Format>
# <MimeType>text/xml</MimeType>
# <Encoding>UTF-8</Encoding>
# <Schema>http://schemas.opengis.net/gml/2.1.1/feature.xsd</Schema>
# </Format>
# </Supported>
# </ComplexData>
# OR
# <ComplexOutput defaultEncoding="UTF-8" defaultFormat="text/XML" defaultSchema="NONE">
# <SupportedComplexData>
# <Format>text/XML</Format>
# <Encoding>UTF-8</Encoding>
# <Schema>NONE</Schema>
# </SupportedComplexData>
# </ComplexOutput>
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
complexDataElement = element . find ( complexDataElementName )
if complexDataElement is not None :
self . dataType = " ComplexData "
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
for supportedComlexDataElement in complexDataElement . findall ( ' SupportedComplexData ' ) :
self . supportedValues . append ( ComplexData ( mimeType = testXMLValue ( supportedComlexDataElement . find ( ' Format ' ) ) ,
encoding = testXMLValue ( supportedComlexDataElement . find ( ' Encoding ' ) ) ,
2014-09-03 08:43:11 -04:00
schema = testXMLValue ( supportedComlexDataElement . find ( ' Schema ' ) )
)
2014-05-13 16:18:38 -04:00
)
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
for formatElement in complexDataElement . findall ( ' Supported/Format ' ) :
self . supportedValues . append ( ComplexData ( mimeType = testXMLValue ( formatElement . find ( ' MimeType ' ) ) ,
encoding = testXMLValue ( formatElement . find ( ' Encoding ' ) ) ,
2014-09-03 08:43:11 -04:00
schema = testXMLValue ( formatElement . find ( ' Schema ' ) )
)
2014-05-13 16:18:38 -04:00
)
2014-09-03 08:43:11 -04:00
defaultFormatElement = complexDataElement . find ( ' Default/Format ' )
2014-05-13 16:18:38 -04:00
if defaultFormatElement is not None :
self . defaultValue = ComplexData ( mimeType = testXMLValue ( defaultFormatElement . find ( ' MimeType ' ) ) ,
encoding = testXMLValue ( defaultFormatElement . find ( ' Encoding ' ) ) ,
2014-09-03 08:43:11 -04:00
schema = testXMLValue ( defaultFormatElement . find ( ' Schema ' ) )
)
2014-05-13 16:18:38 -04:00
class Input ( InputOutput ) :
"""
Class that represents a WPS process input .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , inputElement ) :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# superclass initializer
super ( Input , self ) . __init__ ( inputElement )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <Input maxOccurs="1" minOccurs="0">
# OR
# <MinimumOccurs>1</MinimumOccurs>
self . minOccurs = - 1
if inputElement . get ( " minOccurs " ) is not None :
self . minOccurs = int ( inputElement . get ( " minOccurs " ) )
if inputElement . find ( ' MinimumOccurs ' ) is not None :
2014-09-03 08:43:11 -04:00
self . minOccurs = int ( testXMLValue ( inputElement . find ( ' MinimumOccurs ' ) ) )
2014-05-13 16:18:38 -04:00
self . maxOccurs = - 1
if inputElement . get ( " maxOccurs " ) is not None :
self . maxOccurs = int ( inputElement . get ( " maxOccurs " ) )
if inputElement . find ( ' MaximumOccurs ' ) is not None :
2014-09-03 08:43:11 -04:00
self . maxOccurs = int ( testXMLValue ( inputElement . find ( ' MaximumOccurs ' ) ) )
2014-05-13 16:18:38 -04:00
# <LiteralData>
self . _parseLiteralData ( inputElement , ' LiteralData ' )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ComplexData>
self . _parseComplexData ( inputElement , ' ComplexData ' )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class Output ( InputOutput ) :
"""
Class that represents a WPS process output .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , outputElement ) :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# superclass initializer
super ( Output , self ) . __init__ ( outputElement )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
self . reference = None
self . mimeType = None
self . data = [ ]
2014-09-03 08:43:11 -04:00
self . fileName = None
self . filePath = None
2014-05-13 16:18:38 -04:00
# extract wps namespace from outputElement itself
wpsns = getNamespace ( outputElement )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ns:Reference encoding="UTF-8" mimeType="text/csv"
# href="http://cida.usgs.gov/climate/gdp/process/RetrieveResultServlet?id=1318528582026OUTPUT.601bb3d0-547f-4eab-8642-7c7d2834459e" />
referenceElement = outputElement . find ( nspath ( ' Reference ' , ns = wpsns ) )
if referenceElement is not None :
self . reference = referenceElement . get ( ' href ' )
self . mimeType = referenceElement . get ( ' mimeType ' )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <LiteralOutput>
self . _parseLiteralData ( outputElement , ' LiteralOutput ' )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ComplexData> or <ComplexOutput>
self . _parseComplexData ( outputElement , ' ComplexOutput ' )
2014-09-03 08:43:11 -04:00
# <Data>
2014-05-13 16:18:38 -04:00
# <ns0:Data>
# <ns0:ComplexData mimeType="text/plain">
2014-09-03 08:43:11 -04:00
# 7504912.93758151 -764109.175074507,7750849.82379226 -22141.8611641468,8561828.42371234 -897195.923493867,7724946.16844165 -602984.014261927
2014-05-13 16:18:38 -04:00
# </ns0:ComplexData>
# </ns0:Data>
# OR:
# <ns0:Data>
# <ns0:ComplexData encoding="UTF-8" mimeType="text/xml" schema="http://schemas.opengis.net/gml/2.1.2/feature.xsd">
# <ns3:FeatureCollection xsi:schemaLocation="http://ogr.maptools.org/ output_0n7ij9D.xsd" xmlns:ns3="http://ogr.maptools.org/">
# <gml:boundedBy xmlns:gml="http://www.opengis.net/gml">
# <gml:Box>
# <gml:coord><gml:X>-960123.1421801626</gml:X><gml:Y>4665723.56559387</gml:Y></gml:coord>
# <gml:coord><gml:X>-101288.6510608822</gml:X><gml:Y>5108200.011823481</gml:Y></gml:coord>
# </gml:Box>
2014-09-03 08:43:11 -04:00
# </gml:boundedBy>
2014-05-13 16:18:38 -04:00
# <gml:featureMember xmlns:gml="http://www.opengis.net/gml">
# <ns3:output fid="F0">
# <ns3:geometryProperty><gml:LineString><gml:coordinates>-960123.142180162365548,4665723.565593870356679,0 -960123.142180162365548,4665723.565593870356679,0 -960123.142180162598379,4665723.565593870356679,0 -960123.142180162598379,4665723.565593870356679,0 -711230.141176006174646,4710278.48552671354264,0 -711230.141176006174646,4710278.48552671354264,0 -623656.677859728806652,4848552.374973464757204,0 -623656.677859728806652,4848552.374973464757204,0 -410100.337491964863148,4923834.82589447684586,0 -410100.337491964863148,4923834.82589447684586,0 -101288.651060882242746,5108200.011823480948806,0 -101288.651060882242746,5108200.011823480948806,0 -101288.651060882257298,5108200.011823480948806,0 -101288.651060882257298,5108200.011823480948806,0</gml:coordinates></gml:LineString></ns3:geometryProperty>
# <ns3:cat>1</ns3:cat>
# <ns3:id>1</ns3:id>
# <ns3:fcat>0</ns3:fcat>
# <ns3:tcat>0</ns3:tcat>
# <ns3:sp>0</ns3:sp>
# <ns3:cost>1002619.181</ns3:cost>
# <ns3:fdist>0</ns3:fdist>
# <ns3:tdist>0</ns3:tdist>
# </ns3:output>
# </gml:featureMember>
# </ns3:FeatureCollection>
# </ns0:ComplexData>
# </ns0:Data>
2014-09-03 08:43:11 -04:00
dataElement = outputElement . find ( nspath ( ' Data ' , ns = wpsns ) )
2014-05-13 16:18:38 -04:00
if dataElement is not None :
complexDataElement = dataElement . find ( nspath ( ' ComplexData ' , ns = wpsns ) )
if complexDataElement is not None :
self . dataType = " ComplexData "
self . mimeType = complexDataElement . get ( ' mimeType ' )
#print etree.tostring(complexDataElement)
if complexDataElement . text is not None and complexDataElement . text . strip ( ) is not ' ' :
self . data . append ( complexDataElement . text . strip ( ) )
for child in complexDataElement :
self . data . append ( etree . tostring ( child ) )
literalDataElement = dataElement . find ( nspath ( ' LiteralData ' , ns = wpsns ) )
if literalDataElement is not None :
self . dataType = literalDataElement . get ( ' dataType ' )
if literalDataElement . text is not None and literalDataElement . text . strip ( ) is not ' ' :
self . data . append ( literalDataElement . text . strip ( ) )
2014-09-03 08:43:11 -04:00
def retrieveData ( self , username = None , password = None ) :
"""
Method to retrieve data from server - side reference :
returns " " if the reference is not known .
username , password : credentials to access the remote WPS server
"""
url = self . reference
if url is None :
return " "
# a) 'http://cida.usgs.gov/climate/gdp/process/RetrieveResultServlet?id=1318528582026OUTPUT.601bb3d0-547f-4eab-8642-7c7d2834459e'
# b) 'http://rsg.pml.ac.uk/wps/wpsoutputs/outputImage-11294Bd6l2a.tif'
print ' Output URL= %s ' % url
if ' ? ' in url :
spliturl = url . split ( ' ? ' )
u = openURL ( spliturl [ 0 ] , spliturl [ 1 ] , method = ' Get ' , username = username , password = password )
# extract output filepath from URL query string
self . fileName = spliturl [ 1 ] . split ( ' = ' ) [ 1 ]
else :
u = openURL ( url , ' ' , method = ' Get ' , username = username , password = password )
# extract output filepath from base URL
self . fileName = url . split ( ' / ' ) [ - 1 ]
return u . read ( )
def writeToDisk ( self , path = None , username = None , password = None ) :
"""
Method to write an output of a WPS process to disk :
it either retrieves the referenced file from the server , or write out the content of response embedded output .
filepath : optional path to the output file , otherwise a file will be created in the local directory with the name assigned by the server ,
username , password : credentials to access the remote WPS server
"""
# Check if ExecuteResponse contains reference to server-side output
content = self . retrieveData ( username , password )
# ExecuteResponse contain embedded output
if content is " " and len ( self . data ) > 0 :
self . fileName = self . identifier
for data in self . data :
content = content + data
# write out content
if content is not " " :
if self . fileName == " " :
self . fileName = self . identifier
self . filePath = path + self . fileName
out = open ( self . filePath , ' wb ' )
out . write ( content )
out . close ( )
print ' Output written to file: %s ' % self . filePath
2014-05-13 16:18:38 -04:00
class WPSException :
"""
Class representing an exception raised by a WPS .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , root ) :
self . code = root . attrib . get ( " exceptionCode " , None )
self . locator = root . attrib . get ( " locator " , None )
textEl = root . find ( nspath ( ' ExceptionText ' , ns = getNamespace ( root ) ) )
if textEl is not None :
self . text = textEl . text
else :
self . text = " "
class Process ( object ) :
"""
Class that represents a WPS process .
"""
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , elem , verbose = False ) :
""" Initialization method extracts all available metadata from an XML document (passed in as etree object) """
2014-09-03 08:43:11 -04:00
# <ns0:ProcessDescriptions service="WPS" version="1.0.0"
# xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsDescribeProcess_response.xsd"
2014-05-13 16:18:38 -04:00
# xml:lang="en-US" xmlns:ns0="http://www.opengis.net/wps/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
# OR:
# <ns0:Process ns0:processVersion="1.0.0">
self . _root = elem
self . verbose = verbose
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
wpsns = getNamespace ( elem )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ProcessDescription statusSupported="true" storeSupported="true" ns0:processVersion="1.0.0">
self . processVersion = elem . get ( nspath ( ' processVersion ' , ns = wpsns ) )
self . statusSupported = bool ( elem . get ( " statusSupported " ) )
self . storeSupported = bool ( elem . get ( " storeSupported " ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
for child in elem :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# this element's namespace
ns = getNamespace ( child )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:Identifier xmlns:ows="http://www.opengis.net/ows/1.1">gov.usgs.cida.gdp.wps.algorithm.FeatureWeightedGridStatisticsAlgorithm</ows:Identifier>
if child . tag . endswith ( ' Identifier ' ) :
self . identifier = testXMLValue ( child )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:Title xmlns:ows="http://www.opengis.net/ows/1.1">Feature Weighted Grid Statistics</ows:Title>
elif child . tag . endswith ( ' Title ' ) :
self . title = testXMLValue ( child )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ows:Abstract xmlns:ows="http://www.opengis.net/ows/1.1">This algorithm generates area weighted statistics of a gridded dataset for a set of vector polygon features. Using the bounding-box that encloses the feature data and the time range, if provided, a subset of the gridded dataset is requested from the remote gridded data server. Polygon representations are generated for cells in the retrieved grid. The polygon grid-cell representations are then projected to the feature data coordinate reference system. The grid-cells are used to calculate per grid-cell feature coverage fractions. Area-weighted statistics are then calculated for each feature using the grid values and fractions as weights. If the gridded dataset has a time range the last step is repeated for each time step within the time range or all time steps if a time range was not supplied.</ows:Abstract>
elif child . tag . endswith ( ' Abstract ' ) :
self . abstract = testXMLValue ( child )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
if self . verbose == True :
dump ( self )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <DataInputs>
self . dataInputs = [ ]
for inputElement in elem . findall ( ' DataInputs/Input ' ) :
self . dataInputs . append ( Input ( inputElement ) )
if self . verbose == True :
dump ( self . dataInputs [ - 1 ] , prefix = ' \t Input: ' )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <ProcessOutputs>
self . processOutputs = [ ]
for outputElement in elem . findall ( ' ProcessOutputs/Output ' ) :
self . processOutputs . append ( Output ( outputElement ) )
if self . verbose == True :
dump ( self . processOutputs [ - 1 ] , prefix = ' \t Output: ' )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class FeatureCollection ( ) :
'''
Base class to represent a Feature Collection used as input to a WPS request .
The method getXml ( ) is invoked by the WPS execute ( ) method to build the WPS request .
All subclasses must implement the getXml ( ) method to provide their specific XML .
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
Implements IComplexData .
'''
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self ) :
pass
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def getXml ( self ) :
raise NotImplementedError
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class WFSFeatureCollection ( FeatureCollection ) :
'''
FeatureCollection specified by a WFS query .
All subclasses must implement the getQuery ( ) method to provide the specific query portion of the XML .
'''
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , wfsUrl , wfsQuery ) :
'''
wfsUrl : the WFS service URL
example : wfsUrl = " http://igsarm-cida-gdp2.er.usgs.gov:8082/geoserver/wfs "
wfsQuery : a WFS query instance
'''
self . url = wfsUrl
self . query = wfsQuery
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <wps:Reference xlink:href="http://igsarm-cida-gdp2.er.usgs.gov:8082/geoserver/wfs">
# <wps:Body>
# <wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" service="WFS" version="1.1.0" outputFormat="text/xml; subtype=gml/3.1.1" xsi:schemaLocation="http://www.opengis.net/wfs ../wfs/1.1.0/WFS.xsd">
# .......
# </wfs:GetFeature>
# </wps:Body>
# </wps:Reference>
def getXml ( self ) :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
root = etree . Element ( nspath_eval ( ' wps:Reference ' , namespaces ) , attrib = { nspath_eval ( " xlink:href " , namespaces ) : self . url } )
bodyElement = etree . SubElement ( root , nspath_eval ( ' wps:Body ' , namespaces ) )
getFeatureElement = etree . SubElement ( bodyElement , nspath_eval ( ' wfs:GetFeature ' , namespaces ) ,
attrib = { " service " : " WFS " ,
" version " : " 1.1.0 " ,
" outputFormat " : " text/xml; subtype=gml/3.1.1 " ,
nspath_eval ( " xsi:schemaLocation " , namespaces ) : " %s %s " % ( namespaces [ ' wfs ' ] , ' ../wfs/1.1.0/WFS.xsd ' ) } )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <wfs:Query typeName="sample:CONUS_States">
# <wfs:PropertyName>the_geom</wfs:PropertyName>
# <wfs:PropertyName>STATE</wfs:PropertyName>
# <ogc:Filter>
# <ogc:GmlObjectId gml:id="CONUS_States.508"/>
# </ogc:Filter>
# </wfs:Query>
getFeatureElement . append ( self . query . getXml ( ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
return root
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class WFSQuery ( ) :
'''
Class representing a WFS query , for insertion into a WFSFeatureCollection instance .
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
Implements IComplexData .
'''
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , typeName , propertyNames = [ ] , filters = [ ] ) :
self . typeName = typeName
self . propertyNames = propertyNames
self . filters = filters
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def getXml ( self ) :
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# <wfs:Query typeName="sample:CONUS_States">
# <wfs:PropertyName>the_geom</wfs:PropertyName>
# <wfs:PropertyName>STATE</wfs:PropertyName>
# <ogc:Filter>
# <ogc:GmlObjectId gml:id="CONUS_States.508"/>
# </ogc:Filter>
# </wfs:Query>
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
queryElement = etree . Element ( nspath_eval ( ' wfs:Query ' , namespaces ) , attrib = { " typeName " : self . typeName } )
for propertyName in self . propertyNames :
propertyNameElement = etree . SubElement ( queryElement , nspath_eval ( ' wfs:PropertyName ' , namespaces ) )
propertyNameElement . text = propertyName
if len ( self . filters ) > 0 :
filterElement = etree . SubElement ( queryElement , nspath_eval ( ' ogc:Filter ' , namespaces ) )
for filter in self . filters :
2014-09-03 08:43:11 -04:00
gmlObjectIdElement = etree . SubElement ( filterElement , nspath_eval ( ' ogc:GmlObjectId ' , namespaces ) ,
2014-05-13 16:18:38 -04:00
attrib = { nspath_eval ( ' gml:id ' , namespaces ) : filter } )
return queryElement
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
class GMLMultiPolygonFeatureCollection ( FeatureCollection ) :
'''
Class that represents a FeatureCollection defined as a GML multi - polygon .
'''
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def __init__ ( self , polygons ) :
'''
Initializer accepts an array of polygons , where each polygon is an array of ( lat , lon ) tuples .
Example : polygons = [ [ ( - 102.8184 , 39.5273 ) , ( - 102.8184 , 37.418 ) , ( - 101.2363 , 37.418 ) , ( - 101.2363 , 39.5273 ) , ( - 102.8184 , 39.5273 ) ] ,
[ ( - 92.8184 , 39.5273 ) , ( - 92.8184 , 37.418 ) , ( - 91.2363 , 37.418 ) , ( - 91.2363 , 39.5273 ) , ( - 92.8184 , 39.5273 ) ] ]
'''
self . polygons = polygons
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def getXml ( self ) :
'''
< wps : Data >
< wps : ComplexData mimeType = " text/xml " encoding = " UTF-8 "
schema = " http://schemas.opengis.net/gml/3.1.1/base/feature.xsd " >
< gml : featureMembers xmlns : ogc = " http://www.opengis.net/ogc "
xmlns : draw = " gov.usgs.cida.gdp.draw " xmlns : xsi = " http://www.w3.org/2001/XMLSchema-instance "
xmlns : ows = " http://www.opengis.net/ows " xmlns : gml = " http://www.opengis.net/gml "
xmlns : xlink = " http://www.w3.org/1999/xlink "
xsi : schemaLocation = " gov.usgs.cida.gdp.draw http://cida.usgs.gov/climate/derivative/xsd/draw.xsd " >
< gml : box gml : id = " box.1 " >
< gml : the_geom >
< gml : MultiPolygon srsDimension = " 2 "
srsName = " http://www.opengis.net/gml/srs/epsg.xml#4326 " >
< gml : polygonMember >
< gml : Polygon >
< gml : exterior >
< gml : LinearRing >
< gml : posList > - 102.8184 39.5273 - 102.8184 37.418 - 101.2363 37.418 - 101.2363 39.5273 - 102.8184 39.5273 < / gml : posList >
< / gml : LinearRing >
< / gml : exterior >
< / gml : Polygon >
< / gml : polygonMember >
< / gml : MultiPolygon >
< / gml : the_geom >
< gml : ID > 0 < / gml : ID >
< / gml : box >
< / gml : featureMembers >
< / wps : ComplexData >
< / wps : Data >
'''
dataElement = etree . Element ( nspath_eval ( ' wps:Data ' , namespaces ) )
complexDataElement = etree . SubElement ( dataElement , nspath_eval ( ' wps:ComplexData ' , namespaces ) ,
attrib = { " mimeType " : " text/xml " , " encoding " : " UTF-8 " , " schema " : GML_SCHEMA_LOCATION } )
featureMembersElement = etree . SubElement ( complexDataElement , nspath_eval ( ' gml:featureMembers ' , namespaces ) ,
attrib = { nspath_eval ( " xsi:schemaLocation " , namespaces ) : " %s %s " % ( DRAW_NAMESPACE , DRAW_SCHEMA_LOCATION ) } )
boxElement = etree . SubElement ( featureMembersElement , nspath_eval ( ' gml:box ' , namespaces ) , attrib = { nspath_eval ( " gml:id " , namespaces ) : " box.1 " } )
geomElement = etree . SubElement ( boxElement , nspath_eval ( ' gml:the_geom ' , namespaces ) )
multiPolygonElement = etree . SubElement ( geomElement , nspath_eval ( ' gml:MultiPolygon ' , namespaces ) ,
attrib = { " srsDimension " : " 2 " , " srsName " : " http://www.opengis.net/gml/srs/epsg.xml#4326 " } )
for polygon in self . polygons :
polygonMemberElement = etree . SubElement ( multiPolygonElement , nspath_eval ( ' gml:polygonMember ' , namespaces ) )
polygonElement = etree . SubElement ( polygonMemberElement , nspath_eval ( ' gml:Polygon ' , namespaces ) )
exteriorElement = etree . SubElement ( polygonElement , nspath_eval ( ' gml:exterior ' , namespaces ) )
linearRingElement = etree . SubElement ( exteriorElement , nspath_eval ( ' gml:LinearRing ' , namespaces ) )
posListElement = etree . SubElement ( linearRingElement , nspath_eval ( ' gml:posList ' , namespaces ) )
posListElement . text = ' ' . join ( [ " %s %s " % ( x , y ) for x , y in polygon [ : ] ] )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
idElement = etree . SubElement ( boxElement , nspath_eval ( ' gml:ID ' , namespaces ) )
idElement . text = " 0 "
return dataElement
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
def monitorExecution ( execution , sleepSecs = 3 , download = False , filepath = None ) :
'''
2014-09-03 08:43:11 -04:00
Convenience method to monitor the status of a WPS execution till it completes ( succesfully or not ) ,
and write the output to file after a succesfull job completion .
2014-05-13 16:18:38 -04:00
execution : WPSExecution instance
sleepSecs : number of seconds to sleep in between check status invocations
download : True to download the output when the process terminates , False otherwise
filepath : optional path to output file ( if downloaded = True ) , otherwise filepath will be inferred from response document
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
'''
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
while execution . isComplete ( ) == False :
execution . checkStatus ( sleepSecs = sleepSecs )
print ' Execution status: %s ' % execution . status
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
if execution . isSucceded ( ) :
if download :
execution . getOutput ( filepath = filepath )
else :
2014-09-03 08:43:11 -04:00
for output in execution . processOutputs :
2014-05-13 16:18:38 -04:00
if output . reference is not None :
print ' Output URL= %s ' % output . reference
else :
for ex in execution . errors :
print ' Error: code= %s , locator= %s , text= %s ' % ( ex . code , ex . locator , ex . text )
def printValue ( value ) :
'''
Utility method to format a value for printing .
'''
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# ComplexData type
if isinstance ( value , ComplexData ) :
return " mimeType= %s , encoding= %s , schema= %s " % ( value . mimeType , value . encoding , value . schema )
# other type
else :
return value
def printInputOutput ( value , indent = ' ' ) :
'''
Utility method to inspect an input / output element .
'''
# InputOutput fields
print ' %s identifier= %s , title= %s , abstract= %s , data type= %s ' % ( indent , value . identifier , value . title , value . abstract , value . dataType )
for val in value . allowedValues :
print ' %s Allowed Value: %s ' % ( indent , printValue ( val ) )
for val in value . supportedValues :
print ' %s Supported Value: %s ' % ( indent , printValue ( val ) )
print ' %s Default Value: %s ' % ( indent , printValue ( value . defaultValue ) )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# Input fields
if isinstance ( value , Input ) :
print ' %s minOccurs= %d , maxOccurs= %d ' % ( indent , value . minOccurs , value . maxOccurs )
2014-09-03 08:43:11 -04:00
2014-05-13 16:18:38 -04:00
# Output fields
if isinstance ( value , Output ) :
print ' %s reference= %s , mimeType= %s ' % ( indent , value . reference , value . mimeType )
for datum in value . data :
print ' %s Data Value: %s ' % ( indent , printValue ( datum ) )