* squach contents new branch

* source code explanations

* flake8

* change in requirements

* 	modified:   docs/source/code.rst
	modified:   docs/source/plugins.rst

* 	modified:   docs/source/code.rst
	modified:   pygeoapi/formatter/csv_.py
	modified:   pygeoapi/provider/geojson.py

* changes requred in review code

* 	modified:   .travis.yml
missing "

* change file to use requirements-dev.txt
	modified:   readthedocs.yml

* flask_cors removal from requirements.txt

* text changes
This commit is contained in:
Jorge Samuel Mendes de Jesus
2019-08-14 21:14:14 +02:00
committed by Tom Kralidis
parent 5ab45769db
commit da267e9ed3
36 changed files with 951 additions and 15 deletions
+3
View File
@@ -107,3 +107,6 @@ local.openapi.yml
# misc
*.swp
.pytest_cache
#Eclipse project
.project
+3 -1
View File
@@ -5,7 +5,7 @@ sudo: false
env:
global:
- PYGEOAPI_CONFIG=pygeoapi-config.yml
- PYGEOAPI_CONFIG="$(pwd)/pygeoapi-config.yml"
- CPLUS_INCLUDE_PATH=/usr/include/gdal
- C_INCLUDE_PATH=/usr/include/gdal
@@ -47,9 +47,11 @@ before_script:
script:
- pytest --cov=pygeoapi
- make -C ./docs html
- find . -type f -name "*.py" | xargs flake8
- python3 setup.py --long-description | rst2html5.py
after_success:
- python3 setup.py sdist bdist_wheel --universal
- debuild -b -uc -us
+20
View File
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = pygeoapi
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

