[Git][debian-gis-team/owslib][upstream] New upstream version 0.19.2

Bas Couwenberg gitlab at salsa.debian.org
Fri Mar 13 06:03:21 GMT 2020



Bas Couwenberg pushed to branch upstream at Debian GIS Project / owslib


Commits:
515bfbc1 by Bas Couwenberg at 2020-03-13T06:50:11+01:00
New upstream version 0.19.2
- - - - -


27 changed files:

- .travis.yml
- CHANGES.rst
- VERSION.txt
- docs/en/index.rst
- owslib/__init__.py
- owslib/coverage/wcs100.py
- owslib/coverage/wcs200.py
- owslib/coverage/wcs201.py
- owslib/feature/common.py
- owslib/feature/wfs100.py
- owslib/feature/wfs110.py
- owslib/feature/wfs200.py
- owslib/ogcapi/__init__.py
- owslib/util.py
- owslib/wmts.py
- owslib/wps.py
- requirements-dev.txt
- requirements.txt
- setup.py
- tests/doctests/wfs_MapServerWFSFeature.txt
- − tests/doctests/wmts_RESTonly.txt
- tests/test_ogcapi_features_ldproxy.py
- tests/test_wms_getfeatureinfo_130.py
- + tests/test_wmts_restonly.py
- + tests/test_wps_describeprocess_language.py
- + tests/test_wps_execute_language.py
- + tests/test_wps_getcapabilities_language.py


Changes:

=====================================
.travis.yml
=====================================
@@ -1,6 +1,5 @@
 language: python
 python:
-  - "3.5"
   - "3.6"
   - "3.7"
   - "3.8"


=====================================
CHANGES.rst
=====================================
@@ -1,6 +1,25 @@
 Changes
 =======
 
