Unit 27 - PyWPS intro¶
PyWPS is a server side implementation of the OGC Web Processing Service (OGC WPS) standard implemented in the Python programming language.
OGC Web Processing Service standard provides rules for standardizing inputs and outputs (requests and responses) for geospatial processing services. The standard also defines how a client can request the execution of a process, and how the output from the process is handled. It defines an interface that facilitates the publishing of geospatial processes and clients discovery of and binding to those processes. The data required by the WPS can be delivered across a network or they can be available at the server. (source: PyWPS documentation)
This unit shows how to write your own WPS processes. The processes will be tested in PyWPS demo environment. Download the demo and extract into your working directory.
Install PyWPS and Flask dependency from GRASS Console tab.
Note
On MS Windows download fiona package from https://www.lfd.uci.edu/~gohlke/pythonlibs/ and install it:
python3 -m pip install C:\Users\martin\Downloads\Fiona-1.8.21-cp39-cp39-win_amd64.whl
python3 -m pip install flask==1.1.4 werkzeug==1.0.1 pywps==4.2.11 markupsafe==2.0.1
Go to pywps-flask
directory and start PyWPS demo server
python3 demo.py
Open http://127.0.0.1:5000 in order to see all available WPS demo
processes. Let’s request process description of selected process,
eg. say_hello process. Try to run the process by execute
request.
Example of response:
<wps:LiteralData uom="urn:ogc:def:uom:OGC:1.0:unity" dataType="string">
Hello Martin
</wps:LiteralData>
Let’s continue with creating our own WPS process.
MODIS process¶
Go to pywps-flask/processes
directory and create a new process
(grassbuffer.py
can be used as a template). Example of process
below is based on the script created in Unit 26 - MODIS ST scripting. Let’s focus on
important parts.
Process itself is defined as a Python class, ModisV1
in this
case (line 7). In class constructor input (lines 9
and 11) and output parameters (line 14) are
defined. Every process has its identifier (line 20), title
and abstract. The process will operate in GRASS location defined on
line 30. On line 61 is assumed that space time LST
dataset is located in PERMANENT, see Unit 25 - MODIS ST. For each job (executed
process by a client) PyWPS creates in this location a temporary mapset
which is deleted when process is finished. Process body is implemented
as _handler()
method, see line 40. Resultant statistics
is stored to response output as a simple string on line 80.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | import os
from pywps import Process, LiteralInput, LiteralOutput
__author__ = 'Martin Landa'
class ModisV1(Process):
def __init__(self):
inputs = [LiteralInput('start', 'Start date (eg. 2019-03-01)',
data_type='string'),
LiteralInput('end', 'End date (eg. 2019-04-01)',
data_type='string')
]
outputs = [LiteralOutput('stats', 'Computed LST statistics',
data_type='string')
]
super(ModisV1, self).__init__(
self._handler,
identifier='modis-v1',
version='0.1',
title="Modis process (v1)",
abstract='The process uses the GRASS GIS to compute LST ' \
'statistics for given period in 2019 for Germany',
profile='',
inputs=inputs,
outputs=outputs,
store_supported=True,
status_supported=True,
grass_location="/home/user/grassdata/germany-modis"
)
def check_date(self, date_str):
from datetime import datetime
d = datetime.strptime(date_str, '%Y-%m-%d')
if d.year != 2019:
raise Exception("Only year 2019 allowed")
def _handler(self, request, response):
from subprocess import PIPE
import grass.script as gs
from grass.pygrass.modules import Module
from grass.exceptions import CalledModuleError
start = request.inputs['start'][0].data
end = request.inputs['end'][0].data
self.check_date(start)
self.check_date(end)
output = 'modis_response'
# be silent
os.environ['GRASS_VERBOSE'] = '0'
# need to set computation region (would be nice g.region strds or t.region)
Module('g.region', raster='c_001')
try:
Module('t.rast.series',
input='modis_c@PERMANENT',
output=output,
method='average',
where="start_time > '{start}' and start_time < '{end}'".format(
start=start, end=end
))
except CalledModuleError:
raise Exception('Unable to compute statistics')
ret = Module('r.univar',
flags='g',
map=output,
stdout_=PIPE
)
stats = gs.parse_key_val(ret.outputs.stdout)
outstr = 'Min: {0:.1f};Max: {1:.1f};Mean: {2:.1f}'.format(
float(stats['min']), float(stats['max']), float(stats['mean'])
)
response.outputs['stats'].data = outstr
return response
|
Sample process to download: modis_v1.py
The process has to be activated in demo.py
.
...
from processes.modis_v1 import ModisV1
...
processes = [
...
ModisV1(),
]
Stop running demo PyWPS server by Ctrl+C and start again.
python3 ./demo.py
You should see your modis-v1
process in the list. Click on
DescribeProcess
to check input and outputs parameters description.
Important
In order to use GRASS GIS functionality update PyWPS
configuration. Open pywps.cfg
and set correct GRASS
installation directory, eg.
gisbase=/usr/lib/grass80
On Windows specify path in Unix-like style:
gisbase=/C/Program Files/GRASS GIS 8.0
Now execute the process:
Example of response:
<wps:LiteralData dataType="string">
Min: -8.3;Max: 12.6;Mean: 7.3
</wps:LiteralData>
Tip
When something goes wrong, check logs/pywps.log
for
details.
Úkol
Try to improve the process in order to return something more reasonable than a string, eg. JSON.