Skip to content

Commit

Permalink
Introduction of WPS 2.0.0 templates and tests
Browse files Browse the repository at this point in the history
Rewriting outputs using Jinja2 templates
Introduction WPS 2.0.0 capabilities response
  • Loading branch information
jachym committed Jun 19, 2018
1 parent cde7d3d commit 0f7122d
Show file tree
Hide file tree
Showing 34 changed files with 963 additions and 1,094 deletions.
30 changes: 26 additions & 4 deletions pywps/__init__.py
Expand Up @@ -18,15 +18,37 @@

NAMESPACES = {
'xlink': "http://www.w3.org/1999/xlink",
'wps': "http://www.opengis.net/wps/1.0.0",
'ows': "http://www.opengis.net/ows/1.1",
'wps': "http://www.opengis.net/wps/{wps_version}",
'ows': "http://www.opengis.net/ows/{ows_version}",
'gml': "http://www.opengis.net/gml",
'xsi': "http://www.w3.org/2001/XMLSchema-instance"
}

E = ElementMaker()
WPS = ElementMaker(namespace=NAMESPACES['wps'], nsmap=NAMESPACES)
OWS = ElementMaker(namespace=NAMESPACES['ows'], nsmap=NAMESPACES)
namespaces100 = {k: NAMESPACES[k].format(wps_version="1.0.0", ows_version="1.1") for k in NAMESPACES}
namespaces200 = {k: NAMESPACES[k].format(wps_version="2.0", ows_version="2.0") for k in NAMESPACES}


def get_ElementMakerForVersion(version):
WPS = OWS = None
if version == "1.0.0":
WPS = ElementMaker(namespace=namespaces100['wps'], nsmap=namespaces100)
OWS = ElementMaker(namespace=namespaces100['ows'], nsmap=namespaces100)
elif version == "2.0.0":
WPS = ElementMaker(namespace=namespaces200['wps'], nsmap=namespaces200)
OWS = ElementMaker(namespace=namespaces200['ows'], nsmap=namespaces200)

return WPS, OWS


def get_version_from_ns(ns):
if ns == "http://www.opengis.net/wps/1.0.0":
return "1.0.0"
elif ns == "http://www.opengis.net/wps/2.0":
return "2.0.0"
else:
return None


