[pywps] 03/03: Imported Upstream version 4.0.0~rc1

Bas Couwenberg sebastic at debian.org
Mon Aug 22 21:44:52 UTC 2016


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch upstream
in repository pywps.

commit 6a3dff00999881ee301421759b7ea3e2f4d7140f
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Mon Aug 22 22:45:07 2016 +0200

    Imported Upstream version 4.0.0~rc1
---
 VERSION.txt                         |   2 +-
 docs/api.rst                        |  71 ++++++--
 docs/conf.py                        |  13 +-
 docs/configuration.rst              | 194 +++++++++++++++------
 docs/demobuffer.py                  | 103 +++++++++++
 docs/deployment.rst                 | 168 ++++++++++++++++++
 docs/exceptions.rst                 |   2 +
 docs/external_tools.rst             |  10 ++
 docs/index.rst                      |  31 +++-
 docs/install.rst                    |  99 ++++++-----
 docs/process.rst                    | 338 +++++++++++++++++++++++++++---------
 docs/pywps.png                      | Bin 30115 -> 135853 bytes
 docs/pywps.rst                      |  46 +++++
 docs/wps.rst                        | 228 ++++++++++++++++++++++++
 pywps/__init__.py                   |   4 +-
 pywps/app/Process.py                |  23 +--
 pywps/app/Service.py                |  10 +-
 pywps/app/WPSRequest.py             |   1 +
 pywps/app/WPSResponse.py            |  48 ++---
 pywps/configuration.py              | 125 +++++++------
 pywps/dblog.py                      |  19 +-
 pywps/exceptions.py                 |  10 +-
 pywps/inout/basic.py                |  13 +-
 pywps/inout/formats/__init__.py     |  18 +-
 pywps/inout/formats/lists.py        |  30 ----
 pywps/inout/inputs.py               |  77 ++++----
 pywps/inout/literaltypes.py         |   6 +-
 pywps/inout/outputs.py              |  24 ++-
 pywps/inout/storage.py              |  10 +-
 pywps/validator/complexvalidator.py |  34 ++--
 tox.ini                             |   2 +-
 31 files changed, 1347 insertions(+), 412 deletions(-)

diff --git a/VERSION.txt b/VERSION.txt
index 5f1211e..0db186f 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-4.0.0-alpha2
+4.0.0.rc1
diff --git a/docs/api.rst b/docs/api.rst
index dbcddd0..fd3ca32 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -1,32 +1,74 @@
-===
-API
-===
+#############
+PyWPS API Doc
+#############
 
 .. module:: pywps
 
 
-Defining processes
-------------------
+Process
+=======
 
 .. autoclass:: Process
 
-.. autoclass:: Service
+Inputs and outputs
+==================
 
-.. autoclass:: LiteralInput
+.. autoclass:: pywps.validator.mode.MODE
+    :members:
+    :undoc-members:
 
-.. autoclass:: ComplexInput
+Most of the inputs nad outputs are derived from the `IOHandler` class
+
+.. autoclass:: pywps.inout.basic.IOHandler
+
+
+LiteralData
+-----------
+
+.. autoclass:: LiteralInput
 
 .. autoclass:: LiteralOutput
 
+.. autoclass:: pywps.inout.literaltypes.AnyValue
+
+.. autoclass:: pywps.inout.literaltypes.AllowedValue
+
+.. autodata:: pywps.inout.literaltypes.LITERAL_DATA_TYPES
+
+
+ComplexData
+-----------
+
+.. autoclass:: ComplexInput
+
 .. autoclass:: ComplexOutput
 
 .. autoclass:: Format
+    
+.. autodata:: pywps.inout.formats.FORMATS
+    :annotation:
+    
+    List of out of the box supported formats. User can add custom formats to the
+    array.
+
+.. autofunction:: pywps.validator.complexvalidator.validategml
 
+BoundingBoxData
+---------------
+
+.. autoclass:: BoundingBoxInput
+
+.. autoclass:: BoundingBoxOutput
 
 Request and response objects
 ----------------------------
 
-.. autoclass:: WPSRequest
+.. autodata:: pywps.app.WPSResponse.STATUS
+    :annotation:
+
+    Process status information
+
+.. autoclass:: pywps.app.WPSRequest
    :members:
 
    .. attribute:: operation
@@ -46,5 +88,14 @@ Request and response objects
 
       A MultiDict object containing input values sent by the client.
 
-.. autoclass:: WPSResponse
 
+.. autoclass:: pywps.app.WPSResponse
+    :members:
+
+    .. attribute:: status
+
+        Information about currently running process status
+        :class:`pywps.app.WPSResponse.STATUS`
+
+
+Refer :ref:`exceptions` for their description.
diff --git a/docs/conf.py b/docs/conf.py
index 886fbab..4050405 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -39,7 +39,12 @@ with open('../VERSION.txt') as f:
 release = version
 latex_logo = 'pywps.png'
 
-extensions = ['sphinx.ext.autodoc']
+extensions = ['sphinx.ext.extlinks',
+              'sphinx.ext.autodoc',
+              'sphinx.ext.todo',
+              'sphinx.ext.mathjax',
+              'sphinx.ext.viewcode'
+            ]
 exclude_patterns = ['_build']
 source_suffix = '.rst'
 master_doc = 'index'
@@ -69,8 +74,10 @@ class Mock(object):
 
 MOCK_MODULES = ['lxml', 'lxml.etree', 'lxml.builder']
 
-with open('../requirements.txt') as f:
-    MOCK_MODULES = f.read().splitlines()
+#with open('../requirements.txt') as f:
+#    MOCK_MODULES = f.read().splitlines()
 
 for mod_name in MOCK_MODULES:
     sys.modules[mod_name] = Mock()
+
+todo_include_todos = True
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 3a14875..29197a2 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -1,64 +1,150 @@
+.. _configuration:
+
 =============
 Configuration
 =============
 
-PyWPS is configured using a configuration file. The file uses
-`ConfigParser <https://wiki.python.org/moin/ConfigParserExamples>`_ format. The
-file can be stored anywhere or can be set using `PYWPS_CFG` environment
-variable.
+PyWPS is configured using a configuration file. The file uses the
+`ConfigParser <https://wiki.python.org/moin/ConfigParserExamples>`_ format.
 
 .. versionadded:: 4.0.0
 .. warning:: Compatibility with PyWPS 3.x: major changes have been made
