[Git][debian-gis-team/pywps][master] 5 commits: New upstream version 4.5.1

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Thu Dec 2 05:47:07 GMT 2021



Bas Couwenberg pushed to branch master at Debian GIS Project / pywps


Commits:
52ec3457 by Bas Couwenberg at 2021-12-02T06:32:52+01:00
New upstream version 4.5.1
- - - - -
61694543 by Bas Couwenberg at 2021-12-02T06:32:55+01:00
Update upstream source from tag 'upstream/4.5.1'

Update to upstream version '4.5.1'
with Debian dir 261cbbc8d46d5b676c6be4aa71b73b0fe04ea81a
- - - - -
d3f0f08e by Bas Couwenberg at 2021-12-02T06:33:18+01:00
New upstream release.

- - - - -
632ba80e by Bas Couwenberg at 2021-12-02T06:38:50+01:00
Refresh patches.

- - - - -
f5a9843c by Bas Couwenberg at 2021-12-02T06:39:03+01:00
Set distribution to unstable.

- - - - -


22 changed files:

- .github/workflows/main.yml
- + SECURITY.md
- VERSION.txt
- debian/changelog
- debian/patches/offline-tests.patch
- docs/api_rest.rst
- pywps/__init__.py
- pywps/app/Process.py
- pywps/app/WPSRequest.py
- pywps/dependencies.py
- pywps/inout/basic.py
- pywps/inout/storage/file.py
- pywps/validator/complexvalidator.py
- requirements-extra.txt
- − requirements-gdal.txt
- requirements.txt
- setup.cfg
- + tests/test_assync_inout.py
- tests/test_execute.py
- tests/test_ows.py
- tests/test_storage.py
- tests/validator/test_complexvalidators.py


Changes:

=====================================
.github/workflows/main.yml
=====================================
@@ -4,10 +4,10 @@ on: [ push, pull_request ]
 
 jobs:
   main:
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: [3.6, 3.7, 3.8, 3.9]
+        python-version: [3.7, 3.8, 3.9]
     env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         COVERALLS_SERVICE_NAME: github
@@ -15,7 +15,7 @@ jobs:
     - uses: actions/checkout at v2
     - name: Install packages
       run: |
-        sudo apt-get update && sudo apt-get -y install gdal-bin libgdal-dev libnetcdf-dev libhdf5-dev
+        sudo apt-get update && sudo apt-get -y install libnetcdf-dev libhdf5-dev
     - uses: actions/setup-python at v2
       name: Setup Python ${{ matrix.python-version }}
       with:
@@ -26,17 +26,16 @@ jobs:
         pip3 install -r requirements.txt
         pip3 install -r requirements-dev.txt
         pip3 install -r requirements-extra.txt
-        pip3 install -r requirements-gdal.txt
     - name: run tests ⚙️
       run: pytest -v tests
     - name: run coveralls ⚙️
       run: coveralls
-      if: matrix.python-version == 3.6
+      if: matrix.python-version == 3.7
     - name: build docs 🏗️
       run: |
         pip3 install -e .
         cd docs && make html
-      if: matrix.python-version == 3.6
+      if: matrix.python-version == 3.7
     - name: run flake8 ⚙️
       run: flake8 pywps
-      if: matrix.python-version == 3.6
+      if: matrix.python-version == 3.7


=====================================
SECURITY.md
=====================================
@@ -0,0 +1,16 @@
+# PyWPS Security Policy
+
+## Reporting
+
+Security/vulnerability reports **should not** be submitted through GitHub issues or public discussions, but instead please send your report 
+to **geopython-security nospam @ lists.osgeo.org** - (remove the blanks and 'nospam').  
+
+## Supported Versions
+
+The PyWPS Project Steering Committee will release patches for security vulnerabilities for the following versions:
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 4.5.x | :white_check_mark: |
+| 4.4.x | :white_check_mark: |
+| < 4.4 | previous versions | :x:                |


=====================================
VERSION.txt
=====================================
@@ -1 +1 @@
-4.5.0
+4.5.1


=====================================
debian/changelog
=====================================
@@ -1,12 +1,14 @@
-pywps (4.5.0-2) UNRELEASED; urgency=medium
+pywps (4.5.1-1) unstable; urgency=medium
 
   * Team upload.
+  * New upstream release.
   * Bump Standards-Version to 4.6.0, no changes.
   * Bump debhelper compat to 12, changes:
     - Drop --list-missing from dh_install
   * Drop undefined substitution variables.
+  * Refresh patches.
 