OGCTYPE = {
'measure': 'urn:ogc:def:dataType:OGC:1.1:measure',
Expand Down
10 changes: 6 additions & 4 deletions pywps/app/Common.py
Expand Up @@ -25,9 +25,11 @@ def __init__(self, title, href=None, role=None, type_='simple'):
self.type = type_

def __iter__(self):
yield '{http://www.w3.org/1999/xlink}title', self.title
metadata = {"title": self.title}

if self.href is not None:
yield '{http://www.w3.org/1999/xlink}href', self.href
metadata['href'] = self.href
if self.role is not None:
yield '{http://www.w3.org/1999/xlink}role', self.role
yield '{http://www.w3.org/1999/xlink}type', self.type
metadata['role'] = self.role
metadata['type'] = self.type
yield metadata
74 changes: 17 additions & 57 deletions pywps/app/Process.py
Expand Up @@ -11,7 +11,7 @@
import shutil
import tempfile

from pywps import WPS, OWS, E, dblog
from pywps import get_ElementMakerForVersion, E, dblog
from pywps.response import get_response
from pywps.response.status import STATUS
from pywps.app.WPSRequest import WPSRequest
Expand Down Expand Up @@ -76,62 +76,22 @@ def __init__(self, handler, identifier, title, abstract='', keywords=[], profile
else:
self.status_supported = 'false'

def capabilities_xml(self):
doc = WPS.Process(
OWS.Identifier(self.identifier),
OWS.Title(self.title)
)
if self.abstract:
doc.append(OWS.Abstract(self.abstract))
if self.keywords:
kws = map(OWS.Keyword, self.keywords)
doc.append(OWS.Keywords(*kws))
for m in self.metadata:
doc.append(OWS.Metadata(dict(m)))
if self.profile:
doc.append(OWS.Profile(self.profile))
if self.version != 'None':
doc.attrib['{http://www.opengis.net/wps/1.0.0}processVersion'] = self.version
else:
doc.attrib['{http://www.opengis.net/wps/1.0.0}processVersion'] = 'undefined'

return doc

def describe_xml(self):
input_elements = [i.describe_xml() for i in self.inputs]
output_elements = [i.describe_xml() for i in self.outputs]

doc = E.ProcessDescription(
OWS.Identifier(self.identifier),
OWS.Title(self.title)
)
doc.attrib['{http://www.opengis.net/wps/1.0.0}processVersion'] = self.version

if self.store_supported == 'true':
doc.attrib['storeSupported'] = self.store_supported

if self.status_supported == 'true':
doc.attrib['statusSupported'] = self.status_supported

if self.abstract:
doc.append(OWS.Abstract(self.abstract))

if self.keywords:
kws = map(OWS.Keyword, self.keywords)
doc.append(OWS.Keywords(*kws))

for m in self.metadata:
doc.append(OWS.Metadata(dict(m)))

for p in self.profile:
doc.append(WPS.Profile(p))

if input_elements:
doc.append(E.DataInputs(*input_elements))

doc.append(E.ProcessOutputs(*output_elements))

return doc
@property
def json(self):

return {
'version': self.version,
'identifier': self.identifier,
'title': self.title,
'abstract': self.abstract,
'keywords': self.keywords,
'metadata': [m for m in self.metadata],
'inputs': [i.json for i in self.inputs],
'outputs': [o.json for o in self.outputs],
'store_supported': self.store_supported,
'status_supported': self.status_supported,
'profile': [p for p in self.profile],
}

def execute(self, wps_request, uuid):
self._set_uuid(uuid)
Expand Down
5 changes: 2 additions & 3 deletions pywps/app/Service.py
Expand Up @@ -7,7 +7,7 @@
import tempfile
from werkzeug.exceptions import HTTPException
from werkzeug.wrappers import Request, Response
from pywps import WPS, OWS
from pywps import get_ElementMakerForVersion
from pywps._compat import PY2
from pywps._compat import urlopen
from pywps._compat import urlparse
Expand Down Expand Up @@ -61,7 +61,7 @@ def __init__(self, processes=[], cfgfiles=None):
def get_capabilities(self, wps_request, uuid):

response_cls = response.get_response("capabilities")
return response_cls(wps_request, uuid, processes=self.processes)
return response_cls(wps_request, uuid, version=wps_request.version, processes=self.processes)

def describe(self, wps_request, uuid, identifiers):

Expand Down Expand Up @@ -403,7 +403,6 @@ def __call__(self, http_request):
log_request(request_uuid, wps_request)
response = None
if wps_request.operation == 'getcapabilities':

response = self.get_capabilities(wps_request, request_uuid)

elif wps_request.operation == 'describeprocess':
Expand Down
41 changes: 28 additions & 13 deletions pywps/app/WPSRequest.py
Expand Up @@ -7,19 +7,19 @@
import lxml
import lxml.etree
from werkzeug.exceptions import MethodNotAllowed
from pywps import get_ElementMakerForVersion
import base64
import datetime
from pywps import WPS
from pywps._compat import text_type, PY2
from pywps.app.basic import xpath_ns
from pywps.app.basic import get_xpath_ns
from pywps.inout.basic import LiteralInput, ComplexInput, BBoxInput
from pywps.exceptions import NoApplicableCode, OperationNotSupported, MissingParameterValue, VersionNegotiationFailed, \
InvalidParameterValue, FileSizeExceeded
from pywps import configuration
from pywps.validator.mode import MODE
from pywps.inout.literaltypes import AnyValue, NoValue, ValuesReference, AllowedValue

from pywps.inout.formats import Format
from pywps import get_version_from_ns

import json

Expand All @@ -42,6 +42,9 @@ def __init__(self, http_request=None):
self.inputs = {}
self.outputs = {}
self.raw = None
self.WPS = None
self.OWS = None
self.xpath_ns = None

if self.http_request:
request_parser = self._get_request_parser_method(http_request.method)
Expand Down Expand Up @@ -93,6 +96,8 @@ def _post_request(self):
raise NoApplicableCode(e.msg)

operation = doc.tag
version = get_version_from_ns(doc.nsmap[doc.prefix])
self.set_version(version)
request_parser = self._post_request_parser(operation)
request_parser(doc)

Expand Down Expand Up @@ -180,7 +185,7 @@ def _post_request_parser(self, tagname):
def parse_post_getcapabilities(doc):
"""Parse POST GetCapabilities request
"""
acceptedversions = xpath_ns(
acceptedversions = self.xpath_ns(
doc, '/wps:GetCapabilities/ows:AcceptVersions/ows:Version')
acceptedversions = ','.join(
map(lambda v: v.text, acceptedversions))
Expand All @@ -198,7 +203,7 @@ def parse_post_describeprocess(doc):

wpsrequest.operation = 'describeprocess'
wpsrequest.identifiers = [identifier_el.text for identifier_el in
xpath_ns(doc, './ows:Identifier')]
self.xpath_ns(doc, './ows:Identifier')]

def parse_post_execute(doc):
"""Parse POST Execute request
Expand All @@ -212,7 +217,7 @@ def parse_post_execute(doc):

wpsrequest.operation = 'execute'

identifier = xpath_ns(doc, './ows:Identifier')
identifier = self.xpath_ns(doc, './ows:Identifier')

if not identifier:
raise MissingParameterValue(
Expand All @@ -225,13 +230,13 @@ def parse_post_execute(doc):
wpsrequest.inputs = get_inputs_from_xml(doc)
wpsrequest.outputs = get_output_from_xml(doc)
wpsrequest.raw = False
if xpath_ns(doc, '/wps:Execute/wps:ResponseForm/wps:RawDataOutput'):
if self.xpath_ns(doc, '/wps:Execute/wps:ResponseForm/wps:RawDataOutput'):
wpsrequest.raw = True
# executeResponse XML will not be stored
wpsrequest.store_execute = 'false'

# check if response document tag has been set then retrieve
response_document = xpath_ns(
response_document = self.xpath_ns(
doc, './wps:ResponseForm/wps:ResponseDocument')
if len(response_document) > 0:
wpsrequest.lineage = response_document[
Expand All @@ -241,19 +246,24 @@ def parse_post_execute(doc):
wpsrequest.status = response_document[
0].attrib.get('status', 'false')

if tagname == WPS.GetCapabilities().tag:
if tagname == self.WPS.GetCapabilities().tag:
self.operation = 'getcapabilities'
return parse_post_getcapabilities
elif tagname == WPS.DescribeProcess().tag:
elif tagname == self.WPS.DescribeProcess().tag:
self.operation = 'describeprocess'
return parse_post_describeprocess
elif tagname == WPS.Execute().tag:
elif tagname == self.WPS.Execute().tag:
self.operation = 'execute'
return parse_post_execute
else:
raise InvalidParameterValue(
'Unknown request %r' % tagname, 'request')

def set_version(self, version):
self.version = version
self.xpath_ns = get_xpath_ns(version)
self.WPS, self.OWS = get_ElementMakerForVersion(self.version)

def check_accepted_versions(self, acceptedversions):
"""
:param acceptedversions: string
Expand Down Expand Up @@ -285,7 +295,7 @@ def check_and_set_version(self, version):
raise VersionNegotiationFailed(
'The requested version "%s" is not supported by this server' % version, 'version')
else:
self.version = version
self.set_version(version)

def check_and_set_language(self, language):
"""set this.language
Expand Down Expand Up @@ -429,6 +439,8 @@ def json(self, value):

def get_inputs_from_xml(doc):
the_inputs = {}
version = get_version_from_ns(doc.nsmap[doc.prefix])
xpath_ns = get_xpath_ns(version)
for input_el in xpath_ns(doc, '/wps:Execute/wps:DataInputs/wps:Input'):
[identifier_el] = xpath_ns(input_el, './ows:Identifier')
identifier = identifier_el.text
Expand Down Expand Up @@ -506,6 +518,9 @@ def get_inputs_from_xml(doc):
def get_output_from_xml(doc):
the_output = {}

version = get_version_from_ns(doc.nsmap[doc.prefix])
xpath_ns = get_xpath_ns(version)

if xpath_ns(doc, '/wps:Execute/wps:ResponseForm/wps:ResponseDocument'):
for output_el in xpath_ns(doc, '/wps:Execute/wps:ResponseForm/wps:ResponseDocument/wps:Output'):
[identifier_el] = xpath_ns(output_el, './ows:Identifier')
Expand Down Expand Up @@ -579,7 +594,7 @@ def get_data_from_kvp(data, part=None):
def _check_version(version):
""" check given version
"""
if version != '1.0.0':
if version not in ['1.0.0', '2.0.0']:
return False
else:
return True
Expand Down
33 changes: 23 additions & 10 deletions pywps/app/basic.py
Expand Up @@ -2,26 +2,39 @@
# Copyright 2018 Open Source Geospatial Foundation and others #
# licensed under MIT, Please consult LICENSE.txt for details #
##################################################################
"""
XML tools
"""

import logging
import lxml
from werkzeug.wrappers import Response
from pywps import __version__, NAMESPACES
from pywps import __version__

LOGGER = logging.getLogger('PYWPS')


def xpath_ns(el, path):
return el.xpath(path, namespaces=NAMESPACES)
def get_xpath_ns(version):
"""Get xpath namespace for specified WPS version
currently 1.0.0 or 2.0.0 are supported
"""

def xpath_ns(ele, path):
"""Function, which will return xpath namespace for given
element and xpath
"""
if version == "1.0.0":
from pywps import namespaces100
nsp = namespaces100
elif version == "2.0.0":
from pywps import namespaces200
nsp = namespaces200
return ele.xpath(path, namespaces=nsp)

return xpath_ns


def xml_response(doc):
"""XML response serializer"""

LOGGER.debug('Serializing XML response')
pywps_version_comment = '<!-- PyWPS %s -->\n' % __version__
xml = lxml.etree.tostring(doc, pretty_print=True)
response = Response(pywps_version_comment.encode('utf8') + xml,
content_type='text/xml')
response = Response(doc, content_type='text/xml')
response.status_percentage = 100
return response
2 changes: 1 addition & 1 deletion pywps/dblog.py
Expand Up @@ -137,7 +137,7 @@ def update_response(uuid, response, close=False):
if requests.count():
request = requests.one()
request.time_end = datetime.datetime.now()
request.message = message
request.message = str(message)
request.percent_done = status_percentage
request.status = status
session.commit()
Expand Down

0 comments on commit 0f7122d

Please sign in to comment.