[Git][debian-gis-team/owslib][upstream] New upstream version 0.28.0
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Mon Feb 20 14:19:52 GMT 2023
Bas Couwenberg pushed to branch upstream at Debian GIS Project / owslib
Commits:
adf95013 by Bas Couwenberg at 2023-02-20T15:10:27+01:00
New upstream version 0.28.0
- - - - -
22 changed files:
- .github/workflows/main.yml
- CHANGES.rst
- VERSION.txt
- docs/en/features.rst
- docs/en/usage.rst
- owslib/__init__.py
- owslib/feature/postrequest.py
- owslib/feature/wfs200.py
- owslib/fgdc.py
- owslib/ogcapi/__init__.py
- owslib/ogcapi/coverages.py
- owslib/ogcapi/features.py
- + owslib/ogcapi/maps.py
- owslib/ogcapi/processes.py
- owslib/ogcapi/records.py
- owslib/util.py
- owslib/wmts.py
- tests/doctests/wfs_MapServerWFSFeature.txt → tests/_broken/doctests/wfs_MapServerWFSFeature.txt
- + tests/test_ogcapi_maps_cubewerx.py
- tests/test_ogcapi_processes_pygeoapi.py
- tests/test_ogcapi_records_pycsw.py
- tests/test_wfs_postrequest.py
Changes:
=====================================
.github/workflows/main.yml
=====================================
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: [3.6, 3.7, 3.8, 3.9]
+ python-version: ['3.7', '3.8', '3.9']
lxml: [true, false]
env:
LXML: ${{ matrix.lxml }}
@@ -22,7 +22,7 @@ jobs:
- name: Install packages
run: |
sudo apt-get -y install pandoc
- if: matrix.python-version == 3.6
+ if: matrix.python-version == 3.7
- name: Install requirements 📦
run: |
pip3 install -e .
@@ -34,10 +34,10 @@ jobs:
run: python3 -m pytest
- name: run coveralls ⚙️
run: coveralls
- if: matrix.python-version == 3.6
+ if: matrix.python-version == 3.7
- name: build docs 🏗️
run: cd docs && make html
- if: matrix.python-version == 3.6
+ if: matrix.python-version == 3.7
- name: run flake8 ⚙️
run: flake8 owslib
- if: matrix.python-version == 3.6
+ if: matrix.python-version == 3.7
=====================================
CHANGES.rst
=====================================
@@ -1,6 +1,11 @@
Changes
=======
+0.27.2 (unreleased)
+-------------------
+
+- WFS: Fix set_filter for string inputs (#804)
+
0.27.1 (2022-08-28)
-------------------
=====================================
VERSION.txt
=====================================
@@ -1 +1 @@
-0.27.2
+0.28.0
=====================================
docs/en/features.rst
=====================================
@@ -58,7 +58,9 @@ OGC API Support
+--------------------------------------------------------------------------------------+------------+
| `OGC API - Records - Part 1: Core`_ | draft |
+--------------------------------------------------------------------------------------+------------+
-| `OGC API - Features - Part 3: Filtering and the Common Query Language (CQL) draft`_ | draft |
+| `OGC API - Features - Part 3: Filtering and the Common Query Language (CQL)`_ | draft |
++--------------------------------------------------------------------------------------+------------+
+| `OGC API - Features - Part 4: Create, Replace, Update and Delete`_ | draft |
+--------------------------------------------------------------------------------------+------------+
| `OGC API - Processes - Part 1: Core`_ | 1.0 |
+--------------------------------------------------------------------------------------+------------+
@@ -89,6 +91,7 @@ OGC API Support
.. _`OGC API`: https://ogcapi.ogc.org
.. _`OGC API - Features - Part 1: Core`: https://docs.opengeospatial.org/is/17-069r3/17-069r3.html
.. _`OGC API - Records - Part 1: Core`: https://github.com/opengeospatial/ogcapi-records
-.. _`OGC API - Features - Part 3: Filtering and the Common Query Language (CQL) draft`: https://docs.ogc.org/DRAFTS/19-079.html
+.. _`OGC API - Features - Part 3: Filtering and the Common Query Language (CQL)`: https://docs.ogc.org/DRAFTS/19-079.html
+.. _`OGC API - Features - Part 4: Create, Replace, Update and Delete`: https://docs.ogc.org/DRAFTS/20-002.html
.. _`OGC API - Coverages - Part 1: Core`: https://docs.ogc.org/DRAFTS/19-087.html
.. _`OGC API - Processes - Part 1: Core`: https://docs.ogc.org/is/18-062r2/18-062r2.html
=====================================
docs/en/usage.rst
=====================================
@@ -163,7 +163,7 @@ The `OGC API`_ standards are a clean break from the traditional OGC service arch
using current design patterns (RESTful, JSON, OpenAPI). As such, OWSLib the code follows
the same pattern.
-OGC API - Features 1.0 - Part 1: Core
+OGC API - Features - Part 1: Core 1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: python
@@ -195,7 +195,7 @@ OGC API - Features 1.0 - Part 1: Core
>>> lakes_query['features'][0]['properties']
{u'scalerank': 0, u'name_alt': None, u'admin': None, u'featureclass': u'Lake', u'id': 0, u'name': u'Lake Baikal'}
-OGC API - Coverages 1.0 - Part 1: Core
+OGC API - Coverages - Part 1: Core 1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: python
@@ -230,7 +230,7 @@ OGC API - Coverages 1.0 - Part 1: Core
'float64'
>> gdps_coverage_query = w.coverage('gdps-temperature', range_subset=[1])
-OGC API - Records 1.0 - Part 1: Core
+OGC API - Records - Part 1: Core 1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> from owslib.ogcapi.records import Records
@@ -273,7 +273,63 @@ OGC API - Records 1.0 - Part 1: Core
>>> my_catalogue_cql_json_query['features'][0]['properties']['title']
u'Roadrunner ambush locations'
-OGC API - Processes 1.0 - Part 1: Core
+ >>> import json
+
+ >>> record_data = 'sample-geojson-record.json'
+
+ >>> with open(record_data) as fh:
+ .. data = json.load(fh)
+
+ >>> identifier = data['id']
+
+ >>> w.collection_item_create('my-catalogue', data)
+
+ >>> w.collection_item_update('my-catalogue', identifier, data)
+
+ >>> w.collection_item_delete('my-catalogue', identifier)
+
+
+
+OGC API - Features - Part 4: Create, Replace, Update and Delete
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. note::
+
+ This specification applies to both OGC API - Features and OGC API - Records
+
+
+.. code-block:: python
+
+ import json
+ from owslib.ogcapi.records import Records
+
+ record_data = '/path/to/record.json'
+
+ url = 'http://localhost:8000'
+ collection_id = 'metadata:main'
+
+ r = Records(url)
+
+ cat = r.collection(collection_id)
+
+ with open(record_data) as fh:
+ data = json.load(fh)
+
+ identifier = data['id']
+
+ r.collection_item_delete(collection_id, identifier)
+
+ # insert metadata
+ r.collection_item_create(collection_id, data)
+
+ # update metadata
+ r.collection_item_update(collection_id, identifier, data)
+
+ # delete metadata
+ r.collection_item_delete(collection_id, identifier)
+
+
+OGC API - Processes - Part 1: Core 1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: python
@@ -289,6 +345,20 @@ OGC API - Processes 1.0 - Part 1: Core
>>> hello_world['title']
'Hello World'
+
+OGC API - Maps - Part 1: Core 1.0
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: python
+
+ >>> from owslib.ogcapi.maps import Maps
+ >>> m = Maps('http://localhost:5000')
+ >>> lakes = m.collection('lakes')
+ >>> data = m.map('lakes', width=1200, height=800, transparent=False)
+ >>> with open("output.png", "wb") as fh:
+ ... fh.write(data.getbuffer())
+
+
WCS
---
=====================================
owslib/__init__.py
=====================================
@@ -1 +1 @@
-__version__ = '0.27.2'
+__version__ = '0.28.0'
=====================================
owslib/feature/postrequest.py
=====================================
@@ -175,7 +175,11 @@ class PostRequest_2_0_0(PostRequest):
"""
if isinstance(filter, str):
f = etree.fromstring(filter)
- sub_elem = f.find(util.nspath("Filter", FES_NAMESPACE))
+ if f.tag == util.nspath("Filter", FES_NAMESPACE):
+ sub_elem = f
+ else:
+ sub_elem = f.find(util.nspath("Filter", FES_NAMESPACE))
+
else:
sub_elem = filter
=====================================
owslib/feature/wfs200.py
=====================================
@@ -529,7 +529,7 @@ class ContentMetadata(AbstractContentMetadata):
else:
self.abstract = None
self.keywords = [
- f.text for f in elem.findall(nspath("Keywords", ns=WFS_NAMESPACE))
+ f.text for f in elem.findall(nspath("Keywords/Keyword", ns=OWS_NAMESPACE))
]
# bboxes
=====================================
owslib/fgdc.py
=====================================
@@ -246,11 +246,16 @@ class Keywords(object):
class Ptcontac(object):
""" Process ptcontac """
def __init__(self, md):
- val = md.find('cntinfo/cntorgp/cntorg')
- self.cntorg = util.testXMLValue(val)
- val = md.find('cntinfo/cntorgp/cntper')
- self.cntper = util.testXMLValue(val)
+ ent = md.find('cntinfo/cntorgp')
+ if ent is None:
+ ent = md.find('cntinfo/cntperp')
+
+ if ent is not None:
+ val = ent.find('cntorg')
+ self.cntorg = util.testXMLValue(val)
+ val = ent.find('cntper')
+ self.cntper = util.testXMLValue(val)
val = md.find('cntinfo/cntpos')
self.cntpos = util.testXMLValue(val)
@@ -323,6 +328,9 @@ class Distinfo(object):
digform['name'] = util.testXMLValue(link.find('digtinfo/formname'))
digform['url'] = util.testXMLValue(link.find('digtopt/onlinopt/computer/networka/networkr/'))
self.stdorder['digform'].append(digform)
+ cnt = val.find('distrib')
+ if cnt is not None:
+ self.distrib = Ptcontac(cnt)
class Metainfo(object):
=====================================
owslib/ogcapi/__init__.py
=====================================
@@ -1,5 +1,5 @@
# =============================================================================
-# Copyright (c) 2020 Tom Kralidis
+# Copyright (c) 2022 Tom Kralidis
#
# Author: Tom Kralidis <tomkralidis at gmail.com>
#
@@ -15,7 +15,8 @@ import requests
import yaml
from owslib import __version__
-from owslib.util import Authentication, http_get, http_post
+from owslib.util import (Authentication, http_delete, http_get, http_post,
+ http_put)
LOGGER = logging.getLogger(__name__)
@@ -99,7 +100,7 @@ class API:
if openapi_format == openapi_json_mimetype:
content = response.json()
elif openapi_format == openapi_yaml_mimetype:
- content = yaml.load(response.text)
+ content = yaml.safe_load(response.text)
return content
else:
msg = 'Did not find service-desc link'
@@ -114,7 +115,7 @@ class API:
"""
path = 'conformance'
- return self._request(path)
+ return self._request(path=path)
def _build_url(self, path: str = None, params: dict = {}) -> str:
"""
@@ -141,15 +142,20 @@ class API:
return url
- def _request(self, path: str = None, as_dict: bool = True,
+ def _request(self, method: str = 'GET', path: str = None,
+ data: str = None, as_dict: bool = True,
kwargs: dict = {}) -> dict:
"""
helper function for request/response patterns against OGC API endpoints
@type path: string
@param path: path of request
+ @type method: string
+ @param method: HTTP method (default ``GET``)
+ @type data: string
+ @param data: request data payload
@type as_dict: bool
- @param as_dict: whether to return JSON dict (default True)
+ @param as_dict: whether to return JSON dict (default ``True``)
@type kwargs: string
@param kwargs: ``dict`` of keyword value pair request parameters
@@ -159,28 +165,35 @@ class API:
url = self._build_url(path)
self.request = url
+ LOGGER.debug(f'Method: {method}')
LOGGER.debug(f'Request: {url}')
+ LOGGER.debug(f'Data: {data}')
LOGGER.debug(f'Params: {kwargs}')
- if 'cql' not in kwargs:
+ if method == 'GET':
response = http_get(url, headers=self.headers, auth=self.auth,
params=kwargs)
- else:
- LOGGER.debug('CQL query detected')
- kwargs2 = deepcopy(kwargs)
- cql = kwargs2.pop('cql')
- url2 = self._build_url(path, kwargs2)
- response = http_post(url2, request=cql, auth=self.auth)
+ elif method == 'POST':
+ response = http_post(url, request=data, auth=self.auth)
+ elif method == 'PUT':
+ response = http_put(url, data=data, auth=self.auth)
+ elif method == 'DELETE':
+ response = http_delete(url, auth=self.auth)
LOGGER.debug(f'URL: {response.url}')
+ LOGGER.debug(f'Response status code: {response.status_code}')
- if response.status_code != requests.codes.ok:
+ if not response:
raise RuntimeError(response.text)
self.request = response.url
if as_dict:
- return response.json()
+ if len(response.content) == 0:
+ LOGGER.debug('Empty response')
+ return {}
+ else:
+ return response.json()
else:
return response.content
@@ -199,7 +212,7 @@ class Collections(API):
"""
path = 'collections'
- return self._request(path)
+ return self._request(path=path)
def collection(self, collection_id: str) -> dict:
"""
@@ -212,7 +225,7 @@ class Collections(API):
"""
path = f'collections/{collection_id}'
- return self._request(path)
+ return self._request(path=path)
def collection_queryables(self, collection_id: str) -> dict:
"""
@@ -225,4 +238,4 @@ class Collections(API):
"""
path = f'collections/{collection_id}/queryables'
- return self._request(path)
+ return self._request(path=path)
=====================================
owslib/ogcapi/coverages.py
=====================================
@@ -8,6 +8,7 @@
from io import BytesIO
import logging
+from typing import BinaryIO
from owslib.ogcapi import Collections
from owslib.util import Authentication
@@ -23,11 +24,11 @@ class Coverages(Collections):
__doc__ = Collections.__doc__ # noqa
super().__init__(url, json_, timeout, headers, auth)
- def coverages(self) -> dict:
+ def coverages(self) -> list:
"""
implements /collections filtered on coverages
- @returns: `dict` of filtered collections object
+ @returns: `list` of filtered collections object
"""
coverages_ = []
@@ -67,7 +68,7 @@ class Coverages(Collections):
path = f'collections/{collection_id}/coverage/rangetype'
return self._request(path=path, kwargs=kwargs)
- def coverage(self, collection_id: str, **kwargs: dict) -> dict:
+ def coverage(self, collection_id: str, **kwargs: dict) -> BinaryIO:
"""
implements /collection/{collectionId}/coverage/
=====================================
owslib/ogcapi/features.py
=====================================
@@ -1,12 +1,14 @@
# =============================================================================
-# Copyright (c) 2020 Tom Kralidis
+# Copyright (c) 2022 Tom Kralidis
#
# Author: Tom Kralidis <tomkralidis at gmail.com>
#
# Contact email: tomkralidis at gmail.com
# =============================================================================
+from copy import deepcopy
import logging
+from urllib.parse import urlencode
from owslib.ogcapi import Collections
from owslib.util import Authentication
@@ -22,11 +24,11 @@ class Features(Collections):
__doc__ = Collections.__doc__ # noqa
super().__init__(url, json_, timeout, headers, auth)
- def feature_collections(self) -> dict:
+ def feature_collections(self) -> list:
"""
implements /collections filtered on features
- @returns: `dict` of filtered collections object
+ @returns: `list` of filtered collections object
"""
features_ = []
@@ -46,8 +48,8 @@ class Features(Collections):
@param collection_id: id of collection
@type bbox: list
@param bbox: list of minx,miny,maxx,maxy
- @type datetime: string
- @param datetime: time extent or time instant
+ @type datetime_: string
+ @param datetime_: time extent or time instant
@type limit: int
@param limit: limit number of features
@type offset: int
@@ -64,9 +66,18 @@ class Features(Collections):
if 'bbox' in kwargs:
kwargs['bbox'] = ','.join(list(map(str, kwargs['bbox'])))
-
- path = f'collections/{collection_id}/items'
- return self._request(path=path, kwargs=kwargs)
+ if 'datetime_' in kwargs:
+ kwargs['datetime'] = kwargs['datetime_']
+
+ if 'cql' in kwargs:
+ LOGGER.debug('CQL query detected')
+ kwargs2 = deepcopy(kwargs)
+ cql = kwargs2.pop('cql')
+ path = f'collections/{collection_id}/items?{urlencode(kwargs2)}'
+ return self._request(method='POST', path=path, data=cql, kwargs=kwargs2)
+ else:
+ path = f'collections/{collection_id}/items'
+ return self._request(path=path, kwargs=kwargs)
def collection_item(self, collection_id: str, identifier: str) -> dict:
"""
@@ -82,3 +93,57 @@ class Features(Collections):
path = f'collections/{collection_id}/items/{identifier}'
return self._request(path=path)
+
+ def collection_item_create(self, collection_id: str, data: str) -> bool:
+ """
+ implements POST /collections/{collectionId}/items
+
+ @type collection_id: string
+ @param collection_id: id of collection
+ @type data: string
+ @param data: raw representation of data
+
+ @returns: single feature result
+ """
+
+ path = f'collections/{collection_id}/items'
+ _ = self._request(method='POST', path=path, data=data)
+
+ return True
+
+ def collection_item_update(self, collection_id: str, identifier: str,
+ data: str) -> bool:
+ """
+ implements PUT /collections/{collectionId}/items/{featureId}
+
+ @type collection_id: string
+ @param collection_id: id of collection
+ @type identifier: string
+ @param identifier: feature identifier
+ @type data: string
+ @param data: raw representation of data
+
+ @returns: ``bool`` of deletion result
+ """
+
+ path = f'collections/{collection_id}/items/{identifier}'
+ _ = self._request(method='PUT', path=path, data=data)
+
+ return True
+
+ def collection_item_delete(self, collection_id: str, identifier: str) -> bool:
+ """
+ implements DELETE /collections/{collectionId}/items/{featureId}
+
+ @type collection_id: string
+ @param collection_id: id of collection
+ @type identifier: string
+ @param identifier: feature identifier
+
+ @returns: ``bool`` of deletion result
+ """
+
+ path = f'collections/{collection_id}/items/{identifier}'
+ _ = self._request(method='DELETE', path=path)
+
+ return True
=====================================
owslib/ogcapi/maps.py
=====================================
@@ -0,0 +1,89 @@
+# =============================================================================
+# Copyright (c) 2022 Tom Kralidis
+#
+# Author: Tom Kralidis <tomkralidis at gmail.com>
+#
+# Contact email: tomkralidis at gmail.com
+# =============================================================================
+
+from io import BytesIO
+import logging
+from typing import BinaryIO
+
+from owslib.ogcapi import Collections
+from owslib.util import Authentication
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Maps(Collections):
+ """Abstraction for OGC API - Maps"""
+
+ def __init__(self, url: str, json_: str = None, timeout: int = 30,
+ headers: dict = None, auth: Authentication = None):
+ __doc__ = Collections.__doc__ # noqa
+ super().__init__(url, json_, timeout, headers, auth)
+
+ def maps(self) -> list:
+ """
+ implements /collections filtered on maps
+
+ @returns: `list` of filtered collections object
+ """
+
+ maps_ = []
+ collections_ = super().collections()
+
+ for c_ in collections_['collections']:
+ for l_ in c_['links']:
+ if 'map' in l_['rel']:
+ maps_.append(c_['id'])
+ break
+
+ return maps_
+
+ def map(self, collection_id: str, **kwargs: dict) -> BinaryIO:
+ """
+ implements /collection/{collectionId}/map
+
+ @type collection_id: string
+ @param collection_id: id of collection
+ @type bbox: list
+ @param bbox: list of minx,miny,maxx,maxy
+ @type bbox_crs: str
+ @param bbox_crs: CRS of output map
+ @type datetime_: string
+ @param datetime_: time extent or time instant
+ @type width: int
+ @param width: width of output map
+ @type height: int
+ @param height: height of output map
+ @type transparent: bool
+ @param transparent: whether to apply transparecy to
+ output map (default=True)
+ @type style: str
+ @param style: style name
+
+ @returns: map image
+ """
+
+ kwargs_ = {}
+
+ if 'bbox' in kwargs:
+ kwargs_['bbox'] = ','.join(list(map(str, kwargs['bbox'])))
+ if 'bbox_crs' in kwargs:
+ kwargs_['bbox-crs'] = kwargs['bbox_crs']
+ if 'datetime_' in kwargs:
+ kwargs_['datetime'] = kwargs['datetime_']
+
+ kwargs_['width'] = kwargs.get('width', 800)
+ kwargs_['height'] = kwargs.get('height', 600)
+
+ kwargs_['transparent'] = str(kwargs.get('transparent', True)).lower()
+
+ if 'style' in kwargs:
+ path = f'collections/{collection_id}/styles/{kwargs["style"]}/map'
+ else:
+ path = f'collections/{collection_id}/map'
+
+ return BytesIO(self._request(path=path, as_dict=False, kwargs=kwargs_))
=====================================
owslib/ogcapi/processes.py
=====================================
@@ -22,15 +22,15 @@ class Processes(Collections):
__doc__ = Collections.__doc__ # noqa
super().__init__(url, json_, timeout, headers, auth)
- def processes(self) -> dict:
+ def processes(self) -> list:
"""
implements /processes
- @returns: `dict` of available processes
+ @returns: `list` of available processes
"""
path = 'processes'
- return self._request(path)
+ return self._request(path=path)['processes']
def process(self, process_id: str) -> dict:
"""
@@ -43,4 +43,4 @@ class Processes(Collections):
"""
path = f'processes/{process_id}'
- return self._request(path)
+ return self._request(path=path)
=====================================
owslib/ogcapi/records.py
=====================================
@@ -22,11 +22,11 @@ class Records(Features):
__doc__ = Features.__doc__ # noqa
super().__init__(url, json_, timeout, headers, auth)
- def records(self) -> dict:
+ def records(self) -> list:
"""
implements /collections filtered on records
- @returns: `dict` of filtered collections object
+ @returns: `list` of filtered collections object
"""
records_ = []
=====================================
owslib/util.py
=====================================
@@ -1,6 +1,6 @@
# -*- coding: ISO-8859-15 -*-
# =============================================================================
-# Copyright (c) 2008 Tom Kralidis
+# Copyright (c) 2022 Tom Kralidis
#
# Authors : Tom Kralidis <tomkralidis at gmail.com>
#
@@ -444,7 +444,7 @@ def http_post(url=None, request=None, lang='en-US', timeout=10, username=None, p
return requests.post(url, json=request, headers=headers_, **rkwargs)
-def http_get(*args, **kwargs):
+def http_prepare(*args, **kwargs):
# Copy input kwargs so the dict can be modified
rkwargs = copy.deepcopy(kwargs)
@@ -475,9 +475,33 @@ def http_get(*args, **kwargs):
rkwargs.setdefault('auth', None)
rkwargs.setdefault('cert', rkwargs.get('cert'))
rkwargs.setdefault('verify', rkwargs.get('verify', True))
+
+ return rkwargs
+
+
+def http_get(*args, **kwargs):
+ rkwargs = http_prepare(*args, **kwargs)
return requests.get(*args, **rkwargs)
+def http_put(*args, **kwargs):
+ rkwargs = http_prepare(*args, **kwargs)
+
+ if 'data' in kwargs:
+ if isinstance(kwargs['data'], dict):
+ rkwargs['json'] = kwargs['data']
+ rkwargs.pop('data')
+ else:
+ rkwargs['data'] = kwargs['data']
+
+ return requests.put(*args, **rkwargs)
+
+
+def http_delete(*args, **kwargs):
+ rkwargs = http_prepare(*args, **kwargs)
+ return requests.delete(*args, **rkwargs)
+
+
def element_to_string(element, encoding=None, xml_declaration=False):
"""
Returns a string from a XML object
=====================================
owslib/wmts.py
=====================================
@@ -362,12 +362,14 @@ class WebMapTileService(object):
# choose random ResourceURL if more than one available
resindex = randint(0, numres - 1)
resurl = tileresourceurls[resindex]['template']
- resurl = resurl.replace('{TileMatrixSet}', tilematrixset)
- resurl = resurl.replace('{TileMatrix}', tilematrix)
- resurl = resurl.replace('{TileRow}', str(row))
- resurl = resurl.replace('{TileCol}', str(column))
- resurl = resurl.replace('{Style}', style)
- return resurl
+ return resurl.format(
+ TileMatrixSet=tilematrixset,
+ TileMatrix=tilematrix,
+ TileRow=str(row),
+ TileCol=str(column),
+ Style=style,
+ **kwargs
+ )
return None
=====================================
tests/doctests/wfs_MapServerWFSFeature.txt → tests/_broken/doctests/wfs_MapServerWFSFeature.txt
=====================================
=====================================
tests/test_ogcapi_maps_cubewerx.py
=====================================
@@ -0,0 +1,32 @@
+from io import BytesIO
+
+from tests.utils import service_ok
+
+import pytest
+
+from owslib.ogcapi.maps import Maps
+
+SERVICE_URL = 'https://test.cubewerx.com/cubewerx/cubeserv/demo/ogcapi/EuroRegionalMap/' # noqa
+
+
+ at pytest.mark.online
+ at pytest.mark.skipif(not service_ok(SERVICE_URL),
+ reason='service is unreachable')
+def test_ogcapi_maps_pygeoapi():
+ w = Maps(SERVICE_URL)
+
+ assert w.url == SERVICE_URL
+ assert w.url_query_string is None
+
+ collections = w.collections()
+ assert len(collections) > 0
+
+ maps = w.maps()
+ assert len(maps) > 0
+
+ erm = w.collection('erm')
+ assert erm['id'] == 'erm'
+ assert erm['title'] == 'EuroRegionalMap'
+
+ data = w.map('erm', width=1200, height=800, transparent=False)
+ assert isinstance(data, BytesIO)
=====================================
tests/test_ogcapi_processes_pygeoapi.py
=====================================
@@ -29,7 +29,7 @@ def test_ogcapi_processes_pygeoapi():
assert len(collections) > 0
processes = p.processes()
- assert len(processes) == 1
+ assert len(processes) == 3
hello_world = p.process('hello-world')
assert hello_world['id'] == 'hello-world'
=====================================
tests/test_ogcapi_records_pycsw.py
=====================================
@@ -23,7 +23,7 @@ def test_ogcapi_records_pycsw():
assert paths['/collections/{collectionId}'] is not None
conformance = w.conformance()
- assert len(conformance['conformsTo']) == 12
+ assert len(conformance['conformsTo']) == 13
collections = w.collections()
assert len(collections) > 0
=====================================
tests/test_wfs_postrequest.py
=====================================
@@ -44,6 +44,16 @@ xml_filter_2_0_0 = """<?xml version="1.0" ?>
</wfs:GetFeature>
"""
+raw_2_0_filter = """
+ <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0"
+ xmlns:erl="http://xmlns.earthresourceml.org/earthresourceml-lite/1.0">
+ <fes:PropertyIsEqualTo>
+ <fes:ValueReference>reference</fes:ValueReference>
+ <fes:Literal>gold</fes:Literal>
+ </fes:PropertyIsEqualTo>
+ </fes:Filter>
+ """
+
typename = "ns:typename"
@@ -272,3 +282,17 @@ class TestPostRequest_v_2_0_0():
assert equal_elem is not None
assert propertyname == "status"
assert literal == "rejected"
+
+ def test_filter_root_query(self, requestv200):
+ """Same as test_filter_query, but the filter is the root element."""
+ requestv200.set_filter(raw_2_0_filter)
+
+ filter_elem = requestv200._query.find(util.nspath("Filter", FES_NAMESPACE))
+ equal_elem = filter_elem.find(util.nspath("PropertyIsEqualTo", FES_NAMESPACE))
+ propertyname = equal_elem.findtext(util.nspath("ValueReference", FES_NAMESPACE))
+ literal = equal_elem.findtext(util.nspath("Literal", FES_NAMESPACE))
+
+ assert filter_elem is not None
+ assert equal_elem is not None
+ assert propertyname == "reference"
+ assert literal == "gold"
View it on GitLab: https://salsa.debian.org/debian-gis-team/owslib/-/commit/adf95013ffbacd9406eb9b4bf6d7623f7a4f97c2
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/owslib/-/commit/adf95013ffbacd9406eb9b4bf6d7623f7a4f97c2
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20230220/6ee65e8b/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list