-
Notifications
You must be signed in to change notification settings - Fork 281
add OGC API - EDR client #899
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| @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/ | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From someone who's not familiar with the API, I suggest the docstring should start with what the function does in simple terms.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All |
||||||
|
|
||||||
| @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_) | ||||||
| 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't there a need for a custom docstring ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not at this level, given the building blocks of OGC APIs (collections are the same across APIS). docstrings are more specific deeper into the endpoints.