Skip to content

Commit

Permalink
add OGC API - EDR client (#899)
Browse files Browse the repository at this point in the history
* add OGC API - EDR client

* fixes
  • Loading branch information
tomkralidis authored Dec 18, 2023
1 parent 5d6df7c commit de5d26e
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 23 deletions.
42 changes: 24 additions & 18 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,6 @@ OGC API - Records - Part 1: Core 1.0

>>> w.collection_item_delete('my-catalogue', identifier)



OGC API - Features - Part 4: Create, Replace, Update and Delete
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -300,34 +298,33 @@ OGC API - Features - Part 4: Create, Replace, Update and Delete

.. code-block:: python
import json
from owslib.ogcapi.records import Records
>>> import json
>>> from owslib.ogcapi.records import Records
record_data = '/path/to/record.json'
>>> record_data = '/path/to/record.json'
url = 'http://localhost:8000'
collection_id = 'metadata:main'
>>> url = 'http://localhost:8000'
>>> collection_id = 'metadata:main'
r = Records(url)
>>> r = Records(url)
cat = r.collection(collection_id)
>>> cat = r.collection(collection_id)
with open(record_data) as fh:
data = json.load(fh)
>>> with open(record_data) as fh:
... data = json.load(fh)
identifier = data['id']
>>> identifier = data['id']
r.collection_item_delete(collection_id, identifier)
>>> r.collection_item_delete(collection_id, identifier)
# insert metadata
r.collection_item_create(collection_id, data)
>>> r.collection_item_create(collection_id, data)
# update metadata
r.collection_item_update(collection_id, identifier, data)
>>> r.collection_item_update(collection_id, identifier, data)
# delete metadata
r.collection_item_delete(collection_id, identifier)
>>> r.collection_item_delete(collection_id, identifier)
OGC API - Processes - Part 1: Core 1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -345,7 +342,6 @@ OGC API - Processes - Part 1: Core 1.0
>>> hello_world['title']
'Hello World'
OGC API - Maps - Part 1: Core 1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -358,6 +354,16 @@ OGC API - Maps - Part 1: Core 1.0
>>> with open("output.png", "wb") as fh:
... fh.write(data.getbuffer())
OGC API - Environmental Data Retrieval - Part 1: Core 1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: python
>>> from owslib.ogcapi.edr import EnvironmentalDataRetrieval
>>> e = EnvironmentalDataRetrieval('http://localhost:5000')
>>> icoads_sst = m.collection('icoads-sst')
>>> data = e.query_data('icoads_sst', 'position', coords='POINT(-75 45)', parameter_names='SST,AIRT')
WCS
---
Expand Down
98 changes: 98 additions & 0 deletions owslib/ogcapi/edr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# =============================================================================
# Copyright (c) 2023 Tom Kralidis
#
# Author: Tom Kralidis <tomkralidis@gmail.com>
#
# Contact email: tomkralidis@gmail.com
# =============================================================================

from io import BytesIO
import logging
from typing import BinaryIO

from owslib.ogcapi.features import Features
from owslib.util import Authentication

LOGGER = logging.getLogger(__name__)


class EnvironmentalDataRetrieval(Features):
"""Abstraction for OGC API - Environmental Data Retrieval"""

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)

def data(self) -> list:
"""
implements /collections filtered on EDR data resources
@returns: `list` of filtered collections object
"""

datas = []
collections_ = super().collections()

for c_ in collections_['collections']:
for l_ in c_['links']:
if 'data' in l_['rel']:
datas.append(c_['id'])
break

return datas

def query_data(self, collection_id: str,
query_type: str, **kwargs: dict) -> BinaryIO:
"""
implements /collection/{collectionId}/coverage/
@type collection_id: string
@param collection_id: id of collection
@type query_type: string
@param query_type: query type
@type bbox: list
@param bbox: list of minx,miny,maxx,maxy
@type coords: string
@param coords: well-known text geometry
@type datetime_: string
@type datetime_: string
@param datetime_: time extent or time instant
@type parameter_names: list
@param parameter_names: list of parameter names
@returns: coverage data
"""

kwargs_ = {}