- -- Bas Couwenberg <sebastic at debian.org>  Wed, 08 Sep 2021 17:43:54 +0200
+ -- Bas Couwenberg <sebastic at debian.org>  Thu, 02 Dec 2021 06:38:51 +0100
 
 pywps (4.5.0-1) unstable; urgency=medium
 


=====================================
debian/patches/offline-tests.patch
=====================================
@@ -4,7 +4,7 @@ Forwarded: not-needed
 
 --- a/tests/test_ows.py
 +++ b/tests/test_ows.py
-@@ -126,6 +126,7 @@ def create_sum_one():
+@@ -92,6 +92,7 @@ def create_sum_one():
  
  class ExecuteTests(unittest.TestCase):
  
@@ -12,7 +12,7 @@ Forwarded: not-needed
      def test_wfs(self):
          if not service_ok('https://demo.mapserver.org'):
              self.skipTest("mapserver is unreachable")
-@@ -152,6 +153,7 @@ class ExecuteTests(unittest.TestCase):
+@@ -118,6 +119,7 @@ class ExecuteTests(unittest.TestCase):
          # . the inclusion of output
          # . the type of output
  
@@ -22,17 +22,17 @@ Forwarded: not-needed
              self.skipTest('GRASS lib not found')
 --- a/tests/validator/test_complexvalidators.py
 +++ b/tests/validator/test_complexvalidators.py
-@@ -80,7 +80,8 @@ class ValidateTest(unittest.TestCase):
+@@ -83,7 +83,8 @@ class ValidateTest(unittest.TestCase):
+         self.assertTrue(validategml(gml_input, MODE.NONE), 'NONE validation')
          self.assertTrue(validategml(gml_input, MODE.SIMPLE), 'SIMPLE validation')
-         if WITH_GDAL:
-             self.assertTrue(validategml(gml_input, MODE.STRICT), 'STRICT validation')
--            self.assertTrue(validategml(gml_input, MODE.VERYSTRICT), 'VERYSTRICT validation')
-+            if os.environ.get('OFFLINE_TESTS') == None:
-+                self.assertTrue(validategml(gml_input, MODE.VERYSTRICT), 'VERYSTRICT validation')
+         self.assertTrue(validategml(gml_input, MODE.STRICT), 'STRICT validation')
+-        self.assertTrue(validategml(gml_input, MODE.VERYSTRICT), 'VERYSTRICT validation')
++        if os.environ.get('OFFLINE_TESTS') == None:
++            self.assertTrue(validategml(gml_input, MODE.VERYSTRICT), 'VERYSTRICT validation')
          gml_input.stream.close()
  
      def test_json_validator(self):
-@@ -141,6 +142,8 @@ class ValidateTest(unittest.TestCase):
+@@ -140,6 +141,8 @@ class ValidateTest(unittest.TestCase):
          else:
              self.assertFalse(validatenetcdf(netcdf_input, MODE.STRICT), 'STRICT validation')
  
@@ -43,7 +43,7 @@ Forwarded: not-needed
          opendap_input = ComplexInput('dods', 'opendap test', [FORMATS.DODS,])
 --- a/tests/test_execute.py
 +++ b/tests/test_execute.py
-@@ -234,6 +234,8 @@ def get_output(doc):
+@@ -235,6 +235,8 @@ def get_output(doc):
  class ExecuteTest(unittest.TestCase):
      """Test for Exeucte request KVP request"""
  


=====================================
docs/api_rest.rst
=====================================
@@ -33,14 +33,14 @@ The default mimetype (output format) can be set by adding `&f=json` or `&f=xml`
 
 GET GetCapabilities Request URL:
 
-.. code-block::
+.. code-block:: json
 
     http://localhost:5000/processes/?service=WPS
     http://localhost:5000/wps/?request=GetCapabilities&service=WPS&f=json
 
 GET GetCapabilities Response:
 
