[owslib] 09/11: Imported Upstream version 0.9.2

Johan Van de Wauw johanvdw-guest at moszumanska.debian.org
Thu Sep 24 20:32:12 UTC 2015


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

johanvdw-guest pushed a commit to branch master
in repository owslib.

commit 8519ddcc26c6072d5d10de5f1c6d1022381a60c8
Author: Johan Van de Wauw <johan at vandewauw.be>
Date:   Thu Sep 24 22:26:42 2015 +0200

    Imported Upstream version 0.9.2
---
 VERSION.txt                                  |   2 +-
 examples/wms-getfeatureinfo.py               |  33 +++++++
 owslib/__init__.py                           |   2 +-
 owslib/util.py                               |  19 +++-
 owslib/wms.py                                | 141 +++++++++++++++++++++------
 owslib/wmts.py                               |  71 +++++++++++++-
 tests/doctests/wms_GeoServerCapabilities.txt |  20 ++++
 tests/doctests/wms_getfeatureinfo.txt        |  24 +++++
 tests/doctests/wmts_RESTonly.txt             |  34 +++++++
 tests/doctests/wmts_geoserver21.txt          |   2 +
 tests/resources/wms_geoserver-cap.xml        |  24 +++--
 11 files changed, 325 insertions(+), 47 deletions(-)

diff --git a/VERSION.txt b/VERSION.txt
index f374f66..2003b63 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-0.9.1
+0.9.2
diff --git a/examples/wms-getfeatureinfo.py b/examples/wms-getfeatureinfo.py
new file mode 100644
index 0000000..51ed5e0
--- /dev/null
+++ b/examples/wms-getfeatureinfo.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+# -*- coding: UTF-8 -*-
+__author__ = 'Juergen Weichand'
+
+from owslib.wms import WebMapService
+wms = WebMapService('http://geoserv.weichand.de:8080/geoserver/wms')
+
+# GetMap (image/jpeg)
+response = wms.getmap(
+    layers=['bvv:gmd_ex'],
+    srs='EPSG:31468',
+    bbox=(4500000,5500000,4505000,5505000),
+    size=(500,500),
+    format='image/jpeg')
+
+out = open('/tmp/getmap-response.jpeg', 'wb')
+out.write(response.read())
+out.close()
+
+# GetFeatureInfo (text/html)
+response = wms.getfeatureinfo(
+    layers=['bvv:gmd_ex'],
+    srs='EPSG:31468',
+    bbox=(4500000,5500000,4505000,5505000),
+    size=(500,500),
+    format='image/jpeg',
+    query_layers=['bvv:gmd_ex'],
+    info_format="text/html",
+    xy=(250,250))
+
+out = open('/tmp/getfeatureinfo-response.html', 'wb')
+out.write(response.read())
+out.close()
\ No newline at end of file
diff --git a/owslib/__init__.py b/owslib/__init__.py
index e063736..c57c469 100644
--- a/owslib/__init__.py
+++ b/owslib/__init__.py
@@ -1,3 +1,3 @@
 from __future__ import (absolute_import, division, print_function)
 