+219
View File
@@ -0,0 +1,219 @@
.. _code:
Code documentation
==================
Top level code documentation. Follow link in section for module/class member information
API
---
.. automodule:: pygeoapi.api
:members:
:private-members:
:special-members:
flask_app
---------
.. automodule:: pygeoapi.flask_app
:show-inheritance:
:members:
:private-members:
:special-members:
Logging
-------
.. automodule:: pygeoapi.log
:show-inheritance:
:members:
:private-members:
:special-members:
OpenAPI
-------
.. automodule:: pygeoapi.openapi
:show-inheritance:
:members:
:private-members:
:special-members:
Plugins
-------
.. note:: Please consult section :ref:`plugins`
.. automodule:: pygeoapi.plugin
:show-inheritance:
:members:
:private-members:
:special-members:
Utils
-----
.. automodule:: pygeoapi.util
:show-inheritance:
:members:
:private-members:
:special-members:
Formatter package
-----------------
.. automodule:: pygeoapi.formatter
:show-inheritance:
:members:
:private-members:
:special-members:
Base class
^^^^^^^^^^
.. automodule:: pygeoapi.formatter.base
:show-inheritance:
:members:
:private-members:
:special-members:
csv
^^^
.. automodule:: pygeoapi.formatter.csv_
:show-inheritance:
:members:
:private-members:
:special-members:
Process package
---------------
.. automodule:: pygeoapi.process
:show-inheritance:
:members:
:private-members:
:special-members:
Base class
^^^^^^^^^^
.. automodule:: pygeoapi.process.base
:show-inheritance:
:members:
:private-members:
:special-members:
hello_world
^^^^^^^^^^^
Hello world example process
.. automodule:: pygeoapi.process.hello_world
:show-inheritance:
:members:
:private-members:
:special-members:
.. _data Provider:
Provider
--------
.. automodule:: pygeoapi.provider
:show-inheritance:
:members:
:private-members:
:special-members:
Base class
^^^^^^^^^^
.. automodule:: pygeoapi.provider.base
:show-inheritance:
:members:
:private-members:
:special-members:
CSV provider
^^^^^^^^^^^^
.. automodule:: pygeoapi.provider.csv_
:show-inheritance:
:members:
:private-members:
Elastic provider
^^^^^^^^^^^^^^^^
.. automodule:: pygeoapi.provider.elasticsearch_
:show-inheritance:
:members:
:private-members:
GeoJSON
^^^^^^^
.. automodule:: pygeoapi.provider.geojson
:show-inheritance:
:members:
:private-members:
GeoPackage
^^^^^^^^^^
.. automodule:: pygeoapi.provider.geopackage
:show-inheritance:
:members:
:private-members:
OGR
^^^
.. automodule:: pygeoapi.provider.ogr
:show-inheritance:
:members:
:private-members:
postgresql
^^^^^^^^^^
.. automodule:: pygeoapi.provider.postgresql
:show-inheritance:
:members:
:private-members:
sqlite
^^^^^^
.. automodule:: pygeoapi.provider.sqlite
:show-inheritance:
:members:
:private-members:
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# pygeoapi documentation build configuration file, created by
# sphinx-quickstart on Wed Jul 3 06:22:56 2019.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.ifconfig',
'sphinx.ext.viewcode',
'sphinx.ext.doctest',
'sphinx.ext.githubpages']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'pygeoapi'
copyright = '2019, pygeoapi team'
author = 'pygeoapi team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.6'
# The full version, including alpha/beta/rc tags.
release = ''
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'pygeoapidoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'pygeoapi.tex', 'pygeoapi Documentation',
'pygeoapi team', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'pygeoapi', 'pygeoapi Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'pygeoapi', 'pygeoapi Documentation',
author, 'pygeoapi', 'pygeoapi provides an API to geospatial data',
'Miscellaneous'),
]
+22
View File
@@ -0,0 +1,22 @@
.. _configuration:
Configuration
=============
pygeoapi uses a yaml file as configuration source and the file location is read from the ``PYGEOAPI_CONFIG`` env variable
.. note::
pygeoapi is under high development, and new configuration paramenters are constantely being added. For the lastest parameters
please consult the `pygeoapi-config.yml <https://github.com/geopython/pygeoapi/blob/master/pygeoapi-config.yml>`_ file provided on github
Using ``pygeoapi-config.yml`` as reference we will have the following sections:
* `server` for server related configurations
* `logging` for logging configuration
* `metadata` server and content metadata (information used to populate multiple content)
* `datasets` data content offered by server (collections in WFS3.0)
+111
View File
@@ -0,0 +1,111 @@
.. _docker:
Docker
======
Docker Images ``geopython/pygeoapi:latest`` and versions are `available on DockerHub <https://hub.docker.com/r/geopython/pygeoapi>`_ .
Each Docker Image contains a default configuration ``default.config.yml``
with the project's test data and WFS3 datasets.
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.
Running - Basics
----------------
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:
.. code-block:: console
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**
You can also run all unit tests to verify:
.. code-block:: console
docker run -it geopython/pygeoapi test
Running - Overriding the default config
---------------------------------------
Normally you would override the ``default.config.yml`` with your own ``pygeoapi`` config.
This can be effected best via Docker Volume Mapping.
For example if your config is in ``my.config.yml``:
.. code-block:: console
docker run -p 5000:80 -v $(pwd)/my.config.yml:/pygeoapi/local.config.yml -it geopython/pygeoapi
But better/cleaner is to use ``docker-compose``. Something like:
.. code-block:: yaml
version: "3"
services:
pygeoapi:
image: geopython/pygeoapi:latest
volumes:
- ./my.config.yml:/pygeoapi/local.config.yml
Or you can create a ``Dockerfile`` extending the base Image and **COPY** in your config:
.. code-block:: dockerfile
FROM geopython/pygeoapi:latest
COPY ./my.config.yml /pygeoapi/local.config.yml
See how the demo server is setup (`here <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``:
.. code-block:: console
docker run -p 5000:80 -e SCRIPT_NAME='/mypygeoapi' -v $(pwd)/my.config.yml:/pygeoapi/local.config.yml -it geopython/pygeoapi
browse to **http://localhost:5000/mypygeoapi**
Or within a ``docker-compose.yml`` full example:
.. code-block:: yaml
version: "3"
services:
pygeoapi:
image: geopython/pygeoapi:latest
volumes:
- ./my.config.yml:/pygeoapi/local.config.yml
ports:
- "5000:80"
environment:
- SCRIPT_NAME=/pygeoapi
See `pygeoapi demo service <https://github.com/geopython/demo.pygeoapi.io/tree/master/services/pygeoapi_master>`_ for an full example.
+43
View File
@@ -0,0 +1,43 @@
.. pygeoapi documentation master file, created by
sphinx-quickstart on Wed Jul 3 06:22:56 2019.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pygeoapi's documentation!
====================================
|build-status| |docs| |coverage|
.. toctree::
:maxdepth: 4
:caption: Contents:
pygeoapi
install
openapi
docker
wsgi
configuration
plugins
code
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. |build-status| image:: https://api.travis-ci.org/geopython/pygeoapi.svg?branch=master
:alt: build status
:target: https://travis-ci.org/geopython/pygeoapi
.. |docs| image:: https://readthedocs.org/projects/pygeoapi/badge/?version=latest&style=plastic
:alt: Documentation Status
:target: https://readthedocs.org/projects/pygeoapi
.. |coverage| image:: https://codecov.io/gh/geopython/pygeoapi/branch/master/graph/badge.svg
:alt: Test coverage
:target: https://codecov.io/gh/pygeoapi/pygeoapi.org
+54
View File
@@ -0,0 +1,54 @@
.. _install:
Install
=======
pygeoapi is nativally run as a Flask app (the code struct is an API and Flask is used as a wrapper).
pygeoapi uses two configuration files: **pygeoapi-config.yml** and **openapi.yml**. First configuration contains all the information and setup to run pygeoapi while the second is exclusivally for the openapi.
pygeoapi requires setting ``PYGEOAPI_CONFIG`` and ``PYGEOAPI_OPENAPI`` env variable. ``PYGEOAPI_CONFIG`` points to the yaml file containing the configuration, in the example
bellow we copy the ``local.config.yml`` default configuration to ``pygeoapi-config.yml`` and use this configuration file.
``PYGEOAPI_OPENAPI`` variable is the path to openapi file configuration, this file **needs to be autogenerated** using the ``pygeoapi generate-openapi-document`` command and
the pygeoapi config files e.g: ``pygeoapi generate-openapi-document -c local.config.yml > openapi.yml``. And then setting the env variable to the path:
``export PYGEOAPI_OPENAPI=/path/to/openapi.yml``
For production environments it is recommended to use :ref:`docker` or a specialized WSGI HTTP server :ref:`wsgi`
Copy/paste install
------------------
It is advisable to run pygeoapi inside an isolated enviroment either *virtualenv* or *docker*, mainly to avoid python package conflicts.
.. code-block:: console
#create virtualenv
virtualenv -p python pygeoapi
cd pygeoapi
. bin/activate
git clone https://github.com/geopython/pygeoapi.git
cd pygeoapi
#install requirements
pip install -r requirements.txt
pip install -r requirements-dev.txt
# install source in current directory
pip install -e .
cp pygeoapi-config.yml local.config.yml
#edit configuration file
nano local.config.yml
export PYGEOAPI_CONFIG=/path/to/local.config.yml
# generate OpenAPI Document
pygeoapi generate-openapi-document -c local.config.yml > openapi.yml
export PYGEOAPI_OPENAPI=/path/to/openapi.yml
#Run pygeoapi
pygeoapi serve
If the default configuration was used then we should have pygeoapi running on
.. image:: /_static/openapi_intro_page.png
+64
View File
@@ -0,0 +1,64 @@
.. _openapi:
OpenAPI
=======
`OpenAPI spec <https://swagger.io/docs/specification/about/>`_ is an open specification for REST end points, currentely OGC services are being redefined using such specification.
The REST structure and payload are defined using yaml file structures, the file structure is described here: `<https://swagger.io/docs/specification/basic-structure/>`_
pygeoapi REST end points descriptions on OpenAPI standard are automatically generated based on the configuration file:
.. code-block:: console
pygeoapi generate-openapi-document -c local.config.yml > openapi.yml
The api will them be accessible at `/api` endpoint.
For api demo please check: `<https://demo.pygeoapi.io/master/api>`_
The api page has REST description but also integrated clients that can be used to send requests to the REST end points and see the response provided
Using OpenAPI
-------------
Acessing the openAPI webpage we have the following structure:
.. image:: /_static/openapi_intro_page.png
Please notice that **each dataset** will be represented as a REST end point under `collections`
In this example we will test and `GET` data concerning windmills in the Netherlands, first we will check the avaiable datasets,
by accessing the service's collections:
.. image:: /_static/openapi_get_collections.png
The service collection metadata will contain a description of the collections provided by the server
.. image:: /_static/openapi_get_collections_result.png
The dataset `dutch_windmills` will be available on the `collections` end point, in the following example we'll obtain the specific metadata of the dataset
.. image:: /_static/openapi_get_collection.png
.. image:: /_static/openapi_get_collection_result.png
features/items composing the data are agregated on the `/items` end point, in this REST end point it is possible to obtain all dataset, or restrict
it features/items to a **numerical limit**, **bounding box**, **time stamp**, **pagging** (start index)
.. image:: /_static/openapi_get_item.png
For each feature in dataset we have a **specific identifier** (notice that the identifier is not part of the JSON properties),
.. image:: /_static/openapi_get_item_id.png
This identifier can be used to obtain a specific item from the dataset using the `items\{id}` end point as follows:
.. image:: /_static/openapi_get_item_id2.png
+63
View File
@@ -0,0 +1,63 @@
.. _plugins:
Plugins
=======
In this section we will explain how pygeoapi uses a plugin approach for data providers, formatters and processes.
Plugin data provider plugin
---------------------------
Plugins are in general modules containing derived classed classes that ensure minimal requirements for the plugin to work.
Lets consider the steps for a data provider plugin (source code is located here: :ref:`data Provider`)
#. create a new module file on the `provider folder` (e.g myprovider.py)
#. copy code from `base.py`
#. import base provider class
.. code-block:: python
from pygeoapi.provider.base import BaseProvider
#. create a child class from the `BaseProvider` class with a specific name
.. code-block:: python
class BaseProvider(object):
"""generic Provider ABC"""
def __init__(self, provider_def):
"""
Initialize object
to become:
.. code-block:: python
class MyDataProvider(object):
"""My data provider"""
def __init__(self, provider_def):
"""Inherit from parent class"""
BaseProvider.__init__(self, provider_def)
#. implement class methods.
.. code-block:: python
def query(self):
def get(self, identifier):
def create(self, new_feature):
def update(self, identifier, new_feature):
def delete(self, identifier):
The above class methods are related to the specific URLs defined on the OGC openapi specification:
+16
View File
@@ -0,0 +1,16 @@
.. _pygeoapi:
pygeoapi project
================
pygeoapi is a Python server implementation of the emerging suite of OGC API standards. pygeoapi is development
using the `12-factor app <https://12factor.net/>`_ approach, allowing for easy deployment in cloud systems.
pygeoapi is a OsGEO recognized project (`here <https://www.osgeo.org/projects/pygeoapi/>`_).
Demo server
-----------
There is a demo server on `<https://demo.pygeoapi.io>`_ running the latest (Docker) version from the master branch of this repo. pygeoapi runs there at `https://demo.pygeoapi.io/master <https://demo.pygeoapi.io/master>`_ .
The demo server setup and config is maintained within a seperate GH repo: `<https://github.com/geopython/demo.pygeoapi.io>`_.
+48
View File
@@ -0,0 +1,48 @@
.. _wsgi:
WSGI
====
Web Server Gateway Interface (WSGI) is standard for forwarding request to web applications written on Python language. pygeoapi it self
doesn't implement WSGI since it is an API,
therefore it is required a webframework to access HTTP requests and pass the information to pygeopai
.. code-block:: console
HTTP request --> Flask (flask_app.py) --> pygeopai API
the pygeoapi package integrates `Flask <https://flask.palletsprojects.com/en/1.1.x/>`_ as webframework for defining the API routes/end points and WSGI support.
The flask WSGI server can be easely run as a pygeoapi command:
.. code-block:: console
pygeoapi serve
Running a native Flask server is not adivsable, the prefered option is as follows:
.. code-block:: console
HTTP request --> WSGI server (gunicorn) --> Flask (flask_app.py) --> pygeopai API
By having a specific WSGI server, the HTTPS are efficiently processed into threads/processes. The current docker pygeoapi
implement such strategy (see section: :ref:`docker`), it is prefered to implement pygeopai using docker solutions than running host native WSGI servers.
Running gunicorn
----------------
Gunicorn is one of several WSGI supporting server on python (list of server supporting WSGI: `here <https://wsgi.readthedocs.io/en/latest/servers.html>`_). This server
is simple to run from the command, e.g:
.. code-block:: console
gunicorn pygeoapi.flask_app:APP
For extra configuration parameters like port binding, workers please consult the gunicorn `settings <http://docs.gunicorn.org/en/stable/settings.html>`_
+7 -2
View File
@@ -26,6 +26,9 @@
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
""" Root level code of pygeoapi, parsing content provided by webframework.
Returns content from plugins and sets reponses
"""
from datetime import datetime
import json
@@ -45,11 +48,13 @@ LOGGER = logging.getLogger(__name__)
TEMPLATES = '{}{}templates'.format(os.path.dirname(
os.path.realpath(__file__)), os.sep)
#: Return headers for requests (e.g:X-Powered-By)
HEADERS = {
'Content-Type': 'application/json',
'X-Powered-By': 'pygeoapi {}'.format(__version__)
}
#: Formats allowed for ?f= requests
FORMATS = ['json', 'html']
@@ -833,9 +838,9 @@ def check_format(args, headers):
def to_json(dict_):
"""
serialize dict to json
Serialize dict to json
:param dict_: dict_
:param dict_: `dict` of JSON representation
:returns: JSON string representation
"""
+52 -1
View File
@@ -28,6 +28,8 @@
#
# =================================================================
""" Flask module providing the route paths to the api"""
import os
import click
@@ -61,6 +63,11 @@ api_ = API(CONFIG)
@APP.route('/')
def root():
"""
HTTP root content of pygeopai. Intro page access point
:returns: HTTP response
"""
headers, status_code, content = api_.root(request.headers, request.args)
response = make_response(content, status_code)
@@ -72,6 +79,11 @@ def root():
@APP.route('/api')
def api():
"""
OpenAPI access point
:returns: HTTP response
"""
with open(os.environ.get('PYGEOAPI_OPENAPI')) as ff:
openapi = yaml_load(ff)
@@ -87,6 +99,12 @@ def api():
@APP.route('/conformance')
def api_conformance():
"""
OGC open api conformance access point
:returns: HTTP response
"""
headers, status_code, content = api_.api_conformance(request.headers,
request.args)
@@ -100,6 +118,13 @@ def api_conformance():
@APP.route('/collections')
@APP.route('/collections/<name>')
def describe_collections(name=None):
"""
OGC open api collections access point
:param name: identifier of collection name
:returns: HTTP response
"""
headers, status_code, content = api_.describe_collections(
request.headers, request.args, name)
@@ -113,6 +138,12 @@ def describe_collections(name=None):
@APP.route('/collections/<feature_collection>/items')
@APP.route('/collections/<feature_collection>/items/<feature>')
def dataset(feature_collection, feature=None):
"""
OGC open api collections/{dataset}/items/{feature} access point
:returns: HTTP response
"""
if feature is None:
headers, status_code, content = api_.get_features(
request.headers, request.args, feature_collection)
@@ -131,6 +162,12 @@ def dataset(feature_collection, feature=None):
@APP.route('/processes')
@APP.route('/processes/<name>')
def describe_processes(name=None):
"""
OGC open api processes access point (experimental)
:param name: identifier of process to describe
:returns: HTTP response
"""
headers, status_code, content = api_.describe_processes(
request.headers, request.args, name)
@@ -144,6 +181,13 @@ def describe_processes(name=None):
@APP.route('/processes/<name>/jobs', methods=['GET', 'POST'])
def execute_process(name=None):
"""
OGC open api jobs from processes access point (experimental)
:param name: identifier of process to execute
:returns: HTTP response
"""
if request.method == 'GET':
headers, status_code, content = ({}, 200, "[]")
elif request.method == 'POST':
@@ -162,7 +206,14 @@ def execute_process(name=None):
@click.pass_context
@click.option('--debug', '-d', default=False, is_flag=True, help='debug')
def serve(ctx, debug=False):
"""Serve pygeoapi via Flask"""
"""
Serve pygeoapi via Flask. Runs pygeoapi
as a flask server. Not recommend for production.
:param debug: `bool` of whether to run in debug mode
:returns void
"""
# setup_logger(CONFIG['logging'])
APP.run(debug=True, host=api_.config['server']['bind']['host'],
+2
View File
@@ -26,3 +26,5 @@
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
"""Output formatter package"""
+1 -1
View File
@@ -46,7 +46,7 @@ class CSVFormatter(BaseFormatter):
:param formatter_def: formatter definition
:returns: pygeoapi.formatter.csv_.CSVFormatter
:returns: `pygeoapi.formatter.csv_.CSVFormatter`
"""
geom = False
+2
View File
@@ -27,6 +27,8 @@
#
# =================================================================
"""Logging system"""
import logging
import sys
+3
View File
@@ -26,12 +26,15 @@
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
"""Plugin loader"""
import importlib
import logging
LOGGER = logging.getLogger(__name__)
#: Loads provider plugins to be used by pygeoapi,\
#: formatters and processes available
PLUGINS = {
'provider': {
'CSV': 'pygeoapi.provider.csv_.CSVProvider',
+2
View File
@@ -26,3 +26,5 @@
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
"""OGC process package, each process is an independent module"""
+1 -1
View File
@@ -33,7 +33,7 @@ LOGGER = logging.getLogger(__name__)
class BaseProcessor(object):
"""generic Processor ABC"""
"""generic Processor ABC. Processes are inherited from this class"""
def __init__(self, processor_def, process_metadata):
"""
+2 -1
View File
@@ -33,6 +33,7 @@ from pygeoapi.process.base import BaseProcessor
LOGGER = logging.getLogger(__name__)
#: Process metadata and description
PROCESS_METADATA = {
'version': '0.1.0',
'id': 'hello-world',
@@ -80,7 +81,7 @@ PROCESS_METADATA = {
class HelloWorldProcessor(BaseProcessor):
"""Hello World Processor"""
"""Hello World Processor example"""
def __init__(self, provider_def):
"""
+2
View File
@@ -26,3 +26,5 @@
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
"""Provider module containing the plugins wrapping data sources"""
+13 -8
View File
@@ -52,14 +52,14 @@ class GeoJSONProvider(BaseProvider):
and will override any 'id' provided in the original data.
The feature 'properties' will be preserved.
TODO
- query method should take bbox
- instead of methods returning FeatureCollections,
we should be yielding Features and aggregating in the view
- there are strict id semantics; all features in the input GeoJSON file
must be present and be unique strings. Otherwise it will break.
- How to raise errors in the provider implementation such that
appropriate HTTP responses will be raised
TODO:
* query method should take bbox
* instead of methods returning FeatureCollections,
we should be yielding Features and aggregating in the view
* there are strict id semantics; all features in the input GeoJSON file
must be present and be unique strings. Otherwise it will break.
* How to raise errors in the provider implementation such that
* appropriate HTTP responses will be raised
"""
def __init__(self, provider_def):
@@ -73,6 +73,7 @@ class GeoJSONProvider(BaseProvider):
Yes loading from disk, deserializing and validation
happens on every request. This is not efficient.
"""
if os.path.exists(self.data):
with open(self.data) as src:
data = json.loads(src.read())
@@ -104,6 +105,7 @@ class GeoJSONProvider(BaseProvider):
:returns: FeatureCollection dict of 0..n GeoJSON features
"""
# TODO filter by bbox without resorting to third-party libs
data = self._load()
@@ -124,6 +126,7 @@ class GeoJSONProvider(BaseProvider):
:param identifier: feature id
:returns: dict of single GeoJSON feature
"""
all_data = self._load()
for feature in all_data['features']:
if str(feature['properties'][self.id_field]) == identifier:
@@ -154,6 +157,7 @@ class GeoJSONProvider(BaseProvider):
:param identifier: feature id
:param new_feature: new GeoJSON feature dictionary
"""
all_data = self._load()
for i, feature in enumerate(all_data['features']):
if feature['properties']['id'] == identifier:
@@ -170,6 +174,7 @@ class GeoJSONProvider(BaseProvider):
:param identifier: feature id
"""
all_data = self._load()
for i, feature in enumerate(all_data['features']):
if feature['properties']['id'] == identifier:
+2
View File
@@ -27,6 +27,8 @@
#
# =================================================================
"""Generic util functions used in the code"""
import logging
import yaml
+21
View File
@@ -0,0 +1,21 @@
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/source/conf.py
# Optionally build your docs in additional formats such as PDF and ePub
formats: all
# Optionally set the version of Python and requirements required to build your docs
python:
version: 3.7
install:
- requirements: requirements.txt
- requirements: requirements-dev.txt
+3
View File
@@ -20,3 +20,6 @@ pypandoc
pyOpenSSL
ndg-httpsclient
pyasn1
#Read the docs
sphinx_rtd_theme