update configuration to be resource specific (#393)

This commit is contained in:
Tom Kralidis
2020-04-26 09:57:07 -04:00
committed by GitHub
parent 11ee7053fc
commit 3debd0c750
52 changed files with 275 additions and 215 deletions
+2 -2
View File
@@ -21,8 +21,8 @@ If applicable, add screenshots to help explain your problem.
**Environment**
- OS:
- Python version:
- pygeoapi version:
- Python version:
- pygeoapi version:
**Additional context**
Add any other context about the problem here.
+2 -2
View File
@@ -84,7 +84,7 @@ Your contribution will be under our [license](https://github.com/geopython/pygeo
branch, __base your branch off the ``master`` one__.
* Note that depending on how long it takes for the dev team to merge your
patch, the copy of ``master`` you worked off of may get out of date!
patch, the copy of ``master`` you worked off of may get out of date!
* If you find yourself 'bumping' a pull request that's been sidelined for a
while, __make sure you rebase or merge to latest ``master``__ to ensure a
speedier resolution.
@@ -103,7 +103,7 @@ Your contribution will be under our [license](https://github.com/geopython/pygeo
### Code Formatting
* __Please follow the coding conventions and style used in the pygeoapi repository.__
* __Please follow the coding conventions and style used in the pygeoapi repository.__
* pygeoapi follows the [PEP-8](http://www.python.org/dev/peps/pep-0008/) guidelines
* 80 characters
* spaces, not tabs
+4 -4
View File
@@ -35,15 +35,15 @@ Try the swagger ui at `http://localhost:5000/openapi`
or
```bash
# feature collection metadata
# collection metadata
curl http://localhost:5000/
# conformance
curl http://localhost:5000/conformance
# feature collection
# collection
curl http://localhost:5000/collections/countries
# feature collection limit 100
# collection limit 100
curl http://localhost:5000/collections/countries/items?limit=100
# feature
# collection item
curl http://localhost:5000/collections/countries/items/1
# number of hits
curl http://localhost:5000/collections/countries/items?resulttype=hits
+1 -1
View File
@@ -35,7 +35,7 @@ zappa undeploy -s zappa_settings.json
## node/serverless
The included `serverless.yml` and `pygeoapi-serverless-config.yml` can be used to deploy pygeoapi
The included `serverless.yml` and `pygeoapi-serverless-config.yml` can be used to deploy pygeoapi
on AWS Lambda Serverless Environment.
This requires Amazon Credentials and the Serverless deployment tool.
+9 -2
View File
@@ -81,8 +81,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
obs:
type: collection
title: Observations
description: My cool observations
keywords:
@@ -116,6 +117,7 @@ datasets:
y_field: lat
ne_110m_populated_places_simple:
type: collection
title: Populated Places
description: Point symbols with name attributes. Includes all admin-0 capitals and some other major cities. We favor regional significance over population census in determining our selection of places. Use the scale rankings to filter the number of towns that appear on your map.
keywords:
@@ -143,6 +145,7 @@ datasets:
id_field: geonameid
lakes:
type: collection
title: Large Lakes
description: lakes of the world, public domain
keywords:
@@ -167,6 +170,7 @@ datasets:
id_field: id
countries:
type: collection
title: Countries in the world
description: Countries of the world
keywords:
@@ -191,6 +195,7 @@ datasets:
id_field: ogc_fid
table: ne_110m_admin_0_countries
poi:
type: collection
title: Portuguese point of interrest
description: Portuguese points of interrest obtained from OpenStreetMap. Dataset includes Madeira and Azores islands
keywords:
@@ -222,6 +227,7 @@ datasets:
table: poi_portugal
hotosm_bdi_waterways:
type: collection
title: Waterways of Burundi
description: Waterways of Burundi, Africa. Dataset timestamp 1st Sep 2018 - Humanitarian OpenStreetMap Team (HOT)
keywords:
@@ -256,6 +262,7 @@ datasets:
table: hotosm_bdi_waterways
dutch_georef_stations:
type: collection
title: Dutch Georef Stations via OGR WFS
description: Locations of RD/GNSS-reference stations from Dutch Kadaster PDOK a.k.a RDInfo. Uses MapServer WFS v2 backend via OGRProvider.
keywords:
@@ -301,7 +308,7 @@ datasets:
id_field: gml_id
layer: rdinfo:stations
processes:
hello-world:
type: process
processor:
name: HelloWorld
+1 -1
View File
@@ -1,5 +1,5 @@
pygeoapi (0.7.0-1~bionic0) bionic; urgency=medium
* Numerous CITE compliance fixes
* Elasticsearch: update provider to support ES7
* MongoDB provider implementation
+4 -4
View File
@@ -5,11 +5,11 @@ Files: *
Copyright: Copyright 2019 Tom Kralidis
License: MIT
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom
sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following
conditions:
.
@@ -21,6 +21,6 @@ License: MIT
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
+10 -10
View File
@@ -2,9 +2,9 @@
Docker Image `geopython/pygeoapi:latest` and versions are [available from DockerHub](https://hub.docker.com/r/geopython/pygeoapi).
Each Docker Image contains a default configuration [default.config.yml](default.config.yml) with the project's test data and WFS3/OGC API Features datasets.
Each Docker Image contains a default configuration [default.config.yml](default.config.yml) with the project's test data and OGC API dataset collections.
You can override this default config via Docker Volume mapping or by extending the Docker Image and copying in your config. See an [example for the geoapi demo server](https://github.com/geopython/demo.pygeoapi.io/tree/master/services/pygeoapi) for the latter method.
You can override this default config via Docker Volume mapping or by extending the Docker Image and copying in your config. See an [example for the geoapi demo server](https://github.com/geopython/demo.pygeoapi.io/tree/master/services/pygeoapi) for the latter method.
https://github.com/geopython/demo.pygeoapi.io/tree/master/services Depending on your config you may need specific backends to be available.
@@ -19,9 +19,9 @@ So the chain is:
```
There are a number of examples at [several examples](https://github.com/geopython/pygeoapi/blob/master/docker/examples).
There are a number of examples at [several examples](https://github.com/geopython/pygeoapi/blob/master/docker/examples).
### Installation
### Installation
Install Docker (Ubuntu)
@@ -51,11 +51,11 @@ Run/Create Container
$ sudo docker run --name geoapi -p 5000:80 -v $(pwd)/my.config.yml:/pygeoapi/local.config.yml -it geopython/pygeoapi
```
Go to http://localhost:5000/ and should be up and running.
Go to http://localhost:5000/ and should be up and running.
## Running - Basics
By default this Image will start a `pygeoapi` Docker Container
By default this Image will start a `pygeoapi` Docker Container
using `gunicorn` on internal port 80.
To run with default built-in config and data:
@@ -64,7 +64,7 @@ To run with default built-in config and data:
docker run -p 5000:80 -it geopython/pygeoapi run
# or simply
docker run -p 5000:80 -it geopython/pygeoapi
# then browse to http://localhost:5000/
```
@@ -111,13 +111,13 @@ COPY ./my.config.yml /pygeoapi/local.config.yml
See how the demo server is setup this way at
https://github.com/geopython/demo.pygeoapi.io/tree/master/services/pygeoapi_master
## Running - Running on a sub-path
By default the `pygeoapi` Docker Image will run from the `root` path `/`.
If you need to run from a sub-path and have all internal URLs correct
you need to set `SCRIPT_NAME` environment variable.
For example to run with `my.config.yml` on http://localhost:5000/mypygeoapi:
```
@@ -140,7 +140,7 @@ services:
ports:
- "5000:80"
environment:
- SCRIPT_NAME=/pygeoapi
+12 -2
View File
@@ -87,8 +87,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
obs:
type: collection
title: Observations
description: My cool observations
keywords:
@@ -126,6 +127,7 @@ datasets:
y_field: lat
lakes:
type: collection
title: Large Lakes
description: lakes of the world, public domain
keywords:
@@ -149,6 +151,7 @@ datasets:
id_field: id
countries:
type: collection
title: Countries in the world (SpatialLite Provider)
description: Countries of the world (SpatialLite)
keywords:
@@ -174,6 +177,7 @@ datasets:
table: ne_110m_admin_0_countries
dutch_georef_stations:
type: collection
title: Dutch Georef Stations via OGR WFS
description: Locations of RD/GNSS-reference stations from Dutch Kadaster PDOK a.k.a RDInfo. Uses MapServer WFS v2 backend via OGRProvider.
keywords:
@@ -220,6 +224,7 @@ datasets:
layer: rdinfo:stations
utah_city_locations:
type: collection
title: Cities in Utah via OGR WFS
description: Data from the state of Utah. Standard demo dataset from the deegree WFS server that is used as backend WFS.
keywords:
@@ -265,6 +270,7 @@ datasets:
layer: app:SGID93_LOCATION_UDOTMap_CityLocations
unesco_pois_italy:
type: collection
title: Unesco POIs in Italy via OGR WFS
description: Unesco Points of Interest in Italy. Using GeoSolutions GeoServer WFS demo-server as backend WFS.
keywords:
@@ -309,6 +315,7 @@ datasets:
layer: unesco:Unesco_point
ogr_gpkg_poi:
type: collection
title: Portuguese Points of Interest via OGR GPKG
description: Portuguese Points of Interest obtained from OpenStreetMap. Dataset includes Madeira and Azores islands. Uses GeoPackage backend via OGR provider.
keywords:
@@ -354,6 +361,7 @@ datasets:
layer: poi_portugal
ogr_geojson_lakes:
type: collection
title: Large Lakes OGR GeoJSON Driver
description: lakes of the world, public domain
keywords:
@@ -392,6 +400,7 @@ datasets:
layer: ne_110m_lakes
ogr_addresses_sqlite:
type: collection
title: Dutch addresses (subset Otterlo). OGR SQLite Driver
description: Dutch addresses subset.
keywords:
@@ -433,6 +442,7 @@ datasets:
layer: ogrgeojson
ogr_addresses_gpkg:
type: collection
title: Dutch addresses (subset Otterlo). OGR GeoPackage Driver
description: Dutch addresses subset.
keywords:
@@ -472,7 +482,7 @@ datasets:
id_field: id
layer: OGRGeoJSON
processes:
hello-world:
type: process
processor:
name: HelloWorld
+1 -1
View File
@@ -5,5 +5,5 @@ This folder contains the sub-folders:
- simple
- elastic
The [simple](simple) example will run pygeoapi with Docker with your local config.
The [simple](simple) example will run pygeoapi with Docker with your local config.
The [elastic](elastic) example demonstrates a docker compose configuration to run pygeoapi with local ElasticSearch backend.
+2 -2
View File
@@ -61,12 +61,12 @@ CMD ["/usr/share/elasticsearch/bin/elasticsearch"]
ENTRYPOINT ["/docker-entrypoint.sh"]
# we need to run this on host
# we need to run this on host
#sudo sysctl -w vm.max_map_count=262144
#check indices
#http://localhost:9200/_cat/indices?v
#check spatial data
#http://localhost:9200/ne_110m_populated_places_simple/
#This docker compose was inspired on:
#https://discuss.elastic.co/t/best-practice-for-creating-an-index-when-an-es-docker-container-starts/126651
#https://discuss.elastic.co/t/best-practice-for-creating-an-index-when-an-es-docker-container-starts/126651
#docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" es:latest
@@ -33,4 +33,4 @@
# wait for Elasticsearch to start, then run the setup script to
# create and configure the index.
exec /usr/share/elasticsearch/bin/wait-for-it.sh localhost:9200 -- /add_data.sh &
exec $@
exec $@
+6 -6
View File
@@ -1,7 +1,7 @@
# pygeoapi with ElasticSearch (ES)
These folders contain a Docker Compose configuration necessary to setup a minimal
`pygeoapi` server that uses a local ES backend service.
These folders contain a Docker Compose configuration necessary to setup a minimal
`pygeoapi` server that uses a local ES backend service.
This config is only for local development and testing.
@@ -10,11 +10,11 @@ This config is only for local development and testing.
- official ElasticSearch: **5.6.8** on **CentosOS 7**
- ports **9300** and **9200**
ES requires the host system to have its virtual memory
ES requires the host system to have its virtual memory
parameter (**max_map_count**) [here](https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html)
set as follows:
```
```
sudo sysctl -w vm.max_map_count=262144
```
@@ -32,5 +32,5 @@ To build and run the [Docker compose file](docker-compose.yml) in localhost:
```
sudo sysctl -w vm.max_map_count=262144
docker-compose build
docker-compose up
```
docker-compose up
```
+2 -2
View File
@@ -58,7 +58,7 @@ services:
build: ./ES
container_name: elastic
ports:
- 9300:9300
- 9200:9200
@@ -67,6 +67,6 @@ services:
volumes:
elastic_search_data: {}
#NOTE: Host requires changes in configuration to run ES
#sudo sysctl -w vm.max_map_count=262144
@@ -84,8 +84,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
obs:
type: collection
title: Observations
description: My cool observations
keywords:
@@ -119,6 +120,7 @@ datasets:
y_field: long
ne_110m_populated_places_simple:
type: collection
title: Populated Places
description: Point symbols with name attributes. Includes all admin-0 capitals and some other major cities. We favor regional significance over population census in determining our selection of places. Use the scale rankings to filter the number of towns that appear on your map.
keywords:
@@ -147,6 +149,7 @@ datasets:
id_field: geonameid
lakes:
type: collection
title: Large Lakes
description: lakes of the world, public domain
keywords:
@@ -169,8 +172,9 @@ datasets:
name: GeoJSON
data: tests/data/ne_110m_lakes.geojson
id_field: id
countries:
type: collection
title: Countries in the world
description: Countries of the world
keywords:
@@ -189,13 +193,13 @@ datasets:
temporal:
begin:
end: null # or empty
provider:
provider:
name: SQLiteGPKG
data: tests/data/ne_110m_admin_0_countries.sqlite
id_field: ogc_fid
table: ne_110m_admin_0_countries
processes:
hello-world:
type: process
processor:
name: HelloWorld
@@ -31,7 +31,7 @@
# =================================================================
set +e
echo "Waiting for ElasticSearch container..."
# First wait for ES to be up and then execute the original pygeoapi entrypoint.
+7 -4
View File
@@ -82,8 +82,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
obs:
type: collection
title: Observations
description: My cool observations
keywords:
@@ -117,6 +118,7 @@ datasets:
y_field: long
lakes:
type: collection
title: Large Lakes
description: lakes of the world, public domain
keywords:
@@ -139,8 +141,9 @@ datasets:
name: GeoJSON
data: tests/data/ne_110m_lakes.geojson
id_field: id
countries:
type: collection
title: Countries in the world
description: Countries of the world
keywords:
@@ -159,13 +162,13 @@ datasets:
temporal:
begin:
end: null # or empty
provider:
provider:
name: SQLiteGPKG
data: tests/data/ne_110m_admin_0_countries.sqlite
id_field: ogc_fid
table: ne_110m_admin_0_countries
processes:
hello-world:
type: process
processor:
name: HelloWorld
+1 -1
View File
@@ -127,7 +127,7 @@ Hello world example process
:members:
:private-members:
:special-members:
.. _data Provider:
Provider
+22 -25
View File
@@ -16,8 +16,7 @@ pygeoapi configuration contains the following core sections:
- ``server``: server-wide settings
- ``logging``: logging configuration
- ``metadata``: server-wide metadata (contact, licensing, etc.)
- ``datasets``: dataset collections offered by server
- ``processes``: processes offered by server
- ``resources``: dataset collections, processes and stac-collections offered by the server
.. note::
`Standard YAML mechanisms <https://en.wikipedia.org/wiki/YAML#Advanced_components>`_ can be used (anchors, references, etc.) for reuse and compactness.
@@ -44,7 +43,7 @@ The ``server`` section provides directives on binding and high level tuning.
language: en-US # default server language
cors: true # boolean on whether server should support CORS
pretty_print: true # whether JSON responses should be pretty-printed
limit: 10 # server limit on number of features to return
limit: 10 # server limit on number of items to return
map: # leaflet map setup for HTML pages
url: https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png
attribution: '<a href="https://wikimediafoundation.org/wiki/Maps_Terms_of_Use">Wikimedia maps</a> | Map data &copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>'
@@ -106,15 +105,21 @@ The ``metadata`` section provides settings for overall service metadata and desc
instructions: During hours of service. Off on weekends.
role: pointOfContact
``datasets``
^^^^^^^^^^^^
``resources``
^^^^^^^^^^^^^
The ``datasets`` section lists 1 or more dataset collections to be published by the server.
The ``resources`` section lists 1 or more dataset collections to be published by the server.
The ``resource.type`` property is required. Allowed types are:
- ``collection``
- ``process``
- ``stac-collection``
.. code-block:: yaml
datasets:
resources:
obs:
type: collection # REQUIRED (collection, process, or stac-collection)
title: Observations # title of dataset
description: My cool observations # abstract of dataset
keywords: # list of related keywords
@@ -151,6 +156,12 @@ The ``datasets`` section lists 1 or more dataset collections to be published by
- stn_id
- value
hello-world: # name of process
type: collection # REQUIRED (collection, process, or stac-collection)
processor:
name: HelloWorld # Python path of process defition
.. seealso::
`Linked Data`_ for optionally configuring linked data datasets
@@ -158,20 +169,6 @@ The ``datasets`` section lists 1 or more dataset collections to be published by
:ref:`plugins` for more information on plugins
``processes``
^^^^^^^^^^^^^
.. code-block:: yaml
processes:
hello-world: # name of process
processor:
name: HelloWorld # Python path of process defition
.. note::
See :ref:`plugins` for more information on plugins
Using environment variables
---------------------------
@@ -196,7 +193,7 @@ Linked Data
:align: left
:alt: JSON-LD support
pygeoapi supports structured metadata about a deployed instance, and is also capable of presenting feature data as
pygeoapi supports structured metadata about a deployed instance, and is also capable of presenting data as
structured data. `JSON-LD`_ equivalents are available for each HTML page, and are embedded
as data blocks within the corresponding page for search engine optimisation (SEO). Tools such as the
`Google Structured Data Testing Tool`_ can be used to check the structured representations.
@@ -208,11 +205,11 @@ This metadata is included automatically, and is sufficient for inclusion in majo
For collections, at the level of an item or items, by default the JSON-LD representation adds:
- The GeoJSON JSON-LD `vocabulary and context <https://geojson.org/geojson-ld/>`_ to the ``@context``.
- An ``@id`` for each feature in a collection, that is the URL for that feature (resolving to its HTML representation
- An ``@id`` for each item in a collection, that is the URL for that item (resolving to its HTML representation
in pygeoapi)
.. note::
While this is enough to provide valid RDF (as GeoJSON-LD), it does not allow the *properties* of your features to be
While this is enough to provide valid RDF (as GeoJSON-LD), it does not allow the *properties* of your items to be
unambiguously interpretable.
pygeoapi currently allows for the extension of the ``@context`` to allow properties to be aliased to terms from
@@ -251,7 +248,7 @@ also expressed as `<https://schema.org/DateTime>`_.
This example demonstrates how to use this feature with a CSV data provider, using included sample data. The
implementation of JSON-LD structured data is available for any data provider but is currently limited to defining a
``@context``. Relationships between features can be expressed but is dependent on such relationships being expressed
``@context``. Relationships between items can be expressed but is dependent on such relationships being expressed
by the dataset provider, not pygeoapi.
Summary
@@ -104,7 +104,7 @@ PostgreSQL
provider:
name: PostgreSQL
data:
data:
host: 127.0.0.1
dbname: test
user: postgres
@@ -145,13 +145,13 @@ GeoPackage file:
Data access examples
--------------------
- list all datasets
- list all collections
- http://localhost:5000/collections
- overview of dataset
- http://localhost:5000/collections/foo
- browse features
- http://localhost:5000/collections/foo/items
- paging
- paging
- http://localhost:5000/collections/foo/items?startIndex=10&limit=10
- CSV outputs
- http://localhost:5000/collections/foo/items?f=csv
+8 -5
View File
@@ -15,11 +15,14 @@ to the given directory and specifying allowed file types:
.. code-block:: yaml
provider:
name: FileSystem
data: /Users/tomkralidis/Dev/data/gdps
file_types:
- .grib2
my-stac-resource:
type: stac-collection
...
provider:
name: FileSystem
data: /Users/tomkralidis/Dev/data/gdps
file_types:
- .grib2
.. note::
+1 -1
View File
@@ -61,7 +61,7 @@ Conda
.. code-block:: bash
conda install -c conda-forge pygeoapi
conda install -c conda-forge pygeoapi
UbuntuGIS
---------
+1 -1
View File
@@ -53,7 +53,7 @@ paging and sorting:
.. image:: /_static/openapi_get_item.png
For each feature in our dataset we have a specific identifier. Notice that the identifier is not part of the GeoJSON
For each item in our dataset we have a specific identifier. Notice that the identifier is not part of the GeoJSON
properties, but is provided as a GeoJSON root property of ``id``.
.. image:: /_static/openapi_get_item_id.png
+1 -1
View File
@@ -54,7 +54,7 @@ The below template provides a minimal example (let's call the file ``mycooldata.
class MyCoolDataProvider(BaseProvider):
"""My cool data provider"""
def __init__(self, provider_def):
"""Inherit from parent class"""
+2 -2
View File
@@ -62,7 +62,7 @@ Or you can create a ``Dockerfile`` extending the base image and **copy** in your
.. code-block:: dockerfile
FROM geopython/pygeoapi:latest
FROM geopython/pygeoapi:latest
COPY ./my.config.yml /pygeoapi/local.config.yml
A corresponding example can be found in https://github.com/geopython/demo.pygeoapi.io/tree/master/services/pygeoapi_master
@@ -72,7 +72,7 @@ Deploying on a sub-path
By default the ``pygeoapi`` Docker image will run from the ``root`` path (``/``). If you need to run from a
sub-path and have all internal URLs properly configured, you can set the ``SCRIPT_NAME`` environment variable.
For example to run with ``my.config.yml`` on ``http://localhost:5000/mypygeoapi``:
.. code-block:: bash
+4 -4
View File
@@ -25,11 +25,11 @@ Flask WSGI
Web Server Gateway Interface (WSGI) is a standard for how web servers communicate with Python applications. By
having a WSGI server, HTTP requests are processed into threads/processes for better performance. Flask is a WSGI
implementation which pygeoapi utilizes to communicate with the core API.
.. code-block:: bash
HTTP request <--> Flask (pygeoapi/flask_app.py) <--> pygeoapi API (pygeoapi/api.py)
The Flask WSGI server can be run as follows:
@@ -116,7 +116,7 @@ Gunicorn and Flask
Gunicorn and Flask is simple to run:
.. code-block:: bash
gunicorn pygeoapi.flask_app:APP
.. note::
+1 -1
View File
@@ -72,7 +72,7 @@ This page displays a map and tabular view of the data. Features are clickable o
allowing the user to drill into more information about the feature. The table also allows for drilling
into a feature by clicking the link in a given table row.
Let's checkout the feature close to `Toronto, Ontario, Canada`_.
Let's inspect the feature close to `Toronto, Ontario, Canada`_.
Collection item
+5 -2
View File
@@ -80,8 +80,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
obs:
type: collection
title: Observations
description: My cool observations
keywords:
@@ -119,6 +120,7 @@ datasets:
y_field: lat
lakes:
type: collection
title: Large Lakes
description: lakes of the world, public domain
keywords:
@@ -142,6 +144,7 @@ datasets:
id_field: id
test-data:
type: stac-collection
title: pygeoapi test data
description: pygeoapi test data
keywords:
@@ -165,7 +168,7 @@ datasets:
- .csv
- .grib2
processes:
hello-world:
type: process
processor:
name: HelloWorld
+61 -49
View File
@@ -47,8 +47,8 @@ from pygeoapi.plugin import load_plugin, PLUGINS
from pygeoapi.provider.base import (
ProviderGenericError, ProviderConnectionError, ProviderNotFoundError,
ProviderQueryError, ProviderItemNotFoundError)
from pygeoapi.util import (dategetter, json_serial, render_j2_template,
str2bool, TEMPLATES)
from pygeoapi.util import (dategetter, filter_dict_by_key_value, json_serial,
render_j2_template, str2bool, TEMPLATES)
LOGGER = logging.getLogger(__name__)
@@ -266,7 +266,7 @@ class API:
@jsonldify
def describe_collections(self, headers_, format_, dataset=None):
"""
Provide feature collection metadata
Provide collection metadata
:param headers_: copy of HEADERS object
:param format_: format of requests,
@@ -289,21 +289,22 @@ class API:
'links': []
}
if all([dataset is not None,
dataset not in self.config['datasets'].keys()]):
collections = filter_dict_by_key_value(self.config['resources'],
'type', 'collection')
if all([dataset is not None, dataset not in collections.keys()]):
exception = {
'code': 'InvalidParameterValue',
'description': 'Invalid feature collection'
'description': 'Invalid collection'
}
LOGGER.error(exception)
return headers_, 400, json.dumps(exception)
LOGGER.debug('Creating collections')
for k, v in self.config['datasets'].items():
for k, v in collections.items():
collection = {'links': []}
collection['id'] = k
collection['itemType'] = 'feature'
collection['itemType'] = 'Feature'
collection['title'] = v['title']
collection['description'] = v['description']
collection['keywords'] = v['keywords']
@@ -363,21 +364,21 @@ class API:
collection['links'].append({
'type': 'application/geo+json',
'rel': 'items',
'title': 'Features as GeoJSON',
'title': 'items as GeoJSON',
'href': '{}/collections/{}/items?f=json'.format(
self.config['server']['url'], k)
})
collection['links'].append({
'type': 'application/ld+json',
'rel': 'items',
'title': 'Features as RDF (GeoJSON-LD)',
'title': 'items as RDF (GeoJSON-LD)',
'href': '{}/collections/{}/items?f=jsonld'.format(
self.config['server']['url'], k)
})
collection['links'].append({
'type': 'text/html',
'rel': 'items',
'title': 'Features as HTML',
'title': 'Items as HTML',
'href': '{}/collections/{}/items?f=html'.format(
self.config['server']['url'], k)
})
@@ -486,7 +487,7 @@ class API:
return headers_, 400, json.dumps(exception)
if any([dataset is None,
dataset not in self.config['datasets'].keys()]):
dataset not in self.config['resources'].keys()]):
exception = {
'code': 'InvalidParameterValue',
@@ -499,7 +500,7 @@ class API:
LOGGER.debug('Loading provider')
try:
p = load_plugin('provider',
self.config['datasets'][dataset]['provider'])
self.config['resources'][dataset]['provider'])
except ProviderConnectionError:
exception = {
'code': 'NoApplicableCode',
@@ -534,7 +535,7 @@ class API:
})
if format_ == 'html': # render
queryables['title'] = self.config['datasets'][dataset]['title']
queryables['title'] = self.config['resources'][dataset]['title']
headers_['Content-Type'] = 'text/html'
content = render_j2_template(self.config, 'queryables.html',
queryables)
@@ -545,7 +546,7 @@ class API:
def get_collection_items(self, headers, args, dataset, pathinfo=None):
"""
Queries feature collection
Queries collection
:param headers: dict of HTTP headers
:param args: dict of HTTP request parameters
@@ -563,10 +564,13 @@ class API:
formats = FORMATS
formats.extend(f.lower() for f in PLUGINS['formatter'].keys())
if dataset not in self.config['datasets'].keys():
collections = filter_dict_by_key_value(self.config['resources'],
'type', 'collection')
if dataset not in collections.keys():
exception = {
'code': 'InvalidParameterValue',
'description': 'Invalid feature collection'
'description': 'Invalid collection'
}
LOGGER.error(exception)
return headers_, 400, json.dumps(exception, default=json_serial)
@@ -665,8 +669,8 @@ class API:
datetime_invalid = False
if (datetime_ is not None and
'temporal' in self.config['datasets'][dataset]['extents']):
te = self.config['datasets'][dataset]['extents']['temporal']
'temporal' in collections[dataset]['extents']):
te = collections[dataset]['extents']['temporal']
if te['begin'].tzinfo is None:
te['begin'] = te['begin'].replace(tzinfo=pytz.UTC)
@@ -720,7 +724,7 @@ class API:
LOGGER.debug('Loading provider')
try:
p = load_plugin('provider',
self.config['datasets'][dataset]['provider'])
collections[dataset]['provider'])
except ProviderConnectionError:
exception = {
'code': 'NoApplicableCode',
@@ -869,7 +873,7 @@ class API:
content['links'].append(
{
'type': 'application/json',
'title': self.config['datasets'][dataset]['title'],
'title': collections[dataset]['title'],
'rel': 'collection',
'href': '{}/collections/{}'.format(
self.config['server']['url'], dataset)
@@ -906,7 +910,7 @@ class API:
data=content,
options={
'provider_def':
self.config['datasets'][dataset]['provider']
collections[dataset]['provider']
}
)
@@ -927,13 +931,13 @@ class API:
@pre_process
def get_collection_item(self, headers_, format_, dataset, identifier):
"""
Get a single feature
Get a single collection item
:param headers_: copy of HEADERS object
:param format_: format of requests,
pre checked by pre_process decorator
:param dataset: dataset name
:param identifier: feature identifier
:param identifier: item identifier
:returns: tuple of headers, status code, content
"""
@@ -948,17 +952,19 @@ class API:
LOGGER.debug('Processing query parameters')
if dataset not in self.config['datasets'].keys():
collections = filter_dict_by_key_value(self.config['resources'],
'type', 'collection')
if dataset not in collections.keys():
exception = {
'code': 'InvalidParameterValue',
'description': 'Invalid feature collection'
'description': 'Invalid collection'
}
LOGGER.error(exception)
return headers_, 400, json.dumps(exception)
LOGGER.debug('Loading provider')
p = load_plugin('provider',
self.config['datasets'][dataset]['provider'])
p = load_plugin('provider', collections[dataset]['provider'])
try:
LOGGER.debug('Fetching id {}'.format(identifier))
@@ -1021,7 +1027,7 @@ class API:
}, {
'rel': 'collection',
'type': 'application/json',
'title': self.config['datasets'][dataset]['title'],
'title': collections[dataset]['title'],
'href': '{}/collections/{}'.format(
self.config['server']['url'], dataset)
}, {
@@ -1040,7 +1046,7 @@ class API:
if format_ == 'html': # render
headers_['Content-Type'] = 'text/html'
content['title'] = self.config['datasets'][dataset]['title']
content['title'] = collections[dataset]['title']
content = render_j2_template(self.config, 'item.html',
content)
return headers_, 200, content
@@ -1082,18 +1088,20 @@ class API:
'links': []
}
for key, value in self.config['datasets'].items():
if value['provider']['name'] == 'FileSystem':
content['links'].append({
'rel': 'collection',
'href': '{}/{}?f=json'.format(stac_url, key),
'type': 'application/json'
})
content['links'].append({
'rel': 'collection',
'href': '{}/{}'.format(stac_url, key),
'type': 'text/html'
})
stac_collections = filter_dict_by_key_value(self.config['resources'],
'type', 'stac-collection')
for key, value in stac_collections.items():
content['links'].append({
'rel': 'collection',
'href': '{}/{}?f=json'.format(stac_url, key),
'type': 'application/json'
})
content['links'].append({
'rel': 'collection',
'href': '{}/{}'.format(stac_url, key),
'type': 'text/html'
})
if format_ == 'html': # render
headers_['Content-Type'] = 'text/html'
@@ -1120,7 +1128,10 @@ class API:
if dir_tokens:
dataset = dir_tokens[0]
if dataset not in self.config['datasets']:
stac_collections = filter_dict_by_key_value(self.config['resources'],
'type', 'stac-collection')
if dataset not in stac_collections:
exception = {
'code': 'NotFound',
'description': 'collection not found'
@@ -1130,8 +1141,7 @@ class API:
LOGGER.debug('Loading provider')
try:
p = load_plugin('provider',
self.config['datasets'][dataset]['provider'])
p = load_plugin('provider', stac_collections[dataset]['provider'])
except ProviderConnectionError as err:
LOGGER.error(err)
exception = {
@@ -1143,7 +1153,7 @@ class API:
id_ = '{}-stac'.format(dataset)
stac_version = '0.6.2'
description = self.config['datasets'][dataset]['description']
description = stac_collections[dataset]['description']
content = {
'id': id_,
@@ -1174,7 +1184,7 @@ class API:
if isinstance(stac_data, dict):
content.update(stac_data)
content['links'].extend(self.config['datasets'][dataset]['links'])
content['links'].extend(stac_collections[dataset]['links'])
if format_ == 'html': # render
headers_['Content-Type'] = 'text/html'
@@ -1217,7 +1227,8 @@ class API:
LOGGER.error(exception)
return headers_, 400, json.dumps(exception)
processes_config = self.config.get('processes', {})
processes_config = filter_dict_by_key_value(self.config['resources'],
'type', 'process')
if processes_config:
if process is not None:
@@ -1288,7 +1299,8 @@ class API:
LOGGER.error(exception)
return headers_, 400, json.dumps(exception)
processes = self.config.get('processes', {})
processes = filter_dict_by_key_value(self.config['resources'],
'type', 'process')
if process not in processes:
exception = {
+7 -7
View File
@@ -189,21 +189,21 @@ def get_collection_queryables(name=None):
return response
@APP.route('/collections/<feature_collection>/items')
@APP.route('/collections/<feature_collection>/items/<feature>')
def dataset(feature_collection, feature=None):
@APP.route('/collections/<collection_id>/items')
@APP.route('/collections/<collection_id>/items/<item_id>')
def dataset(collection_id, item_id=None):
"""
OGC open api collections/{dataset}/items/{feature} access point
OGC open api collections/{dataset}/items/{item} access point
:returns: HTTP response
"""
if feature is None:
if item_id is None:
headers, status_code, content = api_.get_collection_items(
request.headers, request.args, feature_collection)
request.headers, request.args, collection_id)
else:
headers, status_code, content = api_.get_collection_item(
request.headers, request.args, feature_collection, feature)
request.headers, request.args, collection_id, item_id)
response = make_response(content, status_code)
+1 -1
View File
@@ -174,7 +174,7 @@ def geojson2geojsonld(config, data, dataset, identifier=None):
:returns: string of rendered JSON (GeoJSON-LD)
"""
context = config['datasets'][dataset].get('context', [])
context = config['resources'][dataset].get('context', [])
data['id'] = (
'{}/collections/{}/items/{}' if identifier
else '{}/collections/{}/items'
+12 -12
View File
@@ -35,7 +35,7 @@ import click
import yaml
from pygeoapi.plugin import load_plugin
from pygeoapi.util import yaml_load
from pygeoapi.util import filter_dict_by_key_value, yaml_load
LOGGER = logging.getLogger(__name__)
@@ -198,8 +198,8 @@ def get_oas_30(cfg):
paths['/collections'] = {
'get': {
'summary': 'Feature Collections',
'description': 'Feature Collections',
'summary': 'Collections',
'description': 'Collections',
'tags': ['server'],
'parameters': [
{'$ref': '#/components/parameters/f'}
@@ -276,10 +276,10 @@ def get_oas_30(cfg):
items_f['schema']['enum'].append('csv')
LOGGER.debug('setting up datasets')
for k, v in cfg['datasets'].items():
if v['provider']['name'] == 'FileSystem':
continue
collections = filter_dict_by_key_value(cfg['resources'],
'type', 'collection')
for k, v in collections.items():
collection_name_path = '/collections/{}'.format(k)
tag = {
'name': k,
@@ -298,7 +298,7 @@ def get_oas_30(cfg):
paths[collection_name_path] = {
'get': {
'summary': 'Get feature collection metadata'.format(v['title']), # noqa
'summary': 'Get collection metadata'.format(v['title']), # noqa
'description': v['description'],
'tags': [k],
'parameters': [
@@ -317,7 +317,7 @@ def get_oas_30(cfg):
paths[items_path] = {
'get': {
'summary': 'Get {} features'.format(v['title']),
'summary': 'Get {} items'.format(v['title']),
'description': v['description'],
'tags': [k],
'parameters': [
@@ -336,7 +336,7 @@ def get_oas_30(cfg):
}
}
p = load_plugin('provider', cfg['datasets'][k]['provider'])
p = load_plugin('provider', collections[k]['provider'])
if p.fields:
queryables_path = '{}/queryables'.format(collection_name_path)
@@ -398,9 +398,9 @@ def get_oas_30(cfg):
'explode': False
})
paths['{}/items/{{featureId}}'.format(collection_name_path)] = {
paths['{}/items/{{itemId}}'.format(collection_name_path)] = {
'get': {
'summary': 'Get {} feature by id'.format(v['title']),
'summary': 'Get {} item by id'.format(v['title']),
'description': v['description'],
'tags': [k],
'parameters': [
@@ -446,7 +446,7 @@ def get_oas_30(cfg):
}
}
processes = cfg.get('processes', {})
processes = filter_dict_by_key_value(cfg['resources'], 'type', 'process')
if processes:
for k, v in processes.items():
+3 -3
View File
@@ -145,8 +145,8 @@ class OGRProvider(BaseProvider):
'EPSG:4326').split(':')[1])
# Optional coordinate transformation inward (requests) and
# outward (responses) when the source layers and WFS3 collections
# differ in EPSG-codes.
# outward (responses) when the source layers and
# OGC API - Features collections differ in EPSG-codes.
self.transform_in = None
self.transform_out = None
if self.source_srs != self.target_srs:
@@ -220,7 +220,7 @@ class OGRProvider(BaseProvider):
{}'.format(source_type)
LOGGER.error(msg)
# ignore errors for ESRIJSON not having geometry member
# see https://github.com/OSGeo/gdal/commit/38b0feed67f80ded32be6c508323d862e1a14474 # noqa
# see https://github.com/OSGeo/gdal/commit/38b0feed67f80ded32be6c508323d862e1a14474 # noqa
self.conn = _ignore_gdal_error(
self.driver, 'Open', self.data_def['source'], 0)
if not self.conn:
+13 -13
View File
@@ -174,28 +174,28 @@ async def get_collection_queryables(request: Request, name=None):
return response
@app.route('/collections/{feature_collection}/items')
@app.route('/collections/{feature_collection}/items/')
@app.route('/collections/{feature_collection}/items/{feature}')
@app.route('/collections/{feature_collection}/items/{feature}/')
async def dataset(request: Request, feature_collection=None, feature=None):
@app.route('/collections/{collection_id}/items')
@app.route('/collections/{collection_id}/items/')
@app.route('/collections/{collection_id}/items/{item_id}')
@app.route('/collections/{collection_id}/items/{item_id}/')
async def dataset(request: Request, collection_id=None, item_id=None):
"""
OGC open api collections/{dataset}/items/{feature} access point
OGC open api collections/{dataset}/items/{item_id} access point
:returns: Starlette HTTP Response
"""
if 'feature_collection' in request.path_params:
feature_collection = request.path_params['feature_collection']
if 'feature' in request.path_params:
feature = request.path_params['feature']
if feature is None:
if 'collection_id' in request.path_params:
collection_id = request.path_params['collection_id']
if 'item_id' in request.path_params:
item_id = request.path_params['item_id']
if item_id is None:
headers, status_code, content = api_.get_collection_items(
request.headers, request.query_params,
feature_collection, pathinfo=request.scope['path'])
collection_id, pathinfo=request.scope['path'])
else:
headers, status_code, content = api_.get_collection_item(
request.headers, request.query_params, feature_collection, feature)
request.headers, request.query_params, collection_id, item_id)
response = Response(content=content, status_code=status_code)
+1 -1
View File
@@ -12,7 +12,7 @@ main {
.crumbs {
background-color:rgb(230, 230, 230);
padding: 6px;
padding: 6px;
}
.crumbs a {
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}{{ super() }} {{ data['title'] }} {% endblock %}
{% block crumbs %}{{ super() }}
{% block crumbs %}{{ super() }}
/ <a href="../collections">Collections</a>
/ <a href="./{{ data['id'] }}">{{ data['title'] }}</a>
{% endblock %}
+1 -1
View File
@@ -17,7 +17,7 @@
</tr>
</thead>
<tbody>
{% for k, v in config['datasets'].items() %}
{% for k, v in filter_dict_by_key_value(config['resources'], 'type', 'collection').items() %}
<tr itemprop="dataset" itemscope itemtype="https://schema.org/Dataset">
<td data-label="name">
<meta itemprop="url" content="{{ config['server']['url'] }}/collections/{{ k }}" />
+2 -2
View File
@@ -11,13 +11,13 @@
{% endif %}
{%- endmacro %}
{% block title %}{{ super() }} {{ data['title'] }} - {{ data['id'] }}{% endblock %}
{% block crumbs %}{{ super() }}
{% block crumbs %}{{ super() }}
/ <a href="../../../collections">Collections</a>
{% for link in data['links'] %}
{% if link.rel == 'collection' %}
/ <a href="{{ link['href'] }}">{{ link['title'] }}</a>
{% endif %}
{% endfor %}
{% endfor %}
/ <a href="../items">Items</a>
/ <a href="./{{ data['id'] }}">Item {{ data['id'] }}</a>
{% endblock %}
+1 -1
View File
@@ -20,7 +20,7 @@
<section id="collection">
<h1>{% for l in data['links'] if l.rel == 'collection' %} {{ l['title'] }} {% endfor %}</h1>
<p>Items in this collection.</p>
</section>
</section>
<section id="items">
{% if data['features'] %}
<div class="row">
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}{{ super() }} {{ data['title'] }} {% endblock %}
{% block crumbs %}{{ super() }}
{% block crumbs %}{{ super() }}
/ <a href="../processes">Processes</a>
/ <a href="./{{ data['id'] }}">{{ data['title'] }}</a>
{% endblock %}
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}{{ super() }} Processes {% endblock %}
{% block crumbs %}{{ super() }}
{% block crumbs %}{{ super() }}
/ <a href="./processes">Processes</a>
{% endblock %}
{% block body %}
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}{{ super() }} {{ data['title'] }} {% endblock %}
{% block crumbs %}{{ super() }}
{% block crumbs %}{{ super() }}
/ <a href="../../collections">Collections</a>
/ <a href="./{{ data['id'] }}">{{ data['title'] }}</a>
/ <a href="./{{ data['id'] }}queryables">Queryables</a>
+1 -1
View File
@@ -26,7 +26,7 @@
<div id="items-map"></div>
<div id="assets">
<h4>Assets</h4>
<table class="striped">
<table class="striped">
<thead>
<tr>
<th>URL</th>
+1 -1
View File
@@ -24,7 +24,7 @@
</tr>
</thead>
<tbody>
{% for k, v in config['datasets'].items() %}
{% for k, v in filter_dict_by_key_value(config['resources'], 'type', 'stac-collection').items() %}
{% if v['provider']['name'] == 'FileSystem' %}
<tr itemprop="dataset" itemscope itemtype="https://schema.org/Dataset">
<td data-label="name">
+17
View File
@@ -220,6 +220,9 @@ def render_j2_template(config, template, data):
env.filters['get_breadcrumbs'] = get_breadcrumbs
env.globals.update(get_breadcrumbs=get_breadcrumbs)
env.filters['filter_dict_by_key_value'] = filter_dict_by_key_value
env.globals.update(filter_dict_by_key_value=filter_dict_by_key_value)
template = env.get_template(template)
return template.render(config=config, data=data, version=__version__)
@@ -261,3 +264,17 @@ def get_breadcrumbs(urlpath):
})
return links
def filter_dict_by_key_value(dict_, key, value):
"""
helper generator function to filter a dict by a dict key
:param dict_: ``dict``
:param key: dict key
:param value: dict key value
:returns: filtered ``dict``
"""
return {k: v for (k, v) in dict_.items() if v[key] == value}
+2 -1
View File
@@ -51,8 +51,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
canada-hydat-daily-mean-02hc003:
type: collection
title: Daily Mean of Water Level or Flow
description: The daily mean is the average of all unit values for a given day.
keywords: [Daily, Daily Mean, Water Level, Flow, Discharge]
+2 -2
View File
@@ -28,7 +28,7 @@ This directory provides test data to demonstrate functionality.
### `obs.csv`
- source: MapServer msautotest suite
- URL: [https://github.com/mapserver/mapserver/blob/branch-7-0/msautotest/wxs/data/obs.csv](https://github.com/mapserver/mapserver/blob/branch-7-0/msautotest/wxs/data/obs.csv)
- URL: [https://github.com/mapserver/mapserver/blob/branch-7-0/msautotest/wxs/data/obs.csv](https://github.com/mapserver/mapserver/blob/branch-7-0/msautotest/wxs/data/obs.csv)
- Copyright (c) 2008-2018 Open Source Geospatial Foundation
- Copyright (c) 1996-2008 Regents of the University of Minnesota
@@ -44,7 +44,7 @@ This directory provides test data to demonstrate functionality.
- source: OpenStreetMap - Humanitarian OpenStreetMap Team (HOT)
- URL: [hotosm_bdi_waterways](https://data.humdata.org/dataset/hotosm_bdi_waterways)
- Waterways of Burundi
- Date of dataset: Sep 01, 2018
- Date of dataset: Sep 01, 2018
- Location: Burundi, Africa
### `CMC_glb_*.grib2`
+6 -6
View File
@@ -42,42 +42,42 @@ COMMENT ON SCHEMA topology IS 'PostGIS Topology schema';
--
-- Name: hstore; Type: EXTENSION; Schema: -; Owner:
-- Name: hstore; Type: EXTENSION; Schema: -; Owner:
--
CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA public;
--
-- Name: EXTENSION hstore; Type: COMMENT; Schema: -; Owner:
-- Name: EXTENSION hstore; Type: COMMENT; Schema: -; Owner:
--
COMMENT ON EXTENSION hstore IS 'data type for storing sets of (key, value) pairs';
--
-- Name: postgis; Type: EXTENSION; Schema: -; Owner:
-- Name: postgis; Type: EXTENSION; Schema: -; Owner:
--
CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA public;
--
-- Name: EXTENSION postgis; Type: COMMENT; Schema: -; Owner:
-- Name: EXTENSION postgis; Type: COMMENT; Schema: -; Owner:
--
COMMENT ON EXTENSION postgis IS 'PostGIS geometry, geography, and raster spatial types and functions';
--
-- Name: postgis_topology; Type: EXTENSION; Schema: -; Owner:
-- Name: postgis_topology; Type: EXTENSION; Schema: -; Owner:
--
CREATE EXTENSION IF NOT EXISTS postgis_topology WITH SCHEMA topology;
--
-- Name: EXTENSION postgis_topology; Type: COMMENT; Schema: -; Owner:
-- Name: EXTENSION postgis_topology; Type: COMMENT; Schema: -; Owner:
--
COMMENT ON EXTENSION postgis_topology IS 'PostGIS topology spatial types and functions';
+3 -2
View File
@@ -80,8 +80,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
obs:
type: collection
title: Observations
description: My cool observations
keywords:
@@ -114,7 +115,7 @@ datasets:
x_field: long
y_field: lat
processes:
hello-world:
type: process
processor:
name: HelloWorld
+3 -2
View File
@@ -80,8 +80,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
obs:
type: collection
title: Observations
description: My cool observations
keywords:
@@ -125,7 +126,7 @@ datasets:
x_field: long
y_field: lat
processes:
hello-world:
type: process
processor:
name: HelloWorld
+8 -3
View File
@@ -80,9 +80,9 @@ metadata:
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
resources:
dutch_georef_stations:
type: collection
title: Dutch Georef Stations via OGR WFS
description: Locations of RD/GNSS-reference stations from Dutch Kadaster PDOK a.k.a RDInfo. Uses MapServer WFS v2 backend via OGRProvider.
keywords:
@@ -130,6 +130,7 @@ datasets:
# Warning: this layer contains about 10 million addresses, the backend WFS seems not optimized
dutch_addresses:
type: collection
title: Dutch Addresses via OGR WFS
description: All Dutch addresses as derived from the key registry BAG. Uses GeoServer WFS v2 backend via OGRProvider. SLOW BACKEND!
keywords:
@@ -176,6 +177,7 @@ datasets:
layer: inspireadressen:inspireadressen
utah_city_locations:
type: collection
title: Cities in Utah via OGR WFS
description: Data from the state of Utah. Standard demo dataset from the deegree WFS server that is used as backend WFS.
keywords:
@@ -221,6 +223,7 @@ datasets:
layer: app:SGID93_LOCATION_UDOTMap_CityLocations
unesco_pois_italy:
type: collection
title: Unesco POIs in Italy via OGR WFS
description: Unesco Points of Interest in Italy. Using GeoSolutions GeoServer WFS demo-server as backend WFS.
keywords:
@@ -265,6 +268,7 @@ datasets:
layer: unesco:Unesco_point
ogr_gpkg_poi:
type: collection
title: Portuguese Points of Interest via OGR GPKG
description: Portuguese Points of Interest obtained from OpenStreetMap. Dataset includes Madeira and Azores islands. Uses GeoPackage backend via OGR provider.
keywords:
@@ -311,6 +315,7 @@ datasets:
sf_311incidents:
type: collection
title: SF 311Incidents via OGR ESRI Feature Server
description: OGR Provider - ESRI Feature Server - SF 311Incidents
keywords:
@@ -390,7 +395,7 @@ datasets:
time_field: data
layer: dpc-covid19-ita-regioni
processes:
hello-world:
type: process
processor:
name: HelloWorld
+4 -8
View File
@@ -246,7 +246,7 @@ def test_get_collection_queryables(config, api_):
assert len(queryables['queryables']) == 6
# test with provider filtered properties
api_.config['datasets']['obs']['provider']['properties'] = ['stn_id']
api_.config['resources']['obs']['provider']['properties'] = ['stn_id']
rsp_headers, code, response = api_.get_collection_queryables(
req_headers, {'f': 'json'}, 'obs')
@@ -480,7 +480,7 @@ def test_get_collection_items(config, api_):
rsp_headers, code, response = api_.get_collection_items(
req_headers, {'datetime': '2002/2014-04-22'}, 'obs')
api_.config['datasets']['obs']['extents'].pop('temporal')
api_.config['resources']['obs']['extents'].pop('temporal')
rsp_headers, code, response = api_.get_collection_items(
req_headers, {'datetime': '2002/2014-04-22'}, 'obs')
@@ -605,7 +605,7 @@ def test_describe_processes(config, api_):
assert len(process['outputTransmission']) == 1
assert len(process['jobControlOptions']) == 1
api_.config['processes'] = {}
api_.config['resources'] = {}
req_headers = make_req_headers()
rsp_headers, code, response = api_.describe_processes(
@@ -613,8 +613,6 @@ def test_describe_processes(config, api_):
processes = json.loads(response)
assert len(processes['processes']) == 0
api_.config.pop('processes')
req_headers = make_req_headers()
rsp_headers, code, response = api_.describe_processes(
req_headers, {}, 'foo')
@@ -645,7 +643,7 @@ def test_execute_process(config, api_):
assert response['outputs'][0]['value'] == 'test'
api_.config['processes'] = {}
api_.config['resources'] = {}
req_headers = make_req_headers()
rsp_headers, code, response = api_.execute_process(req_headers, {},
@@ -654,8 +652,6 @@ def test_execute_process(config, api_):
response = json.loads(response)
assert response['code'] == 'NotFound'
api_.config.pop('processes')
req_headers = make_req_headers()
rsp_headers, code, response = api_.execute_process(req_headers, {},
json.dumps(req_body),