-__version__ = '0.9.1'
+__version__ = '0.9.2'
diff --git a/owslib/util.py b/owslib/util.py
index 1be88a4..22bcaa7 100644
--- a/owslib/util.py
+++ b/owslib/util.py
@@ -147,7 +147,7 @@ def openURL(url_base, data=None, method='Get', cookies=None, username=None, pass
     Uses requests library but with additional checks for OGC service exceptions and url formatting.
     Also handles cookies and simple user password authentication.
     """
-    headers = {}
+    headers = None
     rkwargs = {}
 
     rkwargs['timeout'] = timeout
@@ -165,7 +165,7 @@ def openURL(url_base, data=None, method='Get', cookies=None, username=None, pass
     if method.lower() == 'post':
         try:
             xml = etree.fromstring(data)
-            headers['Content-Type'] = "text/xml"
+            headers = {'Content-Type': 'text/xml'}
         except (ParseError, UnicodeEncodeError):
             pass
 
@@ -173,6 +173,7 @@ def openURL(url_base, data=None, method='Get', cookies=None, username=None, pass
 
     elif method.lower() == 'get':
         rkwargs['params'] = data
+        
     else:
         raise ValueError("Unknown method ('%s'), expected 'get' or 'post'" % method)
 
@@ -181,6 +182,7 @@ def openURL(url_base, data=None, method='Get', cookies=None, username=None, pass
 
     req = requests.request(method.upper(),
                            url_base,
+                           headers=headers,
                            **rkwargs)
 
     if req.status_code in [400, 401]:
@@ -581,3 +583,16 @@ except:  # 2.6
     from ordereddict import OrderedDict
 
 
+def which_etree():
+    """decipher which etree library is being used by OWSLib"""
+
+    which_etree = None
+
+    if 'lxml' in etree.__file__:
+        which_etree = 'lxml.etree'
+    elif 'xml/etree' in etree.__file__:
+        which_etree = 'xml.etree'
+    elif 'elementree' in etree.__file__:
+        which_etree = 'elementtree.ElementTree'
+    
+    return which_etree
diff --git a/owslib/wms.py b/owslib/wms.py
index 88cd147..372a112 100644
--- a/owslib/wms.py
+++ b/owslib/wms.py
@@ -123,13 +123,16 @@ class WebMapService(object):
         #recursively gather content metadata for all layer elements.
         #To the WebMapService.contents store only metadata of named layers.
         def gather_layers(parent_elem, parent_metadata):
+            layers = []
             for index, elem in enumerate(parent_elem.findall('Layer')):
                 cm = ContentMetadata(elem, parent=parent_metadata, index=index+1, parse_remote_metadata=parse_remote_metadata)
                 if cm.id:
                     if cm.id in self.contents:
                         warnings.warn('Content metadata for layer "%s" already exists. Using child layer' % cm.id)
+                    layers.append(cm)
                     self.contents[cm.id] = cm
-                gather_layers(elem, cm)
+                cm.children = gather_layers(elem, cm)
+            return layers
         gather_layers(caps, None)
         
         #exceptions
@@ -160,6 +163,41 @@ class WebMapService(object):
             raise ServiceException(err_message, se_xml)
         return u
 
+    def __build_getmap_request(self, layers=None, styles=None, srs=None, bbox=None,
+               format=None, size=None, time=None, transparent=False,
+               bgcolor=None, exceptions=None, **kwargs):
+
+        request = {'version': self.version, 'request': 'GetMap'}
+
+        # check layers and styles
+        assert len(layers) > 0
+        request['layers'] = ','.join(layers)
+        if styles:
+            assert len(styles) == len(layers)
+            request['styles'] = ','.join(styles)
+        else:
+            request['styles'] = ''
+
+        # size
+        request['width'] = str(size[0])
+        request['height'] = str(size[1])
+
+        request['srs'] = str(srs)
+        request['bbox'] = ','.join([repr(x) for x in bbox])
+        request['format'] = str(format)
+        request['transparent'] = str(transparent).upper()
+        request['bgcolor'] = '0x' + bgcolor[1:7]
+        request['exceptions'] = str(exceptions)
+
+        if time is not None:
+            request['time'] = str(time)
+
+        if kwargs:
+            for kw in kwargs:
+                request[kw]=kwargs[kw]
+
+        return request
+
     def getmap(self, layers=None, styles=None, srs=None, bbox=None,
                format=None, size=None, time=None, transparent=False,
                bgcolor='#FFFFFF',
@@ -213,37 +251,59 @@ class WebMapService(object):
             base_url = next((m.get('url') for m in self.getOperationByName('GetMap').methods if m.get('type').lower() == method.lower()))
         except StopIteration:
             base_url = self.url
-        request = {'version': self.version, 'request': 'GetMap'}
-        
-        # check layers and styles
-        assert len(layers) > 0
-        request['layers'] = ','.join(layers)
-        if styles:
-            assert len(styles) == len(layers)
-            request['styles'] = ','.join(styles)
-        else:
-            request['styles'] = ''
 
-        # size
-        request['width'] = str(size[0])
-        request['height'] = str(size[1])
+        request = self.__build_getmap_request(layers=layers, styles=styles, srs=srs, bbox=bbox,
+               format=format, size=size, time=time, transparent=transparent,
+               bgcolor=bgcolor, exceptions=exceptions, kwargs=kwargs)
         
-        request['srs'] = str(srs)
-        request['bbox'] = ','.join([repr(x) for x in bbox])
-        request['format'] = str(format)
-        request['transparent'] = str(transparent).upper()
-        request['bgcolor'] = '0x' + bgcolor[1:7]
-        request['exceptions'] = str(exceptions)
-        
-        if time is not None:
-            request['time'] = str(time)
+        data = urlencode(request)
         
-        if kwargs:
-            for kw in kwargs:
-                request[kw]=kwargs[kw]
+        u = openURL(base_url, data, method, username=self.username, password=self.password, timeout=timeout or self.timeout)
+
+        # check for service exceptions, and return
+        if u.info()['Content-Type'] == 'application/vnd.ogc.se_xml':
+            se_xml = u.read()
+            se_tree = etree.fromstring(se_xml)
+            err_message = six.text_type(se_tree.find('ServiceException').text).strip()
+            raise ServiceException(err_message, se_xml)
+        return u
+
+
+    def getfeatureinfo(self, layers=None, styles=None, srs=None, bbox=None,
+               format=None, size=None, time=None, transparent=False,
+               bgcolor='#FFFFFF',
+               exceptions='application/vnd.ogc.se_xml',
+               query_layers = None, xy=None, info_format=None, feature_count=20,
+               method='Get',
+               timeout=None,
+               **kwargs
+               ):
+        try:
+            base_url = next((m.get('url') for m in self.getOperationByName('GetFeatureInfo').methods if m.get('type').lower() == method.lower()))
+        except StopIteration:
+            base_url = self.url
+
+        # GetMap-Request
+        request = self.__build_getmap_request(layers=layers, styles=styles, srs=srs, bbox=bbox,
+               format=format, size=size, time=time, transparent=transparent,
+               bgcolor=bgcolor, exceptions=exceptions, kwargs=kwargs)
+
+        # extend to GetFeatureInfo-Request
+        request['request'] = 'GetFeatureInfo'
+
+        if not query_layers:
+            __str_query_layers = ','.join(layers)
+        else:
+            __str_query_layers = ','.join(query_layers)
+
+        request['query_layers'] = __str_query_layers
+        request['x'] = str(xy[0])
+        request['y'] = str(xy[1])
+        request['info_format'] = info_format
+        request['feature_count'] = str(feature_count)
 
         data = urlencode(request)
-        
+
         u = openURL(base_url, data, method, username=self.username, password=self.password, timeout=timeout or self.timeout)
 
         # check for service exceptions, and return
@@ -253,16 +313,13 @@ class WebMapService(object):
             err_message = six.text_type(se_tree.find('ServiceException').text).strip()
             raise ServiceException(err_message, se_xml)
         return u
-        
+
     def getServiceXML(self):
         xml = None
         if self._capabilities is not None:
             xml = etree.tostring(self._capabilities)
         return xml
 
-    def getfeatureinfo(self):
-        raise NotImplementedError
-
     def getOperationByName(self, name): 
         """Return a named content item."""
         for item in self.operations:
@@ -322,7 +379,7 @@ class ContentMetadata:
 
     Implements IContentMetadata.
     """
-    def __init__(self, elem, parent=None, index=0, parse_remote_metadata=False, timeout=30):
+    def __init__(self, elem, parent=None, children=None, index=0, parse_remote_metadata=False, timeout=30):
         if elem.tag != 'Layer':
             raise ValueError('%s should be a Layer' % (elem,))
         
@@ -331,6 +388,8 @@ class ContentMetadata:
             self.index = "%s.%d" % (parent.index, index)
         else:
             self.index = str(index)
+
+        self._children = children
         
         self.id = self.name = testXMLValue(elem.find('Name'))
 
@@ -510,6 +569,24 @@ class ContentMetadata:
         for child in elem.findall('Layer'):
             self.layers.append(ContentMetadata(child, self))
 
+    @property
+    def children(self):
+        return self._children
+
+    @children.setter
+    def children(self, value):
+        if self._children is None:
+            self._children = value
+        else:
+            self._children.extend(value)
+        # If layer is a group and one of its children is queryable, the layer must be queryable.
+        if self._children and self.queryable == 0:
+            for child in self._children:
+                if child.queryable:
+                    self.queryable = child.queryable
+                    break
+
+
     def __str__(self):
         return 'Layer Name: %s Title: %s' % (self.name, self.title)
 
diff --git a/owslib/wmts.py b/owslib/wmts.py
index f915f6f..ec522f4 100644
--- a/owslib/wmts.py
+++ b/owslib/wmts.py
@@ -31,6 +31,7 @@ would be appreciated.
 
 from __future__ import (absolute_import, division, print_function)
 
+from random import randint
 import warnings
 import six
 from six.moves import filter
@@ -199,8 +200,11 @@ class WebMapTileService(object):
 
         # serviceOperations metadata
         self.operations = []
-        for elem in self._capabilities.find(_OPERATIONS_METADATA_TAG)[:]:
-            self.operations.append(OperationsMetadata(elem))
+        serviceop = self._capabilities.find(_OPERATIONS_METADATA_TAG)
+        #  REST only WMTS does not have any Operations
+        if serviceop is not None:
+            for elem in serviceop[:]:
+                self.operations.append(OperationsMetadata(elem))
 
         # serviceContents metadata: our assumption is that services use
         # a top-level layer as a metadata organizer, nothing more.
@@ -293,7 +297,6 @@ LAYER=VIIRS_CityLights_2012&STYLE=default&TILEMATRIXSET=EPSG4326_500m&\
 TILEMATRIX=6&TILEROW=4&TILECOL=4&FORMAT=image%2Fjpeg'
 
         """
-        request = {'version': self.version, 'request': 'GetTile'}
 
         if (layer is None):
             raise ValueError("layer is mandatory (cannot be None)")
@@ -329,6 +332,58 @@ TILEMATRIX=6&TILEROW=4&TILECOL=4&FORMAT=image%2Fjpeg'
         data = urlencode(request, True)
         return data
 
+    def buildTileResource(self, layer=None, style=None, format=None,
+                          tilematrixset=None, tilematrix=None, row=None,
+                          column=None, **kwargs):
+
+        tileresourceurls = []
+        for resourceURL in self[layer].resourceURLs:
+            if resourceURL['resourceType'] == 'tile':
+                tileresourceurls.append(resourceURL)
+        numres = len(tileresourceurls)
+        if numres > 0:
+            # choose random ResourceURL if more than one available
+            resindex = randint(0, numres - 1)
+            resurl = tileresourceurls[resindex]['template']
+            if tilematrixset:
+                resurl = resurl.replace('{TileMatrixSet}', tilematrixset)
+            resurl = resurl.replace('{TileMatrix}', tilematrix)
+            resurl = resurl.replace('{TileRow}', row)
+            resurl = resurl.replace('{TileCol}', column)
+            if style:
+                resurl = resurl.replace('{Style}', style)
+            return resurl
+
+        return None
+
+    @property
+    def restonly(self):
+
+        # if OperationsMetadata is missing completely --> use REST
+        if len(self.operations) == 0:
+            return True
+
+        # check if KVP or RESTful are available
+        restenc = False
+        kvpenc = False
+        for operation in self.operations:
+            if operation.name == 'GetTile':
+                for method in operation.methods:
+                    if 'kvp' in str(method['constraints']).lower():
+                        kvpenc = True
+                    if 'rest' in str(method['constraints']).lower():
+                        restenc = True
+
+        # if KVP is available --> use KVP
+        if kvpenc:
+            return False
+
+        # if the operation has no constraint --> use KVP
+        if not kvpenc and not restenc:
+            return False
+
+        return restenc
+
     def gettile(self, base_url=None, layer=None, style=None, format=None,
                 tilematrixset=None, tilematrix=None, row=None, column=None,
                 **kwargs):
@@ -379,6 +434,16 @@ TILEMATRIX=6&TILEROW=4&TILECOL=4&FORMAT=image%2Fjpeg'
         """
         vendor_kwargs = self.vendor_kwargs or {}
         vendor_kwargs.update(kwargs)
+
+        # REST only WMTS
+        if self.restonly:
+            resurl = self.buildTileResource(
+                layer, style, format, tilematrixset, tilematrix,
+                row, column, **vendor_kwargs)
+            u = openURL(resurl, username=self.username, password=self.password)
+            return u
+
+        # KVP implemetation
         data = self.buildTileRequest(layer, style, format, tilematrixset,
                                      tilematrix, row, column, **vendor_kwargs)
 
diff --git a/tests/doctests/wms_GeoServerCapabilities.txt b/tests/doctests/wms_GeoServerCapabilities.txt
index c8f31ef..ef7eb55 100644
--- a/tests/doctests/wms_GeoServerCapabilities.txt
+++ b/tests/doctests/wms_GeoServerCapabilities.txt
@@ -62,7 +62,27 @@ Test single item accessor
     >>> x = wms['opengeo:poi'].styles
     >>> x == {'point': {'legend': 'http://localhost:8080/geoserver/wms?request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=poi', 'title': 'A boring default style'}}
     True
+
+Test nested layer
+
+    >>> wms['parent_layer'].title
+    'Parent Layer'
+    
+    >>> wms['parent_layer'].queryable
+    1
+    
+    >>> len(wms['parent_layer'].children)
+    1
     
+    >>> wms['parent_layer'].children[0].title
+    'Child Layer'
+    
+    >>> len(wms['child_layer'].children)
+    0
+    
+    >>> wms['child_layer'].parent.title
+    'Parent Layer'
+
 Expect a KeyError for invalid names
 
     >>> wms['utterly bogus'].title
diff --git a/tests/doctests/wms_getfeatureinfo.txt b/tests/doctests/wms_getfeatureinfo.txt
new file mode 100644
index 0000000..a3be31a
--- /dev/null
+++ b/tests/doctests/wms_getfeatureinfo.txt
@@ -0,0 +1,24 @@
+>>> from owslib.wms import WebMapService
+>>> wms = WebMapService('http://geoserv.weichand.de:8080/geoserver/wms')
+
+>>> res1 = wms.getfeatureinfo(layers=['bvv:lkr_ex'], srs='EPSG:31468', bbox=(4500000,5500000,4500500,5500500), size=(500,500), format='image/jpeg', info_format="text/html", xy=(250,250))
+>>> html_string1 = res1.read().decode("utf-8")
+>>> ('lkr_ex' in html_string1)
+True
+>>> ('gmd_ex' in html_string1)
+False
+
+>>> res2 = wms.getfeatureinfo(layers=['bvv:lkr_ex','bvv:gmd_ex'], srs='EPSG:31468', bbox=(4500000,5500000,4500500,5500500), size=(500,500), format='image/jpeg', info_format="text/html", xy=(250,250))
+>>> html_string2 = res2.read().decode("utf-8")
+>>> ('lkr_ex' in html_string2)
+True
+>>> ('gmd_ex' in html_string2)
+True
+
+>>> res3 = wms.getfeatureinfo(layers=['bvv:lkr_ex','bvv:gmd_ex'], srs='EPSG:31468', bbox=(4500000,5500000,4500500,5500500), size=(500,500), format='image/jpeg', query_layers=['bvv:lkr_ex'], info_format="text/html", xy=(250,250))
+>>> html_string3 = res3.read().decode("utf-8")
+>>> ('lkr_ex' in html_string3)
+True
+>>> ('gmd_ex' in html_string3)
+False
+
diff --git a/tests/doctests/wmts_RESTonly.txt b/tests/doctests/wmts_RESTonly.txt
new file mode 100644
index 0000000..4d6de9d
--- /dev/null
+++ b/tests/doctests/wmts_RESTonly.txt
@@ -0,0 +1,34 @@
+Imports:
+
+    >>> from __future__ import (absolute_import, division, print_function)
+    >>> 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()
+
diff --git a/tests/doctests/wmts_geoserver21.txt b/tests/doctests/wmts_geoserver21.txt
index 378d5d6..63f3396 100644
--- a/tests/doctests/wmts_geoserver21.txt
+++ b/tests/doctests/wmts_geoserver21.txt
@@ -27,6 +27,8 @@ Test capabilities
 
     >>> wmts.identification.fees
 
+    >>> wmts.restonly
+    False
 
 Service Provider:
 
diff --git a/tests/resources/wms_geoserver-cap.xml b/tests/resources/wms_geoserver-cap.xml
index 69eecae..729d103 100644
--- a/tests/resources/wms_geoserver-cap.xml
+++ b/tests/resources/wms_geoserver-cap.xml
@@ -140,14 +140,14 @@
         <KeywordList/>
         <SRS>EPSG:4326</SRS>
         <!--WKT definition of this CRS:
-GEOGCS["WGS 84", 
-  DATUM["World Geodetic System 1984", 
-    SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], 
-    AUTHORITY["EPSG","6326"]], 
-  PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], 
-  UNIT["degree", 0.017453292519943295], 
-  AXIS["Geodetic longitude", EAST], 
-  AXIS["Geodetic latitude", NORTH], 
+GEOGCS["WGS 84",
+  DATUM["World Geodetic System 1984",
+    SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
+    AUTHORITY["EPSG","6326"]],
+  PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
+  UNIT["degree", 0.017453292519943295],
+  AXIS["Geodetic longitude", EAST],
+  AXIS["Geodetic latitude", NORTH],
   AUTHORITY["EPSG","4326"]]-->
         <LatLonBoundingBox minx="-74.012" miny="40.708" maxx="-74.002" maxy="40.72"/>
         <BoundingBox SRS="EPSG:4326" minx="-74.012" miny="40.708" maxx="-74.002" maxy="40.72"/>
@@ -169,6 +169,14 @@ GEOGCS["WGS 84",
           </LegendURL>
         </Style>
       </Layer>
+      <Layer queryable="0">
+        <Name>parent_layer</Name>
+        <Title>Parent Layer</Title>
+        <Layer queryable="1">
+            <Name>child_layer</Name>
+            <Title>Child Layer</Title>
+        </Layer>
+      </Layer>
     </Layer>
   </Capability>
 </WMT_MS_Capabilities>

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



More information about the Pkg-grass-devel mailing list