-  to the config file in order to allow for shared configurations with pycsw
-  and other projects.
-
-The configuration file has 2 sections.
-
-PyWPS ships with a sample configuration (``default-sample.cfg``).  Copy the file to ``default.cfg`` and edit the following: 
-
-**[server]**
-
-- **url**: the URL of the resulting service
-- **language**: the ISO 639-1 language and ISO 3166-1 alpha2 country code of the service (e.g. ``en-CA``, ``fr-CA``, ``en-US``)
-- **encoding**: the content type encoding (e.g. ``ISO-8859-1``, see https://docs.python.org/2/library/codecs.html#standard-encodings).  Default value is 'UTF-8'
-- **loglevel**: the logging level (see http://docs.python.org/library/logging.html#logging-levels)
-- **logfile**: the full file path to the logfile
-- **maxoperations**: maximum number of parallel running operations
-- **logdatabase**: SQLite3 file, where the login about requests/responses will be provided. You can set this to `":memory:"` for having the database in memory
-- **maxrequestsize**: maximal request size. 0 for no limit
-- **workdir**: temporary directory for all temporary files (which should be always deleted, once the process is finished
-- **outputpath**: server path for storing output files
-- **outputurl**: corresponding URL
-
-.. note:: `outputpath` and `outputurl` must corespond 
-
-**[metadata:main]**
-
-- **identification_title**: the title of the service
-- **identification_abstract**: some descriptive text about the service
-- **identification_keywords**: comma delimited list of keywords about the service
-- **identification_keywords_type**: keyword type as per the `ISO 19115 MD_KeywordTypeCode codelist <http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode>`_).  Accepted values are ``discipline``, ``temporal``, ``place``, ``theme``, ``stratum``
-- **identification_fees**: fees associated with the service
-- **identification_accessconstraints**: access constraints associated with the service
-- **provider_name**: the name of the service provider
-- **provider_url**: the URL of the service provider
-- **contact_name**: the name of the provider contact
-- **contact_position**: the position title of the provider contact
-- **contact_address**: the address of the provider contact
-- **contact_city**: the city of the provider contact
-- **contact_stateorprovince**: the province or territory of the provider contact
-- **contact_postalcode**: the postal code of the provider contact
-- **contact_country**: the country of the provider contact
-- **contact_phone**: the phone number of the provider contact
-- **contact_fax**: the facsimile number of the provider contact
-- **contact_email**: the email address of the provider contact
-- **contact_url**: the URL to more information about the provider contact
-- **contact_hours**: the hours of service to contact the provider
-- **contact_instructions**: the how to contact the provider contact
-- **contact_role**: the role of the provider contact as per the `ISO 19115 CI_RoleCode codelist <http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#CI_RoleCode>`_).  Accepted values are ``author``, ``processor``, ``publisher``, ``custodian``, ``pointOfContact``, ``distributor``, ``user``, ``resourceProvider``, ``originator``, ``owner``, ``principalInvestigator``
-
-**[grass]**
-- **gisbase**: directory of GRASS GIS instalation, refered as `GISBASE <https://grass.osgeo.org/grass73/manuals/variables.html>`_
+  to the config file in order to allow for shared configurations with `PyCSW
+  <http://pycsw.org/>`_ and other projects.
+
+The configuration file has 3 sections:
+
+    * `metadata:main` for the server metadata inputs
+    * `server` for server configuration
+    * `grass` for *optional* configuration to support `GRASS GIS
+      <http://grass.osgeo.org>`_
+
+PyWPS ships with a sample configuration file (``default-sample.cfg``). 
+A similar file is also available in the `demo` service as
+described in :ref:`demo` section.
+
+Copy the file to ``default.cfg`` and edit the following: 
+
+[metadata:main]
+---------------
+
+The `[metadata:main]` section was designed according to the `PyCSW project
+configuration file <http://docs.pycsw.org/en/latest/configuration.html>`_.
+
+:identification_title:
+    the title of the service
+:identification_abstract:
+    some descriptive text about the service
+:identification_keywords:
+    comma delimited list of keywords about the service
+:identification_keywords_type:
+    keyword type as per the `ISO 19115 MD_KeywordTypeCode codelist
+    <http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode>`_).
+    Accepted values are ``discipline``, ``temporal``, ``place``, ``theme``,
+    ``stratum``
+:identification_fees:
+    fees associated with the service
+:identification_accessconstraints:
+    access constraints associated with the service
+:provider_name:
+    the name of the service provider
+:provider_url:
+    the URL of the service provider
+:contact_name:
+    the name of the provider contact
+:contact_position:
+    the position title of the provider contact
+:contact_address:
+    the address of the provider contact
+:contact_city:
+    the city of the provider contact
+:contact_stateorprovince:
+    the province or territory of the provider contact
+:contact_postalcode:
+    the postal code of the provider contact
+:contact_country:
+    the country of the provider contact
+:contact_phone:
+    the phone number of the provider contact
+:contact_fax:
+    the facsimile number of the provider contact
+:contact_email:
+    the email address of the provider contact
+:contact_url:
+    the URL to more information about the provider contact
+:contact_hours:
+    the hours of service to contact the provider
+:contact_instructions:
+    the how to contact the provider contact
+:contact_role:
+    the role of the provider contact as per the `ISO 19115 CI_RoleCode codelist
+    <http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#CI_RoleCode>`_).
+    Accepted values are ``author``, ``processor``, ``publisher``, ``custodian``,
+    ``pointOfContact``, ``distributor``, ``user``, ``resourceProvider``,
+    ``originator``, ``owner``, ``principalInvestigator``
+
+[server]
+--------
+
+:url:
+    the URL of the WPS service endpoint
+
+:language:
+    the ISO 639-1 language and ISO 3166-1 alpha2 country code of the service
+    (e.g. ``en-CA``, ``fr-CA``, ``en-US``)
+
+:encoding:
+    the content type encoding (e.g. ``ISO-8859-1``, see
+    https://docs.python.org/2/library/codecs.html#standard-encodings).  Default
+    value is 'UTF-8'
+
+:loglevel:
+    the logging level (see
+    http://docs.python.org/library/logging.html#logging-levels)
+
+:logfile:
+    the full file path to the log file
+
+:parallelprocesses:
+    maximum number of parallel running processes - set this number carefully.
+    The effective number of parallel running processes is limited by the number 
+    of cores  in the processor of the hosting machine. As well, speed and 
+    response time of hard drives impact ultimate processing performance. A 
+    reasonable number of parallel running processes is not higher than the 
+    number of processor cores.
+
+:logdatabase:
+    SQLite3 file, where the login about requests/responses is to be stored. It
+    can be set to `":memory:"` to store the database in memory.
+
+:maxrequestsize:
+    maximal request size. 0 for no limit 
+    
+:workdir: 
+    a directory to store all temporary files (which should be always deleted, 
+    once the process is finished).
+    
+:outputpath: 
+    server path where to store output files.
+
+:outputurl:
+    corresponding URL
+
+.. note:: `outputpath` and `outputurl` must corespond. `outputpath` is the name
+        of the resulting target directory, where all output data files are
+        stored (with unique names). `outputurl` is the corresponding full URL, 
+        which is targeting to `outputpath` directory.
+
+        Example: `outputpath=/var/www/wps/outputs` shall correspond with
+        `outputurl=http://foo.bar/wps/outputs`
+
+
+[grass]
+-------
+
+:gisbase:
+  directory of the GRASS GIS instalation, refered as `GISBASE
+  <https://grass.osgeo.org/grass73/manuals/variables.html>`_
 
 -----------
 Sample file
diff --git a/docs/demobuffer.py b/docs/demobuffer.py
new file mode 100644
index 0000000..4c1b966
--- /dev/null
+++ b/docs/demobuffer.py
@@ -0,0 +1,103 @@
+# PyWPS-4 example process to be used for the documenatation and as demonstration
+# how to create custom process instance
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 PyWPS Project Steering Committee
+# https://opensource.org/licenses/MIT
+#
+__author__ = 'Jachym Cepicky'
+
+from pywps import Process, LiteralInput, ComplexOutput, ComplexInput, Format
+from pywps.validator.mode import MODE
+from pywps.inout.formats import FORMATS
+
+inpt_vector = ComplexInput(
+    'vector',
+    'Vector map',
+    supported_formats=[Format('application/gml+xml')],
+    mode=MODE.STRICT
+)
+
+inpt_size = LiteralInput('size', 'Buffer size', data_type='float')
+
+out_output = ComplexOutput(
+    'output',
+    'HelloWorld Output',
+    supported_formats=[Format('application/gml+xml')]
+)
+
+inputs = [inpt_vector, inpt_size]
+outputs = [out_output]
+
+class DemoBuffer(Process):
+    def __init__(self):
+
+        super(DemoBuffer, self).__init__(
+            _handler,
+            identifier='demobuffer',
+            version='1.0.0',
+            title='Buffer',
+            abstract='This process demonstrates, how to create any process in PyWPS environment',
+            inputs=inputs,
+            outputs=outputs,
+            store_supported=True,
+            status_supported=True
+        )
+
+ at staticmethod
+def _handler(request, response):
+    """Handler method - this method obtains request object and response
+    object and creates the buffer
+    """
+
+    from osgeo import ogr
+
+    # obtaining input with identifier 'vector' as file name
+    input_file = request.inputs['vector'][0].file
+
+    # obtaining input with identifier 'size' as data directly
+    size = request.inputs['size'][0].data
+
+    # open file the "gdal way"
+    input_source = ogr.Open(input_file)
+    input_layer = input_source.GetLayer()
+    layer_name = input_layer.GetName()
+
+    # create output file
+    driver = ogr.GetDriverByName('GML')
+    output_source = driver.CreateDataSource(layer_name,
+        ["XSISCHEMAURI=http://schemas.opengis.net/gml/2.1.2/feature.xsd"])
+    output_layer = output_source.CreateLayer(layer_name, None, ogr.wkbUnknown)
+
+    # get feature count
+    count = input_layer.GetFeatureCount()
+    index = 0
+
+    # make buffer for each feature
+    while index < count:
+
+        response.update_status('Buffering feature %s' % index, float(index)/count)
+
+        # get the geometry
+        input_feature = input_layer.GetNextFeature()
+        input_geometry = input_feature.GetGeometryRef()
+
+        # make the buffer
+        buffer_geometry = input_geometry.Buffer(
+                float(size)
+        )
+
+        # create output feature to the file
+        output_feature = ogr.Feature(feature_def=output_layer.GetLayerDefn())
+        output_feature.SetGeometryDirectly(buffer_geometry)
+        output_layer.CreateFeature(output_feature)
+        output_feature.Destroy()
+        index += 1
+
+    # set output format
+    response.outputs['output'].output_format = FORMATS.GML
+
+    # set output data as file name
+    response.outputs['output'].file = layer_name
+
+    return response
diff --git a/docs/deployment.rst b/docs/deployment.rst
new file mode 100644
index 0000000..5619aa3
--- /dev/null
+++ b/docs/deployment.rst
@@ -0,0 +1,168 @@
+.. _deployment:
+
+=================================
+Deployment to a production server
+=================================
+
+As already described in the :ref:`installation` section, no specific deployment
+procedures are for PyWPS when using flask-based server. But this formula is not 
+intended to be used in a production environment. For production, `Apache httpd
+<https://httpd.apache.org/>`_ or `nginx <https://nginx.org/>`_ servers are
+more advised. PyWPS is runs as a `WSGI
+<https://wsgi.readthedocs.io/en/latest/>`_ application on those servers. PyWPS
+relies on the `Werkzeug <http://werkzeug.pocoo.org/>`_ library for this purpose.
+
+Deoploying an individual PyWPS instance
+---------------------------------------
+
+PyWPS should be installed in your computer (as per the :ref:`installation` 
+section). As a following step, you can now create several instances of your WPS 
+server.
+
+It is advisable for each PyWPS instance to have its own directory, where the 
+WSGI file along with available processes should reside. Therefore create a new
+directory for the PyWPS instance::
+
+    $ sudo mkdir /var/www/pywps/
+
+    # create a directory for your processes too
+    $ sudo mkdir /var/www/pywps/processes
+
+.. note:: In this configuration example it is assumed that there is only one
+        instance of PyWPS on the server.
+        
+Each instance is represented by a single `WSGI` script (written in Python), 
+which:
+
+    1. Loads the configuration files
+    2. Serves processes
+    3. Takes care about maximum number of concurrent processes and similar
+
+Creating a PyWPS `WSGI` instance
+--------------------------------
+
+An example WSGI script is distributed along with PyWPS-Demo service, as 
+described in the :ref:`installation` section. The script is actually 
+straightforward - in fact, it's a just wrapper around the PyWPS server with a 
+list of processes and configuration files passed as arguments. Here is an 
+example of a PyWPS WSGI script::
+
+    $ $EDITOR /var/www/pywps/pywps.wcgi
+
+.. code-block:: python
+    :linenos:
+
+    #!/usr/bin/env python3
+
+    from pywps.app.Service import Service
+
+    # processes need to be installed in PYTHON_PATH
+    from processes.sleep import Sleep
+    from processes.ultimate_question import UltimateQuestion
+    from processes.centroids import Centroids
+    from processes.sayhello import SayHello
+    from processes.feature_count import FeatureCount
+    from processes.buffer import Buffer
+    from processes.area import Area
+
+    processes = [
+        FeatureCount(),
+        SayHello(),
+        Centroids(),
+        UltimateQuestion(),
+        Sleep(),
+        Buffer(),
+        Area()
+    ]
+
+    # Service accepts two parameters:
+    # 1 - list of process instances
+    # 2 - list of configuration files
+    application = Service(
+        processes,
+        ['/var/www/pywps/pywps.cfg']
+    )
+
+.. note:: The WSGI script is assuming that there are already some
+        processes at hand that can be directly included. Also it assumes, that
+        the configuration file already exists - which is not the case yet.
+
+        The Configuration is described in next chapter (:ref:`configuration`), 
+        as well as process creation and deployment (:ref:`process`).
+
+Deployment on Apache2 httpd server
+----------------------------------
+
+First, the WSGI module must be installed and enabled::
+
+    $ sudo apt-get install libapache2-mod-wsgi
+    $ sudo a2enmod wsgi
+
+You then can edit your site configuration file
+(`/etc/apache2/sites-enabled/yoursite.conf`) and add the following::
+
+        # PyWPS-4
+        WSGIDaemonProcess pywps user=www-data group=www-data processes=2 threads=5
+        WSGIScriptAlias /pywps /var/www/pywps/pywps.wsgi
+
+        <Directory /home/jachym/www/htdocs/wps/>
+            WSGIScriptReloading On
+            WSGIProcessGroup group
+            WSGIApplicationGroup %{GLOBAL}
+            Order deny,allow
+            Allow from all
+        </Directory>
+
+.. note:: `WSGIScriptAlias` points to the `pywps.wsgi` script created
+        before - it will be available under the url http://localhost/pywps
+
+And of course restart the server::
+    
+    $ sudo service apache2 restart
+
+
+Deployment on nginx
+-------------------
+
+.. note:: We are currently missing documentation about `nginx`.
+        Please help documenting the deployment of PyWPS to nginx.
+
+You should be able to deploy PyWPS on nginx as a standard WSGI application. The
+best documentation is probably to be found at `Readthedocs
+<http://uwsgi-docs.readthedocs.io/en/latest/WSGIquickstart.html>`_.
+
+.. _deployment-testing:
+
+Testing the deployment of a PyWPS instance
+------------------------------------------
+
+.. note:: For the purpose of this documentation, it is assumed that you've
+        installed PyWPS using the `localhost` server domain name.
+
+As stated, before, PyWPS should be available at http://localhost/pywps, we now
+can visit the url (or use `wget`)::
+
+    # the --content-error parameter makes sure, error response is displayed
+    $ wget --content-error -O - "http://localhost/pywps"
+
+The result should be an XML-encoded error message.
+
+.. code-block:: xml
+
+    <?xml version="1.0" encoding="UTF-8"?>
+    <!-- PyWPS 4.0.0-alpha2 -->
+    <ows:ExceptionReport xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd" version="1.0.0">
+        <ows:Exception exceptionCode="MissingParameterValue" locator="service" >
+            <ows:ExceptionText>service</ows:ExceptionText>
+        </ows:Exception>
+    </ows:ExceptionReport>
+
+The server responded with the :py:class:`pywps.exceptions.MissingParameterValue` 
+exception, telling us that the parameter `service` was not set. This is  
+compliant with the OGC WPS standard, since each request mast have at least the 
+`service` and `request` parameters. We can say for now, that this PyWPS 
+instance is properly deployed on the server, since it returns proper exception 
+report.
+
+We now have to configure the instance by editing the `pywps.cfg` file and adding
+some processes.
diff --git a/docs/exceptions.rst b/docs/exceptions.rst
index b53ef33..0015cb7 100644
--- a/docs/exceptions.rst
+++ b/docs/exceptions.rst
@@ -1,3 +1,5 @@
+.. _exceptions:
+
 ==========
 Exceptions
 ==========
diff --git a/docs/external_tools.rst b/docs/external_tools.rst
new file mode 100644
index 0000000..417c37e
--- /dev/null
+++ b/docs/external_tools.rst
@@ -0,0 +1,10 @@
+########################
+PyWPS and external tools
+########################
+
+=========
+GRASS GIS
+=========
+
+.. todo:: How to setup and get GRASS GIS up and running with PyWPS and example
+        process
diff --git a/docs/index.rst b/docs/index.rst
index 2348d97..c5a7ee9 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -2,30 +2,45 @@
 Welcome to the PyWPS-4 documentation!
 =====================================
 
-.. note:: PyWPS-4 is still in pre-release state, there is no stable release yet,
-    but we are on it
+.. note:: Please be awere that PyWPS-4 is still in pre-release state, 
+   there is no stable release yet.
+   
 
-PyWPS is implementation of `OGC Web Processing Service (OGC WPS) standard
-<http://opengeospatial.org/standards/wps>`_ on the server side, using `Python
-<http://python.org>`_ programming language. PyWPS has a bicycle in it's logo,
-because:
+PyWPS is a server side implementation of the `OGC Web Processing Service 
+(OGC WPS) standard <http://opengeospatial.org/standards/wps>`_ , using the 
+`Python <http://python.org>`_ programming language. PyWPS is currently 
+supporting WPS 1.0.0. Support for the version 2.0.0. of OGC WPS standard is 
+presently being planned.
 
-* It's simple maintain
+PyWPS has a bicycle in it's logo, because:
+
+* It's simple to maintain
 * It's fast to drive
 * It can carry a lot
 * It's easy to hack
 
+**Mount your bike and setup & configure your PyWPS instance!**
+
+.. todo::
+    * request queue management (probably linked from documentation)
+    * inputs and outputs IOhandler class description (file, stream, ...)
+
 Contents:
+---------
 
 .. toctree::
    :maxdepth: 2
 
+   wps
+   pywps
    install
    configuration
    process
-   exceptions
+   deployment
    migration
+   external_tools
    api
+   exceptions
 
 
 
diff --git a/docs/install.rst b/docs/install.rst
index 65e0b7e..0c1e71b 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -1,62 +1,81 @@
-====================
-PyWPS-4 Installation
-====================
+.. _installation:
 
+============
+Installation
+============
 
-.. note:: PyWPS-4 is not tested on MS Windows platform. Please join the
-    development, if you need this platform to be supported. It's mainly because
-    lack of multiprocessing library.  It is used to process asynchronous
-    execution, i.e., when making requests storing the response document and
-    updating a status document displaying the progress of execution.
 
+.. note:: PyWPS-4 is not tested on the MS Windows platform. Please join the
+    development team if you need this platform to be supported. This is mainly 
+    because of the lack of a multiprocessing library.  It is used to process 
+    asynchronous execution, i.e., when making requests storing the response 
+    document and updating a status document displaying the progress of 
+    execution.
 
-Dependencies
-~~~~~~~~~~~~
 
-PyWPS-4 runs on Python 2.7, 3.3 or newer.
+Dependencies and requirements
+-----------------------------
 
-Prior to installing PyWPS-4, Git and the Python bindings for GDAL must be installed in the system. 
-In Debian based systems these packages can be installed with a tool like *apt*::
+PyWPS-4 runs on Python 2.7, 3.3 or newer. PyWPS is currently tested and
+developed on Linux (mostly Ubuntu). In the documentation we take this 
+distribution as reference.
 
-    $ sudo apt-get install git python-gdal
+Prior to installing PyWPS-4, Git and the Python bindings for GDAL must be
+installed in the system.  In Debian based systems these packages can be
+installed with a tool like *apt*::
 
+    $ sudo apt install git python-gdal
 
-PyWPS-4
-~~~~~~~
 
-The easiest way to install PyWPS-4 is using the Python Package Index (PIP). 
-It fetches the source code from the repository and installs it automatically in the system.
-This might require superuser permissions (e.g. *sudo* in Debian based systems)::
+Download and install
+--------------------
 
-    $ sudo pip install -e git+https://github.com/pywps/pywps-4.git@master#egg=pywps-dev
+Using PIP
+        The easiest way to install PyWPS-4 is using the Python Package Index
+        (PIP).  It fetches the source code from the repository and installs it
+        automatically in the system.  This might require superuser permissions
+        (e.g. *sudo* in Debian based systems)::
 
-In alternative PyWPS-4 can be installed manually.
-It requires the cloning of the source code from the repository and then the usage of the *setup.py* script.
-An example again for Debian based systems (note the usage of *sudo* for install)::
+            $ sudo pip install -e git+https://github.com/geopython/pywps.git@master#egg=pywps-dev
 
-    $ git clone https://github.com/pywps/pywps-4.git
+Manual installation
+        In alternative PyWPS-4 can be installed manually.
+        It requires the cloning of the source code from the repository and then the
+        usage of the `setup.py` script.  An example again for Debian based systems (note
+        the usage of `sudo` for install)::
 
-    $ cd pywps-4/
+            $ git clone https://github.com/geopython/pywps.git pywps-4
 
-Then install deps using pip::
+            $ cd pywps-4/
 
-    $ pip install -r requirements.txt
-    $ pip install -r requirements-dev.txt  # for developer tasks
+        Then install the package dependencies using pip::
 
-And install PyWPS system-wide::
+            $ pip install -r requirements.txt
+            $ pip install -r requirements-dev.txt  # for developer tasks
 
-    $ sudo python setup.py install
+        To install PyWPS system-wide run::
 
-The demo service
-~~~~~~~~~~~~~~~~
+            $ sudo python setup.py install
 
-To use PyWPS-4 the user must code processes and publish them through a service.
-A demo service is available that makes up a good starting point for first time users.
-It can be cloned directly into the user area:
-
-    $ git clone https://github.com/pywps/pywps-4-demo.git
+.. _demo:
 
-It may be run right away through the *demo.py* script. 
-First time users should start by studying the demo project structure and then code their own processes.
+The demo service and its sample processes
+-----------------------------------------
 
-Full more details please consult the :ref:`process` section.
+To use PyWPS-4 the user must code processes and publish them through a service.
+A demo service is available that makes up a good starting point for first time
+users. This launches a very simple built-in server (relying on `flask
+<http://flask.pocoo.org/>`_), which is good enough for testing but probably not
+appropriate for production.  It can be cloned directly into the user
+area::
+
+    $ git clone https://github.com/geopython/pywps-demo.git
+
+It may be run right away through the `demo.py` script.  First time users should
+start by studying the demo project structure and then code their own processes.
+
+Full more details please consult the :ref:`process` section. The `demo` service 
+contains some basic processes too, so you could get started with some examples 
+(like `area`, `buffer`, `feature_count` and `grassbuffer`). These processes are 
+to be taken just as inspiration and code documentation - most of them do not
+make any sense (e.g. `sayhello`).
diff --git a/docs/process.rst b/docs/process.rst
index 3ceb3d7..6421af3 100644
--- a/docs/process.rst
+++ b/docs/process.rst
@@ -2,62 +2,154 @@
 
 .. _process:
 
-=========
+#########
 Processes
-=========
+#########
 
-PyWPS-4 works with processes and services. A process is a class containing an handler method
-and specifying inputs and outputs. A service is a collection of processes.
+.. versionadded:: 4.0.0
 
+.. todo::
+    * Input validation
+    * IOHandler
+
+PyWPS works with processes and services. A process is a Python `Class` 
+containing an `handler` method and a list of inputs and outputs. A PyWPS 
+service instance is then a collection of selected processes. 
+
+PyWPS does not ship with any processes predefined - it's on you, as user of
+PyWPS to set up the processes of your choice. PyWPS is here to help you 
+publishing your awesome geospatial operation on the web - it takes care of
+communication and security, you then have to add the content.
+
+.. note:: There are some example processes in the `PyWPS-Demo`_ project.
+
+Writing a Process
+=================
+
+.. note:: At this place, you should prepare your environment for final
+        :ref:`deployment`. At least, you should create a single directory with
+        your processes, which is typically named `processes`::
+
+        $ mkdir processes
+
+        In this directory, we will create single python scripts containing
+        processes.
+
+        Processes can be located *anywhere in the system* as long as their 
+        location is identified in the :envvar:`PYTHONPATH` environment 
+        variable, and can be imported in the final server instance.
 
-Writing a process class
-~~~~~~~~~~~~~~~~~~~~~~~
 A processes is coded as a class inheriting from :class:`Process`.
-In the *demo* server they are kept inside the *processes* folder.
-Here is a very basic example::
+In the `PyWPS-Demo`_ server they are
+kept inside the *processes* folder, usually in separated files.
 
-    from pywps import Process, LiteralInput, LiteralOutput
+The instance of a *Process* needs following attributes to be configured:
 
-    class HelloWorld(Process):
-        def __init__(self):
-            inputs = [LiteralInput('name', 'Name of a person', data_type='string')]
-            outputs = [LiteralOutput('output', 'HelloWorld Output', data_type='string')]
-
-            super(HelloWorld, self).__init__(
-                self._handler,
-                identifier='hello_world',
-                version='0.1',
-                title='My very first process!',
-                abstract='This process takes the name of a person and displays Hello World with it.',
-                inputs=inputs,
-                outputs=outputs
-            )
-            
-The first argument to the super class *__init__* method is the handler method. 
-The second is the process identifier, that is used to distinguish this from 
-other processes. Both these arguments are mandatory.
+:identifier:
+    unique identifier of the process
+:title:
+    corresponding title
+:inputs:
+    list of process inputs
+:outputs:
+    list of process outputs
+:handler:
+    method which recieves :class:`pywps.app.WPSRequest` and :class:`pywps.app.WPSResponse` as inputs.
 
-The handler is a class method (or any callable object), that takes a request and a response
-object as arguments, and returns a response object. Like so::
+Example vector buffer process
+=============================
 
-    @staticmethod
-    def _handler(request, response):
-        response.outputs['output'].data = 'Hello world!'
-        return response
+As an example, we will create a *buffer* process - which will take a vector
+file as the input, create specified the buffer around the data (using `Shapely
+<http://toblerity.org/shapely/>`_),  and return back the result.
+
+Therefore, the process will have two inputs: 
+
+* `ComplexData` input - the vector file
+* `LiteralData` input - the buffer size
+
+And it will have one output:
+
+* `ComplexData` output - the final buffer
 
-request is an instance of :class:`WPSRequest`.
-response is an instance of :class:`WPSResponse`.
+The process can be called `demobuffer` and we can now start coding it::
 
-These classes accept :class:`LiteralInput`
-values. The values can be strings (that become literal outputs) or
-:class:`FileReference` objects (that become complex outputs).
+    $ cd processes
+    $ $EDITOR demobuffer.py
+
+At the beginning, we have to import the required classes and modules
+    
+Here is a very basic example:
+
+.. literalinclude:: demobuffer.py
+   :language: python
+   :lines: 10-12
+   :linenos:
+   :lineno-start: 10
+
+As the next step, we define a list of inputs. The first input is
+:class:`pywps.ComplexInput` with the identifier `vector`, title `Vector map`
+and there is only one allowed format: GML.
+
+The next input is :class:`pywps.LiteralInput`, with the identifier `size` and
+the data type set to `float`:
+
+.. literalinclude:: demobuffer.py
+   :language: python
+   :lines: 14-21
+   :linenos:
+   :lineno-start: 14
+
+Next we define the output `output` as :class:`pywps.ComplexOutput`. This
+output supports GML format only.
+
+.. literalinclude:: demobuffer.py
+   :language: python
+   :lines: 23-27
+   :linenos:
+   :lineno-start: 23
+
+Next we create a new list variables for inputs and outputs.
+
+.. literalinclude:: demobuffer.py
+   :language: python
+   :lines: 29-30
+   :linenos:
+   :lineno-start: 29
+
+Next we define the *handler* method. In it, *geospatial analysis
+may happen*. The method gets a :class:`pywps.app.WPSRequest` and a
+:class:`pywps.app.WPSResponse` object as parameters. In our case, we
+calculate the buffer around each vector feature using 
+`GDAL/OGR library <http://gdal.org>`_. We will not got much into the details, 
+what you should note is how to get input data from the 
+:class:`pywps.app.WPSRequest` object and how to set data as outputs in the 
+:class:`pywps.app.WPSResponse` object.
+
+.. literalinclude:: demobuffer.py
+   :language: python
+   :pyobject: _handler
+   :emphasize-lines: 8-12, 50-54
+   :linenos:
+   :lineno-start: 45
+
+At the end, we put everything together and create new a `DemoBuffer` class with
+handler, inputs and outputs. It's based on :class:`pywps.Process`:
+
+.. literalinclude:: demobuffer.py
+   :pyobject: DemoBuffer
+   :language: python
+   :linenos:
+   :lineno-start: 32
 
 
 Declaring inputs and outputs
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+============================
+
 Clients need to know which inputs the processes expects. They can be declared
-as :class:`Input` objects in the :class:`Process` class declaration::
+as :class:`pywps.Input` objects in the :class:`Process` class declaration:
 
+.. code-block:: python
 
     from pywps import Process, LiteralInput, LiteralOutput
 
@@ -79,32 +171,77 @@ as :class:`Input` objects in the :class:`Process` class declaration::
             )
             ...
 
-:class:`LiteralInput`
-    A simple value embedded in the request. The first argument is a
-    name. The second argument is the type, one of `string`, `float`,
-    `integer` or `boolean`.
+.. note:: A more generic description can be found in :ref:`wps` chapter.
+
+LiteralData
+-----------
+
+* :class:`LiteralInput` 
+* :class:`LiteralOutput`
+
+A simple value embedded in the request. The first argument is a
+name. The second argument is the type, one of `string`, `float`,
+`integer` or `boolean`.
+
+ComplexData
+-----------
+
+* :class:`ComplexInput`
+* :class:`ComplexOutput`
+
+A large data object, for example a layer. ComplexData do have a `format` 
+attribute as one of their key properties. It's either a list of supported 
+formats or a single (already selected) format. It shall be an instance of
+the :class:`pywps.inout.formats.Format` class. 
+
+ComplexData :class:`Format` and input validation
+------------------------------------------------
+The ComplexData needs as one of its parameters a list of supported data 
+formats. They are derived from the :class:`Format` class. A :class:`Format` 
+instance needs, among others, a `mime_type` parameter, a `validate`
+method -- which is used for input data validation -- and also a `mode` 
+parameter -- defining how strict the validation should be (see 
+:class:`pywps.validator.mode.MODE`).
 
-:class:`ComplexInput`
-    A large data object, for example a layer. The first argument is a
-    name. The second argument is a list of one or more formats, e.g.
-    ``text/xml`` for GML files or ``application/json`` for GeoJSON
-    files.
+The `Validate` method is up to you, the user, to code. It requires two input
+paramers - `data_input` (a :class:`ComplexInput` object), and `mode`. This
+methid must return a `boolean` value indicating whether the input data are
+considered valid or not for given `mode`. You can draw inspiration from the
+:py:func:`pywps.validator.complexvalidator.validategml` method.
 
-:class:`LiteralOutput`
-    A simple value embedded in the response. The first argument is a
-    name. The second argument is the type, one of `string`, `float`,
-    `integer` or `boolean`.
+The good news is: there are already predefined validation methods for the ESRI
+Shapefile, GML and GeoJSON formats, using GDAL/OGR. There is also an XML Schema 
+validaton and a JSON schema validator - you just have to pick the propper 
+supported formats from the :class:`pywps.inout.formats.FORMATS` list and set 
+the validation mode to your :class:`ComplexInput` object.
 
-:class:`ComplexOutput`
-    Same as :class:`ComplexInput`. The first argument is a
-    name. The second argument is a list of one or more formats, e.g.
-    ``text/xml`` for GML files or ``application/json`` for GeoJSON
-    files.
+Even better news is: you can define custom validation functions and validate
+input data according to your needs.
 
+BoundingBoxData
+---------------
 
-Reading input
-~~~~~~~~~~~~~
-Handlers receive an input argument, a :class:`WPSRequest` object. Input
+* :class:`BoundingBoxInput`
+* :class:`BoundingBoxOutput`
+
+BoundingBoxData contain information about the bounding box of the desired area
+and coordinate reference system. Interesting attributes of the BoundingBoxData
+are:
+
+`crs`
+    current coordinate reference system
+`dimensions`
+    number of dimensions
+`ll`
+    pair of coordinates (or triplet) of the lower-left corner
+`ur`
+    pair of coordinates (or triplet) of the upper-right corner
+
+
+Accessing the inputs and outputs in the `handler` method
+========================================================
+
+Handlers receive as input argument a :class:`WPSRequest` object. Input
 values are found in the `inputs` dictionary::
 
     @staticmethod
@@ -114,16 +251,34 @@ values are found in the `inputs` dictionary::
         return response
 
 `inputs` is a plain Python dictionary.
-Input can be set and read in different ways including as a file, as data
-- like string or numbers - or as a stream::
+Most of the inputs and outputs are derived from the :class:`IOHandler` class. 
+This enables the user to access the data in 3 different ways:
+
+`input.file`
+    Returns a file name - you can access the data using the name of the file
+    stored on the hard drive.
+`input.data`
+    Is the direct link to the data themselves. No need to create a file object
+    on the hard drive or opening the file and closing it - PyWPS will do
+    everything for you.
+`input.stream`
+    Provides the IOStream of the data. No need for opening the file, you just
+    have to `read()` the data.
+
+PyWPS will persistently transform the input (and output) data to the desired 
+form. You can also set the data for your `Output` object like `output.data = 1` 
+or `output.file = "myfile.json"` - it works the same way.
+
+Example::
 
     request.inputs['file_input'][0].file
     request.inputs['data_input'][0].data
     request.inputs['stream_input'][0].stream
 
-Because there could be multiple input values with the same identifier, the inputs are accessed with an index.
-For `LiteralInput`, the value is a string. For `ComplexInput`, the value
-is an open file object, with a `mime_type` attribute::
+Because there could be multiple input values with the same identifier, the
+inputs are accessed with an index.  For `LiteralInput`, the value is a string.
+For `ComplexInput`, the value is an open file object, with a `mime_type`
+attribute::
 
     @staticmethod
     def handler(request, response):
@@ -135,13 +290,28 @@ is an open file object, with a `mime_type` attribute::
         response.outputs['output'].data = msg
         return response
 
+Progress and status report
+==========================
+
+OGC WPS standard enables asynchronous process execution call, that is in
+particular useful, when the process execution takes longer time - process
+instance is set to background and WPS Execute Response document with `ProcessAccepted`
+messag is returned immediately to the client. The client has to check
+`statusLocation` URL, where the current status report is deployed, say every
+n-seconds or n-minutes (depends on calculation time). Content of the response is
+usually `percentDone` information about the progress along with `statusMessage`
+text information, what is currently happening.
+
+You can set process status any time in the `handler` using the
+:py:func:`WPSResponse.update_status` function.
+
 
 Returning large data
-~~~~~~~~~~~~~~~~~~~~
+====================
 WPS allows for a clever method of returning a large data file: instead
 of embedding the data in the response, it can be saved separately, and
-a URL returned from where the data can be downloaded. In the current
-implementation, the PyWPS-4 core will save the file in a folder specified
+a URL is returned from where the data can be downloaded. In the current
+implementation, PyWPS-4 saves the file in a folder specified
 in the configuration passed by the service (or in a default location).
 The URL returned is embedded in the XML response.
 
@@ -162,34 +332,39 @@ Or a POST request::
     </wps:ResponseForm>
     ...
 
-**output** is the identifier of the output the user wishes to have be stored
+**output** is the identifier of the output the user wishes to have stored
 and accessible from a URL. The user may request as many outputs by reference
-as need, but only *one* may be requested in RAW format.
+as needed, but only *one* may be requested in RAW format.
 
 
-Publishing a process
-~~~~~~~~~~~~~~~~~~~~
+Process deployment
+==================
 In order for clients to invoke processes, a PyWPS
 :class:`Service` class must be present with the ability to listen for requests. 
 An instance of this class must created, receiving instances of
 all the desired processes classes.
 
-In the *demo* application the :class:`Service` class instance is created in 
+In the *demo* service the :class:`Service` class instance is created in the
 :class:`Server` class. :class:`Server` is a development server that relies 
-on `Flask`_. The publication
-of processes is encapsulated in *demo.py*, where a main method
-passes a list of processes instances to the :class:`Server` class::
+on `Flask`_. The publication of processes is encapsulated in *demo.py*, where 
+a main method passes a list of processes instances to the 
+:class:`Server` class::
 
     from pywps import Service
     from processes.helloworld import HelloWorld
+    from processes.demobuffer import DemoBuffer
 
     ...
-    processes = [ HelloWorld() ]
+    processes = [ DemoBuffer(), ... ]
 
     server = Server(processes=processes)
+
     ...
 
-The *demo* application is a `WSGI application`_ that accepts incoming `Execute`
+Running the dev server
+======================
+
+The :ref:`demo` server is a `WSGI application`_ that accepts incoming `Execute`
 requests and calls the appropriate process to handle them. It also
 answers `GetCapabilities` and `DescribeProcess` requests based on the
 process identifier and their inputs and outputs.
@@ -199,11 +374,11 @@ process identifier and their inputs and outputs.
 
 A host, a port, a config file and the processes can be passed as arguments to the 
 :class:`Server` constructor.
-**host** and **port** will be **prioritized** if passed to the constructor, 
+**host** and **port** will be **prioritised** if passed to the constructor, 
 otherwise the contents of the config file (*pywps.cfg*) are used. 
 
 
-Use `run` method start the server::
+Use the `run` method to start the server::
 
     ...
     s = Server(host='0.0.0.0', processes=processes, config_file=config_file)
@@ -215,5 +390,6 @@ Use `run` method start the server::
 To make the server visible from another computer, replace ``localhost`` with ``0.0.0.0``.
     
 .. _Flask: http://flask.pocoo.org
+.. _PyWPS-Demo: http://github.com/geopython/pywps-demo
 
 
diff --git a/docs/pywps.png b/docs/pywps.png
index a42b4da..505e2fe 100644
Binary files a/docs/pywps.png and b/docs/pywps.png differ
diff --git a/docs/pywps.rst b/docs/pywps.rst
new file mode 100644
index 0000000..ddabe2a
--- /dev/null
+++ b/docs/pywps.rst
@@ -0,0 +1,46 @@
+.. _pywps:
+
+=====
+PyWPS
+=====
+
+.. todo:: 
+
+    * how are thnigs organised
+    * storage
+    * dblog
+    * relationship to grass gis
+
+PyWPS philosophy
+----------------
+
+PyWPS is simple, fast to run, has low requirements on system resources, is
+modular. PyWPS solves the problem of exposing geospatial calculations to the
+web, taking care of security, data download, request acceptance, process running
+and final response construction. Therefore PyWPS has a bicycle in its logo.
+
+Why is PyWPS there
+------------------
+
+Many scientific researchers and geospatial services provider need to setup
+system, where the geospatial operations would be calculated on the server, while
+the system resources could be exposed to clients. PyWPS is here, so that you
+could set up the server fast, deploy your awesome geospatial calculation and
+expose it to the world. PyWPS is written in Python with support for many
+geospatial tools out there, like GRASS GIS, R-Project or GDAL. Python is the
+most geo-positive scripting language out there, therefore all the best tools
+have their bindings to Python in their pocket.
+
+PyWPS History
+-------------
+
+PyWPS started in 2006 as scholarship funded by `German Foundation for
+Environment <http://dbu.de>`_. During the years, it grow to version 4.0.x. In
+2015, we officially entered to `OSGeo <http://osgeo.org>`_ incubation process.
+In 2016, `Project Steering Committee <http://pywps.org/development/psc.html>`_ has started.
+PyWPS was originally hosted by the `Wald server <http://wald.intevation.org>`_,
+nowadays, we moved to `GeoPython group on GitHub
+<http://gitub.com/geopython/>`_. Since 2016, we also have new domain `PyWPS.org
+<http://pywps.org>`_.
+
+You can find more at `history page <http://pywps.org/history>`_.
diff --git a/docs/wps.rst b/docs/wps.rst
new file mode 100644
index 0000000..29e4389
--- /dev/null
+++ b/docs/wps.rst
@@ -0,0 +1,228 @@
+.. _wps:
+
+====================================
+OGC Web Processing Service (OGC WPS)
+====================================
+
+`OGC Web Processing Service <http://opengeospatial.org/standards>`_ 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.
+
+.. note:: This description is mainly refering to 1.0.0 version standard, since
+        PyWPS implements this version only. There is also 2.0.0 version, which
+        we are about to implement in near future.
+
+WPS is intended to be state-less protocol (like any OGC services). For every
+request-response action, the negotiation between the server and the client has
+to start. There is no official way, how to make the server "remember", what was
+before, there is no communication history between the server and the client.
+
+Process
+-------
+
+A process `p` is a function that for each input returns a corresponding output
+
+.. math::
+
+        p: X \rightarrow Y
+
+where `X` denotes the domain of arguments `x` and `Y` denotes the co-domain of values `y`.
+
+Within the specification, process arguments are referred to as *process inputs* and result
+values are referred to as *process outputs*. Processes that have no process inputs represent
+value generators that deliver constant or random process outputs.
+
+*Process* is just some geospatial operation, which has it's in- and outputs and
+which is deployed on the server. It can be something relatively simple (adding
+two raster maps together) or very complicated (climate change model). It can
+take short time (seconds) or long (days) to be calculated. Process is, what you,
+as PyWPS user, want to expose to other people and let their data processed.
+
+Every process has
+
+Identifier
+    Unique process identifier
+
+Title
+    Human readable title
+
+Abstract
+    Longer description of the process, what it does, how is it supposed to be
+    used
+
+And list of in- and outputs.
+
+Data in- and outputs
+--------------------
+OGC WPS defines 3 types of data inputs and data outputs *LiteralData*,
+*ComplexData* and *BoundingBoxData*.
+
+All data types do need to have following attributes:
+
+Identifier
+    Unique input identifier
+
+Title
+    Human readable title
+
+Abstract
+    Longer description of data input or output, so that the user could get
+    oriented.
+
+minOccurs
+    Minimal occurrence of the input (e.g. there can be more bands of raster file
+    and they all can be passed as input using the same identifier)
+
+maxOccurs
+    Maxium number of times, the input or output is present
+
+Depending on the data type (Literal, Complex, BoundingBox), other attributes
+might occur too.
+
+LiteralData
+~~~~~~~~~~~
+Literal data is any text string, usually short. It's used for passing single
+parameters like numbers or text parameters. WPS enables to the server, to define
+`allowedValues` - list or intervals of allowed values, as well as data type
+(integer, float, string).  Additional attributes can be set, such as `units` or
+`encoding`.
+
+ComplexData
+~~~~~~~~~~~
+Complex data are usually raster or vector files, but basically any (usually
+file based) data, which are usually processed (or result of the process). The
+input can be specified more using `mimeType`, XML `schema` or `encoding` (such
+as `base64` for raster data.
+
+.. note:: PyWPS (like every server) supports limited list `mimeTypes`. In case
+        you need some new format, just create pull request in our repository.
+        Refer :const:`pywps.inout.formats.FORMATS` for more details.
+
+Usually, the minimum requirement for input data identification is `mimeType`.
+That usually is `application/gml+xml` for `GML
+<http://opengeospatial.org/standards/gml>`_-encoded vector files, `image/tiff;
+subtype=geotiff` for raster files. The input or output can also be result of any
+OGC OWS service.
+
+BoundingBoxData
+~~~~~~~~~~~~~~~
+.. todo:: add reference to OGC OWS Common spec
+
+BoundingBox data are specified in OGC OWS Common specification as two pairs of
+coordinate (for 2D and 3D space). They can either be encoded in WGS84 or EPSG
+code can be passed too. They are intended to be used as definition of the target
+region.
+
+.. note:: In real life, BoundingBox data are not that commonly used
+
+Passing data to process instance
+--------------------------------
+There are 3 typical ways, how to pass the input data from the client to the
+server:
+
+**Data are on the server already**
+    In the first case, the data are already stored on the server (from the point
+    of view of the client). This is the simplest case.
+
+**Data are send to the server along with the request**
+    In this case, the data are directly part of the XML encoded document send via
+    HTTP POST. Some clients/servers are expecting the data to be inserted in
+    `CDATA` section. The data can be text based (JSON), XML based (GML) or even
+    raster based - in this case, they are usually encoded using `base64
+    <https://docs.python.org/3/library/base64.html>`_.
+
+**Reference link to target service is passed**
+    Client does not have to pass the data itself, client can just send reference
+    link to target data service (or file). In such case, for example OGC WFS
+    `GetFeatureType` URL can be passed and server will download the data
+    automatically.
+
+    Although this is usually used for `ComplexData` input type, it can be used
+    for literal and bounding box data too.
+
+Sychronous versus asynchronous process request
+----------------------------------------------
+
+There are two modes of process instance execution: Synchronous and asynchronous.
+
+Synchronous mode
+    The client sends the `Execute` request to the server and waits with open
+    server connection, till the process is calculated and final response is
+    returned back. This is useful for fast calculations which do not take
+    longer then a couple of seconds (`Apache2 httpd server uses 300 seconds <http://httpd.apache.org/docs/2.4/mod/core.html#timeout>`_ as default value for ConnectionTimeout).
+
+Asynchronous mode
+    Client sends the `Execute` request with explicit request for asynchronous
+    mode. If supported by the process (in PyWPS, we have a configuration for
+    that), the server returns back `ProcessAccepted` response immediately with
+    URL, where the client can regularly check for *process execution status*. 
+
+    .. note:: As you see, using WPS, the client has to apply *pull* method for
+        the communication with the server. Client has to be the active element
+        in the communication - server is just responding to clients request and
+        is not actively *pushing* any information (like it would if e.g. web
+        sockets would be implemented).
+
+Process status
+--------------
+`Process status` is generic status of the process instance, reporting to the
+client, how does the calculation go. There are 4 types of process statuses
+
+ProcessAccepted
+    Process was accepted by the server and the process execution will start
+    soon.
+
+ProcessStarted
+    Process calculation has started. The status also contains report about
+    `percentDone` - calculation progress and `statusMessage` - text reporting
+    current calculation state (example: *"Caculationg buffer"* - 33%).
+
+ProcessFinished
+    Process instance performed the calculation successfully and the final
+    `Execute` response is returned to the client and/or stored on final location
+
+ProcessFailed
+    There was something wrong with the process instance and the server reports
+    `server exception` (see :py:mod:`pywps.exceptions`) along with the message,
+    what could possibly go wrong.
+
+Request encoding, HTTP GET and POST
+-----------------------------------
+The request can be encoded either using Key-value-pairs (KVP) or as the
+XML-formatted document.
+
+Key-value-pair
+    is usually sent via `HTTP GET request method
+    <https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods>`_
+    encoded directly in the URL. The keys and values are separated with `=` sign and
+    each pair is separated with `&` sign (with `?` at the beginning of the request.
+    Example could be the *get capabilities reques*::
+
+            http://server.domain/wps?service=WPS&request=GetCapabilities&version=1.0.0
+
+    In this example, there are 3 pairs of input parameter: service, request and
+    version with values `WPS`, `GetCapabilities` and `1.0.0` respectively.
+
+XML
+    is document sent via `HTTP POST request method
+    <https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods>`_.
+    The XML document can be more rich, having more parameters, better to be
+    parsed in complex structures. Client can also encode whole datasets to the
+    request, including raster (encoded using base64) or vector data (usually as GML file).::
+
+        <?xml version="1.0" encoding="UTF-8"?>
+        <wps:GetCapabilities language="cz" service="WPS" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsGetCapabilities_request.xsd">
+          <wps:AcceptVersions>
+            <ows:Version>1.0.0</ows:Version>
+          </wps:AcceptVersions>
+        </wps:GetCapabilities>
+
+.. note:: Even it might be looking more complicated to use XML over KVP, for
+        some complex request it usually is more safe and efficient to use XML
+        encoding. The KVP way, especially for WPS Execute request can be tricky
+        and lead to unpredictable errors.
diff --git a/pywps/__init__.py b/pywps/__init__.py
index da92b38..1726312 100644
--- a/pywps/__init__.py
+++ b/pywps/__init__.py
@@ -28,14 +28,14 @@
 ##############################################################################
 
 import logging
+
 import os
 
 from lxml.builder import ElementMaker
 
-__version__ = '4.0.0-alpha2'
+__version__ = '4.0.0-beta1'
 
 LOGGER = logging.getLogger('PYWPS')
-
 LOGGER.debug('setting core variables')
 
 PYWPS_INSTALL_DIR = os.path.dirname(os.path.abspath(__file__))
diff --git a/pywps/app/Process.py b/pywps/app/Process.py
index d7a2595..d322f51 100644
--- a/pywps/app/Process.py
+++ b/pywps/app/Process.py
@@ -33,6 +33,7 @@ import tempfile
 
 from pywps import WPS, OWS, E, dblog
 from pywps.app.WPSResponse import WPSResponse
+from pywps.app.WPSResponse import STATUS
 from pywps.app.WPSRequest import WPSRequest
 import pywps.configuration as config
 from pywps._compat import PY2
@@ -46,8 +47,8 @@ class Process(object):
     """
     :param handler: A callable that gets invoked for each incoming
                     request. It should accept a single
-                    :class:`~WPSRequest` argument and return a
-                    :class:`~WPSResponse` object.
+                    :class:`pywps.app.WPSRequest` argument and return a
+                    :class:`pywps.app.WPSResponse` object.
     :param identifier: Name of this process.
     :param inputs: List of inputs accepted by this process. They
                    should be :class:`~LiteralInput` and :class:`~ComplexInput`
@@ -143,7 +144,7 @@ class Process(object):
 
     def execute(self, wps_request, uuid):
         self._set_uuid(uuid)
-        async = False
+        self.async = False
         wps_response = WPSResponse(self, wps_request, self.uuid)
 
         LOGGER.debug('Check if status storage and updating are supported by this process')
@@ -156,14 +157,14 @@ class Process(object):
                 if self.status_supported != 'true':
                     raise OperationNotSupported('Process does not support the updating of status')
 
-                wps_response.status = WPSResponse.STORE_AND_UPDATE_STATUS
-                async = True
+                wps_response.status = STATUS.STORE_AND_UPDATE_STATUS
+                self.async = True
             else:
-                wps_response.status = WPSResponse.STORE_STATUS
+                wps_response.status = STATUS.STORE_STATUS
 
         LOGGER.debug('Check if updating of status is not required then no need to spawn a process')
 
-        wps_response = self._execute_process(async, wps_request, wps_response)
+        wps_response = self._execute_process(self.async, wps_request, wps_response)
 
         return wps_response
 
@@ -209,7 +210,7 @@ class Process(object):
             if running < maxparalel:
                 wps_response = self._run_process(wps_request, wps_response)
             else:
-                raise ServerBusy('Maximum number of paralel running processes reached. Please try later.')
+                raise ServerBusy('Maximum number of parallel running processes reached. Please try later.')
 
         return wps_response
 
@@ -240,10 +241,10 @@ class Process(object):
             self._set_grass()
             wps_response = self.handler(wps_request, wps_response)
 
-            # if status not yet set to 100% then do it after execution was successful
             if (not wps_response.status_percentage) or (wps_response.status_percentage != 100):
                 LOGGER.debug('Updating process status to 100% if everything went correctly')
-                wps_response.update_status('PyWPS Process finished', 100, wps_response.DONE_STATUS)
+                wps_response.update_status('PyWPS Process finished', 100,
+                        STATUS.DONE_STATUS, clean=self.async)
         except Exception as e:
             traceback.print_exc()
             LOGGER.debug('Retrieving file and line number where exception occurred')
@@ -280,7 +281,7 @@ class Process(object):
             new_wps_request = WPSRequest()
             new_wps_request.json = json.loads(request_json)
             new_wps_response = WPSResponse(self, new_wps_request, uuid)
-            new_wps_response.status = WPSResponse.STORE_AND_UPDATE_STATUS
+            new_wps_response.status = STATUS.STORE_AND_UPDATE_STATUS
             self._set_uuid(uuid)
             self._run_async(new_wps_request, new_wps_response)
             dblog.remove_stored(uuid)
diff --git a/pywps/app/Service.py b/pywps/app/Service.py
index 66b8843..d5e4a5b 100644
--- a/pywps/app/Service.py
+++ b/pywps/app/Service.py
@@ -292,8 +292,9 @@ class Service(object):
         try:
             process = self.processes[identifier]
 
-            workdir = config.get_config_value('server', 'workdir')
-            tempdir = tempfile.mkdtemp(prefix='pyws_process_', dir=workdir)
+            workdir = os.path.abspath(
+                    config.get_config_value('server', 'workdir'))
+            tempdir = tempfile.mkdtemp(prefix='pywps_process_', dir=workdir)
             process.set_workdir(tempdir)
         except KeyError:
             raise InvalidParameterValue("Unknown process '%r'" % identifier, 'Identifier')
@@ -313,7 +314,7 @@ class Service(object):
         LOGGER.debug('Checking if datainputs is required and has been passed')
         if process.inputs:
             if wps_request.inputs is None:
-                raise MissingParameterValue('', 'datainputs')
+                raise MissingParameterValue('Missing "datainputs" parameter', 'datainputs')
 
         LOGGER.debug('Checking if all mandatory inputs have been passed')
         data_inputs = {}
@@ -472,9 +473,8 @@ class Service(object):
             complex_data_handler(data_input, inpt)
 
             outinputs.append(data_input)
-
         if len(outinputs) < source.min_occurs:
-            raise MissingParameterValue(locator=source.identifier)
+            raise MissingParameterValue(description="Given data input is missing", locator=source.identifier)
         return outinputs
 
     def create_literal_inputs(self, source, inputs):
diff --git a/pywps/app/WPSRequest.py b/pywps/app/WPSRequest.py
index 60c7257..8da6deb 100644
--- a/pywps/app/WPSRequest.py
+++ b/pywps/app/WPSRequest.py
@@ -431,6 +431,7 @@ def get_inputs_from_xml(doc):
 
         complex_data = xpath_ns(input_el, './wps:Data/wps:ComplexData')
         if complex_data:
+
             complex_data_el = complex_data[0]
             inpt = {}
             inpt['identifier'] = identifier_el.text
diff --git a/pywps/app/WPSResponse.py b/pywps/app/WPSResponse.py
index b5b7695..f720bf9 100644
--- a/pywps/app/WPSResponse.py
+++ b/pywps/app/WPSResponse.py
@@ -8,20 +8,20 @@ from pywps.app.basic import xml_response
 from pywps.exceptions import NoApplicableCode
 import pywps.configuration as config
 from pywps.dblog import update_response
+from collections import namedtuple
 
+_STATUS = namedtuple('Status', 'NO_STATUS, STORE_STATUS,'
+        'STORE_AND_UPDATE_STATUS, DONE_STATUS')
 
-class WPSResponse(object):
+STATUS = _STATUS(0, 1, 2, 3)
 
-    NO_STATUS = 0
-    STORE_STATUS = 1
-    STORE_AND_UPDATE_STATUS = 2
-    DONE_STATUS = 3
+class WPSResponse(object):
 
     def __init__(self, process, wps_request, uuid):
         """constructor
 
-        :param process: instance of  class:`pywps.app.Process.Process`
-        :param wps_request: instance of class:`pywps.app.WPSRequest.WPSRequest`
+        :param pywps.app.Process.Process process:
+        :param pywps.app.WPSRequest.WPSRequest wps_request:
         :param uuid: string this request uuid
         """
 
@@ -29,12 +29,21 @@ class WPSResponse(object):
         self.wps_request = wps_request
         self.outputs = {o.identifier: o for o in process.outputs}
         self.message = ''
-        self.status = self.NO_STATUS
+        self.status = STATUS.NO_STATUS
         self.status_percentage = 0
         self.doc = None
         self.uuid = uuid
 
-    def update_status(self, message=None, status_percentage=None, status=None):
+    def update_status(self, message=None, status_percentage=None, status=None,
+            clean=True):
+        """
+        Update status report of currently running process instance
+
+        :param str message: Message you need to share with the client
+        :param int status_percentage: Percent done (number betwen <0-100>)
+        :param pywps.app.WPSResponse.STATUS status: process status - user should usually
+            ommit this parameter
+        """
 
         if message:
             self.message = message
@@ -45,17 +54,16 @@ class WPSResponse(object):
         if status_percentage:
             self.status_percentage = status_percentage
 
-        # rebuild the doc and update the status xml file
-        self.doc = self._construct_doc()
-
-
         # check if storing of the status is requested
-        if self.status >= self.STORE_STATUS:
-            self.write_response_doc(self.doc)
+        if self.status >= STATUS.STORE_AND_UPDATE_STATUS:
+
+            # rebuild the doc and update the status xml file
+            self.doc = self._construct_doc()
+            self.write_response_doc(self.doc, clean)
 
         update_response(self.uuid, self)
 
-    def write_response_doc(self, doc):
+    def write_response_doc(self, doc, clean=True):
         # TODO: check if file/directory is still present, maybe deleted in mean time
 
         try:
@@ -64,7 +72,7 @@ class WPSResponse(object):
                 f.flush()
                 os.fsync(f.fileno())
 
-            if self.status >= self.DONE_STATUS:
+            if self.status >= STATUS.DONE_STATUS and clean:
                 self.process.clean()
 
         except IOError as e:
@@ -125,7 +133,7 @@ class WPSResponse(object):
             '?service=WPS&request=GetCapabilities'
         )
 
-        if self.status >= self.STORE_STATUS:
+        if self.status >= STATUS.STORE_STATUS:
             if self.process.status_location:
                 doc.attrib['statusLocation'] = self.process.status_url
 
@@ -147,7 +155,7 @@ class WPSResponse(object):
 
         # Status XML
         # return the correct response depending on the progress of the process
-        if self.status >= self.STORE_AND_UPDATE_STATUS:
+        if self.status >= STATUS.STORE_AND_UPDATE_STATUS:
             if self.status_percentage == 0:
                 self.message = 'PyWPS Process %s accepted' % self.process.identifier
                 status_doc = self._process_accepted()
@@ -199,7 +207,7 @@ class WPSResponse(object):
         except Exception as exp:
             raise NoApplicableCode(exp)
 
-        if self.status >= self.DONE_STATUS:
+        if self.status >= STATUS.DONE_STATUS:
             self.process.clean()
 
         return xml_response(doc)
diff --git a/pywps/configuration.py b/pywps/configuration.py
index 6557ff2..898cead 100755
--- a/pywps/configuration.py
+++ b/pywps/configuration.py
@@ -39,7 +39,7 @@ else:
     import configparser
 
 
-config = None
+CONFIG = None
 LOGGER = logging.getLogger("PYWPS")
 
 
@@ -53,14 +53,14 @@ def get_config_value(section, option):
     :returns: value found in the configuration file
     """
 
-    if not config:
+    if not CONFIG:
         load_configuration()
 
     value = ''
 
-    if config.has_section(section):
-        if config.has_option(section, option):
-            value = config.get(section, option)
+    if CONFIG.has_section(section):
+        if CONFIG.has_option(section, option):
+            value = CONFIG.get(section, option)
 
             # Convert Boolean string to real Boolean values
             if value.lower() == "false":
@@ -79,58 +79,59 @@ def load_configuration(cfgfiles=None):
     :param cfgfiles: list of configuration files
     """
 
-    global config
+    global CONFIG
 
     LOGGER.info('loading configuration')
     if PY2:
-        config = ConfigParser.SafeConfigParser()
+        CONFIG = ConfigParser.SafeConfigParser()
     else:
-        config = configparser.ConfigParser()
+        CONFIG = configparser.ConfigParser()
 
     LOGGER.debug('setting default values')
-    config.add_section('server')
-    config.set('server', 'encoding', 'utf-8')
-    config.set('server', 'language', 'en-US')
-    config.set('server', 'url', 'http://localhost/wps')
-    config.set('server', 'maxprocesses', '30')
-    config.set('server', 'maxsingleinputsize', '1mb')
-    config.set('server', 'maxrequestsize', '3mb')
-    config.set('server', 'temp_path', tempfile.gettempdir())
-    config.set('server', 'processes_path', '')
+    CONFIG.add_section('server')
+    CONFIG.set('server', 'encoding', 'utf-8')
+    CONFIG.set('server', 'language', 'en-US')
+    CONFIG.set('server', 'url', 'http://localhost/wps')
+    CONFIG.set('server', 'maxprocesses', '30')
+    CONFIG.set('server', 'maxsingleinputsize', '1mb')
+    CONFIG.set('server', 'maxrequestsize', '3mb')
+    CONFIG.set('server', 'temp_path', tempfile.gettempdir())
+    CONFIG.set('server', 'processes_path', '')
     outputpath = tempfile.gettempdir()
-    config.set('server', 'outputurl', 'file:///%s' % outputpath)
-    config.set('server', 'outputpath', outputpath)
-    config.set('server', 'logfile', '')
-    config.set('server', 'loglevel', 'INFO')
-    config.set('server', 'workdir',  tempfile.gettempdir())
-    config.set('server', 'parallelprocesses', '2')
-
-    config.add_section('metadata:main')
-    config.set('metadata:main', 'identification_title', 'PyWPS Processing Service')
-    config.set('metadata:main', 'identification_abstract', 'PyWPS is an implementation of the Web Processing Service standard from the Open Geospatial Consortium. PyWPS is written in Python.')
-    config.set('metadata:main', 'identification_keywords', 'PyWPS,WPS,OGC,processing')
-    config.set('metadata:main', 'identification_keywords_type', 'theme')
-    config.set('metadata:main', 'identification_fees', 'NONE')
-    config.set('metadata:main', 'identification_accessconstraints', 'NONE')
-    config.set('metadata:main', 'provider_name', 'Organization Name')
-    config.set('metadata:main', 'provider_url', 'http://pywps.org/')
-    config.set('metadata:main', 'contact_name', 'Lastname, Firstname')
-    config.set('metadata:main', 'contact_position', 'Position Title')
-    config.set('metadata:main', 'contact_address', 'Mailing Address')
-    config.set('metadata:main', 'contact_city', 'City')
-    config.set('metadata:main', 'contact_stateorprovince', 'Administrative Area')
-    config.set('metadata:main', 'contact_postalcode', 'Zip or Postal Code')
-    config.set('metadata:main', 'contact_country', 'Country')
-    config.set('metadata:main', 'contact_phone', '+xx-xxx-xxx-xxxx')
-    config.set('metadata:main', 'contact_fax', '+xx-xxx-xxx-xxxx')
-    config.set('metadata:main', 'contact_email', 'Email Address')
-    config.set('metadata:main', 'contact_url', 'Contact URL')
-    config.set('metadata:main', 'contact_hours', 'Hours of Service')
-    config.set('metadata:main', 'contact_instructions', 'During hours of service.  Off on weekends.')
-    config.set('metadata:main', 'contact_role', 'pointOfContact')
-
-    config.add_section('grass')
-    config.set('grass', 'gisbase', '')
+    CONFIG.set('server', 'outputurl', 'file:///%s' % outputpath)
+    CONFIG.set('server', 'outputpath', outputpath)
+    CONFIG.set('server', 'logfile', '')
+    CONFIG.set('server', 'logdatabase', ':memory:')
+    CONFIG.set('server', 'loglevel', 'INFO')
+    CONFIG.set('server', 'workdir',  tempfile.gettempdir())
+    CONFIG.set('server', 'parallelprocesses', '2')
+
+    CONFIG.add_section('metadata:main')
+    CONFIG.set('metadata:main', 'identification_title', 'PyWPS Processing Service')
+    CONFIG.set('metadata:main', 'identification_abstract', 'PyWPS is an implementation of the Web Processing Service standard from the Open Geospatial Consortium. PyWPS is written in Python.')
+    CONFIG.set('metadata:main', 'identification_keywords', 'PyWPS,WPS,OGC,processing')
+    CONFIG.set('metadata:main', 'identification_keywords_type', 'theme')
+    CONFIG.set('metadata:main', 'identification_fees', 'NONE')
+    CONFIG.set('metadata:main', 'identification_accessconstraints', 'NONE')
+    CONFIG.set('metadata:main', 'provider_name', 'Organization Name')
+    CONFIG.set('metadata:main', 'provider_url', 'http://pywps.org/')
+    CONFIG.set('metadata:main', 'contact_name', 'Lastname, Firstname')
+    CONFIG.set('metadata:main', 'contact_position', 'Position Title')
+    CONFIG.set('metadata:main', 'contact_address', 'Mailing Address')
+    CONFIG.set('metadata:main', 'contact_city', 'City')
+    CONFIG.set('metadata:main', 'contact_stateorprovince', 'Administrative Area')
+    CONFIG.set('metadata:main', 'contact_postalcode', 'Zip or Postal Code')
+    CONFIG.set('metadata:main', 'contact_country', 'Country')
+    CONFIG.set('metadata:main', 'contact_phone', '+xx-xxx-xxx-xxxx')
+    CONFIG.set('metadata:main', 'contact_fax', '+xx-xxx-xxx-xxxx')
+    CONFIG.set('metadata:main', 'contact_email', 'Email Address')
+    CONFIG.set('metadata:main', 'contact_url', 'Contact URL')
+    CONFIG.set('metadata:main', 'contact_hours', 'Hours of Service')
+    CONFIG.set('metadata:main', 'contact_instructions', 'During hours of service.  Off on weekends.')
+    CONFIG.set('metadata:main', 'contact_role', 'pointOfContact')
+
+    CONFIG.add_section('grass')
+    CONFIG.set('grass', 'gisbase', '')
 
     if not cfgfiles:
         cfgfiles = _get_default_config_files_location()
@@ -138,7 +139,7 @@ def load_configuration(cfgfiles=None):
     if isinstance(cfgfiles, str):
         cfgfiles = [cfgfiles]
 
-    loaded_files = config.read(cfgfiles)
+    loaded_files = CONFIG.read(cfgfiles)
     if loaded_files:
         LOGGER.info('Configuration file(s) %s loaded', loaded_files)
     else:
@@ -149,11 +150,25 @@ def load_configuration(cfgfiles=None):
 def _check_config():
     """Check some configuration values
     """
-    workdir = get_config_value('server', 'workdir')
+    global CONFIG
+
+    def checkdir(confid):
+
+        confvalue = get_config_value('server', confid)
+
+        if not os.path.isdir(confvalue):
+            LOGGER.warning('server->%s configuration value %s is not directory'
+                    % (confid, confvalue))
+
+        if not os.path.isabs(confvalue):
+            LOGGER.warning(
+                    'server->%s configuration value %s is not absolute path, making it absolute to %s' %\
+                        (confid, confvalue, os.path.abspath(confvalue)))
+            CONFIG.set('server', confid, os.path.abspath(confvalue))
+
+
+    [checkdir(n) for n in  ['workdir', 'outputpath']]
 
-    if not os.path.isdir(workdir):
-        LOGGER.warning('server->workdir configuration value %s is not directory'
-                % workdir)
 
 
 def _get_default_config_files_location():
diff --git a/pywps/dblog.py b/pywps/dblog.py
index eccb8e3..4f687df 100644
--- a/pywps/dblog.py
+++ b/pywps/dblog.py
@@ -13,6 +13,7 @@ import os
 
 LOGGER = logging.getLogger('PYWPS')
 _CONNECTION = None
+_DATABASE = None
 
 def log_request(uuid, request):
     """Write OGC WPS request (only the necessary parts) to database logging
@@ -47,7 +48,7 @@ def get_running():
     conn = get_connection()
     cur = conn.cursor()
 
-    res = cur.execute('SELECT uuid FROM pywps_requests WHERE percent_done < 100')
+    res = cur.execute('SELECT uuid FROM pywps_requests WHERE percent_done < 100 and percent_done > -1')
 
     return res.fetchall()
 
@@ -133,14 +134,24 @@ def get_connection():
 
     LOGGER.debug('Initializing database connection')
     global _CONNECTION
+    global _DATABASE
 
     if _CONNECTION:
         return _CONNECTION
 
-    database = configuration.get_config_value('server', 'logdatabase')
+    if not _DATABASE:
+        database = configuration.get_config_value('server', 'logdatabase')
 
-    if not database:
-        database = ':memory:'
+        if not database:
+            database = ':memory:'
+        elif database == ':memory:':
+            pass
+        else:
+            database = os.path.abspath(database)
+
+        _DATABASE = database
+    else:
+        database = _DATABASE
 
     connection = sqlite3.connect(database)
     if check_db_table(connection):
diff --git a/pywps/exceptions.py b/pywps/exceptions.py
index 03c1234..a9c9f87 100644
--- a/pywps/exceptions.py
+++ b/pywps/exceptions.py
@@ -39,7 +39,7 @@ import logging
 
 from pywps import __version__
 
-logging.basicConfig()
+#logging.basicConfig()
 LOGGER = logging.getLogger('PYWPS')
 
 class NoApplicableCode(HTTPException):
@@ -83,10 +83,10 @@ class NoApplicableCode(HTTPException):
         return text_type((
             u'<?xml version="1.0" encoding="UTF-8"?>\n'
             u'<!-- PyWPS %(version)s -->\n'
-            u'<ows:ExceptionReport xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd" version="1.0.0">'
-            u'<ows:Exception exceptionCode="%(name)s" locator="%(locator)s" >'
-            u'%(description)s'
-            u'</ows:Exception>'
+            u'<ows:ExceptionReport xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd" version="1.0.0">\n'
+            u'  <ows:Exception exceptionCode="%(name)s" locator="%(locator)s" >\n'
+            u'      %(description)s\n'
+            u'  </ows:Exception>\n'
             u'</ows:ExceptionReport>'
         ) % {
             'version': __version__,
diff --git a/pywps/inout/basic.py b/pywps/inout/basic.py
index f268e8d..ef88557 100644
--- a/pywps/inout/basic.py
+++ b/pywps/inout/basic.py
@@ -466,7 +466,18 @@ class BBoxInput(BasicIO, BasicBoundingBox, IOHandler):
 
     @property
     def json(self):
-        """Get JSON representation of the input
+        """Get JSON representation of the input. It returns following keys in
+        the JSON object:
+
+            * identifier
+            * title
+            * abstract
+            * type
+            * crs
+            * bbox
+            * dimensions
+            * workdir
+            * mode
         """
         return {
             'identifier': self.identifier,
diff --git a/pywps/inout/formats/__init__.py b/pywps/inout/formats/__init__.py
index 24f0f7a..4ecedef 100644
--- a/pywps/inout/formats/__init__.py
+++ b/pywps/inout/formats/__init__.py
@@ -50,20 +50,22 @@ _get_mimetypes()
 
 class Format(object):
     """Input/output format specification
+
+    Predefined Formats are stored in :class:`pywps.inout.formats.FORMATS`
+
+    :param str mime_type: mimetype definition
+    :param str schema: xml schema definition
+    :param str encoding: base64 or not
+    :param function validate: function, which will perform validation. e.g.
+    :param number mode: validation mode
+    :param str extension: file extension
     """
+
     def __init__(self, mime_type,
                  schema=None, encoding=None,
                  validate=emptyvalidator, mode=MODE.SIMPLE,
                  extension=None):
         """Constructor
-
-        :param mime_type: mimetype definition
-        :param schema: xml schema definition
-        :param encoding: base64 or not
-        :param validate: function, which will perform validation. e.g.
-        :param mode: validation mode
-        :param extension: file extension
-        pywps.validator.complexvalidator.validategml
         """
 
         self._mime_type = None
diff --git a/pywps/inout/formats/lists.py b/pywps/inout/formats/lists.py
deleted file mode 100644
index cee5e0f..0000000
--- a/pywps/inout/formats/lists.py
+++ /dev/null
@@ -1,30 +0,0 @@
-"""List of supported formats
-"""
-from collections import namedtuple
-
-_FORMAT = namedtuple('FormatDefinition', 'mime_type,'
-                     'extension, schema')
-_FORMATS = namedtuple('FORMATS', 'GEOJSON, JSON, SHP, GML, GEOTIFF, WCS,'
-                                 'WCS100, WCS110, WCS20, WFS, WFS100,'
-                                 'WFS110, WFS20, WMS, WMS130, WMS110,'
-                                 'WMS100')
-FORMATS = _FORMATS(
-    _FORMAT('application/vnd.geo+json', '.geojson', None),
-    _FORMAT('application/json', '.json', None),
-    _FORMAT('application/x-zipped-shp', '.zip', None),
-    _FORMAT('application/gml+xml', '.gml', None),
-    _FORMAT('image/tiff; subtype=geotiff', '.tiff', None),
-    _FORMAT('application/xogc-wcs', '.xml', None),
-    _FORMAT('application/x-ogc-wcs; version=1.0.0', '.xml', None),
-    _FORMAT('application/x-ogc-wcs; version=1.1.0', '.xml', None),
-    _FORMAT('application/x-ogc-wcs; version=2.0', '.xml', None),
-    _FORMAT('application/x-ogc-wfs', '.xml', None),
-    _FORMAT('application/x-ogc-wfs; version=1.0.0', '.xml', None),
-    _FORMAT('application/x-ogc-wfs; version=1.1.0', '.xml', None),
-    _FORMAT('application/x-ogc-wfs; version=2.0', '.xml', None),
-    _FORMAT('application/x-ogc-wms', '.xml', None),
-    _FORMAT('application/x-ogc-wms; version=1.3.0', '.xml', None),
-    _FORMAT('application/x-ogc-wms; version=1.1.0', '.xml', None),
-    _FORMAT('application/x-ogc-wms; version=1.0.0', '.xml', None)
-)
-
diff --git a/pywps/inout/inputs.py b/pywps/inout/inputs.py
index b894aa3..f55e16c 100644
--- a/pywps/inout/inputs.py
+++ b/pywps/inout/inputs.py
@@ -8,14 +8,18 @@ from pywps.inout.literaltypes import AnyValue
 class BoundingBoxInput(basic.BBoxInput):
 
     """
-    :param identifier: The name of this input.
-    :param data_type: Type of literal input (e.g. `string`, `float`...).
+    :param string identifier: The name of this input.
+    :param string title: Human readable title
+    :param string abstract: Longer text description
     :param crss: List of supported coordinate reference system (e.g. ['EPSG:4326'])
+    :param int dimensions: 2 or 3
+    :param int min_occurs: how many times this input occurs
+    :param int max_occurs: how many times this input occurs
     """
 
     def __init__(self, identifier, title, crss, abstract='',
                  dimensions=2, metadata=None, min_occurs=1,
-                 max_occurs=1, as_reference=False,
+                 max_occurs=1,
                  mode=MODE.NONE):
         if metadata is None:
             metadata = []
@@ -26,7 +30,7 @@ class BoundingBoxInput(basic.BBoxInput):
         self.metadata = metadata
         self.min_occurs = int(min_occurs)
         self.max_occurs = int(max_occurs)
-        self.as_reference = as_reference
+        self.as_reference = False
 
     def describe_xml(self):
         """
@@ -94,29 +98,24 @@ class BoundingBoxInput(basic.BBoxInput):
 
 
 class ComplexInput(basic.ComplexInput):
-
     """
-    Complex Input
+    Complex data input
+
+    :param str identifier: The name of this input.
+    :param str title: Title of the input
+    :param  pywps.inout.formats.Format supported_formats: List of supported formats
+    :param pywps.inout.formats.Format data_format: default data format
+    :param str abstract: Input abstract
+    :param list metada: TODO
+    :param int min_occurs: minimum occurence
+    :param int max_occurs: maximum occurence
+    :param pywps.validator.mode.MODE mode: validation mode (none to strict)
     """
 
     def __init__(self, identifier, title, supported_formats=None,
                  data_format=None, abstract='', metadata=[], min_occurs=1,
-                 max_occurs=1, as_reference=False, mode=MODE.NONE):
-        """
-        :param str identifier: The name of this input.
-        :param str title: Title of the input
-        :param list supported_formats: List of supported
-            :py:class:`pywps.inout.formats.Format`
-        :param :py:class:`pywps.inout.formats.Format data_format`
-            default data format
-        :param str abstract: Input abstract
-        :param list metada: TODO
-        :param int min_occurs: minimum occurence
-        :param int max_occurs: maximum occurence
-        :param bool as_reference: input is reference to URL
-        :param :py:obj:`pywps.validator.mode.MODE` mode: validation mode (none to
-            strict)
-        """
+                 max_occurs=1, mode=MODE.NONE):
+        """constructor"""
 
         if metadata is None:
             metadata = []
@@ -127,7 +126,7 @@ class ComplexInput(basic.ComplexInput):
         self.metadata = metadata
         self.min_occurs = int(min_occurs)
         self.max_occurs = int(max_occurs)
-        self.as_reference = as_reference
+        self.as_reference = False
         self.url = ''
         self.method = ''
         self.max_size = int(0)
@@ -234,30 +233,24 @@ class ComplexInput(basic.ComplexInput):
 
 
 class LiteralInput(basic.LiteralInput):
-
     """
-    Literal Input class
+    :param str identifier: The name of this input.
+    :param str title: Title of the input
+    :param pywps.inout.literaltypes.LITERAL_DATA_TYPES data_type: data type
+    :param str abstract: Input abstract
+    :param list metadata: TODO
+    :param str uoms: units
+    :param int min_occurs: minimum occurence
+    :param int max_occurs: maximum occurence
+    :param pywps.validator.mode.MODE mode: validation mode (none to strict)
+    :param pywps.inout.literaltypes.AnyValue allowed_values: or :py:class:`pywps.inout.literaltypes.AllowedValue` object
     """
 
     def __init__(self, identifier, title, data_type='integer', abstract='',
                  metadata=None, uoms=None, default=None,
-                 min_occurs=1, max_occurs=1, as_reference=False,
+                 min_occurs=1, max_occurs=1,
                  mode=MODE.SIMPLE, allowed_values=AnyValue):
-        """
-        :param str identifier: The name of this input.
-        :param str title: Title of the input
-        :param :py:class:`pywps.inout.literalatypes.LITERAL_DATA_TYPES` data_type:
-           data type
-        :param str abstract: Input abstract
-        :param list metadata: TODO
-        :param str uoms: units
-        :param int min_occurs: minimum occurence
-        :param int max_occurs: maximum occurence
-        :param bool as_reference: input is reference to URL
-        :param :py:obj:`pywps.validator.mode.MODE` mode: validation mode
-            (none to strict)
-        :param allowed_values: :py:class:`pywps.inout.literal_types.AnyValues`
-            or :py:class:`pywps.inout.literaltypes.AllowedValue` object
+        """Constructor
         """
 
         basic.LiteralInput.__init__(self, identifier=identifier, title=title,
@@ -268,7 +261,7 @@ class LiteralInput(basic.LiteralInput):
         self.default = default
         self.min_occurs = int(min_occurs)
         self.max_occurs = int(max_occurs)
-        self.as_reference = as_reference
+        self.as_reference = False
 
     def describe_xml(self):
         """Return DescribeProcess Output element
diff --git a/pywps/inout/literaltypes.py b/pywps/inout/literaltypes.py
index 4944580..b27a213 100644
--- a/pywps/inout/literaltypes.py
+++ b/pywps/inout/literaltypes.py
@@ -55,7 +55,11 @@ class AllowedValue(AnyValue):
     the values are evaluated in literal validator functions
 
     :param pywps.validator.allowed_value.ALLOWEDVALUETYPE allowed_type: VALUE or RANGE
-    :param value:
+    :param value: single value
+    :param minval: minimal value in case of Range
+    :param maxval: maximal value in case of Range
+    :param spacing: spacing in case of Range
+    :param pywps.input.literaltypes.RANGECLOSURETYPE range_closure:
     """
 
     def __init__(self, allowed_type=ALLOWEDVALUETYPE.VALUE, value=None,
diff --git a/pywps/inout/outputs.py b/pywps/inout/outputs.py
index 935dbbe..08a9dc4 100644
--- a/pywps/inout/outputs.py
+++ b/pywps/inout/outputs.py
@@ -10,6 +10,13 @@ import lxml.etree as etree
 class BoundingBoxOutput(basic.BBoxInput):
     """
     :param identifier: The name of this input.
+    :param str title: Title of the input
+    :param str abstract: Input abstract
+    :param crss: List of supported coordinate reference system (e.g. ['EPSG:4326'])
+    :param int dimensions: number of dimensions (2 or 3)
+    :param int min_occurs: minimum occurence
+    :param int max_occurs: maximum occurence
+    :param pywps.validator.mode.MODE mode: validation mode (none to strict)
     """
 
     def __init__(self, identifier, title, crss, abstract='',
@@ -80,11 +87,10 @@ class ComplexOutput(basic.ComplexOutput):
     """
     :param identifier: The name of this output.
     :param title: Readable form of the output name.
-    :param supported_formats: List of supported
-            output formats for this output.
-            Should be list of :class:`~Format` object.
-            The first format in the list will be used as the default.
-    :param abstract: Description of the output
+    :param pywps.inout.formats.Format  supported_formats: List of supported
+        formats. The first format in the list will be used as the default.
+    :param str abstract: Description of the output
+    :param pywps.validator.mode.MODE mode: validation mode (none to strict)
     """
 
     def __init__(self, identifier, title,  supported_formats=None,
@@ -200,9 +206,11 @@ class ComplexOutput(basic.ComplexOutput):
 class LiteralOutput(basic.LiteralOutput):
     """
     :param identifier: The name of this output.
-    :param data_type: Type of literal input (e.g. `string`, `float`...).
-    :param value: Resulting value
-            Should be :class:`~String` object.
+    :param str title: Title of the input
+    :param pywps.inout.literaltypes.LITERAL_DATA_TYPES data_type: data type
+    :param str abstract: Input abstract
+    :param str uoms: units
+    :param pywps.validator.mode.MODE mode: validation mode (none to strict)
     """
 
     def __init__(self, identifier, title, data_type='string', abstract='',
diff --git a/pywps/inout/storage.py b/pywps/inout/storage.py
index 43fe2c5..3e3cad6 100644
--- a/pywps/inout/storage.py
+++ b/pywps/inout/storage.py
@@ -73,10 +73,7 @@ class FileStorage(StorageAbstract):
         """
         """
         self.target = config.get_config_value('server', 'outputpath')
-        self.output_url = '%s%s' % (
-            config.get_config_value('server', 'url'),
-            config.get_config_value('server', 'outputurl')
-        )
+        self.output_url = config.get_config_value('server', 'outputurl')
 
     def store(self, output):
         import shutil, tempfile, math
@@ -84,7 +81,8 @@ class FileStorage(StorageAbstract):
         file_name = output.file
 
         file_block_size = os.stat(file_name).st_blksize
-        avail_size = get_free_space(self.target)
+        # get_free_space delivers the numer of free blocks, not the available size!
+        avail_size = get_free_space(self.target) * file_block_size
         file_size = os.stat(file_name).st_size
 
         # calculate space used according to block size
@@ -95,7 +93,7 @@ class FileStorage(StorageAbstract):
 
         (prefix, suffix) = os.path.splitext(file_name)
         if not suffix:
-            suffix = output.output_format.get_extension()
+            suffix = output.output_format.extension
         (file_dir, file_name) = os.path.split(prefix)
         output_name = tempfile.mkstemp(suffix=suffix, prefix=file_name,
                                        dir=self.target)[1]
diff --git a/pywps/validator/complexvalidator.py b/pywps/validator/complexvalidator.py
index d60f547..baa6369 100644
--- a/pywps/validator/complexvalidator.py
+++ b/pywps/validator/complexvalidator.py
@@ -28,28 +28,30 @@
 import logging
 
 from pywps.validator.mode import MODE
-from pywps.inout.formats.lists import FORMATS
+from pywps.inout.formats import FORMATS
 import mimetypes
 import os
 
 LOGGER = logging.getLogger('PYWPS')
 
 def validategml(data_input, mode):
-    """GML validation example
-
-    >>> import StringIO
-    >>> class FakeInput(object):
-    ...     gml = open('point.gml','w')
-    ...     gml.write('''<?xml version="1.0" ?>
-    ...     <gml:featureMember xmlns:gml="http://www.opengis.net/gml" xsi:schemaLocation="http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><feature:feature xmlns:feature="http://example.com/feature"><feature:geometry><gml:Point><gml:coordinates decimal="." cs=", " ts=" ">-1, 1</gml:coordinates></gml:Point></feature:geometry></feature:feature></gml:featureMember>''')
-    ...     gml.close()
-    ...     file = 'point.gml'
-    >>> class fake_data_format(object):
-    ...     mimetype = 'application/gml+xml'
-    >>> fake_input = FakeInput()
-    >>> fake_input.data_format = fake_data_format()
-    >>> validategml(fake_input, MODE.SIMPLE)
-    True
+    """GML validation function
+
+    :param data_input: :class:`ComplexInput`
+    :param pywps.validator.mode.MODE mode:
+
+    This function validates GML input based on given validation mode. Following
+    happens, if `mode` parameter is given:
+
+    `MODE.NONE`
+        it will return always `True`
+    `MODE.SIMPLE`
+        the mimetype will be checked
+    `MODE.STRICT`
+        `GDAL/OGR <http://gdal.org/>`_ is used for getting the propper format.
+    `MODE.VERYSTRICT`
+        the :class:`lxml.etree` is used along with given input `schema` and the
+        GML file is properly validated against given schema.
     """
 
     LOGGER.info('validating GML; Mode: %s', mode)
diff --git a/tox.ini b/tox.ini
index e48692d..84355b9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -20,5 +20,5 @@ deps=
 
 commands=
 	# check first which version is installed "gdal-config --version"
-	pip install GDAL==1.10.0 --global-option=build_ext --global-option="-I/usr/include/gdal"
+	pip install GDAL==2.1.0 --global-option=build_ext --global-option="-I/usr/include/gdal"
     python -m unittest tests

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/pywps.git



More information about the Pkg-grass-devel mailing list