-.. code-block::
+.. code-block:: json
 
     {
       "pywps_version": "4.5.0",
@@ -113,14 +113,14 @@ GET GetCapabilities Response:
 
 GET DescribeProcess Request URL:
 
-.. code-block::
+.. code-block:: json
 
     http://localhost:5000/processes/say_hello?service=WPS
     http://localhost:5000/wps/?request=DescribeProcess&service=WPS&identifier=say_hello&version=1.0.0&f=json
 
 GET DescribeProcess Response:
 
-.. code-block::
+.. code-block:: json
 
     {
       "pywps_version": "4.5.0",
@@ -178,13 +178,13 @@ GET DescribeProcess Response:
 
 GET Execute Request URL:
 
-.. code-block::
+.. code-block:: json
 
     http://localhost:5000/wps?/service=wps&version=1.0.0&request=execute&Identifier=say_hello&storeExecuteResponse=true&DataInputs=name=Dude&f=json
 
 GET Execute Response:
 
-.. code-block::
+.. code-block:: json
 
     {
         "status": {
@@ -200,13 +200,13 @@ GET Execute Response:
 
 GET Execute Request URL (Raw output):
 
-.. code-block::
+.. code-block:: json
 
     http://localhost:5000/wps?/service=wps&version=1.0.0&request=execute&Identifier=say_hello&storeExecuteResponse=true&DataInputs=name=Dude&RawDataOutput=output
 
 GET Execute Response:
 
-.. code-block::
+.. code-block:: json
 
     Hello Dude
 
@@ -224,13 +224,13 @@ Example of a `Say Hello` POST request:
 
 POST Execute Request URL:
 
-.. code-block::
+.. code-block:: json
 
     http://localhost:5000/jobs
 
 POST Execute Request Body:
 
-.. code-block::
+.. code-block:: json
 
     {
         "identifier": "say_hello",
@@ -241,7 +241,7 @@ POST Execute Request Body:
 
 POST Execute Response:
 
-.. code-block::
+.. code-block:: json
 
     {
         "status": {
@@ -260,7 +260,7 @@ Example of a `Say Hello` POST request with raw output:
 
 POST Execute Request Body:
 
-.. code-block::
+.. code-block:: json
 
     {
         "identifier": "say_hello",
@@ -273,7 +273,7 @@ POST Execute Request Body:
 
 POST Execute Response:
 
-.. code-block::
+.. code-block:: json
 
     Hello Dude
 
@@ -281,13 +281,13 @@ Alternatively, the `identifier` and optionally the raw output name can be encode
 
 POST Execute Request URL (with `identifier`):
 
-.. code-block::
+.. code-block:: json
 
     http://localhost:5000/jobs/say_hello
 
 POST Execute Request Body:
 
-.. code-block::
+.. code-block:: json
 
     {
         "name": "Dude"
@@ -295,7 +295,7 @@ POST Execute Request Body:
 
 POST Execute Response:
 
-.. code-block::
+.. code-block:: json
 
     {
         "status": {
@@ -311,13 +311,13 @@ POST Execute Response:
 
 POST Execute Request URL (with `identifier` and output name):
 
-.. code-block::
+.. code-block:: json
 
     http://localhost:5000/jobs/say_hello/output
 
 POST Execute Request Body:
 
-.. code-block::
+.. code-block:: json
 
     {
         "name": "Dude"
@@ -325,14 +325,14 @@ POST Execute Request Body:
 
 POST Execute Response:
 
-.. code-block::
+.. code-block:: json
 
     Hello Dude
 
 
 Example for a reference input:
 
-.. code-block::
+.. code-block:: json
 
     "raster": {
         "type": "reference",
@@ -342,7 +342,7 @@ Example for a reference input:
 Example for a BoundingBox input:
 (bbox default axis order is yx (EPSG:4326), i.e. miny, minx, maxy, maxx)
 
-.. code-block::
+.. code-block:: json
 
     "extent": {
         "type": "bbox",
@@ -353,7 +353,7 @@ Example for a BoundingBox input:
 Example for a ComplexInput input:
 (the data is a standard GeoJSON)
 
-.. code-block::
+.. code-block:: json
 
     "cutline": {
         "type": "complex",


=====================================
pywps/__init__.py
=====================================
@@ -9,7 +9,7 @@ import os
 
 from lxml.builder import ElementMaker
 
-__version__ = "4.5.0"
+__version__ = "4.5.1"
 
 LOGGER = logging.getLogger('PYWPS')
 LOGGER.debug('setting core variables')


=====================================
pywps/app/Process.py
=====================================
@@ -458,6 +458,9 @@ class Process(object):
 
                 is_reference = wps_request.outputs[wps_outpt].get('asReference', 'false')
                 mimetype = wps_request.outputs[wps_outpt].get('mimetype', '')
+                if not isinstance(mimetype, str):
+                    mimetype = ''
+
                 if is_reference.lower() == 'true':
                     # check if store is supported
                     if self.store_supported == 'false':
@@ -471,9 +474,9 @@ class Process(object):
                 for outpt in self.outputs:
                     if outpt.identifier == wps_outpt:
                         outpt.as_reference = is_reference
-                        if isinstance(outpt, ComplexOutput) and mimetype != '':
+                        if isinstance(outpt, ComplexOutput) and mimetype:
                             data_format = [f for f in outpt.supported_formats if f.mime_type == mimetype]
                             if len(data_format) == 0:
                                 raise InvalidParameterValue(
-                                    'MimeType ' + mimetype + ' not valid')
+                                    f"MimeType {mimetype} not valid")
                             outpt.data_format = data_format[0]


=====================================
pywps/app/WPSRequest.py
=====================================
@@ -108,7 +108,7 @@ class WPSRequest(object):
             try:
                 doc = etree.fromstring(self.http_request.get_data())
             except Exception as e:
-                raise NoApplicableCode(e.msg)
+                raise NoApplicableCode(str(e))
             operation = doc.tag
             version = get_version_from_ns(doc.nsmap[doc.prefix])
             self.set_version(version)
@@ -122,7 +122,7 @@ class WPSRequest(object):
             try:
                 jdoc = json.loads(self.http_request.get_data())
             except Exception as e:
-                raise NoApplicableCode(e.msg)
+                raise NoApplicableCode(str(e))
             if self.identifier is not None:
                 jdoc = {'inputs': jdoc}
             else:
@@ -491,8 +491,13 @@ class WPSRequest(object):
                     inpt_def = {"data": inpt_def}
                 if 'identifier' not in inpt_def:
                     inpt_def['identifier'] = identifier
-                inpt = input_from_json(inpt_def)
-                self.inputs[identifier].append(inpt)
+                try:
+                    inpt = input_from_json(inpt_def)
+                    self.inputs[identifier].append(inpt)
+                except Exception as e:
+                    LOGGER.warning(e)
+                    LOGGER.warning(f'skipping input: {identifier}')
+                    pass
 
 
 def get_inputs_from_xml(doc):


=====================================
pywps/dependencies.py
=====================================
@@ -6,13 +6,6 @@
 import warnings
 
 try:
-    import osgeo
-    from osgeo import gdal, ogr
-except ImportError:
-    warnings.warn('Complex validation requires GDAL/OGR support.')
-    ogr = None
-
-try:
-    import netCDF4
+    import netCDF4  # noqa
 except ImportError:
     warnings.warn('Complex validation requires netCDF4 support.')


=====================================
pywps/inout/basic.py
=====================================
@@ -250,16 +250,23 @@ class IOHandler(object):
         value_type = value_type or getattr(self, '_default_type')
 
         if value:
-            if value_type == SOURCE_TYPE.DATA:
-                self.data = value
-            elif value_type == SOURCE_TYPE.MEMORY:
-                raise NotImplementedError
-            elif value_type == SOURCE_TYPE.FILE:
-                self.file = value
-            elif value_type == SOURCE_TYPE.STREAM:
-                self.stream = value
-            elif value_type == SOURCE_TYPE.URL:
-                self.url = value
+            # only set default when a value is optional
+            if self.min_occurs == 0:
+                if value_type == SOURCE_TYPE.DATA:
+                    self.data = value
+                elif value_type == SOURCE_TYPE.MEMORY:
+                    raise NotImplementedError
+                elif value_type == SOURCE_TYPE.FILE:
+                    self.file = value
+                elif value_type == SOURCE_TYPE.STREAM:
+                    self.stream = value
+                elif value_type == SOURCE_TYPE.URL:
+                    self.url = value
+            else:
+                # when a value is requried the default value will be ignored
+                LOGGER.warning(
+                    "The given default value will not be used"
+                    " because is is required to provide a value.")
 
     def _build_file_name(self, href=''):
         """Return a file name for the local system."""


=====================================
pywps/inout/storage/file.py
=====================================
@@ -69,6 +69,14 @@ class FileStorage(CachedStorage):
         self.copy_function = copy_function
 
     def _do_store(self, output):
+        """Copy output to final storage location.
+
+        - Create output directory
+        - Check available file space
+        - Create output file name, taking care of possible duplicates
+        - Copy / link output in work directory to output directory
+        - Return store type, output path and output URL
+        """
         import platform
         import math
         import tempfile
@@ -78,6 +86,11 @@ class FileStorage(CachedStorage):
 
         request_uuid = output.uuid or uuid.uuid1()
 
+        # Create a target folder for each request
+        target = os.path.join(self.target, str(request_uuid))
+        if not os.path.exists(target):
+            os.makedirs(target)
+
         # st.blksize is not available in windows, skips the validation on windows
         if platform.system() != 'Windows':
             file_block_size = os.stat(file_name).st_blksize
@@ -91,11 +104,6 @@ class FileStorage(CachedStorage):
             if avail_size < actual_file_size:
                 raise NotEnoughStorage('Not enough space in {} to store {}'.format(self.target, file_name))
 
-        # create a target folder for each request
-        target = os.path.join(self.target, str(request_uuid))
-        if not os.path.exists(target):
-            os.makedirs(target)
-
         # build output name
         output_name, suffix = _build_output_name(output)
         # build tempfile in case of duplicates
@@ -116,7 +124,7 @@ class FileStorage(CachedStorage):
         url = self.url("{}/{}".format(request_uuid, just_file_name))
         LOGGER.info('File output URI: {}'.format(url))
 
-        return (STORE_TYPE.PATH, output_name, url)
+        return STORE_TYPE.PATH, output_name, url
 
     @staticmethod
     def copy(src, dst, copy_function=None):
@@ -134,7 +142,7 @@ class FileStorage(CachedStorage):
             try:
                 os.link(src, dst)
             except Exception:
-                LOGGER.warn("Could not create hardlink. Fallback to copy.")
+                LOGGER.warning("Could not create hardlink. Fallback to copy.")
                 FileStorage.copy(src, dst)
         else:
             shutil.copy2(src, dst)


=====================================
pywps/validator/complexvalidator.py
=====================================
@@ -35,7 +35,7 @@ def validategml(data_input, mode):
     `MODE.SIMPLE`
         the mimetype will be checked
     `MODE.STRICT`
-        `GDAL/OGR <http://gdal.org/>`_ is used for getting the proper format.
+        `Fiona` is used for getting the proper format.
     `MODE.VERYSTRICT`
         the :class:`lxml.etree` is used along with given input `schema` and the
         GML file is properly validated against given schema.
@@ -55,11 +55,11 @@ def validategml(data_input, mode):
 
     if mode >= MODE.STRICT:
 
-        from pywps.dependencies import ogr
-        data_source = ogr.Open(data_input.file)
-        if data_source:
-            passed = (data_source.GetDriver().GetName() == "GML")
-        else:
+        try:
+            import fiona
+            data_source = fiona.open(data_input.file)
+            passed = (data_source.driver == "GML")
+        except (ModuleNotFoundError, ImportError):
             passed = False
 
     if mode >= MODE.VERYSTRICT:
@@ -89,7 +89,7 @@ def validategpx(data_input, mode):
     `MODE.SIMPLE`
         the mimetype will be checked
     `MODE.STRICT`
-        `GDAL/OGR <http://gdal.org/>`_ is used for getting the proper format.
+        `Fiona` is used for getting the proper format.
     `MODE.VERYSTRICT`
         the :class:`lxml.etree` is used along with given input `schema` and the
         GPX file is properly validated against given schema.
@@ -109,11 +109,11 @@ def validategpx(data_input, mode):
 
     if mode >= MODE.STRICT:
 
-        from pywps.dependencies import ogr
-        data_source = ogr.Open(data_input.file)
-        if data_source:
-            passed = (data_source.GetDriver().GetName() == "GPX")
-        else:
+        try:
+            import fiona
+            data_source = fiona.open(data_input.file)
+            passed = (data_source.driver == "GPX")
+        except (ModuleNotFoundError, ImportError):
             passed = False
 
     if mode >= MODE.VERYSTRICT:
@@ -249,11 +249,11 @@ def validategeojson(data_input, mode):
 
     if mode >= MODE.STRICT:
 
-        from pywps.dependencies import ogr
-        data_source = ogr.Open(data_input.file)
-        if data_source:
-            passed = (data_source.GetDriver().GetName() == "GeoJSON")
-        else:
+        try:
+            import fiona
+            data_source = fiona.open(data_input.file)
+            passed = (data_source.driver == "GeoJSON")
+        except (ModuleNotFoundError, ImportError):
             passed = False
 
     if mode >= MODE.VERYSTRICT:
@@ -317,22 +317,11 @@ def validateshapefile(data_input, mode):
 
     if mode >= MODE.STRICT:
 
-        from pywps.dependencies import ogr
-
-        import zipfile
-        z = zipfile.ZipFile(data_input.file)
-        shape_name = None
-        for name in z.namelist():
-            z.extract(name, data_input.tempdir)
-            if os.path.splitext(name)[1].lower() == '.shp':
-                shape_name = name
-
-        if shape_name:
-            data_source = ogr.Open(os.path.join(data_input.tempdir, shape_name))
-
-        if data_source:
-            passed = (data_source.GetDriver().GetName() == "ESRI Shapefile")
-        else:
+        try:
+            import fiona
+            sf = fiona.open(data_input.file)
+            passed = (sf.driver == "ESRI Shapefile")
+        except (ModuleNotFoundError, ImportError):
             passed = False
 
     return passed
@@ -357,10 +346,10 @@ def validategeotiff(data_input, mode):
     if mode >= MODE.STRICT:
 
         try:
-            from pywps.dependencies import osgeo # noqa
-            data_source = osgeo.gdal.Open(data_input.file)
-            passed = (data_source.GetDriver().ShortName == "GTiff")
-        except ImportError:
+            from geotiff import GeoTiff
+            data_source = GeoTiff(data_input.file)
+            passed = (data_source.crs_code > 0)
+        except (ModuleNotFoundError, ImportError):
             passed = False
 
     return passed


=====================================
requirements-extra.txt
=====================================
@@ -1 +1 @@
-netCDF4
\ No newline at end of file
+netCDF4


=====================================
requirements-gdal.txt deleted
=====================================
@@ -1,3 +0,0 @@
-# On your system check the GDAL version using gdalinfo --version, and adjust
-# the GDAL version here to suit your system
-GDAL==2.1.0 --global-option=build_ext --global-option="-I/usr/include/gdal"


=====================================
requirements.txt
=====================================
@@ -8,3 +8,5 @@ SQLAlchemy
 werkzeug
 MarkupSafe
 humanize
+geotiff
+fiona


=====================================
setup.cfg
=====================================
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 4.5.0
+current_version = 4.5.1
 commit = False
 tag = False
 parse = (?P<major>\d+)\.(?P<minor>\d+).(?P<patch>\d+)


=====================================
tests/test_assync_inout.py
=====================================
@@ -0,0 +1,68 @@
+##################################################################
+# Copyright 2018 Open Source Geospatial Foundation and others    #
+# licensed under MIT, Please consult LICENSE.txt for details     #
+##################################################################
+
+from pywps import Service, Process, LiteralInput, ComplexOutput
+from pywps import FORMATS
+from pywps import get_ElementMakerForVersion
+from pywps.tests import client_for
+
+VERSION = "1.0.0"
+
+WPS, OWS = get_ElementMakerForVersion(VERSION)
+
+
+def create_inout():
+
+    def inout(request, response):
+        response.outputs['text'].data = request.inputs['text'][0].data
+        return response
+
+    return Process(handler=inout,
+                   identifier='inout',
+                   title='InOut',
+                   inputs=[
+                       LiteralInput('text', 'Text', data_type='string')
+                   ],
+                   outputs=[
+                        ComplexOutput(
+                            'text',
+                            title='Text',
+                            supported_formats=[FORMATS.TEXT, ]
+                            ),
+                   ],
+                   store_supported=True,
+                   status_supported=True
+                   )
+
+
+def test_assync_inout():
+    client = client_for(Service(processes=[create_inout()]))
+    request_doc = WPS.Execute(
+        OWS.Identifier('inout'),
+        WPS.DataInputs(
+            WPS.Input(
+                OWS.Identifier('text'),
+                WPS.Data(
+                    WPS.LiteralData(
+                        "Hello World"
+                    )
+                )
+            )
+        ),
+        WPS.ResponseForm(
+            WPS.ResponseDocument(
+                WPS.Output(
+                    OWS.Identifier("text")
+                ),
+            ),
+        ),
+        version="1.0.0"
+    )
+    resp = client.post_xml(doc=request_doc)
+    assert resp.status_code == 200
+
+    # TODO:
+    # . extract the status URL from the response
+    # . send a status request


=====================================
tests/test_execute.py
=====================================
@@ -131,6 +131,7 @@ def create_complex_proces(mime_type: str = 'gml'):
                        ComplexInput(
                            'complex',
                            'Complex input',
+                           min_occurs=0,
                            default="DEFAULT COMPLEX DATA",
                            supported_formats=[frmt])
                    ],


=====================================
tests/test_ows.py
=====================================
@@ -10,7 +10,6 @@ import os
 import tempfile
 import unittest
 from pywps import Service, Process, ComplexInput, ComplexOutput, Format, FORMATS, get_format
-from pywps.dependencies import ogr
 from pywps.exceptions import NoApplicableCode
 from pywps import get_ElementMakerForVersion
 import pywps.configuration as config
@@ -26,41 +25,8 @@ def create_feature():
 
     def feature(request, response):
         input = request.inputs['input'][0].file
-        # What do we need to assert a Complex input?
-        # assert type(input) is str
-
-        # open the input file
-        try:
-            inSource = ogr.Open(input)
-        except Exception as e:
-            return "Could not open given vector file: {}".format(e)
-        inLayer = inSource.GetLayer()
-
-        # create output file
-        out = 'point'
-        outPath = os.path.join(tempfile.gettempdir(), out)
-
-        driver = ogr.GetDriverByName('GML')
-        outSource = driver.CreateDataSource(
-            outPath,
-            ["XSISCHEMAURI=http://schemas.opengis.net/gml/2.1.2/feature.xsd"])
-        outLayer = outSource.CreateLayer(out, None, ogr.wkbUnknown)
-
-        # get the first feature
-        inFeature = inLayer.GetNextFeature()
-        inGeometry = inFeature.GetGeometryRef()
-
-        # make the buffer
-        buff = inGeometry.Buffer(float(100000))
-
-        # create output feature to the file
-        outFeature = ogr.Feature(feature_def=outLayer.GetLayerDefn())
-        outFeature.SetGeometryDirectly(buff)
-        outLayer.CreateFeature(outFeature)
-        outFeature.Destroy()
-
         response.outputs['output'].data_format = FORMATS.GML
-        response.outputs['output'].file = outPath
+        response.outputs['output'].file = input
         return response
 
     return Process(handler=feature,


=====================================
tests/test_storage.py
=====================================
@@ -2,6 +2,7 @@
 # Copyright 2018 Open Source Geospatial Foundation and others    #
 # licensed under MIT, Please consult LICENSE.txt for details     #
 ##################################################################
+import pytest
 
 from pywps.inout.storage.builder import StorageBuilder
 from pywps.inout.storage.file import FileStorage
@@ -9,26 +10,45 @@ from pywps.inout.storage.s3 import S3Storage
 
 from pywps import configuration
 
+from pathlib import Path
 import unittest
+import tempfile
 
-class StorageBuilderTests(unittest.TestCase):
+
+ at pytest.fixture
+def fake_output(tmp_path):
+    class FakeOutput(object):
+        """Fake output object for testing."""
+        def __init__(self):
+            self.identifier = "fake_output"
+            self.file = self._get_file()
+            self.uuid = None
+
+        def _get_file(self):
+            fn = tmp_path / 'file.tiff'
+            fn.touch()
+            return str(fn.absolute())
+
+    return FakeOutput()
+
+
+class TestStorageBuilder():
 
     def test_default_storage(self):
         storage = StorageBuilder.buildStorage()
-        self.assertIsInstance(storage, FileStorage)
-
+        assert isinstance(storage, FileStorage)
 
     def test_s3_storage(self):
         configuration.CONFIG.set('server', 'storagetype', 's3')
         storage = StorageBuilder.buildStorage()
-        self.assertIsInstance(storage, S3Storage)
-
-def load_tests(loader=None, tests=None, pattern=None):
-    """Load local tests
-    """
-    if not loader:
-        loader = unittest.TestLoader()
-    suite_list = [
-        loader.loadTestsFromTestCase(StorageBuilderTests)
-    ]
-    return unittest.TestSuite(suite_list)
\ No newline at end of file
+        assert isinstance(storage, S3Storage)
+
+    def test_recursive_directory_creation(self, fake_output):
+        """Test that outputpath is created."""
+        configuration.CONFIG.set('server', 'storagetype', 'file')
+        outputpath = Path(tempfile.gettempdir()) / "a" / "b" / "c"
+        configuration.CONFIG.set('server', 'outputpath', str(outputpath))
+        storage = StorageBuilder.buildStorage()
+
+        storage.store(fake_output)
+        assert outputpath.exists()


=====================================
tests/validator/test_complexvalidators.py
=====================================
@@ -8,34 +8,40 @@
 
 import unittest
 import pytest
-import sys
-from pywps.validator.complexvalidator import *
+from pywps.validator.mode import MODE
+from pywps.validator.complexvalidator import (
+    validategml,
+    # validategpx,
+    # validatexml,
+    validatejson,
+    validategeojson,
+    validateshapefile,
+    validategeotiff,
+    validatenetcdf,
+    validatedods,
+)
 from pywps.inout.formats import FORMATS
 from pywps import ComplexInput
 from pywps.inout.basic import SOURCE_TYPE
 import tempfile
 import os
 
-try:
-    import osgeo
-except ImportError:
-    WITH_GDAL = False
-else:
-    WITH_GDAL = True
 
 try:
-    import netCDF4
+    import netCDF4  # noqa
 except ImportError:
     WITH_NC4 = False
 else:
     WITH_NC4 = True
 
+
 def get_input(name, schema, mime_type):
 
     class FakeFormat(object):
         mimetype = 'text/plain'
         schema = None
         units = None
+
         def validate(self, data):
             return True
 
@@ -67,20 +73,17 @@ class ValidateTest(unittest.TestCase):
     def setUp(self):
         pass
 
-
     def tearDown(self):
         pass
 
-    @unittest.skip('long')
     def test_gml_validator(self):
         """Test GML validator
         """
         gml_input = get_input('gml/point.gml', 'point.xsd', FORMATS.GML.mime_type)
         self.assertTrue(validategml(gml_input, MODE.NONE), 'NONE validation')
         self.assertTrue(validategml(gml_input, MODE.SIMPLE), 'SIMPLE validation')
-        if WITH_GDAL:
-            self.assertTrue(validategml(gml_input, MODE.STRICT), 'STRICT validation')
-            self.assertTrue(validategml(gml_input, MODE.VERYSTRICT), 'VERYSTRICT validation')
+        self.assertTrue(validategml(gml_input, MODE.STRICT), 'STRICT validation')
+        self.assertTrue(validategml(gml_input, MODE.VERYSTRICT), 'VERYSTRICT validation')
         gml_input.stream.close()
 
     def test_json_validator(self):
@@ -99,9 +102,8 @@ class ValidateTest(unittest.TestCase):
                                   FORMATS.GEOJSON.mime_type)
         self.assertTrue(validategeojson(geojson_input, MODE.NONE), 'NONE validation')
         self.assertTrue(validategeojson(geojson_input, MODE.SIMPLE), 'SIMPLE validation')
-        if WITH_GDAL:
-            self.assertTrue(validategeojson(geojson_input, MODE.STRICT), 'STRICT validation')
-            self.assertTrue(validategeojson(geojson_input, MODE.VERYSTRICT), 'VERYSTRICT validation')
+        self.assertTrue(validategeojson(geojson_input, MODE.STRICT), 'STRICT validation')
+        self.assertTrue(validategeojson(geojson_input, MODE.VERYSTRICT), 'VERYSTRICT validation')
         geojson_input.stream.close()
 
     def test_shapefile_validator(self):
@@ -111,8 +113,7 @@ class ValidateTest(unittest.TestCase):
                 FORMATS.SHP.mime_type)
         self.assertTrue(validateshapefile(shapefile_input, MODE.NONE), 'NONE validation')
         self.assertTrue(validateshapefile(shapefile_input, MODE.SIMPLE), 'SIMPLE validation')
-        if WITH_GDAL:
-            self.assertTrue(validateshapefile(shapefile_input, MODE.STRICT), 'STRICT validation')
+        self.assertTrue(validateshapefile(shapefile_input, MODE.STRICT), 'STRICT validation')
         shapefile_input.stream.close()
 
     def test_geotiff_validator(self):
@@ -122,8 +123,6 @@ class ValidateTest(unittest.TestCase):
                                   FORMATS.GEOTIFF.mime_type)
         self.assertTrue(validategeotiff(geotiff_input, MODE.NONE), 'NONE validation')
         self.assertTrue(validategeotiff(geotiff_input, MODE.SIMPLE), 'SIMPLE validation')
-        if not WITH_GDAL:
-            self.skipTest('GDAL not Installed')
         self.assertTrue(validategeotiff(geotiff_input, MODE.STRICT), 'STRICT validation')
         geotiff_input.stream.close()
 
@@ -161,12 +160,12 @@ class ValidateTest(unittest.TestCase):
                                      default_type=SOURCE_TYPE.URL,
                                      mode=MODE.SIMPLE)
 
-
     def test_fail_validator(self):
         fake_input = get_input('point.xsd', 'point.xsd', FORMATS.SHP.mime_type)
         self.assertFalse(validategml(fake_input, MODE.SIMPLE), 'SIMPLE validation invalid')
         fake_input.stream.close()
 
+
 def load_tests(loader=None, tests=None, pattern=None):
     if not loader:
         loader = unittest.TestLoader()



View it on GitLab: https://salsa.debian.org/debian-gis-team/pywps/-/compare/2a76a22620b8cb54f59702a4647e97420f43c4c6...f5a9843cd80ac73b3202ecef7809594d9f3af2b5

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/pywps/-/compare/2a76a22620b8cb54f59702a4647e97420f43c4c6...f5a9843cd80ac73b3202ecef7809594d9f3af2b5
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20211202/e423d599/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list