Introduce OGRProvider: WFS backend support (#119)

* #89 fix check_format function

* #89 fix check_format function - fix default return

* geopython/pygeoapi#58 first version OGRProvider with working WFS tests/config

* geopython/pygeoapi#58 second version, ogr2ogr-like reprojection support - more to follow

* geopython/pygeoapi#58 3rd version, support Sourcetypes SHP and GPKG with tests+travis stuff

* geopython/pygeoapi#58 fixed geopython/pygeoapi#95 for OGR Provider and its tests

* geopython/pygeoapi#58 use more performant backend-WFS in pygeoapi-config.yml

* #58 4th version: WFS backend ok, including OGR Python paging gotchas fixed ready for PR

* #58 fix Travis build for GDAL Python bindings

* #58 fix Travis build: Unit tests failed: missing Shapefile .zip now added

* #58 #119 rework from PR comments: config, tests, quotes
This commit is contained in:
Just van den Broecke
2019-05-15 18:57:12 +02:00
committed by Tom Kralidis
parent 1a3f4eeb02
commit 4e5233f39d
16 changed files with 1721 additions and 10 deletions
+17 -10
View File
@@ -3,6 +3,12 @@ language: python
dist: xenial
sudo: false
env:
global:
- PYGEOAPI_CONFIG=pygeoapi-config.yml
- CPLUS_INCLUDE_PATH=/usr/include/gdal
- C_INCLUDE_PATH=/usr/include/gdal
python:
- "3.6"
- "3.7"
@@ -14,24 +20,25 @@ services:
addons:
postgresql: 9.6
before_install:
- sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable -y
- sudo apt-get -qq update
- sudo apt-get install -qq build-essential python3-dev python3-setuptools
- sudo apt-get install -y libsqlite3-mod-spatialite pandoc devscripts
- sudo apt-get install -y postgresql-9.6-postgis-2.4
- sudo apt-get install -y libgdal-dev gdal-bin
install:
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
- python setup.py install
# follow GDAL installed version for Python bindings
- pip3 install GDAL==`gdalinfo --version | cut -d' ' -f2 | cut -d',' -f1`
- pip3 install -r requirements.txt
- pip3 install -r requirements-dev.txt
- python3 setup.py install
env:
- PYGEOAPI_CONFIG=pygeoapi-config.yml
before_script:
- sleep 20
- python tests/load_es_data.py tests/data/ne_110m_populated_places_simple.geojson
- python3 tests/load_es_data.py tests/data/ne_110m_populated_places_simple.geojson
- pygeoapi generate-openapi-document -c pygeoapi-config.yml > pygeoapi-openapi.yml
- psql -U postgres -c 'create database test'
- psql -U postgres -d test -c 'create extension postgis'
@@ -40,8 +47,8 @@ before_script:
script:
- pytest --cov=pygeoapi
- find . -type f -name "*.py" | xargs flake8
- python setup.py --long-description | rst2html5.py
- python3 setup.py --long-description | rst2html5.py
after_success:
- python setup.py sdist bdist_wheel --universal
- python3 setup.py sdist bdist_wheel --universal
- debuild -b -uc -us
+47
View File
@@ -226,6 +226,53 @@ datasets:
id_field: osm_id
table: hotosm_bdi_waterways
dutch_georef_stations:
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:
- Netherlands
- GNSS
- Surveying
- Holland
- RD
crs:
- CRS84
links:
- type: text/html
rel: canonical
title: information
href: http://www.nationaalgeoregister.nl/geonetwork/srv/dut/catalog.search#/metadata/3ebe56dc-5f09-4fb3-b224-55c2db4ca2fd?tab=general
hreflang: nl-NL
extents:
spatial:
bbox: [50.7539, 7.21097, 53.4658, 3.37087]
temporal:
begin: None
end: now # or empty
provider:
name: OGR
data:
source_type: WFS
source: WFS:http://geodata.nationaalgeoregister.nl/rdinfo/wfs?
source_srs: EPSG:28992
target_srs: EPSG:4326
source_capabilities:
paging: True
source_options:
# OGR_WFS_VERSION: 1.1.0
OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN: NO
gdal_ogr_options:
EMPTY_AS_NULL: NO
GDAL_CACHEMAX: 64
# GDAL_HTTP_PROXY: (optional proxy)
# GDAL_PROXY_AUTH: (optional auth for remote WFS)
CPL_DEBUG: NO
id_field: gml_id
layer: rdinfo:stations
processes:
hello-world:
processor:
+1
View File
@@ -38,6 +38,7 @@ PLUGINS = {
'Elasticsearch': 'pygeoapi.provider.elasticsearch_.ElasticsearchProvider', # noqa
'GeoJSON': 'pygeoapi.provider.geojson.GeoJSONProvider',
'GeoPackage': 'pygeoapi.provider.geopackage.GeoPackageProvider',
'OGR': 'pygeoapi.provider.ogr.OGRProvider',
'PostgreSQL': 'pygeoapi.provider.postgresql.PostgreSQLProvider',
'SQLite': 'pygeoapi.provider.sqlite.SQLiteProvider'
},
+531
View File
@@ -0,0 +1,531 @@
# =================================================================
#
# Authors: Just van den Broecke <justb4@gmail.com>
#
# Copyright (c) 2019 Just van den Broecke
#
# 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
# 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 the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# 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
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
import importlib
import logging
from osgeo import gdal as osgeo_gdal
from osgeo import ogr as osgeo_ogr
from osgeo import osr as osgeo_osr
from pygeoapi.provider.base import (BaseProvider)
LOGGER = logging.getLogger(__name__)
class OGRProvider(BaseProvider):
"""OGR Provider"""
# To deal with some OGR Source-Driver specifics.
SOURCE_HELPERS = {
'WFS': 'pygeoapi.provider.ogr.WFSHelper',
'ESRI Shapefile': 'pygeoapi.provider.ogr.ShapefileHelper',
'ESRIJSON': 'pygeoapi.provider.ogr.ESRIJSONHelper',
'GPKG': 'pygeoapi.provider.ogr.GPKGHelper'
}
def __init__(self, provider_def):
"""
Initialize object
# Typical OGRProvider YAML config:
provider:
name: OGR
data:
source_type: WFS
source: WFS:http://geodata.nationaalgeoregister.nl/rdinfo/wfs?
source_srs: EPSG:28992
target_srs: EPSG:4326
source_capabilities:
paging: True
source_options:
OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN: NO
gdal_ogr_options:
EMPTY_AS_NULL: NO
GDAL_CACHEMAX: 64
# GDAL_HTTP_PROXY: (optional proxy)
# GDAL_PROXY_AUTH: (optional auth for remote WFS)
CPL_DEBUG: NO
id_field: gml_id
layer: rdinfo:stations
:param provider_def: provider definition
:returns: pygeoapi.providers.ogr.OGRProvider
"""
BaseProvider.__init__(self, provider_def)
self.ogr = osgeo_ogr
# http://trac.osgeo.org/gdal/wiki/PythonGotchas
self.gdal = osgeo_gdal
self.gdal.UseExceptions()
LOGGER.info("Using GDAL/OGR version: %d"
% int(osgeo_gdal.VersionInfo('VERSION_NUM')))
# GDAL error handler function
# http://pcjericks.github.io/py-gdalogr-cookbook/gdal_general.html
def gdal_error_handler(err_class, err_num, err_msg):
err_type = {
osgeo_gdal.CE_None: 'None',
osgeo_gdal.CE_Debug: 'Debug',
osgeo_gdal.CE_Warning: 'Warning',
osgeo_gdal.CE_Failure: 'Failure',
osgeo_gdal.CE_Fatal: 'Fatal'
}
err_msg = err_msg.replace('\n', ' ')
err_class = err_type.get(err_class, 'None')
LOGGER.error('Error Number: %s, Type: %s, Msg: %s'
% (err_num, err_class, err_msg))
# install error handler
self.gdal.PushErrorHandler(gdal_error_handler)
LOGGER.debug('Setting OGR properties')
self.data_def = provider_def['data']
# Generic GDAL/OGR options (optional)
gdal_ogr_options = self.data_def.get('gdal_ogr_options', {})
for key in gdal_ogr_options:
self.gdal.SetConfigOption(key, str(gdal_ogr_options[key]))
# Driver-specific options (optional)
source_options = self.data_def.get('source_options', {})
for key in source_options:
self.gdal.SetConfigOption(key, str(source_options[key]))
self.source_capabilities = self.data_def.get('source_capabilities',
{'paging': False})
self.source_srs = int(self.data_def.get('source_srs',
'EPSG:4326').split(':')[1])
self.target_srs = int(self.data_def.get('target_srs',
'EPSG:4326').split(':')[1])
# Optional coordinate transformation inward (requests) and
# outward (responses) when the source layers and WFS3 collections
# differ in EPSG-codes.
self.transform_in = None
self.transform_out = None
if self.source_srs != self.target_srs:
source = osgeo_osr.SpatialReference()
source.ImportFromEPSG(self.source_srs)
target = osgeo_osr.SpatialReference()
target.ImportFromEPSG(self.target_srs)
self.transform_in = \
osgeo_osr.CoordinateTransformation(target, source)
self.transform_out = \
osgeo_osr.CoordinateTransformation(source, target)
self._load_source_helper(self.data_def['source_type'])
# Init
self.driver = None
self.conn = None
self.layer_name = provider_def.get('layer', None)
def _open(self):
source_type = self.data_def['source_type']
self.driver = self.ogr.GetDriverByName(source_type)
if not self.driver:
msg = 'No Driver for Source: {}'.format(source_type)
LOGGER.error(msg)
raise Exception(msg)
self.conn = self.driver.Open(self.data_def['source'], 0)
if not self.conn:
msg = 'Cannot open OGR Source: %s' % self.data_def['source']
LOGGER.error(msg)
raise Exception(msg)
# Always need to disable paging immediately after Open!
if self.source_capabilities['paging']:
self.source_helper.disable_paging()
def _close(self):
self.conn = None
LOGGER.debug('closed self.conn')
self.driver = None
def _get_layer(self):
if not self.conn:
self._open()
if not self.layer_name:
# E.g. Shapefiles may not have explicitly named Layers
layer = self.conn.GetLayer(0)
else:
layer = self.conn.GetLayerByName(self.layer_name)
if not layer:
msg = 'Cannot get Layer {} from OGR Source'.format(self.layer_name)
LOGGER.error(msg)
raise Exception(msg)
return layer
def get_fields(self):
"""
Get provider field information (names, types)
:returns: dict of fields
"""
fields = {}
try:
layer_defn = self._get_layer().GetLayerDefn()
for fld in range(layer_defn.GetFieldCount()):
field_defn = layer_defn.GetFieldDefn(fld)
fieldName = field_defn.GetName()
fieldTypeCode = field_defn.GetType()
fieldType = field_defn.GetFieldTypeName(fieldTypeCode)
fields[fieldName] = fieldType.lower()
# fieldWidth = layer_defn.GetFieldDefn(fld).GetWidth()
# GetPrecision = layer_defn.GetFieldDefn(fld).GetPrecision()
except Exception as err:
LOGGER.error(err)
finally:
self._close()
return fields
def query(self, startindex=0, limit=10, resulttype='results',
bbox=[], time=None, properties=[], sortby=[]):
"""
Query OGR source
:param startindex: starting record to return (default 0)
:param limit: number of records to return (default 10)
:param resulttype: return results or hit limit (default results)
:param bbox: bounding box [minx,miny,maxx,maxy]
:param time: temporal (datestamp or extent)
:param properties: list of tuples (name, value)
:param sortby: list of dicts (property, order)
:returns: dict of 0..n GeoJSON features
"""
result = None
try:
if self.source_capabilities['paging']:
self.source_helper.enable_paging(startindex, limit)
layer = self._get_layer()
if bbox:
LOGGER.debug('processing bbox parameter')
minx, miny, maxx, maxy = bbox
wkt = "POLYGON (({minx} {miny},{minx} {maxy},{maxx} {maxy}," \
"{maxx} {miny},{minx} {miny}))".format(
minx=float(minx), miny=float(miny),
maxx=float(maxx), maxy=float(maxy))
polygon = self.ogr.CreateGeometryFromWkt(wkt)
if self.transform_in:
polygon.Transform(self.transform_in)
layer.SetSpatialFilter(polygon)
# layer.SetSpatialFilterRect(
# float(minx), float(miny), float(maxx), float(maxy))
if resulttype == 'hits':
LOGGER.debug('hits only specified')
result = self._response_feature_hits(layer)
elif resulttype == 'results':
LOGGER.debug('results specified')
result = self._response_feature_collection(layer, limit)
else:
LOGGER.error('Invalid resulttype: %s' % resulttype)
except Exception as err:
LOGGER.error(err)
finally:
self._close()
return result
def get(self, identifier):
"""
Get Feature by id
:param identifier: feature id
:returns: feature collection
"""
result = None
try:
LOGGER.debug('Fetching identifier {}'.format(identifier))
layer = self._get_layer()
layer.SetAttributeFilter("{field} = '{id}'".format(
field=self.id_field, id=identifier))
ogr_feature = layer.GetNextFeature()
result = self._ogr_feature_to_json(ogr_feature)
except Exception as err:
LOGGER.error(err)
finally:
self._close()
return result
def __repr__(self):
return '<OGRProvider> {}'.format(self.data)
def _load_source_helper(self, source_type):
"""
Loads Source Helper by name.
:param Source type: Source type name
:returns: Source Helper object
"""
if source_type not in OGRProvider.SOURCE_HELPERS.keys():
msg = 'No Helper found for OGR Source type: {}'.format(source_type)
LOGGER.exception(msg)
raise InvalidHelperError(msg)
# Create object from full package.class name string.
source_helper_class = OGRProvider.SOURCE_HELPERS[source_type]
packagename, classname = source_helper_class.rsplit('.', 1)
module = importlib.import_module(packagename)
class_ = getattr(module, classname)
self.source_helper = class_(self)
def _ogr_feature_to_json(self, ogr_feature):
geom = ogr_feature.GetGeometryRef()
if self.transform_out:
# Optionally reproject the geometry
geom.Transform(self.transform_out)
json_feature = ogr_feature.ExportToJson(as_object=True)
json_feature['id'] = json_feature['properties'].pop(self.id_field)
return json_feature
def _response_feature_collection(self, layer, limit):
"""
Assembles output from Layer query as
GeoJSON FeatureCollection structure.
:returns: GeoJSON FeatureCollection
"""
feature_collection = {
'type': 'FeatureCollection',
'features': []
}
# See https://github.com/OSGeo/gdal/blob/master/autotest/
# ogr/ogr_wfs.py#L313
layer.ResetReading()
ogr_feature = layer.GetNextFeature()
count = 0
while ogr_feature is not None:
json_feature = self._ogr_feature_to_json(ogr_feature)
feature_collection['features'].append(json_feature)
count += 1
if count == limit:
break
ogr_feature = layer.GetNextFeature()
return feature_collection
def _response_feature_hits(self, layer):
"""
Assembles GeoJSON hits from OGR Feature count
e.g: http://localhost:5000/collections/
hotosm_bdi_waterways/items?resulttype=hits
:returns: GeoJSON FeaturesCollection
"""
return {
'type': 'FeatureCollection',
'numberMatched': layer.GetFeatureCount(),
'features': []
}
class InvalidHelperError(Exception):
"""Invalid helper"""
pass
class SourceHelper:
def __init__(self, provider):
"""
Initialize object
:param provider: provider instance
:returns: pygeoapi.providers.ogr.SourceHelper
"""
self.provider = provider
def enable_paging(self, startindex=-1, limit=-1):
"""
Enable paged access to dataset (OGR Driver-specific)
"""
pass
def disable_paging(self):
"""
Disable paged access to dataset (OGR Driver-specific)
"""
pass
class GPKGHelper(SourceHelper):
def __init__(self, provider):
"""
Initialize object
:param provider: provider instance
:returns: pygeoapi.providers.ogr.SourceHelper
"""
self.provider = provider
SourceHelper.__init__(self, provider)
class ShapefileHelper(SourceHelper):
def __init__(self, provider):
"""
Initialize object
:param provider: provider instance
:returns: pygeoapi.providers.ogr.SourceHelper
"""
self.provider = provider
SourceHelper.__init__(self, provider)
class ESRIJSONHelper(SourceHelper):
def __init__(self, provider):
"""
Initialize object
:param provider: provider instance
:returns: pygeoapi.providers.ogr.SourceHelper
"""
self.provider = provider
SourceHelper.__init__(self, provider)
def enable_paging(self, startindex=-1, limit=-1):
"""
Enable paged access to dataset (OGR Driver-specific)
"""
if startindex < 0:
return
self.provider.gdal.SetConfigOption(
'ESRIJSON_FEATURE_SERVER_PAGING', 'ON')
self.provider.gdal.SetConfigOption(
'OGR_ESRIJSON_START_INDEX', str(startindex))
self.provider.gdal.SetConfigOption(
'OGR_ESRIJSON_PAGE_SIZE', str(limit))
def disable_paging(self):
"""
Disable paged access to dataset (OGR Driver-specific)
"""
self.provider.gdal.SetConfigOption(
'ESRIJSON_FEATURE_SERVER_PAGING', None)
self.provider.gdal.SetConfigOption(
'OGR_ESRIJSON_PAGE_SIZE', None)
class WFSHelper(SourceHelper):
def __init__(self, provider):
"""
Initialize object
:param provider: provider instance
:returns: pygeoapi.providers.ogr.SourceHelper
"""
self.provider = provider
SourceHelper.__init__(self, provider)
def enable_paging(self, startindex=-1, limit=-1):
"""
Enable paged access to dataset (OGR Driver-specific)
"""
if startindex < 0:
return
self.provider.gdal.SetConfigOption(
'OGR_WFS_PAGING_ALLOWED', 'ON')
self.provider.gdal.SetConfigOption(
'OGR_WFS_BASE_START_INDEX', str(startindex))
self.provider.gdal.SetConfigOption(
'OGR_WFS_PAGE_SIZE', str(limit))
def disable_paging(self):
"""
Disable paged access to dataset (OGR Driver-specific)
"""
self.provider.gdal.SetConfigOption(
'OGR_WFS_PAGING_ALLOWED', None)
self.provider.gdal.SetConfigOption(
'OGR_WFS_PAGE_SIZE', None)
+1
View File
@@ -15,3 +15,4 @@ pytest-env
pyOpenSSL==17.5.0
ndg-httpsclient==0.4.4
pyasn1==0.4.2
GDAL>=2.2
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
+328
View File
@@ -0,0 +1,328 @@
server:
bind:
host: 0.0.0.0
port: 5000
url: http://localhost:5000/
mimetype: application/json; charset=UTF-8
encoding: utf-8
language: en-US
cors: true
pretty_print: true
limit: 10
# templates: /path/to/templates
logging:
level: ERROR
#logfile: /tmp/pygeoapi.log
metadata:
identification:
title: pygeoapi default instance
description: pygeoapi provides an API to geospatial data
keywords:
- geospatial
- data
- api
keywords_type: theme
terms_of_service: None
url: http://example.org
license:
name: CC-BY 4.0 license
url: https://creativecommons.org/licenses/by/4.0/
provider:
name: Organization Name
url: https://pygeoapi.io
contact:
name: Lastname, Firstname
position: Position Title
address: Mailing Address
city: City
stateorprovince: Administrative Area
postalcode: Zip or Postal Code
country: Country
phone: +xx-xxx-xxx-xxxx
fax: +xx-xxx-xxx-xxxx
email: you@example.org
url: Contact URL
hours: Hours of Service
instructions: During hours of service. Off on weekends.
role: pointOfContact
datasets:
dutch_georef_stations:
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:
- Netherlands
- GNSS
- Surveying
- Holland
- RD
crs:
- CRS84
links:
- type: text/html
rel: canonical
title: information
href: http://www.nationaalgeoregister.nl/geonetwork/srv/dut/catalog.search#/metadata/3ebe56dc-5f09-4fb3-b224-55c2db4ca2fd?tab=general
hreflang: nl-NL
extents:
spatial:
bbox: [50.7539, 7.21097, 53.4658, 3.37087]
temporal:
begin: None
end: now # or empty
provider:
name: OGR
data:
source_type: WFS
source: WFS:http://geodata.nationaalgeoregister.nl/rdinfo/wfs?
source_srs: EPSG:28992
target_srs: EPSG:4326
source_capabilities:
paging: True
source_options:
# OGR_WFS_VERSION: 1.1.0
OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN: NO
gdal_ogr_options:
EMPTY_AS_NULL: NO
GDAL_CACHEMAX: 64
# GDAL_HTTP_PROXY: (optional proxy)
# GDAL_PROXY_AUTH: (optional auth for remote WFS)
CPL_DEBUG: NO
id_field: gml_id
layer: rdinfo:stations
# Warning: this layer contains about 10 million addresses, the backend WFS seems not optimized
dutch_addresses:
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:
- Netherlands
- Addresses
- Europe
- Holland
- BAG
crs:
- CRS84
links:
- type: text/html
rel: canonical
title: information
href: http://www.nationaalgeoregister.nl/geonetwork/srv/dut/catalog.search#/metadata/3a97fbe4-2b0d-4e9c-9644-276883400dd7
hreflang: nl-NL
extents:
spatial:
bbox: [50.7539, 7.21097, 53.4658, 3.37087]
temporal:
begin: None
end: now # or empty
provider:
name: OGR
data:
source_type: WFS
source: WFS:http://geodata.nationaalgeoregister.nl/inspireadressen/wfs?
source_srs: EPSG:28992
target_srs: EPSG:4326
source_capabilities:
paging: True
source_options:
# OGR_WFS_VERSION: 2.0.0
OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN: NO
gdal_ogr_options:
EMPTY_AS_NULL: NO
GDAL_CACHEMAX: 64
# GDAL_HTTP_PROXY: (optional proxy)
# GDAL_PROXY_AUTH: (optional auth for remote WFS)
CPL_DEBUG: NO
id_field: gml_id
layer: inspireadressen:inspireadressen
utah_city_locations:
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:
- USA
- deegree
- Utah
- Demo data
crs:
- CRS84
links:
- type: text/html
rel: canonical
title: information
href: http://download.deegree.org/documentation/3.3.20/html/lightly.html#example-workspace-2-utah-webmapping-services
hreflang: en-US
extents:
spatial:
bbox: [-112.108489, 39.854053, -111.028628, 40.460098]
temporal:
begin: None
end: now # or empty
provider:
name: OGR
data:
source_type: WFS
source: WFS:http://demo.deegree.org/utah-workspace/services/wfs?TYPENAME=app:SGID93_LOCATION_UDOTMap_CityLocations
source_srs: EPSG:26912
target_srs: EPSG:4326
source_capabilities:
paging: True
source_options:
# OGR_WFS_VERSION: 2.0.0
OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN: NO
gdal_ogr_options:
EMPTY_AS_NULL: NO
GDAL_CACHEMAX: 64
# GDAL_HTTP_PROXY: (optional proxy)
# GDAL_PROXY_AUTH: (optional auth for remote WFS)
CPL_DEBUG: NO
id_field: NAME
layer: app:SGID93_LOCATION_UDOTMap_CityLocations
unesco_pois_italy:
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:
- Italy
- Unesco
- Demo
crs:
- CRS84
links:
- type: text/html
rel: canonical
title: information
href: https://mapstore2.geo-solutions.it/mapstore/#/dashboard/5593
hreflang: en-US
extents:
spatial:
bbox: [36.0, 17.0, 46.0, 18.0]
temporal:
begin: None
end: now # or empty
provider:
name: OGR
data:
source_type: WFS
source: WFS:https://demo.geo-solutions.it/geoserver/wfs
source_srs: EPSG:32632
target_srs: EPSG:4326
source_capabilities:
paging: True
source_options:
# OGR_WFS_VERSION: 1.1.0
OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN: NO
gdal_ogr_options:
EMPTY_AS_NULL: NO
GDAL_CACHEMAX: 64
# GDAL_HTTP_PROXY: (optional proxy)
# GDAL_PROXY_AUTH: (optional auth for remote WFS)
CPL_DEBUG: NO
id_field: gml_id
layer: unesco:Unesco_point
ogr_gpkg_poi:
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:
- Portugal
- POI
- Point of Interrest
- Madeira
- Azores
- OSM
- Open Street Map
- NaturaGIS
crs:
- CRS84
links:
- type: text/html
rel: canonical
title: information
href: https://wiki.openstreetmap.org/wiki/Points_of_interest/
hreflang: en-US
extents:
spatial:
bbox: [-31.2687 32.5898 -6.18992 42.152]
temporal:
begin: None
end: now # or empty
provider:
name: OGR
data:
source_type: GPKG
source: tests/data/poi_portugal.gpkg
source_srs: EPSG:4326
target_srs: EPSG:4326
source_capabilities:
paging: True
gdal_ogr_options:
EMPTY_AS_NULL: NO
GDAL_CACHEMAX: 64
# GDAL_HTTP_PROXY: (optional proxy)
# GDAL_PROXY_AUTH: (optional auth for remote WFS)
CPL_DEBUG: NO
id_field: osm_id
layer: poi_portugal
sf_311incidents:
title: SF 311Incidents via OGR ESRI Feature Server
description: OGR Provider - ESRI Feature Server - SF 311Incidents
keywords:
- USA
- ESRI
crs:
- CRS84
links:
- type: text/html
rel: canonical
title: information
href: http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0
hreflang: en-US
extents:
spatial:
bbox: [-180, -90, 180, 90]
temporal:
begin: None
end: now # or empty
provider:
name: OGR
data:
source_type: ESRIJSON
source: ESRIJSON:http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0/query?where=objectid+%3D+objectid&outfields=*&f=json
source_srs: EPSG:4326
target_srs: EPSG:4326
source_capabilities:
paging: True
gdal_ogr_options:
EMPTY_AS_NULL: NO
GDAL_CACHEMAX: 64
# GDAL_HTTP_PROXY: (optional proxy)
# GDAL_PROXY_AUTH: (optional auth for remote WFS)
CPL_DEBUG: NO
id_field: objectid
processes:
hello-world:
processor:
name: HelloWorld
+251
View File
@@ -0,0 +1,251 @@
# Needs to be run like: python3 -m pytest
import logging
import pytest
from pygeoapi.provider.ogr import OGRProvider
LOGGER = logging.getLogger(__name__)
@pytest.fixture()
def config_poi_portugal():
return {
'name': 'OGR',
'data': {
'source_type': 'GPKG',
'source': './tests/data/poi_portugal.gpkg',
'source_srs': 'EPSG:4326',
'target_srs': 'EPSG:4326',
'source_capabilities': {
'paging': True
},
},
'id_field': 'osm_id',
'layer': 'poi_portugal'
}
def test_query(config_poi_portugal):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_poi_portugal)
feature_collection = p.query()
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert features is not None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
def test_get(config_poi_portugal):
p = OGRProvider(config_poi_portugal)
result = p.get(5156778016)
assert result['id'] == 5156778016
assert 'tourist_info' in result['properties']['fclass']
# Testing with GeoPackage files with identical features
# (all 2481 addresses in Otterlo Netherlands)
# in different projections.
@pytest.fixture()
def config_gpkg_4326():
return {
'name': 'OGR',
'data': {
'source_type': 'GPKG',
'source':
'./tests/data/dutch_addresses_4326.gpkg',
'source_srs': 'EPSG:4326',
'target_srs': 'EPSG:4326',
'source_capabilities': {
'paging': True
},
},
'id_field': 'id'
}
# Note that this Shapefile is zipped, as OGR supports /vsizip/!
@pytest.fixture()
def config_gpkg_28992():
return {
'name': 'OGR',
'data': {
'source_type': 'GPKG',
'source':
'./tests/data/dutch_addresses_28992.gpkg',
'source_srs': 'EPSG:28992',
'target_srs': 'EPSG:4326',
'source_capabilities': {
'paging': True
},
},
'id_field': 'id'
}
def test_get_fields_4326(config_gpkg_4326):
"""Testing field types"""
p = OGRProvider(config_gpkg_4326)
results = p.get_fields()
assert results['straatnaam'] == 'string'
assert results['huisnummer'] == 'string'
def test_get_28992(config_gpkg_28992):
"""Testing query for a specific object"""
p = OGRProvider(config_gpkg_28992)
result = p.get('inspireadressen.1747652')
assert result['id'] == 'inspireadressen.1747652'
assert 'Mosselsepad' in result['properties']['straatnaam']
def test_get_4326(config_gpkg_4326):
"""Testing query for a specific object"""
p = OGRProvider(config_gpkg_4326)
result = p.get('inspireadressen.1747652')
assert result['id'] == 'inspireadressen.1747652'
assert 'Mosselsepad' in result['properties']['straatnaam']
def test_query_hits_28992(config_gpkg_28992):
"""Testing query on entire collection for hits"""
p = OGRProvider(config_gpkg_28992)
feature_collection = p.query(resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
assert hits == 2481
def test_query_hits_4326(config_gpkg_4326):
"""Testing query on entire collection for hits"""
p = OGRProvider(config_gpkg_4326)
feature_collection = p.query(resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
assert hits == 2481
def test_query_bbox_hits_4326(config_gpkg_4326):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_gpkg_4326)
# feature_collection = p.query(
# bbox=[120000, 480000, 124000, 487000], resulttype='hits')
feature_collection = p.query(
bbox=[5.763409, 52.060197, 5.769256, 52.061976], resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
print('hits={}'.format(hits))
assert hits is 1
def test_query_bbox_hits_28992(config_gpkg_28992):
"""Testing query for a valid JSON object with geometry, single address"""
p = OGRProvider(config_gpkg_28992)
# feature_collection = p.query(
# bbox=(180800, 452500, 181200, 452700), resulttype='hits')
feature_collection = p.query(
bbox=[5.763409, 52.060197, 5.769256, 52.061976], resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
print('hits={}'.format(hits))
assert hits is 1
def test_query_bbox_28992(config_gpkg_28992):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_gpkg_28992)
# feature_collection = p.query(
# bbox=[180800, 452500, 181200, 452700], resulttype='results')
feature_collection = p.query(
bbox=(5.763409, 52.060197, 5.769256, 52.061976), resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 1
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
assert properties['straatnaam'] == 'Planken Wambuisweg'
def test_query_bbox_4326(config_gpkg_4326):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_gpkg_4326)
# feature_collection = p.query(
# bbox=[180800, 452500, 181200, 452700], resulttype='results')
feature_collection = p.query(
bbox=(5.763409, 52.060197, 5.769256, 52.061976), resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 1
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
assert properties['straatnaam'] == 'Planken Wambuisweg'
def test_query_with_limit_28992(config_gpkg_28992):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_gpkg_28992)
feature_collection = p.query(limit=2, resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 2
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
def test_query_with_limit_4326(config_gpkg_4326):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_gpkg_4326)
feature_collection = p.query(limit=5, resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 5
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
+209
View File
@@ -0,0 +1,209 @@
# Needs to be run like: python3 -m pytest
import logging
import pytest
from pygeoapi.provider.ogr import OGRProvider
LOGGER = logging.getLogger(__name__)
# Testing with Shapefiles with identical features
# (all 2481 addresses in Otterlo Netherlands)
# in different projections.
@pytest.fixture()
def config_shapefile_4326():
return {
'name': 'OGR',
'data': {
'source_type': 'ESRI Shapefile',
'source':
'./tests/data/dutch_addresses_shape_4326/inspireadressen.shp',
'source_capabilities': {
'paging': True
},
},
'id_field': 'id'
}
# Note that this Shapefile is zipped, as OGR supports /vsizip/!
@pytest.fixture()
def config_shapefile_28992():
return {
'name': 'OGR',
'data': {
'source_type': 'ESRI Shapefile',
'source':
'/vsizip/./tests/data/dutch_addresses_shape_28992.zip',
'source_srs': 'EPSG:28992',
'target_srs': 'EPSG:4326',
'source_capabilities': {
'paging': True
},
},
'id_field': 'id'
}
def test_get_fields_4326(config_shapefile_4326):
"""Testing field types"""
p = OGRProvider(config_shapefile_4326)
results = p.get_fields()
assert results['straatnaam'] == 'string'
assert results['huisnummer'] == 'string'
def test_get_28992(config_shapefile_28992):
"""Testing query for a specific object"""
p = OGRProvider(config_shapefile_28992)
result = p.get('inspireadressen.1747652')
assert result['id'] == 'inspireadressen.1747652'
assert 'Mosselsepad' in result['properties']['straatnaam']
def test_get_4326(config_shapefile_4326):
"""Testing query for a specific object"""
p = OGRProvider(config_shapefile_4326)
result = p.get('inspireadressen.1747652')
assert result['id'] == 'inspireadressen.1747652'
assert 'Mosselsepad' in result['properties']['straatnaam']
def test_query_hits_28992(config_shapefile_28992):
"""Testing query on entire collection for hits"""
p = OGRProvider(config_shapefile_28992)
feature_collection = p.query(resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
assert hits == 2481
def test_query_hits_4326(config_shapefile_4326):
"""Testing query on entire collection for hits"""
p = OGRProvider(config_shapefile_4326)
feature_collection = p.query(resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
assert hits == 2481
def test_query_bbox_hits_4326(config_shapefile_4326):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_shapefile_4326)
# feature_collection = p.query(
# bbox=[120000, 480000, 124000, 487000], resulttype='hits')
feature_collection = p.query(
bbox=[5.763409, 52.060197, 5.769256, 52.061976], resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
print('hits={}'.format(hits))
assert hits is 1
def test_query_bbox_hits_28992(config_shapefile_28992):
"""Testing query for a valid JSON object with geometry, single address"""
p = OGRProvider(config_shapefile_28992)
# feature_collection = p.query(
# bbox=(180800, 452500, 181200, 452700), resulttype='hits')
feature_collection = p.query(
bbox=[5.763409, 52.060197, 5.769256, 52.061976], resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
print('hits={}'.format(hits))
assert hits is 1
def test_query_bbox_28992(config_shapefile_28992):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_shapefile_28992)
# feature_collection = p.query(
# bbox=[180800, 452500, 181200, 452700], resulttype='results')
feature_collection = p.query(
bbox=(5.763409, 52.060197, 5.769256, 52.061976), resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 1
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
assert properties['straatnaam'] == 'Planken Wambuisweg'
def test_query_bbox_4326(config_shapefile_4326):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_shapefile_4326)
# feature_collection = p.query(
# bbox=[180800, 452500, 181200, 452700], resulttype='results')
feature_collection = p.query(
bbox=(5.763409, 52.060197, 5.769256, 52.061976), resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 1
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
assert properties['straatnaam'] == 'Planken Wambuisweg'
def test_query_with_limit_28992(config_shapefile_28992):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_shapefile_28992)
feature_collection = p.query(limit=2, resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 2
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
def test_query_with_limit_4326(config_shapefile_4326):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_shapefile_4326)
feature_collection = p.query(limit=5, resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 5
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
+335
View File
@@ -0,0 +1,335 @@
# Needs to be run like: python3 -m pytest
import logging
import pytest
from pygeoapi.provider.ogr import OGRProvider
LOGGER = logging.getLogger(__name__)
@pytest.fixture()
def config_MapServer_WFS():
return {
'name': 'OGR',
'data': {
'source_type': 'WFS',
'source': 'WFS:http://geodata.nationaalgeoregister.nl/rdinfo/wfs?',
'source_srs': 'EPSG:28992',
'target_srs': 'EPSG:4326',
'source_capabilities': {
'paging': True
},
'source_options': {
'OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN': 'NO'
},
'gdal_ogr_options': {
'GDAL_CACHEMAX': '64',
# 'GDAL_HTTP_PROXY': (optional proxy)
# 'GDAL_PROXY_AUTH': (optional auth for remote WFS)
'CPL_DEBUG': 'NO'
},
},
'id_field': 'gml_id',
'layer': 'rdinfo:stations'
}
@pytest.fixture()
def config_GeoServer_WFS():
return {
'name': 'OGR',
'data': {
'source_type': 'WFS',
'source':
'WFS:https://geodata.nationaalgeoregister.nl'
+ '/inspireadressen/wfs?',
'source_srs': 'EPSG:28992',
'target_srs': 'EPSG:28992',
'source_capabilities': {
'paging': True
},
'source_options': {
'OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN': 'NO'
},
'gdal_ogr_options': {
'GDAL_CACHEMAX': '64',
# 'GDAL_HTTP_PROXY': (optional proxy)
# 'GDAL_PROXY_AUTH': (optional auth for remote WFS)
'CPL_DEBUG': 'NO'
},
},
'id_field': 'gml_id',
'layer': 'inspireadressen:inspireadressen'
}
@pytest.fixture()
def config_geosol_gs_WFS():
return {
'name': 'OGR',
'data': {
'source_type': 'WFS',
'source':
'WFS:https://demo.geo-solutions.it/geoserver/wfs?',
'source_srs': 'EPSG:32632',
'target_srs': 'EPSG:4326',
'source_capabilities': {
'paging': True
},
'source_options': {
'OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN': 'NO'
},
'gdal_ogr_options': {
'GDAL_CACHEMAX': '64',
# 'GDAL_HTTP_PROXY': (optional proxy)
# 'GDAL_PROXY_AUTH': (optional auth for remote WFS)
'CPL_DEBUG': 'NO'
},
},
'id_field': 'gml_id',
'layer': 'unesco:Unesco_point'
}
def test_get_fields_gs(config_GeoServer_WFS):
"""Testing field types"""
p = OGRProvider(config_GeoServer_WFS)
results = p.get_fields()
assert results['straatnaam'] == 'string'
assert results['huisnummer'] == 'integer'
def test_get_ms(config_MapServer_WFS):
"""Testing query for a specific object"""
p = OGRProvider(config_MapServer_WFS)
result = p.get('stations.4403')
assert result['id'] == 'stations.4403'
assert '01' in result['properties']['station']
def test_get_geosol_gs(config_geosol_gs_WFS):
"""Testing query for a specific object"""
p = OGRProvider(config_geosol_gs_WFS)
result = p.get('Unesco_point.123')
assert result['id'] == 'Unesco_point.123'
assert 'Centro storico di San Gimignano' in result['properties']['sito']
def test_get_gs(config_GeoServer_WFS):
"""Testing query for a specific object"""
p = OGRProvider(config_GeoServer_WFS)
result = p.get('inspireadressen.1747652')
assert result['id'] == 'inspireadressen.1747652'
assert 'Mosselsepad' in result['properties']['straatnaam']
def test_query_hits_ms(config_MapServer_WFS):
"""Testing query on entire collection for hits"""
p = OGRProvider(config_MapServer_WFS)
feature_collection = p.query(resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
assert hits > 5000
def test_query_hits_geosol_gs(config_geosol_gs_WFS):
"""Testing query on entire collection for hits"""
p = OGRProvider(config_geosol_gs_WFS)
feature_collection = p.query(resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
assert hits == 186
# OK, but backend WFS takes too much time....
# def test_query_hits_gs(config_GeoServer_WFS):
# """Testing query on entire collection for hits"""
#
# p = OGRProvider(config_GeoServer_WFS)
# feature_collection = p.query(resulttype='hits')
# assert feature_collection.get('type', None) == 'FeatureCollection'
# features = feature_collection.get('features', None)
# assert len(features) is 0
# hits = feature_collection.get('numberMatched', None)
# assert hits is not None
# assert hits > 8000000
def test_query_bbox_hits_ms(config_MapServer_WFS):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_MapServer_WFS)
# feature_collection = p.query(
# bbox=[120000, 480000, 124000, 487000], resulttype='hits')
feature_collection = p.query(
bbox=[4.874016, 52.306852, 4.932020, 52.370004], resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
print('hits={}'.format(hits))
assert hits > 1
def test_query_bbox_hits_gs(config_GeoServer_WFS):
"""Testing query for a valid JSON object with geometry, single address"""
p = OGRProvider(config_GeoServer_WFS)
feature_collection = p.query(
bbox=(180800, 452500, 181200, 452700), resulttype='hits')
# feature_collection = p.query(bbox=(
# 5.763409, 52.060197, 5.769256, 52.061976), resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
print('hits={}'.format(hits))
assert hits is 1
def test_query_bbox_hits_geosol_gs(config_geosol_gs_WFS):
"""Testing query for a valid JSON object with geometry, single address"""
p = OGRProvider(config_geosol_gs_WFS)
feature_collection = p.query(
bbox=(681417.0, 4849032.0, 681417.3, 4849032.3), resulttype='hits')
# feature_collection = p.query(bbox=(
# 5.763409, 52.060197, 5.769256, 52.061976), resulttype='hits')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) is 0
hits = feature_collection.get('numberMatched', None)
assert hits is not None
print('hits={}'.format(hits))
assert hits is 1
def test_query_bbox_ms(config_MapServer_WFS):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_MapServer_WFS)
# feature_collection = p.query(
# bbox=[120000, 480000, 124000, 487000], resulttype='results')
feature_collection = p.query(
bbox=[4.874016, 52.306852, 4.932020, 52.370004], resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) > 0
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
def test_query_bbox_gs(config_GeoServer_WFS):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_GeoServer_WFS)
feature_collection = p.query(
bbox=[180800, 452500, 181200, 452700], resulttype='results')
# feature_collection = p.query(
# bbox=(5.763409, 52.060197, 5.769256, 52.061976), resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 1
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
assert properties['straatnaam'] == 'Planken Wambuisweg'
def test_query_bbox_geosol_gs(config_geosol_gs_WFS):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_geosol_gs_WFS)
# feature_collection = p.query(
# bbox=[120000, 480000, 124000, 487000], resulttype='results')
feature_collection = p.query(
bbox=(681417.0, 4849032.0, 681417.3, 4849032.3),
resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 1
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
assert properties['sito'] == 'Centro storico di Firenze'
geometry = feature.get('geometry', None)
assert geometry is not None
def test_query_with_limit_ms(config_MapServer_WFS):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_MapServer_WFS)
feature_collection = p.query(limit=2, resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 2
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
geometry = feature.get('geometry', None)
assert geometry is not None
def test_query_with_startindex(config_MapServer_WFS):
"""Testing query for a valid JSON object with geometry"""
p = OGRProvider(config_MapServer_WFS)
feature_collection = p.query(startindex=20, limit=5, resulttype='results')
assert feature_collection.get('type', None) == 'FeatureCollection'
features = feature_collection.get('features', None)
assert len(features) == 5
hits = feature_collection.get('numberMatched', None)
assert hits is None
feature = features[0]
properties = feature.get('properties', None)
assert properties is not None
assert feature['id'] == 'stations.21'
assert '101696.68' in properties['xrd']
geometry = feature.get('geometry', None)
assert geometry is not None
#
# # OK, but backend GeoServer PDOK WFS takes too much time....
# # def test_query_with_limit_gs(config_GeoServer_WFS):
# #
# # p = OGRProvider(config_GeoServer_WFS)
# # feature_collection = p.query(limit=5, resulttype='results')
# # assert feature_collection.get('type', None) == 'FeatureCollection'
# # features = feature_collection.get('features', None)
# # assert len(features) == 5
# # hits = feature_collection.get('numberMatched', None)
# # assert hits is None
# # feature = features[0]
# # properties = feature.get('properties', None)
# # assert properties is not None
# # geometry = feature.get('geometry', None)
# # assert geometry is not None