+0.19.2 (2020-03-13)
+-------------------
+
+This release is an update.
+It drops Python 3.5 support and adds language support to the WPS module.
+
+A full list of commits for 0.19.2 can be found at:
+
+https://github.com/geopython/OWSLib/commits/0.19.2
+
+- Dropped Python 3.5 support (#659).
+- Fix pyproj deprecation (only use pyproj>=2) (#661).
+- WPS: Added support for multiple languages (#654, #655).
+- OGC API: fix api media type handling (#653).
+- WMTS: fix cartopy examples (#656).
+- Tests: fix wms tests (#657).
+- WCS: added WCS code example do documentation (#658).
+- WCS: fix params list (#663).
+
 0.19.1 (2020-01-29)
 -------------------
 


=====================================
VERSION.txt
=====================================
@@ -1 +1 @@
-0.19.1
+0.19.2


=====================================
docs/en/index.rst
=====================================
@@ -36,7 +36,7 @@ Standards Support
 +-----------------------+-----------------------------+
 | `OGC WFS`_            | 1.0.0, 1.1.0, 2.0.0, 3.0    |
 +-----------------------+-----------------------------+
-| `OGC WCS`_            | 1.0.0, 1.1.0                |
+| `OGC WCS`_            | 1.0.0, 1.1.0, 2.0, 2.0.1    |
 +-----------------------+-----------------------------+
 | `OGC WMC`_            | 1.1.0                       |
 +-----------------------+-----------------------------+
@@ -253,7 +253,7 @@ compatible with a `Fiona schema object <https://fiona.readthedocs.io/en/latest/f
 
 ::
 
-    >>> wfs11.get_schema('bvv:vg_ex')
+    >>> wfs11.get_schema('bvv:vg_ex')
     >>> {'properties': {'land': 'string', 'modellart': 'string', 'objart': 'string', 'objart_txt': 'string', 'objid': 'string', 'hdu_x': 'short', 'beginn': 'string', 'ende': 'string', 'adm': 'string', 'avg': 'string', 'bez_gem': 'string', 'bez_krs': 'string', 'bez_lan': 'string', 'bez_rbz': 'string', 'sch': 'string'}, 'geometry': '3D MultiPolygon', 'geometry_column': 'geom'}
 
 Download GML using ``typename`` and ``filter``. OWSLib currently only
@@ -300,7 +300,7 @@ services)
 OGC API - Features 1.0
 ----------------------
 
-The OGC API - Features standar is a clean break from the traditional OGC service architecture
+The OGC API - Features standard is a clean break from the traditional OGC service architecture
 (RESTful, JSON, OpenAPI) and as such OWSLib the code follows the same pattern.
 
 .. code-block:: python
@@ -329,6 +329,48 @@ The OGC API - Features standar is a clean break from the traditional OGC service
 WCS
 ---
 
+.. code-block:: python
+
+  >>> # Import OWSLib in Python once installed
+  ... from owslib.wcs import WebCoverageService
+
+  >>> # Create coverage object
+  ... my_wcs = WebCoverageService('http://ows.rasdaman.org/rasdaman/ows',
+  ...                             version='2.0.1')
+
+  >>> # Get list of coverages
+  ... print my_wcs.contents.keys()
+  ['RadianceColor', 'test_irr_cube_2', 'test_mean_summer_airtemp', 'test_double_1d', 'INSPIRE_EL', 'AverageChlorophyllScaled', 'INSPIRE_OI_RGB', 'Temperature4D', 'INSPIRE_OI_IR', 'visible_human', 'INSPIRE_WS_LC', 'meris_lai', 'climate_earth', 'mean_summer_airtemp', 'multiband', 'ls8_coastal_aerosol', 'NN3_3', 'NN3_2', 'NN3_1', 'NN3_4', 'AvgTemperatureColorScaled', 'AverageChloroColorScaled', 'lena', 'Germany_DTM', 'climate_cloud', 'FiLCCoverageBit', 'AverageChloroColor', 'LandsatMultiBand', 'RadianceColorScaled', 'AvgLandTemp', 'NIR', 'BlueMarbleCov']
+
+  >>> # Get geo-bounding boxes and native CRS
+  ... my_wcs.contents['AverageChlorophyllScaled'].boundingboxes
+  [{'nativeSrs': 'http://ows.rasdaman.org/def/crs-compound?1=http://ows.rasdaman.org/def/crs/EPSG/0/4326&2=http://ows.rasdaman.org/def/crs/OGC/0/UnixTime', 'bbox': (-90.0, -180.0, 90.0, 180.0)}]
+
+  >>> # Get axis labels
+  ... my_wcs.contents['AverageChlorophyllScaled'].grid.axislabels
+  ['Lat', 'Long', 'unix']
+
+  >>> # Get dimension
+  ... my_wcs.contents['AverageChlorophyllScaled'].grid.dimension
+  3
+
+  >>> # Get grid lower and upper bounds
+  ... my_wcs.contents['AverageChlorophyllScaled'].grid.lowlimits
+  ['0', '0', '0']
+
+  >>> my_wcs.contents['AverageChlorophyllScaled'].grid.highlimits
+  ['119', '239', '5']
+
+  >>> # Get offset vectors for geo axes
+  ... my_wcs.contents['AverageChlorophyllScaled'].grid.offsetvectors
+  [['-1.5', '0', '0'], ['0', '1.5', '0'], ['0', '0', '1']]
+  
+  >>> # For coverage with time axis get the date time values
+  ... my_wcs.contents['AverageChlorophyllScaled'].timepositions
+  [datetime.datetime(2015, 1, 1, 0, 0), datetime.datetime(2015, 2, 1, 0, 0), datetime.datetime(2015, 3, 1, 0, 0), datetime.datetime(2015, 4, 1, 0, 0), datetime.datetime(2015, 5, 1, 0, 0), datetime.datetime(2015, 7, 1, 0, 0)]
+
+
+
 CSW
 ---
 


=====================================
owslib/__init__.py
=====================================
@@ -1 +1 @@
-__version__ = '0.19.1'
+__version__ = '0.19.2'


=====================================
owslib/coverage/wcs100.py
=====================================
@@ -18,7 +18,7 @@ import os
 import errno
 
 import logging
-from owslib.util import log
+from owslib.util import log, makeString
 
 
 #  function to save writing out WCS namespace in full each time
@@ -94,14 +94,6 @@ class WebCoverageService_1_0_0(WCSBase):
             items.append((item, self.contents[item]))
         return items
 
-    def __makeString(self, value):
-        # using repr unconditionally breaks things in some circumstances if a value is already a string
-        if type(value) is not str:
-            sval = repr(value)
-        else:
-            sval = value
-        return sval
-
     def getCoverage(self, identifier=None, bbox=None, time=None, format=None, crs=None, width=None, height=None,
                     resx=None, resy=None, resz=None, parameter=None, method='Get', **kwargs):
         """Request and return a coverage from the WCS as a file-like object
@@ -134,7 +126,7 @@ class WebCoverageService_1_0_0(WCSBase):
         request['Coverage'] = identifier
         # request['identifier'] = ','.join(identifier)
         if bbox:
-            request['BBox'] = ','.join([self.__makeString(x) for x in bbox])
+            request['BBox'] = ','.join([makeString(x) for x in bbox])
         else:
             request['BBox'] = None
         if time:


=====================================
owslib/coverage/wcs200.py
=====================================
@@ -113,14 +113,6 @@ class WebCoverageService_2_0_0(WCSBase):
             items.append((item, self.contents[item]))
         return items
 
-    def __makeString(self, value):
-        # using repr unconditionally breaks things in some circumstances if a value is already a string
-        if type(value) is not str:
-            sval = repr(value)
-        else:
-            sval = value
-        return sval
-
     def getCoverage(
         self,
         identifier=None,
@@ -224,16 +216,6 @@ class WebCoverageService_2_0_0(WCSBase):
         u = openURL(base_url, data, method, self.cookies, auth=self.auth)
         return u
 
-    def is_number(self, s):
-        """simple helper to test if value is number as requests with numbers dont
-        need quote marks
-        """
-        try:
-            float(s)
-            return True
-        except ValueError:
-            return False
-
     def getOperationByName(self, name):
         """Return a named operation item."""
         for item in self.operations:


=====================================
owslib/coverage/wcs201.py
=====================================
@@ -113,14 +113,6 @@ class WebCoverageService_2_0_1(WCSBase):
             items.append((item, self.contents[item]))
         return items
 
-    def __makeString(self, value):
-        # using repr unconditionally breaks things in some circumstances if a value is already a string
-        if type(value) is not str:
-            sval = repr(value)
-        else:
-            sval = value
-        return sval
-
     def getCoverage(
         self,
         identifier=None,
@@ -225,16 +217,6 @@ class WebCoverageService_2_0_1(WCSBase):
         u = openURL(base_url, data, method, self.cookies, auth=self.auth)
         return u
 
-    def is_number(self, s):
-        """simple helper to test if value is number as requests with numbers dont
-        need quote marks
-        """
-        try:
-            float(s)
-            return True
-        except ValueError:
-            return False
-
     def getOperationByName(self, name):
         """Return a named operation item."""
         for item in self.operations:


=====================================
owslib/feature/common.py
=====================================
@@ -1,21 +1,9 @@
-from io import StringIO
 from owslib.etree import etree
 from owslib.util import Authentication, openURL
 
 from urllib.parse import urlencode, parse_qsl
 
 
-def makeStringIO(strval):
-    """
-    Helper method to make sure the StringIO being returned will work.
-
-    Differences between Python 2.7/3.x mean we have a lot of cases to handle.
-
-    TODO: skipped Python 2.x support. Is this still necessary?
-    """
-    return StringIO(strval.decode())
-
-
 class WFSCapabilitiesReader(object):
     """Read and parse capabilities document into a lxml.etree infoset
     """


=====================================
owslib/feature/wfs100.py
=====================================
@@ -8,6 +8,7 @@
 
 from owslib import util
 
+from io import BytesIO
 from urllib.parse import urlencode
 from owslib.util import (
     testXMLValue,
@@ -27,7 +28,6 @@ from owslib.feature.schema import get_schema
 from owslib.feature.common import (
     WFSCapabilitiesReader,
     AbstractContentMetadata,
-    makeStringIO,
 )
 
 import pyproj
@@ -308,16 +308,16 @@ class WebFeatureService_1_0_0(object):
                 tree = etree.fromstring(data)
             except BaseException:
                 # Not XML
-                return makeStringIO(data)
+                return BytesIO(data)
             else:
                 if tree.tag == "{%s}ServiceExceptionReport" % OGC_NAMESPACE:
                     se = tree.find(nspath("ServiceException", OGC_NAMESPACE))
                     raise ServiceException(str(se.text).strip())
                 else:
-                    return makeStringIO(data)
+                    return BytesIO(data)
         else:
             if have_read:
-                return makeStringIO(data)
+                return BytesIO(data)
             return u
 
     def getOperationByName(self, name):
@@ -395,14 +395,16 @@ class ContentMetadata(AbstractContentMetadata):
         self.boundingBoxWGS84 = None
 
         if b is not None and srs is not None:
-            wgs84 = pyproj.Proj(init="epsg:4326")
+            wgs84 = pyproj.Proj("epsg:4326")
             try:
-                src_srs = pyproj.Proj(init=srs.text)
+                src_srs = pyproj.Proj(srs.text)
                 mincorner = pyproj.transform(
-                    src_srs, wgs84, b.attrib["minx"], b.attrib["miny"]
+                    src_srs, wgs84, b.attrib["minx"], b.attrib["miny"],
+                    always_xy=True,
                 )
                 maxcorner = pyproj.transform(
-                    src_srs, wgs84, b.attrib["maxx"], b.attrib["maxy"]
+                    src_srs, wgs84, b.attrib["maxx"], b.attrib["maxy"],
+                    always_xy=True,
                 )
 
                 self.boundingBoxWGS84 = (


=====================================
owslib/feature/wfs110.py
=====================================
@@ -7,6 +7,7 @@
 # Contact email: tomkralidis at gmail.com
 # =============================================================================
 
+from io import BytesIO
 from urllib.parse import urlencode
 from owslib.util import (
     testXMLValue,
@@ -33,7 +34,6 @@ from owslib.feature import WebFeatureService_
 from owslib.feature.common import (
     WFSCapabilitiesReader,
     AbstractContentMetadata,
-    makeStringIO,
 )
 from owslib.namespaces import Namespaces
 from owslib.util import log, openURL
@@ -346,16 +346,16 @@ class WebFeatureService_1_1_0(WebFeatureService_):
                 tree = etree.fromstring(data)
             except BaseException:
                 # Not XML
-                return makeStringIO(data)
+                return BytesIO(data)
             else:
                 if tree.tag == "{%s}ServiceExceptionReport" % namespaces["ogc"]:
                     se = tree.find(nspath_eval("ServiceException", namespaces["ogc"]))
                     raise ServiceException(str(se.text).strip())
                 else:
-                    return makeStringIO(data)
+                    return BytesIO(data)
         else:
             if have_read:
-                return makeStringIO(data)
+                return BytesIO(data)
             return u
 
     def getOperationByName(self, name):


=====================================
owslib/feature/wfs200.py
=====================================
@@ -18,11 +18,11 @@ from owslib.feature import WebFeatureService_
 from owslib.feature.common import (
     WFSCapabilitiesReader,
     AbstractContentMetadata,
-    makeStringIO,
 )
 from owslib.namespaces import Namespaces
 
 # other imports
+from io import BytesIO
 from urllib.parse import urlencode
 
 import logging
@@ -313,16 +313,16 @@ class WebFeatureService_2_0_0(WebFeatureService_):
                 tree = etree.fromstring(data)
             except BaseException:
                 # Not XML
-                return makeStringIO(data)
+                return BytesIO(data)
             else:
                 if tree.tag == "{%s}ServiceExceptionReport" % OGC_NAMESPACE:
                     se = tree.find(nspath("ServiceException", OGC_NAMESPACE))
                     raise ServiceException(str(se.text).strip())
                 else:
-                    return makeStringIO(data)
+                    return BytesIO(data)
         else:
             if have_read:
-                return makeStringIO(data)
+                return BytesIO(data)
             return u
 
     def getpropertyvalue(


=====================================
owslib/ogcapi/__init__.py
=====================================
@@ -8,9 +8,10 @@
 
 import json
 import logging
-
 from urllib.parse import urljoin
 
+import yaml
+
 from owslib import __version__
 from owslib.util import http_get
 
@@ -68,15 +69,33 @@ class API(object):
         """
 
         url = None
+        openapi_format = None
 
+        openapi_json_mimetype = 'application/vnd.oai.openapi+json;version=3.0'
+        openapi_yaml_mimetype = 'application/vnd.oai.openapi;version=3.0'
+
+        LOGGER.debug('Searching for OpenAPI JSON Document')
         for l in self.links:
-            if l['rel'] == 'service-desc':
+            if l['rel'] == 'service-desc' and l['type'] == openapi_json_mimetype:
+                openapi_format = openapi_json_mimetype
                 url = l['href']
+                break
+
+            LOGGER.debug('Searching for OpenAPI YAML Document')
+            if url is None:
+                if l['rel'] == 'service-desc' and l['type'] == openapi_yaml_mimetype:
+                    openapi_format = openapi_yaml_mimetype
+                    url = l['href']
+                    break
 
         if url is not None:
             LOGGER.debug('Request: {}'.format(url))
-            response = http_get(url, headers=REQUEST_HEADERS, auth=self.auth).json()
-            return response
+            response = http_get(url, headers=REQUEST_HEADERS, auth=self.auth)
+            if openapi_format == openapi_json_mimetype:
+                content = response.json()
+            elif openapi_format == openapi_yaml_mimetype:
+                content = yaml.load(response.text)
+            return content
         else:
             msg = 'Did not find service-desc link'
             LOGGER.error(msg)


=====================================
owslib/util.py
=====================================
@@ -786,22 +786,43 @@ def datetime_from_ansi(ansi):
     return datumOrigin + timedelta(ansi)
 
 
-def param_list_to_url_string(self, param_list, param_name):
-    """Converts list of tuples for certain WCS GetCoverage keyword arguments (subsets, resolutions, sizes) to a url-enconded
-    string
+def is_number(s):
+    """simple helper to test if value is number as requests with numbers don't
+    need quote marks
+    """
+    try:
+        float(s)
+        return True
+    except ValueError:
+        return False
+
+
+def makeString(value):
+    # using repr unconditionally breaks things in some circumstances if a
+    # value is already a string
+    if type(value) is not str:
+        sval = repr(value)
+    else:
+        sval = value
+    return sval
+
+
+def param_list_to_url_string(param_list, param_name):
+    """Converts list of tuples for certain WCS GetCoverage keyword arguments
+    (subsets, resolutions, sizes) to a url-encoded string
     """
     string = ''
     for param in param_list:
         if len(param) > 2:
-            if not self.is_number(param[1]):
-                string += "&" + urlencode({param_name: param[0] + '("' + self.__makeString(param[1]) + '","' + self.__makeString(param[2]) + '")'})  # noqa
+            if not is_number(param[1]):
+                string += "&" + urlencode({param_name: param[0] + '("' + makeString(param[1]) + '","' + makeString(param[2]) + '")'})  # noqa
             else:
-                string += "&" + urlencode({param_name: param[0] + "(" + self.__makeString(param[1]) + "," + self.__makeString(param[2]) + ")"})  # noqa
+                string += "&" + urlencode({param_name: param[0] + "(" + makeString(param[1]) + "," + makeString(param[2]) + ")"})  # noqa
         else:
-            if not self.is_number(param[1]):
-                string += "&" + urlencode({param_name: param[0] + '("' + self.__makeString(param[1]) + '")'})
+            if not is_number(param[1]):
+                string += "&" + urlencode({param_name: param[0] + '("' + makeString(param[1]) + '")'})  # noqa
             else:
-                string += "&" + urlencode({param_name: param[0] + "(" + self.__makeString(param[1]) + ")"})
+                string += "&" + urlencode({param_name: param[0] + "(" + makeString(param[1]) + ")"})  # noqa
     return string
 
 


=====================================
owslib/wmts.py
=====================================
@@ -639,7 +639,7 @@ class TileMatrixSetLink(object):
                         if tml.tilematrix in tilematrixlimits:
                             msg = ('TileMatrixLimits with tileMatrix "%s" '
                                    'already exists' % tml.tilematrix)
-                            raise KeyError(msg)
+                            warnings.warn(msg, RuntimeWarning)
                         tilematrixlimits[tml.tilematrix] = tml
 
                 links.append(TileMatrixSetLink(uri, tilematrixlimits))


=====================================
owslib/wps.py
=====================================
@@ -224,7 +224,7 @@ class WebProcessingService(object):
     """
 
     def __init__(self, url, version=WPS_DEFAULT_VERSION, username=None, password=None, verbose=False, skip_caps=False,
-                 headers=None, verify=None, cert=None, timeout=None, auth=None):
+                 headers=None, verify=None, cert=None, timeout=None, auth=None, language=None):
         """
         Initialization method resets the object status.
         By default it will execute a GetCapabilities invocation to the remote service,
@@ -241,6 +241,7 @@ class WebProcessingService(object):
         self.verbose = verbose
         self.headers = headers
         self.timeout = timeout
+        self.language = language
 
         # fields populated by method invocations
         self._capabilities = None
@@ -248,6 +249,7 @@ class WebProcessingService(object):
         self.provider = None
         self.operations = []
         self.processes = []
+        self.languages = None
 
         if not skip_caps:
             self.getcapabilities()
@@ -260,7 +262,11 @@ class WebProcessingService(object):
 
         # read capabilities document
         reader = WPSCapabilitiesReader(
-            version=self.version, verbose=self.verbose, auth=self.auth)
+            version=self.version,
+            verbose=self.verbose,
+            auth=self.auth,
+            language=self.language,
+        )
         if xml:
             # read from stored XML file
             self._capabilities = reader.readFromString(xml)
@@ -283,7 +289,11 @@ class WebProcessingService(object):
 
         # read capabilities document
         reader = WPSDescribeProcessReader(
-            version=self.version, verbose=self.verbose, auth=self.auth)
+            version=self.version,
+            verbose=self.verbose,
+            auth=self.auth,
+            language=self.language,
+        )
         if xml:
             # read from stored XML file
             rootElement = reader.readFromString(xml)
@@ -333,7 +343,8 @@ class WebProcessingService(object):
             verbose=self.verbose,
             headers=self.headers,
             timeout=self.timeout,
-            auth=self.auth
+            auth=self.auth,
+            language=self.language,
         )
 
         # build XML request from parameters
@@ -401,7 +412,7 @@ class WebProcessingService(object):
         # loop over children WITHOUT requiring a specific namespace
         for element in root:
 
-            # thie element's namespace
+            # this element's namespace
             ns = getNamespace(element)
 
             # <ows:ServiceIdentification> metadata
@@ -448,17 +459,33 @@ class WebProcessingService(object):
                     if self.verbose is True:
                         dump(self.processes[-1])
 
+            # <wps:Languages>
+            #   <wps:Default>
+            #     <ows:Language>en-US</ows:Language>
+            #   </wps:Default>
+            #   <wps:Supported>
+            #     <ows:Language>en-US</ows:Language>
+            #     <ows:Language>fr-CA</ows:Language>
+            #     ......
+            #   </wps:Supported>
+            # </wps:Languages>
+            elif element.tag.endswith('Languages'):
+                self.languages = Languages(element)
+                if self.verbose:
+                    dump(self.languages)
+
 
 class WPSReader(object):
     """
     Superclass for reading a WPS document into a lxml.etree infoset.
     """
 
-    def __init__(self, version=WPS_DEFAULT_VERSION, verbose=False, timeout=30, auth=None):
+    def __init__(self, version=WPS_DEFAULT_VERSION, verbose=False, timeout=30, auth=None, language=None):
         self.version = version
         self.verbose = verbose
         self.timeout = timeout
         self.auth = auth or Authentication()
+        self.language = language
 
     def _readFromUrl(self, url, data, timeout, method='Get', username=None, password=None,
                      headers=None, verify=True, cert=None):
@@ -470,6 +497,8 @@ class WPSReader(object):
         _fix_auth(self.auth, username, password, verify, cert)
         if method == 'Get':
             # full HTTP request url
+            if self.language:
+                data["language"] = self.language
             request_url = build_get_url(url, data, overwrite=True)
             log.debug(request_url)
 
@@ -506,10 +535,10 @@ class WPSCapabilitiesReader(WPSReader):
     Utility class that reads and parses a WPS GetCapabilities document into a lxml.etree infoset.
     """
 
-    def __init__(self, version=WPS_DEFAULT_VERSION, verbose=False, timeout=None, auth=None):
+    def __init__(self, version=WPS_DEFAULT_VERSION, verbose=False, timeout=None, auth=None, language=None):
         # superclass initializer
         super(WPSCapabilitiesReader, self).__init__(
-            version=version, verbose=verbose, timeout=timeout, auth=auth)
+            version=version, verbose=verbose, timeout=timeout, auth=auth, language=language)
 
     def readFromUrl(self, url, username=None, password=None,
                     headers=None, verify=None, cert=None):
@@ -532,10 +561,10 @@ class WPSDescribeProcessReader(WPSReader):
     Class that reads and parses a WPS DescribeProcess document into a etree infoset
     """
 
-    def __init__(self, version=WPS_DEFAULT_VERSION, verbose=False, timeout=None, auth=None):
+    def __init__(self, version=WPS_DEFAULT_VERSION, verbose=False, timeout=None, auth=None, language=None):
         # superclass initializer
         super(WPSDescribeProcessReader, self).__init__(
-            version=version, verbose=verbose, timeout=timeout, auth=auth)
+            version=version, verbose=verbose, timeout=timeout, auth=auth, language=language)
 
     def readFromUrl(self, url, identifier, username=None, password=None,
                     headers=None, verify=None, cert=None):
@@ -559,9 +588,9 @@ class WPSExecuteReader(WPSReader):
     Class that reads and parses a WPS Execute response document into a etree infoset
     """
 
-    def __init__(self, verbose=False, timeout=None, auth=None):
+    def __init__(self, verbose=False, timeout=None, auth=None, language=None):
         # superclass initializer
-        super(WPSExecuteReader, self).__init__(verbose=verbose, timeout=timeout, auth=auth)
+        super(WPSExecuteReader, self).__init__(verbose=verbose, timeout=timeout, auth=auth, language=language)
 
     def readFromUrl(self, url, data={}, method='Get', username=None, password=None,
                     headers=None, verify=None, cert=None):
@@ -581,7 +610,7 @@ class WPSExecution(object):
     """
 
     def __init__(self, version=WPS_DEFAULT_VERSION, url=None, username=None, password=None, verbose=False,
-                 headers=None, verify=None, cert=None, timeout=None, auth=None):
+                 headers=None, verify=None, cert=None, timeout=None, auth=None, language=None):
 
         # initialize fields
         self.url = url
@@ -591,6 +620,7 @@ class WPSExecution(object):
         self.auth = auth or Authentication()
         _fix_auth(self.auth, username, password, verify, cert)
         self.timeout = timeout
+        self.language = language
 
         # request document
         self.request = None
@@ -648,6 +678,8 @@ class WPSExecution(object):
         root = etree.Element(nspath_eval('wps:Execute', namespaces))
         root.set('service', 'WPS')
         root.set('version', WPS_DEFAULT_VERSION)
+        if self.language:
+            root.set('language', self.language)
         root.set(nspath_eval('xsi:schemaLocation', namespaces), '%s %s' %
                  (namespaces['wps'], WPS_DEFAULT_SCHEMA_LOCATION))
 
@@ -765,7 +797,7 @@ class WPSExecution(object):
         :param int sleepSecs: number of seconds to sleep before returning control to the caller.
         """
 
-        reader = WPSExecuteReader(verbose=self.verbose, auth=self.auth)
+        reader = WPSExecuteReader(verbose=self.verbose, auth=self.auth, language=self.language)
         if response is None:
             # override status location
             if url is not None:
@@ -1914,3 +1946,21 @@ def printInputOutput(value, indent=''):
               indent, value.reference, value.mimeType)))
         for datum in value.data:
             print(('{} Data Value: {}'.format(indent, printValue(datum))))
+
+
+class Languages(object):
+    """Initialize a WPS Languages construct"""
+    def __init__(self, infoset):
+        self._root = infoset
+        self.default = None
+        self.supported = []
+
+        for element in self._root:
+            if element.tag.endswith('Default'):
+                self.default = testXMLValue(element[0])
+            elif element.tag.endswith('Supported'):
+                for child in element:
+                    self.supported.append(testXMLValue(child))
+
+    def __repr__(self):
+        return "<owslib.wps.Languages default='{}' supported={}>".format(self.default, self.supported)


=====================================
requirements-dev.txt
=====================================
@@ -4,7 +4,3 @@ pytest>=3.6
 pytest-cov
 Pillow
 tox
-# install libraries to stop SSL related InsecurePlatformWarning
-pyopenssl        ; python_version < '2.7.9'
-ndg-httpsclient  ; python_version < '2.7.9'
-pyasn1           ; python_version < '2.7.9'


=====================================
requirements.txt
=====================================
@@ -1,4 +1,5 @@
 python-dateutil>=1.5
 pytz
 requests>=1.0
-pyproj
+pyproj >=2
+pyyaml


=====================================
setup.py
=====================================
@@ -28,7 +28,7 @@ setup(name              = 'OWSLib',
       maintainer_email  = 'tomkralidis at gmail.com',
       url               = 'https://geopython.github.io/OWSLib',
       install_requires  = reqs,
-      python_requires   = '>=3.5',
+      python_requires   = '>=3.6',
       cmdclass          = {'test': PyTest},
       packages          = find_packages(exclude=["docs", "etc", "examples", "tests"]),
       classifiers       = [


=====================================
tests/doctests/wfs_MapServerWFSFeature.txt
=====================================
@@ -7,7 +7,7 @@ Test the getfeature method
 
     >>> wfs = WebFeatureService('http://nsidc.org/cgi-bin/atlas_south?', version='1.0.0')
     >>> response = wfs.getfeature(typename=['glaciers'], maxfeatures=5)
-    >>> response.read().find('<wfs:FeatureCollection') > 0
+    >>> response.read().find(b'<wfs:FeatureCollection') > 0
     True
 
 Handle service exception


=====================================
tests/doctests/wmts_RESTonly.txt deleted
=====================================
@@ -1,33 +0,0 @@
-Imports:
-
-    >>> from tests.utils import scratch_file
-
-ServiceMetadata:
-
-    >>> from owslib.wmts import WebMapTileService
-    >>> wmts = WebMapTileService("http://geoserv.weichand.de/mapproxy/wmts/1.0.0/WMTSCapabilities.xml")
-    >>> wmts.identification.type
-    'OGC WMTS'
-    >>> wmts.identification.version
-    '1.0.0'
-    >>> wmts.identification.title
-    'WMTS-Testserver DOP80'
-
-Content:
-
-    >>> sorted(list(wmts.contents))
-    ['dop80']
-
-RESTful WMTS:
-
-  >>> wmts.restonly
-  True
-
-  >>> wmts.buildTileResource(layer='dop80', tilematrixset='webmercator', tilematrix='11', row='706', column='1089')
-  'http://geoserv.weichand.de/mapproxy/wmts/dop80/webmercator/11/1089/706.png'
-
-  >>> tile = wmts.gettile(layer='dop80', tilematrixset='webmercator', tilematrix='11', row='706', column='1089')
-  >>> out = open(scratch_file('bvv_bayern_dop80.png'), 'wb')
-  >>> bytes_written = out.write(tile.read())
-  >>> out.close()
-


=====================================
tests/test_ogcapi_features_ldproxy.py
=====================================
@@ -8,7 +8,6 @@ SERVICE_URL = 'https://www.ldproxy.nrw.de/rest/services/kataster/?f=json'
 
 
 @pytest.mark.online
- at pytest.mark.skip(reason='api() call fails. See issue #625')
 @pytest.mark.skipif(not service_ok(SERVICE_URL),
                     reason='service is unreachable')
 def test_ogcapi_features_ldproxy():
@@ -20,6 +19,8 @@ def test_ogcapi_features_ldproxy():
     conformance = w.conformance()
     assert len(conformance['conformsTo']) == 5
 
-    api = w.api()
-    assert api['components']['parameters'] is not None
-    assert api['paths'] is not None
+    # TODO: remove pytest.raises once ldproxy is fixed/updated
+    with pytest.raises(RuntimeError):
+        api = w.api()
+        assert api['components']['parameters'] is not None
+        assert api['paths'] is not None


=====================================
tests/test_wms_getfeatureinfo_130.py
=====================================
@@ -18,7 +18,6 @@ def test_wms_getfeatureinfo_130():
         info_format="text/html", xy=(250, 250))
     html_string1 = res1.read().decode("utf-8")
     assert 'lkr_ex' in html_string1
-    assert 'gmd_ex' in html_string1
 
     res2 = wms.getfeatureinfo(
         layers=['bvv:lkr_ex', 'bvv:gmd_ex'], srs='EPSG:31468',


=====================================
tests/test_wmts_restonly.py
=====================================
@@ -0,0 +1,32 @@
+from tests.utils import scratch_file
+from tests.utils import service_ok
+
+from owslib.wmts import WebMapTileService
+
+import pytest
+
+SERVICE_URL = "http://geoserv.weichand.de/mapproxy/wmts/1.0.0/WMTSCapabilities.xml"
+
+
+ at pytest.mark.online
+ at pytest.mark.skipif(not service_ok(SERVICE_URL),
+                    reason="WMTS service is unreachable")
+def test_wmts_rest_only():
+    # ServiceMetadata
+    wmts = WebMapTileService(SERVICE_URL)
+    assert wmts.identification.type == 'OGC WMTS'
+    assert wmts.identification.version == '1.0.0'
+    assert wmts.identification.title == 'WMTS-Testserver DOP80'
+    # Content
+    assert sorted(list(wmts.contents)) == ['dop80']
+    # RESTful WMTS
+    assert wmts.restonly
+    resource = wmts.buildTileResource(
+        layer='dop80', tilematrixset='webmercator', tilematrix='11', row='706', column='1089')
+    assert resource == 'http://geoserv.weichand.de/mapproxy/wmts/dop80/webmercator/11/1089/706.png'
+
+    tile = wmts.gettile(
+        layer='dop80', tilematrixset='webmercator', tilematrix='11', row='706', column='1089')
+    out = open(scratch_file('bvv_bayern_dop80.png'), 'wb')
+    bytes_written = out.write(tile.read())
+    out.close()


=====================================
tests/test_wps_describeprocess_language.py
=====================================
@@ -0,0 +1,18 @@
+from owslib.wps import WebProcessingService
+import owslib.wps
+
+
+def test_wps_describeprocess_language(monkeypatch):
+
+    def mock_open_url(*args, **kwargs):
+        assert 'language=fr-CA' in args[1]
+
+        class FakeResponse:
+            def read(self):
+                return b'<xml></xml>'
+
+        return FakeResponse()
+
+    monkeypatch.setattr(owslib.wps, "openURL", mock_open_url)
+    wps = WebProcessingService('http://www.example.com', language='fr-CA', skip_caps=True)
+    wps.describeprocess('all')


=====================================
tests/test_wps_execute_language.py
=====================================
@@ -0,0 +1,31 @@
+from owslib.wps import WebProcessingService
+import owslib.wps
+
+
+def test_wps_execute_language(monkeypatch):
+
+    def raise_on_log_error(*a):
+        """Make sure the errors are raised, not only caught and logged"""
+        raise AssertionError
+
+    monkeypatch.setattr(owslib.wps.log, "error", raise_on_log_error)
+
+    monkeypatch.setattr(owslib.wps.WPSExecution, "parseResponse", lambda *a: None)
+    wps = WebProcessingService('http://www.example.com', language='fr-CA', skip_caps=True)
+    execution = wps.execute('test', [], response=b'<xml></xml>')
+
+    assert b'language="fr-CA"' in execution.request
+
+    def mock_open_url(*args, **kwargs):
+        assert 'language=fr-CA' in args[1]
+
+        class FakeResponse:
+            def read(self):
+                return b'<xml></xml>'
+
+        return FakeResponse()
+
+    monkeypatch.setattr(owslib.wps, "openURL", mock_open_url)
+
+    execution.status = 'ProcessSucceeded'
+    execution.checkStatus(url='http://www.example.com', response=None, sleepSecs=0)


=====================================
tests/test_wps_getcapabilities_language.py
=====================================
@@ -0,0 +1,36 @@
+from owslib.wps import WebProcessingService
+import owslib.wps
+from owslib.etree import etree
+
+
+def test_wps_getcapabilities_language(monkeypatch):
+
+    def mock_open_url(*args, **kwargs):
+        assert 'language=fr-CA' in args[1]
+
+        class FakeResponse:
+            def read(self):
+                return b'<xml></xml>'
+
+        return FakeResponse()
+
+    monkeypatch.setattr(owslib.wps, "openURL", mock_open_url)
+    WebProcessingService('http://www.example.com', language='fr-CA')
+
+
+def test_wps_getcapabilities_parse_languages():
+    xml = """
+    <wps:Languages xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows">
+        <wps:Default>
+            <ows:Language>en-US</ows:Language>
+        </wps:Default>
+        <wps:Supported>
+            <ows:Language>en-US</ows:Language>
+            <ows:Language>fr-CA</ows:Language>
+        </wps:Supported>
+    </wps:Languages>
+    """
+    element = etree.fromstring(xml)
+    languages = owslib.wps.Languages(element)
+    assert languages.default == 'en-US'
+    assert languages.supported == ['en-US', 'fr-CA']



View it on GitLab: https://salsa.debian.org/debian-gis-team/owslib/-/commit/515bfbc1a8f63a0f763c0c6cb2b6d1d896701a96

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/owslib/-/commit/515bfbc1a8f63a0f763c0c6cb2b6d1d896701a96
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/20200313/8d63b016/attachment-0001.html>


More information about the Pkg-grass-devel mailing list