[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