Hello community,

here is the log from the commit of package python-OWSLib for openSUSE:Factory 
checked in at 2020-12-08 13:24:30
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-OWSLib (Old)
 and      /work/SRC/openSUSE:Factory/.python-OWSLib.new.5913 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-OWSLib"

Tue Dec  8 13:24:30 2020 rev:3 rq:853715 version:0.20.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-OWSLib/python-OWSLib.changes      
2020-03-03 10:20:21.495161562 +0100
+++ /work/SRC/openSUSE:Factory/.python-OWSLib.new.5913/python-OWSLib.changes    
2020-12-08 13:25:49.574747971 +0100
@@ -1,0 +2,11 @@
+Mon Dec  7 09:31:35 UTC 2020 - Bruno Friedmann <[email protected]>
+
+- update to version 0.20.0
+  + Provides initial support for draft OGC API - Records standard. 
+  + WFS: make wfs:FeatureTypeList optional for 1.1 and 2.0 (#673)
+  + OGC API - Records: initial draft implementation (#679, #693)
+  + WPS: add support for retrieving data from local filesystem (huard, #681)
+  + WMTS: add support for boundingboxes (kordian-kowalski, #687)
+  + Authentication: Enable switching off SSL verification (Samweli, #685)
+
+-------------------------------------------------------------------

Old:
----
  OWSLib-0.19.1.tar.gz

New:
----
  OWSLib-0.20.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-OWSLib.spec ++++++
--- /var/tmp/diff_new_pack.IkRrjU/_old  2020-12-08 13:25:50.082749420 +0100
+++ /var/tmp/diff_new_pack.IkRrjU/_new  2020-12-08 13:25:50.086749431 +0100
@@ -22,14 +22,14 @@
 %define         oldpython python
 %define         skip_python2 1
 Name:           python-OWSLib
-Version:        0.19.1
+Version:        0.20.0
 Release:        0
 Summary:        Python interface to OGC Web Services
 License:        BSD-3-Clause
 Group:          Productivity/Scientific/Other
 URL:            http://geopython.github.com/OWSLib/
 Source:         
https://files.pythonhosted.org/packages/source/O/OWSLib/OWSLib-%{version}.tar.gz
-BuildRequires:  %{python_module devel}
+BuildRequires:  %{python_module devel} > 3.6
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros

++++++ OWSLib-0.19.1.tar.gz -> OWSLib-0.20.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/CHANGES.rst 
new/OWSLib-0.20.0/CHANGES.rst
--- old/OWSLib-0.19.1/CHANGES.rst       2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/CHANGES.rst       2020-06-05 14:29:33.000000000 +0200
@@ -1,6 +1,42 @@
 Changes
 =======
 
+0.20.0 (2020-06-05)
+-------------------
+
+This release provides initial support for the draft OGC API - Records
+standard.
+
+A full list of commits for 0.20.0 can be found at:
+
+https://github.com/geopython/OWSLib/commits/0.20.0
+
+- WFS: make wfs:FeatureTypeList optional for 1.1 and 2.0 (#673)
+- OGC API - Records: initial draft implementation (#679, #693)
+- WPS: add support for retrieving data from local filesystem (huard, #681)
+- WMTS: add support for boundingboxes (kordian-kowalski, #687)
+- Authentication: Enable switching off SSL verification (Samweli, #685)
+
+
+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)
 -------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/OWSLib.egg-info/PKG-INFO 
new/OWSLib-0.20.0/OWSLib.egg-info/PKG-INFO
--- old/OWSLib-0.19.1/OWSLib.egg-info/PKG-INFO  2020-01-31 17:18:13.000000000 
+0100
+++ new/OWSLib-0.20.0/OWSLib.egg-info/PKG-INFO  2020-06-05 14:35:06.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: OWSLib
-Version: 0.19.1
+Version: 0.20.0
 Summary: OGC Web Service utility library
 Home-page: https://geopython.github.io/OWSLib
 Author: Sean Gillies
@@ -155,7 +155,7 @@
           make html
           ./publish.sh
           # update on PyPI (must be a maintainer)
-          python setup.py sdist upload
+          python setup.py sdist bdist_wheel --universal upload
         
         Support
         -------
@@ -172,4 +172,4 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Topic :: Scientific/Engineering :: GIS
-Requires-Python: >=3.5
+Requires-Python: >=3.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/OWSLib.egg-info/SOURCES.txt 
new/OWSLib-0.20.0/OWSLib.egg-info/SOURCES.txt
--- old/OWSLib-0.19.1/OWSLib.egg-info/SOURCES.txt       2020-01-31 
17:18:13.000000000 +0100
+++ new/OWSLib-0.20.0/OWSLib.egg-info/SOURCES.txt       2020-06-05 
14:35:06.000000000 +0200
@@ -54,6 +54,7 @@
 owslib/map/wms130.py
 owslib/ogcapi/__init__.py
 owslib/ogcapi/features.py
+owslib/ogcapi/records.py
 owslib/owscontext/__init__.py
 owslib/owscontext/atom.py
 owslib/owscontext/common.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/OWSLib.egg-info/requires.txt 
new/OWSLib-0.20.0/OWSLib.egg-info/requires.txt
--- old/OWSLib-0.19.1/OWSLib.egg-info/requires.txt      2020-01-31 
17:18:13.000000000 +0100
+++ new/OWSLib-0.20.0/OWSLib.egg-info/requires.txt      2020-06-05 
14:35:06.000000000 +0200
@@ -1,4 +1,5 @@
-pyproj
 python-dateutil>=1.5
 pytz
 requests>=1.0
+pyproj>=2
+pyyaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/PKG-INFO new/OWSLib-0.20.0/PKG-INFO
--- old/OWSLib-0.19.1/PKG-INFO  2020-01-31 17:18:13.000000000 +0100
+++ new/OWSLib-0.20.0/PKG-INFO  2020-06-05 14:35:06.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: OWSLib
-Version: 0.19.1
+Version: 0.20.0
 Summary: OGC Web Service utility library
 Home-page: https://geopython.github.io/OWSLib
 Author: Sean Gillies
@@ -155,7 +155,7 @@
           make html
           ./publish.sh
           # update on PyPI (must be a maintainer)
-          python setup.py sdist upload
+          python setup.py sdist bdist_wheel --universal upload
         
         Support
         -------
@@ -172,4 +172,4 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Topic :: Scientific/Engineering :: GIS
-Requires-Python: >=3.5
+Requires-Python: >=3.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/README.rst new/OWSLib-0.20.0/README.rst
--- old/OWSLib-0.19.1/README.rst        2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/README.rst        2020-06-05 14:34:23.000000000 +0200
@@ -145,7 +145,7 @@
   make html
   ./publish.sh
   # update on PyPI (must be a maintainer)
-  python setup.py sdist upload
+  python setup.py sdist bdist_wheel --universal upload
 
 Support
 -------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/VERSION.txt 
new/OWSLib-0.20.0/VERSION.txt
--- old/OWSLib-0.19.1/VERSION.txt       2020-01-31 17:13:16.000000000 +0100
+++ new/OWSLib-0.20.0/VERSION.txt       2020-06-05 14:29:33.000000000 +0200
@@ -1 +1 @@
-0.19.1
+0.20.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/__init__.py 
new/OWSLib-0.20.0/owslib/__init__.py
--- old/OWSLib-0.19.1/owslib/__init__.py        2020-01-31 17:13:09.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/__init__.py        2020-06-05 14:29:33.000000000 
+0200
@@ -1 +1 @@
-__version__ = '0.19.1'
+__version__ = '0.20.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/coverage/wcs100.py 
new/OWSLib-0.20.0/owslib/coverage/wcs100.py
--- old/OWSLib-0.19.1/owslib/coverage/wcs100.py 2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/coverage/wcs100.py 2020-03-29 03:39:03.000000000 
+0200
@@ -18,7 +18,7 @@
 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 @@
             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 @@
         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:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/coverage/wcs200.py 
new/OWSLib-0.20.0/owslib/coverage/wcs200.py
--- old/OWSLib-0.19.1/owslib/coverage/wcs200.py 2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/coverage/wcs200.py 2020-03-29 03:39:03.000000000 
+0200
@@ -113,14 +113,6 @@
             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 @@
         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:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/coverage/wcs201.py 
new/OWSLib-0.20.0/owslib/coverage/wcs201.py
--- old/OWSLib-0.19.1/owslib/coverage/wcs201.py 2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/coverage/wcs201.py 2020-03-29 03:39:03.000000000 
+0200
@@ -113,14 +113,6 @@
             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 @@
         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:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/feature/__init__.py 
new/OWSLib-0.20.0/owslib/feature/__init__.py
--- old/OWSLib-0.19.1/owslib/feature/__init__.py        2020-01-31 
17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/owslib/feature/__init__.py        2020-06-05 
13:05:14.000000000 +0200
@@ -176,7 +176,7 @@
             request["query"] = str(filter)
         if typename:
             typename = (
-                [typename] if type(typename) == type("") else typename
+                [typename] if isinstance(typename, str) else typename
             )  # noqa: E721
             if int(self.version.split(".")[0]) >= 2:
                 request["typenames"] = ",".join(typename)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/feature/common.py 
new/OWSLib-0.20.0/owslib/feature/common.py
--- old/OWSLib-0.19.1/owslib/feature/common.py  2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/feature/common.py  2020-03-29 03:39:03.000000000 
+0200
@@ -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
     """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/feature/schema.py 
new/OWSLib-0.20.0/owslib/feature/schema.py
--- old/OWSLib-0.19.1/owslib/feature/schema.py  2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/feature/schema.py  2020-04-23 13:17:57.000000000 
+0200
@@ -84,7 +84,8 @@
 
     :return dict: schema
     """
-
+    if elements is None:
+        return None
     schema = {"properties": {}, "required": [], "geometry": None}
 
     schema_key = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/feature/wfs100.py 
new/OWSLib-0.20.0/owslib/feature/wfs100.py
--- old/OWSLib-0.19.1/owslib/feature/wfs100.py  2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/feature/wfs100.py  2020-03-29 03:39:03.000000000 
+0200
@@ -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.common import (
     WFSCapabilitiesReader,
     AbstractContentMetadata,
-    makeStringIO,
 )
 
 import pyproj
@@ -308,16 +308,16 @@
                 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 @@
         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 = (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/feature/wfs110.py 
new/OWSLib-0.20.0/owslib/feature/wfs110.py
--- old/OWSLib-0.19.1/owslib/feature/wfs110.py  2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/feature/wfs110.py  2020-04-23 13:17:57.000000000 
+0200
@@ -7,6 +7,7 @@
 # Contact email: [email protected]
 # =============================================================================
 
+from io import BytesIO
 from urllib.parse import urlencode
 from owslib.util import (
     testXMLValue,
@@ -33,7 +34,6 @@
 from owslib.feature.common import (
     WFSCapabilitiesReader,
     AbstractContentMetadata,
-    makeStringIO,
 )
 from owslib.namespaces import Namespaces
 from owslib.util import log, openURL
@@ -186,9 +186,10 @@
         features = self._capabilities.findall(
             nspath_eval("wfs:FeatureTypeList/wfs:FeatureType", namespaces)
         )
-        for feature in features:
-            cm = ContentMetadata(feature, parse_remote_metadata, 
headers=self.headers, auth=self.auth)
-            self.contents[cm.id] = cm
+        if features is not None:
+            for feature in features:
+                cm = ContentMetadata(feature, parse_remote_metadata, 
headers=self.headers, auth=self.auth)
+                self.contents[cm.id] = cm
 
         # exceptions
         self.exceptions = [
@@ -346,16 +347,16 @@
                 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):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/feature/wfs200.py 
new/OWSLib-0.20.0/owslib/feature/wfs200.py
--- old/OWSLib-0.19.1/owslib/feature/wfs200.py  2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/feature/wfs200.py  2020-04-23 13:17:57.000000000 
+0200
@@ -18,11 +18,11 @@
 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
@@ -141,16 +141,17 @@
         featuretypelistelem = self._capabilities.find(
             nspath("FeatureTypeList", ns=WFS_NAMESPACE)
         )
-        featuretypeelems = featuretypelistelem.findall(
-            nspath("FeatureType", ns=WFS_NAMESPACE)
-        )
-        if serviceidentelem is not None:
-            for f in featuretypeelems:
-                kwds = f.findall(nspath("Keywords/Keyword", ns=OWS_NAMESPACE))
-                if kwds is not None:
-                    for kwd in kwds[:]:
-                        if kwd.text not in self.identification.keywords:
-                            self.identification.keywords.append(kwd.text)
+        if featuretypelistelem is not None:
+            featuretypeelems = featuretypelistelem.findall(
+                nspath("FeatureType", ns=WFS_NAMESPACE)
+            )
+            if serviceidentelem is not None:
+                for f in featuretypeelems:
+                    kwds = f.findall(nspath("Keywords/Keyword", 
ns=OWS_NAMESPACE))
+                    if kwds is not None:
+                        for kwd in kwds[:]:
+                            if kwd.text not in self.identification.keywords:
+                                self.identification.keywords.append(kwd.text)
 
         # TODO: update serviceProvider metadata, miss it out for now
         serviceproviderelem = 
self._capabilities.find(nspath("ServiceProvider"))
@@ -313,16 +314,16 @@
                 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(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/fes.py 
new/OWSLib-0.20.0/owslib/fes.py
--- old/OWSLib-0.19.1/owslib/fes.py     2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/owslib/fes.py     2020-04-23 13:17:57.000000000 +0200
@@ -184,6 +184,15 @@
     """ Abstraction for Filter_Capabilities """
     def __init__(self, elem):
         # Spatial_Capabilities
+
+        if elem is None:
+            self.spatial_operands = []
+            self.spatial_operators = []
+            self.temporal_operators = []
+            self.temporal_operands = []
+            self.scalar_comparison_operators = []
+            return
+
         self.spatial_operands = [f.text for f in elem.findall(util.nspath_eval(
             
'ogc:Spatial_Capabilities/ogc:GeometryOperands/ogc:GeometryOperand', 
namespaces))]
         self.spatial_operators = []
@@ -207,6 +216,16 @@
 class FilterCapabilities200(object):
     """Abstraction for Filter_Capabilities 2.0"""
     def __init__(self, elem):
+
+        if elem is None:
+            self.spatial_operands = []
+            self.spatial_operators = []
+            self.temporal_operators = []
+            self.temporal_operands = []
+            self.scalar_comparison_operators = []
+            self.conformance = []
+            return
+
         # Spatial_Capabilities
         self.spatial_operands = [f.attrib.get('name') for f in 
elem.findall(util.nspath_eval(
             
'fes:Spatial_Capabilities/fes:GeometryOperands/fes:GeometryOperand', 
namespaces))]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/ogcapi/__init__.py 
new/OWSLib-0.20.0/owslib/ogcapi/__init__.py
--- old/OWSLib-0.19.1/owslib/ogcapi/__init__.py 2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/ogcapi/__init__.py 2020-06-05 13:39:21.000000000 
+0200
@@ -8,11 +8,13 @@
 
 import json
 import logging
-
 from urllib.parse import urljoin
 
+import requests
+import yaml
+
 from owslib import __version__
-from owslib.util import http_get
+from owslib.util import Authentication, http_get
 
 LOGGER = logging.getLogger(__name__)
 
@@ -22,14 +24,15 @@
 
 
 class API(object):
-    """Abstraction for OGC API Common version 1.0"""
+    """Abstraction for OGC API - Common version 1.0"""
 
-    def __init__(self, url, json_=None, timeout=30, headers=None, auth=None):
+    def __init__(self, url: str, json_: str = None, timeout: int = 30,
+                 headers: dict = None, auth: Authentication = None):
         """
         Initializer; implements /
 
         @type url: string
-        @param url: url of WFS root document
+        @param url: url of OGC API landing page document
         @type json_: string
         @param json_: json object
         @param headers: HTTP headers to send with requests
@@ -51,7 +54,7 @@
         self.timeout = timeout
         self.headers = REQUEST_HEADERS
         if headers:
-            self.headers = self.headers.update(headers)
+            self.headers.update(headers)
         self.auth = auth
 
         if json_ is not None:  # static JSON string
@@ -60,7 +63,7 @@
             response = http_get(url, headers=self.headers, 
auth=self.auth).json()
             self.links = response['links']
 
-    def api(self):
+    def api(self) -> dict:
         """
         implements /api
 
@@ -68,47 +71,59 @@
         """
 
         url = None
+        openapi_format = None
 
-        for l in self.links:
-            if l['rel'] == 'service-desc':
-                url = l['href']
+        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 link in self.links:
+            if link['rel'] == 'service-desc' and link['type'] == 
openapi_json_mimetype:
+                openapi_format = openapi_json_mimetype
+                url = link['href']
+                break
+
+            LOGGER.debug('Searching for OpenAPI YAML Document')
+            if url is None:
+                if link['rel'] == 'service-desc' and link['type'] == 
openapi_yaml_mimetype:
+                    openapi_format = openapi_yaml_mimetype
+                    url = link['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)
             raise RuntimeError(msg)
 
-    def conformance(self):
+    def conformance(self) -> dict:
         """
         implements /conformance
 
         @returns: `dict` of conformance object
         """
 
-        url = self._build_url('conformance')
-        LOGGER.debug('Request: {}'.format(url))
-        response = http_get(url, headers=self.headers, auth=self.auth).json()
+        path = 'conformance'
+        return self._request(path)
 
-        return response
-
-    def collections(self):
+    def collections(self) -> dict:
         """
         implements /collections
 
         @returns: `dict` of collections object
         """
 
-        url = self._build_url('collections')
-        LOGGER.debug('Request: {}'.format(url))
-        response = http_get(url, headers=self.headers, auth=self.auth).json()
-
-        return response['collections']
+        path = 'collections'
+        return self._request(path)
 
-    def collection(self, collection_id):
+    def collection(self, collection_id) -> dict:
         """
         implements /collections/{collectionId}
 
@@ -119,18 +134,27 @@
         """
 
         path = 'collections/{}'.format(collection_id)
-        url = self._build_url(path)
-        LOGGER.debug('Request: {}'.format(url))
-        response = http_get(url, headers=self.headers, auth=self.auth).json()
+        return self._request(path)
+
+    def collection_queryables(self, collection_id) -> dict:
+        """
+        implements /collections/{collectionId}/queryables
+
+        @type collection_id: string
+        @param collection_id: id of collection
 
-        return response
+        @returns: `dict` of feature collection queryables
+        """
+
+        path = 'collections/{}/queryables'.format(collection_id)
+        return self._request(path)
 
-    def _build_url(self, path=None):
+    def _build_url(self, path=None) -> str:
         """
         helper function to build an OGC API URL
 
         @type path: string
-        @param path: path of WFS URL
+        @param path: path of OGC API URL
 
         @returns: fully constructed URL path
         """
@@ -146,3 +170,26 @@
         LOGGER.debug('URL: {}'.format(url))
 
         return url
+
+    def _request(self, path=None, kwargs={}) -> dict:
+        """
+        helper function for request/response patterns against OGC API endpoints
+
+        @type path: string
+        @param path: path of request
+        @type kwargs: string
+        @param kwargs: ``dict`` of keyword value pair request parameters
+
+        @returns: response as JSON ``dict``
+        """
+
+        url = self._build_url(path)
+
+        LOGGER.debug('Request: {}'.format(url))
+
+        response = http_get(url, headers=self.headers, auth=self.auth,
+                            params=kwargs)
+        if response.status_code != requests.codes.ok:
+            raise RuntimeError(response.text)
+
+        return response.json()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/ogcapi/features.py 
new/OWSLib-0.20.0/owslib/ogcapi/features.py
--- old/OWSLib-0.19.1/owslib/ogcapi/features.py 2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/ogcapi/features.py 2020-06-05 13:39:21.000000000 
+0200
@@ -6,13 +6,10 @@
 # Contact email: [email protected]
 # =============================================================================
 
-import json
 import logging
 
-from urllib.parse import urljoin
-
-from owslib.ogcapi import API, REQUEST_HEADERS
-from owslib.util import http_get
+from owslib.ogcapi import API
+from owslib.util import Authentication
 
 LOGGER = logging.getLogger(__name__)
 
@@ -20,11 +17,12 @@
 class Features(API):
     """Abstraction for OGC API - Features"""
 
-    def __init__(self, url, json_=None, timeout=30, headers=None, auth=None):
+    def __init__(self, url: str, json_: str = None, timeout: int = 30,
+                 headers: dict = None, auth: Authentication = None):
         __doc__ = API.__doc__  # noqa
         super().__init__(url, json_, timeout, headers, auth)
 
-    def collection_items(self, collection_id, **kwargs):
+    def collection_items(self, collection_id: str, **kwargs: dict) -> dict:
         """
         implements /collection/{collectionId}/items
 
@@ -38,6 +36,8 @@
         @param limit: limit number of features
         @type startindex: int
         @param startindex: start position of results
+        @type q: string
+        @param q: full text search
 
         @returns: feature results
         """
@@ -46,14 +46,9 @@
             kwargs['bbox'] = ','.join(kwargs['bbox'])
 
         path = 'collections/{}/items'.format(collection_id)
-        url = self._build_url(path)
-        LOGGER.debug('Request: {}'.format(url))
-        response = http_get(
-            url, headers=self.headers, params=kwargs, auth=self.auth
-        ).json()
-        return response
+        return self._request(path, kwargs)
 
-    def collection_item(self, collection_id, identifier):
+    def collection_item(self, collection_id: str, identifier: str) -> dict:
         """
         implements /collections/{collectionId}/items/{featureId}
 
@@ -66,7 +61,4 @@
         """
 
         path = 'collections/{}/items/{}'.format(collection_id, identifier)
-        url = self._build_url(path)
-        LOGGER.debug('Request: {}'.format(url))
-        response = http_get(url, headers=self.headers, auth=self.auth).json()
-        return response
+        return self._request(path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/ogcapi/records.py 
new/OWSLib-0.20.0/owslib/ogcapi/records.py
--- old/OWSLib-0.19.1/owslib/ogcapi/records.py  1970-01-01 01:00:00.000000000 
+0100
+++ new/OWSLib-0.20.0/owslib/ogcapi/records.py  2020-06-05 13:39:21.000000000 
+0200
@@ -0,0 +1,23 @@
+# =============================================================================
+# Copyright (c) 2020 Tom Kralidis
+#
+# Author: Tom Kralidis <[email protected]>
+#
+# Contact email: [email protected]
+# =============================================================================
+
+import logging
+
+from owslib.ogcapi.features import Features
+from owslib.util import Authentication
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Records(Features):
+    """Abstraction for OGC API - Records"""
+
+    def __init__(self, url: str, json_: str = None, timeout: int = 30,
+                 headers: dict = None, auth: Authentication = None):
+        __doc__ = Features.__doc__  # noqa
+        super().__init__(url, json_, timeout, headers, auth)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/ows.py 
new/OWSLib-0.20.0/owslib/ows.py
--- old/OWSLib-0.19.1/owslib/ows.py     2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/owslib/ows.py     2020-04-23 13:17:57.000000000 +0200
@@ -239,7 +239,10 @@
         self.miny = None
         self.maxx = None
         self.maxy = None
-
+        self.crs = None
+        self.dimensions = 2
+        if elem is None:
+            return
         val = elem.attrib.get('crs') or 
elem.attrib.get('{{{}}}crs'.format(namespace))
         if val:
             try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/util.py 
new/OWSLib-0.20.0/owslib/util.py
--- old/OWSLib-0.19.1/owslib/util.py    2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/owslib/util.py    2020-05-21 03:02:42.000000000 +0200
@@ -170,14 +170,13 @@
             auth.password = password
         if cert:
             auth.cert = cert
-        if verify and not auth.verify:
-            auth.verify = verify
+        verify = verify and auth.verify
     else:
         auth = Authentication(username, password, cert, verify)
     if auth.username and auth.password:
         rkwargs['auth'] = (auth.username, auth.password)
     rkwargs['cert'] = auth.cert
-    rkwargs['verify'] = auth.verify
+    rkwargs['verify'] = verify
 
     # FIXUP for WFS in particular, remove xml style namespace
     # @TODO does this belong here?
@@ -786,22 +785,43 @@
     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
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/wmts.py 
new/OWSLib-0.20.0/owslib/wmts.py
--- old/OWSLib-0.19.1/owslib/wmts.py    2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/owslib/wmts.py    2020-06-05 13:05:14.000000000 +0200
@@ -48,6 +48,7 @@
 # Version 1.0.0, document 07-057r7
 
 _ABSTRACT_TAG = _OWS_NS + 'Abstract'
+_BOUNDING_BOX_TAG = _OWS_NS + 'BoundingBox'
 _IDENTIFIER_TAG = _OWS_NS + 'Identifier'
 _LOWER_CORNER_TAG = _OWS_NS + 'LowerCorner'
 _OPERATIONS_METADATA_TAG = _OWS_NS + 'OperationsMetadata'
@@ -639,7 +640,7 @@
                         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))
@@ -659,6 +660,31 @@
         return fmt.format(self=self)
 
 
+class BoundingBox(object):
+    """
+    Represents a BoundingBox element
+    """
+
+    def __init__(self, elem) -> None:
+        if elem.tag != _BOUNDING_BOX_TAG:
+            raise ValueError('%s should be a BoundingBox' % elem)
+
+        lc = elem.find(_LOWER_CORNER_TAG)
+        uc = elem.find(_UPPER_CORNER_TAG)
+
+        self.ll = [float(s) for s in lc.text.split()]
+        self.ur = [float(s) for s in uc.text.split()]
+
+        self.crs = elem.attrib.get('crs')
+        self.extent = (self.ll[0], self.ll[1], self.ur[0], self.ur[1])
+
+    def __repr__(self):
+        fmt = ('<BoundingBox'
+               ', crs={self.crs}'
+               ', extent={self.extent}>')
+        return fmt.format(self=self)
+
+
 class ContentMetadata:
     """
     Abstraction for WMTS layer metadata.
@@ -684,9 +710,16 @@
 
         self.abstract = testXMLValue(elem.find(_ABSTRACT_TAG))
 
-        # bboxes
+        # Bounding boxes
+        # There may be multiple, using different CRSes
+        self.boundingBox = []
+
+        bbs = elem.findall(_BOUNDING_BOX_TAG)
+        for b in bbs:
+            self.boundingBox.append(BoundingBox(b))
+
+        # WGS84 Bounding box
         b = elem.find(_WGS84_BOUNDING_BOX_TAG)
-        self.boundingBox = None
         if b is not None:
             lc = b.find(_LOWER_CORNER_TAG)
             uc = b.find(_UPPER_CORNER_TAG)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/owslib/wps.py 
new/OWSLib-0.20.0/owslib/wps.py
--- old/OWSLib-0.19.1/owslib/wps.py     2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/owslib/wps.py     2020-05-20 17:00:56.000000000 +0200
@@ -84,7 +84,7 @@
 * python wps-pml-script-2.py
 
 The file wps-client.py contains a command-line client that can be used to 
submit a "GetCapabilities",
-"DescribeProcess" or "Execute" request to an arbitratry WPS server. For 
example, you can run it as follows:
+"DescribeProcess" or "Execute" request to an arbitrary WPS server. For 
example, you can run it as follows:
 
 * cd examples
 * To prints out usage and example invocations: wps-client -help
@@ -224,7 +224,7 @@
     """
 
     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 @@
         self.verbose = verbose
         self.headers = headers
         self.timeout = timeout
+        self.language = language
 
         # fields populated by method invocations
         self._capabilities = None
@@ -248,6 +249,7 @@
         self.provider = None
         self.operations = []
         self.processes = []
+        self.languages = None
 
         if not skip_caps:
             self.getcapabilities()
@@ -260,7 +262,11 @@
 
         # 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 @@
 
         # 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 @@
             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 @@
         # 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,28 +459,46 @@
                     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):
         """
         Method to get and parse a WPS document, returning an elementtree 
instance.
         :param str url: WPS service base url.
-        :param str data: GET: dictionary of HTTP (key, value) parameter pairs, 
POST: XML document to post
+        :param {} data: GET: dictionary of HTTP (key, value) parameter pairs, 
POST: XML document to post
         """
         _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 @@
     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 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 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 @@
     """
 
     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 @@
         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 @@
         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 @@
         :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:
@@ -819,46 +851,52 @@
     def isNotComplete(self):
         return not self.isComplete()
 
-    def getOutput(self, filepath=None):
+    def getOutput(self, filepath=None, identifier=None):
         """
         Method to write the outputs of a WPS process to a file:
         either retrieves the referenced files from the server, or writes out 
the content of response embedded output.
 
         :param filepath: optional path to the output file, otherwise a file 
will be created in the local directory with
                   the name assigned by the server, or default name 'wps.out' 
for embedded output.
+        :param: identifier: optional identifier of the output that should be 
written.
+                  For backward compatibility it will default to the first 
output.
         """
 
         if self.isSucceded():
             content = b''
-            for output in self.processOutputs:
-
-                output_content = output.retrieveData(
-                    self.auth.username, self.auth.password,
-                    headers=self.headers, verify=self.auth.verify, 
cert=self.auth.cert)
-
+            output = None
+            if self.processOutputs:
+                if identifier:
+                    # filter outputs by identifier
+                    outputs = [o for o in self.processOutputs if o.identifier 
== identifier]
+                    if outputs:
+                        output = outputs[0]
+                else:
+                    # take the first found output
+                    output = self.processOutputs[0]
+            if output:
                 # ExecuteResponse contains reference to server-side output
-                if output_content != b'':
-                    content = content + output_content
+                if output.reference:
+                    content = output.retrieveData(
+                        self.auth.username, self.auth.password,
+                        headers=self.headers, verify=self.auth.verify, 
cert=self.auth.cert)
                     if filepath is None:
                         filepath = output.fileName
-
                 # ExecuteResponse contain embedded output
-                if len(output.data) > 0:
+                elif len(output.data) > 0:
                     if filepath is None:
                         filepath = 'wps.out'
                     for data in output.data:
                         content = content + data.encode()
-
             # write out content
-            if content != '':
+            if content != b'':
                 out = open(filepath, 'wb')
                 out.write(content)
                 out.close()
-                log.info('Output written to file: %s' % filepath)
-
+                log.info(f'Output written to file: {filepath}')
         else:
             raise Exception(
-                "Execution not successfully completed: status=%s" % 
self.status)
+                f"Execution not successfully completed: status={self.status}")
 
     def submitRequest(self, request):
         """
@@ -1385,19 +1423,28 @@
         # a) 
'http://cida.usgs.gov/climate/gdp/process/RetrieveResultServlet?id=1318528582026OUTPUT.601bb3d0-547f-4eab-8642-7c7d2834459e'
  # noqa
         # b) 'http://rsg.pml.ac.uk/wps/wpsoutputs/outputImage-11294Bd6l2a.tif'
         log.info('Output URL=%s' % url)
+
+        # Extract output filepath from base URL
+        self.fileName = url.split('/')[-1]
+
+        # The link is a local file.
+        # Useful when running local tests during development.
+        if url.startswith("file://"):
+            with open(url[7:]) as f:
+                return f.read()
+
         if '?' in url:
             spliturl = url.split('?')
+            # Extract output filepath from URL query string
+            self.fileName = spliturl[1].split('=')[1]
+
             u = openURL(spliturl[0], spliturl[
                         1], method='Get', username=username, password=password,
                         headers=headers, verify=verify, cert=cert)
-            # extract output filepath from URL query string
-            self.fileName = spliturl[1].split('=')[1]
         else:
             u = openURL(
                 url, '', method='Get', username=username, password=password,
                 headers=headers, verify=verify, cert=cert)
-            # extract output filepath from base URL
-            self.fileName = url.split('/')[-1]
 
         return u.read()
 
@@ -1407,7 +1454,7 @@
         Method to write an output of a WPS process to disk:
         it either retrieves the referenced file from the server, or write out 
the content of response embedded output.
 
-        :param filepath: optional path to the output file, otherwise a file 
will be created in the local directory
+        :param path: optional path to the output file, otherwise a file will 
be created in the local directory
                   with the name assigned by the server,
         :param username: credentials to access the remote WPS server
         :param password: credentials to access the remote WPS server
@@ -1914,3 +1961,21 @@
               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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/requirements-dev.txt 
new/OWSLib-0.20.0/requirements-dev.txt
--- old/OWSLib-0.19.1/requirements-dev.txt      2020-01-31 17:12:37.000000000 
+0100
+++ new/OWSLib-0.20.0/requirements-dev.txt      2020-06-05 14:34:55.000000000 
+0200
@@ -3,8 +3,7 @@
 pytest>=3.6
 pytest-cov
 Pillow
+sphinx
 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'
+twine
+wheel
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/requirements.txt 
new/OWSLib-0.20.0/requirements.txt
--- old/OWSLib-0.19.1/requirements.txt  2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/requirements.txt  2020-03-29 03:39:03.000000000 +0200
@@ -1,4 +1,5 @@
 python-dateutil>=1.5
 pytz
 requests>=1.0
-pyproj
+pyproj >=2
+pyyaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OWSLib-0.19.1/setup.py new/OWSLib-0.20.0/setup.py
--- old/OWSLib-0.19.1/setup.py  2020-01-31 17:12:37.000000000 +0100
+++ new/OWSLib-0.20.0/setup.py  2020-03-29 03:39:03.000000000 +0200
@@ -28,7 +28,7 @@
       maintainer_email  = '[email protected]',
       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       = [
_______________________________________________
openSUSE Commits mailing list -- [email protected]
To unsubscribe, email [email protected]
List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette
List Archives: 
https://lists.opensuse.org/archives/list/[email protected]

Reply via email to