if 'bbox' in kwargs:
kwargs_['bbox'] = ','.join(list(map(str, kwargs['bbox'])))
if 'parameter_names' in kwargs:
kwargs_['parameter_names'] = ','.join(kwargs['parameter_names'])

query_args_map = {
'coords': 'coords',
'corridor_width': 'corridor-width',
'corridor_height': 'corridor-height',
'crs': 'crs',
'cube-z': 'cube-z',
'datetime_': 'datetime',
'height': 'height',
'height_units': 'height-units',
'resolution_x': 'resolution-x',
'resolution_y': 'resolution-y',
'resolution_z': 'resolution-z',
'width': 'width',
'width_units': 'width-units',
'within': 'within',
'z': 'z'
}

for key, value in query_args_map.items():
if key in kwargs:
kwargs_[value] = kwargs[key]

path = f'collections/{collection_id}/{query_type}'

return self._request(path=path, kwargs=kwargs_)
43 changes: 43 additions & 0 deletions tests/test_ogcapi_edr_pygeoapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from tests.utils import service_ok

import pytest

from owslib.ogcapi.edr import EnvironmentalDataRetrieval

SERVICE_URL = 'https://demo.pygeoapi.io/master/'


@pytest.mark.online
@pytest.mark.skipif(not service_ok(SERVICE_URL),
reason='service is unreachable')
def test_ogcapi_coverages_pygeoapi():
w = EnvironmentalDataRetrieval(SERVICE_URL)

assert w.url == SERVICE_URL
assert w.url_query_string is None

api = w.api()
assert api['components']['parameters'] is not None
paths = api['paths']
assert paths is not None
assert paths['/collections/icoads-sst'] is not None

conformance = w.conformance()
assert len(conformance['conformsTo']) > 1

collections = w.collections()
assert len(collections) > 0

datas = w.data()
assert len(datas) > 0

icoads = w.collection('icoads-sst')
assert icoads['id'] == 'icoads-sst'
assert icoads['title'] == 'International Comprehensive Ocean-Atmosphere Data Set (ICOADS)' # noqa
assert icoads['description'] == 'International Comprehensive Ocean-Atmosphere Data Set (ICOADS)' # noqa

parameter_names = icoads['parameter_names'].keys()
assert sorted(parameter_names) == ['AIRT', 'SST', 'UWND', 'VWND']

response = w.query_data('icoads-sst', 'position', coords='POINT(-75 45)')
assert isinstance(response, dict)
4 changes: 2 additions & 2 deletions tests/test_ogcapi_features_pygeoapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ def test_ogcapi_features_pygeoapi():
assert lakes['title'] == 'Large Lakes'
assert lakes['description'] == 'lakes of the world, public domain'

#lakes_queryables = w.collection_queryables('lakes')
#assert len(lakes_queryables['queryables']) == 6
# lakes_queryables = w.collection_queryables('lakes')
# assert len(lakes_queryables['queryables']) == 6

# Minimum of limit param is 1
with pytest.raises(RuntimeError):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_ogcapi_processes_pygeoapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_ogcapi_processes_pygeoapi():
assert len(collections) > 0

processes = p.processes()
assert len(processes) == 5
assert len(processes) == 6

hello_world = p.process('hello-world')
assert hello_world['id'] == 'hello-world'
Expand Down
4 changes: 2 additions & 2 deletions tests/test_ogcapi_records_pycsw.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_ogcapi_records_pycsw():
assert paths['/collections/{collectionId}'] is not None

conformance = w.conformance()
assert len(conformance['conformsTo']) == 18
assert len(conformance['conformsTo']) == 14

collections = w.collections()
assert len(collections) > 0
Expand All @@ -40,7 +40,7 @@ def test_ogcapi_records_pycsw():
assert isinstance(w.response, dict)

pycsw_cite_demo_queryables = w.collection_queryables('metadata:main')
assert len(pycsw_cite_demo_queryables['properties'].keys()) == 12
assert len(pycsw_cite_demo_queryables['properties'].keys()) == 13

# Minimum of limit param is 1
with pytest.raises(RuntimeError):
Expand Down

0 comments on commit de5d26e

Please sign in to comment.