Skip to content

Commit 40c8fe0

Browse files
authored
Merge branch 'geopython:master' into deploy
2 parents 3a2a4ef + bc76849 commit 40c8fe0

97 files changed

Lines changed: 1993 additions & 990 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/main.yml

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ jobs:
124124
pip3 install -r requirements-django.txt
125125
python3 setup.py install
126126
pip3 install --global-option=build_ext --global-option="-I/usr/include/gdal" GDAL==`gdal-config --version`
127-
#pip3 install --upgrade rasterio==1.1.8
128127
- name: setup test data ⚙️
129128
run: |
130129
python3 tests/load_es_data.py tests/data/ne_110m_populated_places_simple.geojson geonameid
@@ -137,50 +136,20 @@ jobs:
137136
mysql -h 127.0.0.1 -P 3306 -u root -p'mysql' test_geo_app < tests/data/mysql_data.sql
138137
docker ps
139138
python3 tests/load_oracle_data.py
140-
- name: run unit tests ⚙️
139+
- name: run API tests ⚙️
140+
run: pytest tests/api --ignore-glob='*_live.py'
141+
- name: run Formatter tests ⚙️
142+
run: pytest tests/formatter
143+
- name: run Provider tests ⚙️
141144
env:
142145
POSTGRESQL_PASSWORD: ${{ secrets.DatabasePassword || 'postgres' }}
143-
run: |
144-
pytest tests/api
145-
pytest tests/test_api_ogr_provider.py
146-
pytest tests/test_base_provider.py
147-
pytest tests/test_config.py
148-
pytest tests/test_csv__formatter.py
149-
pytest tests/test_csv__provider.py
150-
pytest tests/test_django.py
151-
pytest tests/test_elasticsearch__provider.py
152-
pytest tests/test_opensearch__provider.py
153-
pytest tests/test_esri_provider.py
154-
pytest tests/test_filesystem_provider.py
155-
pytest tests/test_geojson_provider.py
156-
pytest tests/test_linked_data.py
157-
pytest tests/test_mongo_provider.py
158-
pytest tests/test_ogr_csv_provider.py
159-
pytest tests/test_ogr_esrijson_provider.py
160-
pytest tests/test_ogr_gpkg_provider.py
161-
pytest tests/test_ogr_shapefile_provider.py
162-
pytest tests/test_ogr_sqlite_provider.py
163-
pytest tests/test_ogr_wfs_provider.py
164-
pytest tests/test_postgresql_manager.py
165-
# pytest tests/test_ogr_wfs_provider_live.py # NOTE: these are skipped in the file but listed here for completeness
166-
pytest tests/test_openapi.py
167-
pytest tests/test_oracle_provider.py
168-
pytest tests/test_parquet_provider.py
169-
pytest tests/test_postgresql_provider.py
170-
pytest tests/test_postgresql_mvt_provider.py
171-
pytest tests/test_mysql_provider.py
172-
pytest tests/test_rasterio_provider.py
173-
pytest tests/test_sensorthings_edr_provider.py
174-
pytest tests/test_sensorthings_provider.py
175-
pytest tests/test_socrata_provider.py
176-
# pytest tests/test_socrata_provider_live.py.py # NOTE: these are skipped in the file but listed here for completeness
177-
pytest tests/test_sqlite_geopackage_provider.py
178-
pytest tests/test_tinydb_catalogue_provider.py
179-
pytest tests/test_tinydb_manager_for_parallel_requests.py
180-
pytest tests/test_util.py
181-
pytest tests/test_xarray_netcdf_provider.py
182-
pytest tests/test_xarray_zarr_provider.py
183-
pytest tests/test_admin_api.py
146+
run: pytest tests/provider --ignore-glob='*_live.py'
147+
- name: run Manager tests ⚙️
148+
env:
149+
POSTGRESQL_PASSWORD: ${{ secrets.DatabasePassword || 'postgres' }}
150+
run: pytest tests/manager
151+
- name: run other tests ⚙️
152+
run: pytest tests/other --ignore-glob='*_live.py'
184153
- name: failed tests 🚩
185154
if: ${{ failure() }}
186155
run: |

Dockerfile

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# Copyright (c) 2020 Tom Kralidis
99
# Copyright (c) 2019 Just van den Broecke
1010
# Copyright (c) 2025 Francesco Bartoli
11-
# Copyright (c) 2024 Angelos Tzotsos
11+
# Copyright (c) 2025 Angelos Tzotsos
1212
# Copyright (c) 2023 Bernhard Mallinger
1313
#
1414
# Permission is hereby granted, free of charge, to any person
@@ -34,7 +34,7 @@
3434
#
3535
# =================================================================
3636

