Unit 27 - PyWPS intro

PyWPS is a server side implementation of the OGC Web Processing Service (OGC WPS) standard, using the Python programming language.

OGC Web Processing Service standard provides rules for standardizing how 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 simple environment of PyWPS demo. Download the demo and extract into your working directory.

Install PyWPS and Flask dependency

sudo pip install pywps flask

Go to pywps-flask directory and start your PyWPS demo server

python demo.py

Go to 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.

http://localhost:5000/wps?request=Execute&service=WPS&identifier=say_hello&version=1.0.0&datainputs=name=Martin

You should get similar response as below.

<wps:LiteralData dataType="urn:ogc:def:dataType:OGC:1.1:string" uom="urn:ogc:def:uom:OGC:1.0:unity">
Hello Martin
</wps:LiteralData>

Well, we have working demo, so let’s continue with creating our first WPS process.

MODIS process

Go to pywps-flask directory and create your first process in processes directory (you can use grassbuffer.py 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 you define input (lines 9 and 11) and output parameters (line 14). 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. 2017-03-01)',
                               data_type='string'),
                  LiteralInput('end', 'End date (eg. 2017-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 2017 for Germany',
            profile='',
            inputs=inputs,
            outputs=outputs,
            store_supported=True,
            status_supported=True,
            grass_location="/opt/grassdata/germany-modis"
        )

    def check_date(self, date_str):
        from datetime import datetime

        d = datetime.strptime(date_str, '%Y-%m-%d')
        if d.year != 2017:
            raise Exception("Only year 2017 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

We have to activate the process in demo.py (which implements PyWPS demo server). Assuming that you named file with process as modis_v1.py.

...
from processes.modis_v1 import ModisV1
...

processes = [
 ...
 ModisV1(),
]

Stop running demo PyWPS server by Ctrl+C and start again.

python ./demo.py

You should see your modis-v1 process in the list. Click on DescribeProcess to check input and outputs parameters description.

../_images/modis-v1.svg

Fig. 118 Process modis-v1 available on PyWPS demo server.

Important

In order to use GRASS GIS functionality update PyWPS configuration. Open pywps.cfg and set correct GRASS installation directory, eg.

gisbase=/usr/lib/grass-7.4.0

Now you can finally execute your first WPS process!

http://localhost:5000/wps?request=Execute&service=WPS&identifier=modis-v1&version=1.0.0&datainputs=start=2017-03-01;end=2017-04-01

Example of response:

<wps:LiteralData dataType="urn:ogc:def:dataType:OGC:1.1:string">
Min: -5.4;Max: 13.8;Mean: 8.0
</wps:LiteralData>

Tip

When something goes wrong, check logs/pywps.log for details.

Try to improve process in order to return something more usable than a string, eg. JSON.