37-
FROM ubuntu:jammy-20240911.1
37+
FROM ubuntu:jammy-20250714
3838

3939
LABEL maintainer="Just van den Broecke <justb4@gmail.com>"
4040

@@ -140,6 +140,10 @@ RUN python3 -m pip install --no-cache-dir -e .
140140
RUN \
141141
# Set default config and entrypoint for Docker Image
142142
cp /pygeoapi/docker/default.config.yml /pygeoapi/local.config.yml \
143-
&& cp /pygeoapi/docker/entrypoint.sh /entrypoint.sh
143+
&& cp /pygeoapi/docker/entrypoint.sh /entrypoint.sh \
144+
# compile language files
145+
&& cd /pygeoapi \
146+
&& for i in locale/*; do echo $i && pybabel compile -d locale -l `basename $i`; done
147+
144148

145149
ENTRYPOINT ["/entrypoint.sh"]

docker/entrypoint.sh

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ echo "START /entrypoint.sh"
3737
set +e
3838

3939
export PYGEOAPI_HOME=/pygeoapi
40-
export PYGEOAPI_CONFIG="${PYGEOAPI_HOME}/local.config.yml"
41-
export PYGEOAPI_OPENAPI="${PYGEOAPI_HOME}/local.openapi.yml"
40+
41+
if [[ -z "$PYGEOAPI_CONFIG" ]]; then
42+
export PYGEOAPI_CONFIG="${PYGEOAPI_HOME}/local.config.yml"
43+
fi
44+
if [[ -z "$PYGEOAPI_OPENAPI" ]]; then
45+
export PYGEOAPI_OPENAPI="${PYGEOAPI_HOME}/local.openapi.yml"
46+
fi
4247

4348
# gunicorn env settings with defaults
4449
SCRIPT_NAME=${SCRIPT_NAME:=/}
@@ -62,6 +67,8 @@ function error() {
6267
# Workdir
6368
cd ${PYGEOAPI_HOME}
6469

70+
echo "Default config in ${PYGEOAPI_CONFIG}"
71+
6572
echo "Trying to generate openapi.yml"
6673
pygeoapi openapi generate ${PYGEOAPI_CONFIG} --output-file ${PYGEOAPI_OPENAPI}
6774

@@ -114,8 +121,12 @@ case ${entry_cmd} in
114121

115122
# Run pygeoapi server with hot reload
116123
run-with-hot-reload)
117-
# Lock all Python files (for gunicorn hot reload)
118-
find . -type f -name "*.py" | xargs chmod 0444
124+
# Lock all Python files (for gunicorn hot reload), if running with user root
125+
if [[ $(id -u) -eq 0 ]]
126+
then
127+
echo "Running pygeoapi as root"
128+
find . -type f -name "*.py" | xargs chmod 0444
129+
fi
119130

120131
# Start with hot reload options
121132
start_gunicorn --reload --reload-extra-file ${PYGEOAPI_CONFIG}

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def __getattr__(cls, name):
112112
# built documents.
113113
#
114114
# The short X.Y version.
115-
version = '0.21.dev0'
115+
version = '0.22.dev0'
116116
# The full version, including alpha/beta/rc tags.
117117
release = version
118118

docs/source/configuration.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ default.
250250
mimetype: application/json # required: format mimetype
251251
options: # optional options to pass to provider (i.e. GDAL creation)
252252
option_name: option_value
253+
include_extra_query_parameters: false # include extra query parameters that are not part of the collection properties (default: false)
253254
254255
hello-world: # name of process
255256
type: process # REQUIRED (collection, process, or stac-collection)

docs/source/data-publishing/ogcapi-features.rst

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ parameters.
3939
.. note::
4040

4141
* All Providers that support `bbox` also support the `bbox-crs` parameter. `bbox-crs` is handled within pygeoapi core.
42-
* All Providers support the `crs` parameter to reproject (transform) response data. Some, like PostgreSQL and OGR, perform this natively: '✅n'.
42+
* All Providers support the `crs` parameter to reproject (transform) response data. Some, like PostgreSQL and OGR, perform this natively.
4343

4444

4545
Connection examples
@@ -558,12 +558,19 @@ The ``ORACLE_POOL_MIN`` and ``ORACLE_POOL_MAX`` environment variables are used t
558558
If none or only one of the environment variables is set, session pooling will not be activated and standalone connections are established at every request.
559559

560560

561+
Extra_params
562+
""""""""""""
563+
The Oracle provider allows for additional parameters that can be passed in the request. It allows for the processing of additional parameters that are not defined in the ``pygeoapi-config.yml`` to be passed to a custom SQL-Manipulator-Plugin. An example use case of this is advanced filtering without exposing the filtered columns like follows ``.../collections/some_data/items?is_recent=true``. The ``SqlManipulator`` plugin's ``process_query`` method would receive ``extra_params = {'is_recent': 'true'}`` and could dynamically add a custom condition to the SQL query, like ``AND SYSDATE - create_date < 30``.
564+
565+
The ``include_extra_query_parameters`` has to be set to ``true`` for the collection in ``pygeoapi-config.yml``. This ensures that the additional request parameters (e.g. ``is_recent=true``) are not discarded.
566+
567+
561568
Custom SQL Manipulator Plugin
562569
"""""""""""""""""""""""""""""
563570
The provider supports a SQL-Manipulator-Plugin class. With this, the SQL statement could be manipulated. This is
564571
useful e.g. for authorization at row level or manipulation of the explain plan with hints.
565572

566-
An example an more information about that feature you can find in the test class in tests/test_oracle_provider.py.
573+
More information and examples about this feature can be found in ``tests/provider/test_oracle_provider.py``.
567574

568575
.. _Parquet:
569576

@@ -804,6 +811,32 @@ To publish a TinyDB (`see website <https://tinydb.readthedocs.io>`_) index, the
804811
id_field: identifier
805812
time_field: datetimefield
806813
814+
.. _including-extra-query-parameters:
815+
816+
Including extra query parameters
817+
--------------------------------
818+
819+
By default, pygeoapi ignores any extra query parameters. For example, for a given ``.../items`` query, the query key-value pair ``foo1=bar1`` (if ``foo1`` is not a valid property of a given collection) would be ignored by pygeoapi as well as the underlying provider.
820+
821+
To include/accept extra query parameters, the ``include_extra_query_parameters`` directive can be set in provider configuration:
822+
823+
.. code-block:: yaml
824+
825+
providers:
826+
- type: feature
827+
editable: true|false # optional, default is false
828+
name: TinyDB
829+
data: /path/to/file.db
830+
id_field: identifier
831+
time_field: datetimefield
832+
include_extra_query_parameters: true
833+
834+
835+
With the above configuration, pygeoapi will pass ``foo1=bar1`` to the underlying provider. If the underlying provider does not have ``foo1`` as a queryable property, then an exception will be returned citing an unknown property.
836+
837+
Extra query parameters are useful for custom providers who may wish for specific functionality to be triggered by query parameters that are not bound to a given collection's properties.
838+
839+
807840
Controlling the order of properties
808841
-----------------------------------
809842

docs/source/data-publishing/ogcapi-processes.rst

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
Publishing processes via OGC API - Processes
44
============================================
55

6+
.. note::
7+
8+
Publishing processes via pygeoapi requires knowledge and development of Python code.
9+
610
`OGC API - Processes`_ provides geospatial data processing functionality in a standards-based
711
fashion (inputs, outputs).
812

@@ -37,7 +41,76 @@ The below configuration is an example of a process defined as part of a custom P
3741
# the MyProcess class must subclass from pygeoapi.process.base.BaseProcessor
3842
name: my_package.my_module.my_file.MyProcess
3943
40-
See :ref:`example-custom-pygeoapi-processing-plugin` for processing plugin examples.
44+
Documenting process metadata
45+
----------------------------
46+
47+
When defining a process, various metadata must be supplied in order to enable discovery and description
48+
of inputs and outputs. The metadata is realized by a Python dictionary in a given process that is
49+
supplied to process initialization at runtime.
50+
51+
Below is a sample process definition as a Python dictionary:
52+
53+
.. code-block:: python
54+
55+
PROCESS_METADATA = {
56+
'version': '0.2.0', # the version of the process
57+
'id': 'hello-world', # process identifier
58+
'title': 'Hello World', # process title, can also be multilingual
59+
'description': 'An example process that takes a name as input, and echoes ' # process description, can also be multilingual
60+
'it back as output. Intended to demonstrate a simple '
61+
'process with a single literal input.',
62+
'jobControlOptions': ['sync-execute', 'async-execute'], # whether the process can be executed in sync or async mode
63+
'keywords': ['hello world', 'example', 'echo'], # keywords associated with the process
64+
'links': [{ # a list of 1..n # link objects relevant to the process
65+
'type': 'text/html',
66+
'rel': 'about',
67+
'title': 'information',
68+
'href': 'https://example.org/process',
69+
'hreflang': 'en-US'
70+
}],
71+
'inputs': { # process inputs (one key per input), structured as JSON Schema
72+
'name': {
73+
'title': 'Name',
74+
'description': 'The name of the person or entity that you wish to'
75+
'be echoed back as an output',
76+
'schema': {
77+
'type': 'string'
78+
},
79+
'minOccurs': 1,
80+
'maxOccurs': 1,
81+
'keywords': ['full name', 'personal']
82+
},
83+
'message': {
84+
'title': 'Message',
85+
'description': 'An optional message to echo as well',
86+
'schema': {
87+
'type': 'string'
88+
},
89+
'minOccurs': 0,
90+
'maxOccurs': 1,
91+
'keywords': ['message']
92+
}
93+
},
94+
'outputs': { # outputs
95+
'echo': { # an identifier for the output
96+
'title': 'Hello, world',
97+
'description': 'A "hello world" echo with the name and (optional)'
98+
' message submitted for processing',
99+
'schema': { # output definition, structured as JSON Schema
100+
'type': 'object',
101+
'contentMediaType': 'application/json'
102+
}
103+
}
104+
},
105+
'example': { # example request payload
106+
'inputs': {
107+
'name': 'World',
108+
'message': 'An optional message.',
109+
}
110+
}
111+
}
112+
113+
See :ref:`example-custom-pygeoapi-processing-plugin` for full processing plugin examples.
41114

42115
Processing and response handling
43116
--------------------------------

docs/source/data-publishing/ogcapi-records.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ parameters.
1818
:header: Provider, properties (filters), resulttype, q, bbox, datetime, sortby, properties (display), domains, CQL, transactions
1919
:align: left
2020

21-
`ElasticsearchCatalogue`_,✅,results/hits,✅,✅,✅,✅,✅,✅,✅
22-
`TinyDBCatalogue`_,✅,results/hits,✅,✅,✅,✅,❌,✅,✅,✅,✅
23-
`CSWFacade`_,✅,results/hits,✅,✅,✅,,❌,✅,❌,❌
21+
`ElasticsearchCatalogue`_,✅,results/hits,✅,✅,✅,✅,✅,✅,✅,✅
22+
`TinyDBCatalogue`_,✅,results/hits,✅,✅,✅,✅,❌,✅,✅,✅
23+
`CSWFacade`_,✅,results/hits,✅,✅,✅,,❌,✅,❌,❌
2424

2525

2626
Below are specific connection examples based on supported providers.
@@ -96,6 +96,11 @@ CSW Record core model is supported as a baseline.
9696
title_field: title
9797
9898
99+
Including extra query parameters
100+
--------------------------------
101+
102+
See the :ref:`publishing vector section <including-extra-query-parameters>` for more information on including extra query parameters.
103+
99104
Metadata search examples
100105
------------------------
101106

docs/source/data-publishing/ogcapi-tiles.rst

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ This code block shows how to configure pygeoapi to read Mapbox vector tiles gene
4949
zoom:
5050
min: 0
5151
max: 5
52-
# MVT-elastic always uses WebMercatorQuad tiling scheme
52+
# MVT-tippecanoe always uses WebMercatorQuad tiling scheme
5353
format:
5454
name: pbf
5555
mimetype: application/vnd.mapbox-vector-tile
@@ -103,12 +103,12 @@ Following block shows how to configure pygeoapi to read Mapbox vector tiles from
103103
- type: tile
104104
name: MVT-proxy
105105
data: http://localhost:7800/public.ne_50m_admin_0_countries/{z}/{x}/{y}.mvt
106-
options:
107-
zoom:
108-
min: 0
109-
max: 15
110-
schemes:
111-
- WebMercatorQuad # this option is needed in the MVT-proxy provider
106+
options:
107+
zoom:
108+
min: 0
109+
max: 15
110+
schemes:
111+
- WebMercatorQuad # this option is needed in the MVT-proxy provider
112112
format:
113113
name: pbf
114114
mimetype: application/vnd.mapbox-vector-tile
@@ -201,6 +201,16 @@ This code block shows how to configure pygeoapi to read map tiles from a WMTS.
201201
min: 0
202202
max: 20
203203
204+
205+
Providing custom Tile Matrix Set definitions
206+
--------------------------------------------
207+
208+
By default, pygeoapi provides the ``WorldCRS84Quad`` and ``WebMercatorQuad`` TMS
209+
definitions, for tile providers to use accordingly. Additional TMS definitions
210+
may be added in pygeoapi's ``resources/definitions/tiles`` (for example, by adding
211+
TMS definition files directly, volume mapping / Docker ``COPY``, Docker Compose ``volumes``, etc.).
212+
213+
204214
Data access examples
205215
--------------------
206216

0 commit comments

Comments
 (0)