Skip to content

Commit 46c0133

Browse files
Merge pull request #1 from Botts-Innovative-Research/dev
v 0.1
2 parents 5ec198e + cf9ebe1 commit 46c0133

22 files changed

Lines changed: 1417 additions & 26 deletions

File tree

.github/workflows/docs_pages.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Docs2Pages
2+
on:
3+
push:
4+
tags: '*'
5+
pull_request:
6+
branches:
7+
- master
8+
9+
jobs:
10+
build-docs:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@master
15+
with:
16+
fetch-depth: 0
17+
- uses: actions/setup-python@v2
18+
with:
19+
python-version: 3.9
20+
- uses: abatilo/actions-poetry@v2.1.3
21+
- name: install
22+
run: poetry install -E amazon -E docs
23+
- name: Build documentation
24+
run: |
25+
mkdir gh-pages
26+
touch gh-pages/.nojekyll
27+
cd docs/
28+
poetry run sphinx-build -b html . _build
29+
cp -r _build/* ../gh-pages/
30+
- name: Deploy documentation
31+
if: ${{ github.event_name == 'push' }}
32+
uses: JamesIves/github-pages-deploy-action@4.1.4
33+
with:
34+
branch: gh-pages
35+
folder: gh-pages

docs/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = source
9+
BUILDDIR = build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
# Catch-all target: route all unknown targets to Sphinx using the new
18+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+
%: Makefile
20+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

docs/make.bat

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
@ECHO OFF
2+
3+
pushd %~dp0
4+
5+
REM Command file for Sphinx documentation
6+
7+
if "%SPHINXBUILD%" == "" (
8+
set SPHINXBUILD=sphinx-build
9+
)
10+
set SOURCEDIR=source
11+
set BUILDDIR=build
12+
13+
%SPHINXBUILD% >NUL 2>NUL
14+
if errorlevel 9009 (
15+
echo.
16+
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
17+
echo.installed, then set the SPHINXBUILD environment variable to point
18+
echo.to the full path of the 'sphinx-build' executable. Alternatively you
19+
echo.may add the Sphinx directory to PATH.
20+
echo.
21+
echo.If you don't have Sphinx installed, grab it from
22+
echo.https://www.sphinx-doc.org/
23+
exit /b 1
24+
)
25+
26+
if "%1" == "" goto help
27+
28+
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29+
goto end
30+
31+
:help
32+
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33+
34+
:end
35+
popd

docs/source/conf.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Configuration file for the Sphinx documentation builder.
2+
#
3+
# For the full list of built-in configuration values, see the documentation:
4+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
5+
6+
# -- Project information -----------------------------------------------------
7+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8+
9+
project = 'OSHConnect-Python'
10+
copyright = '2024, Ian Patterson'
11+
author = 'Ian Patterson'
12+
release = '0.1'
13+
14+
# -- General configuration ---------------------------------------------------
15+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
16+
17+
18+
extensions = [
19+
'sphinx.ext.doctest',
20+
'sphinx.ext.duration',
21+
'sphinx.ext.autodoc',
22+
'sphinx.ext.autosummary',
23+
]
24+
templates_path = ['_templates']
25+
exclude_patterns = []
26+
27+
# -- Options for HTML output -------------------------------------------------
28+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
29+
30+
html_theme = 'alabaster'
31+
html_static_path = ['_static']

docs/source/index.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.. OSHConnect-Python documentation master file, created by
2+
sphinx-quickstart on Tue Jun 25 11:43:33 2024.
3+
You can adapt this file completely to your liking, but it should at least
4+
contain the root `toctree` directive.
5+
6+
Welcome to OSHConnect-Python's documentation!
7+
=============================================
8+
9+
.. toctree::
10+
:maxdepth: 2
11+
:caption: Contents:
12+
13+
14+
15+
Indices and tables
16+
==================
17+
18+
* :ref:`genindex`
19+
* :ref:`modindex`
20+
* :ref:`search`
21+
22+
23+
OSHConnect-Python
24+
=================
25+
OSHConnect-Python is the Python version of the OSHConnect family of application libraries inteded to provide a simple
26+
and straightforward way to interact with OpenSensorHub (or another CSAPI server) by way of OGC API - Connected Systems.
27+
It supports or will support at the time of a 1.0 release Part 1 and Part 2 of the Connected Systems api, as well as
28+
certain streaming features made possible by OpenSensorHub.
29+
30+
OSHConnect
31+
==========
32+
33+
.. automodule:: oshconnect
34+
:members:
35+
:undoc-members:
36+
:show-inheritance:

external_models/__init__.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# ==============================================================================
2+
# Copyright (c) 2024 Botts Innovative Research, Inc.
3+
# Date: 2024/5/31
4+
# Author: Ian Patterson
5+
# Contact Email: ian@botts-inc.com
6+
# ==============================================================================
7+
from __future__ import annotations
8+
9+
from typing import Any
10+
11+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
12+
from shapely import Point
13+
from typing_extensions import Self
14+
15+
16+
class BoundingBox(BaseModel):
17+
model_config = ConfigDict(arbitrary_types_allowed=True)
18+
19+
lower_left_corner: Point = Field(..., description="The lower left corner of the bounding box.")
20+
upper_right_corner: Point = Field(..., description="The upper right corner of the bounding box.")
21+
min_value: float = Field(None, description="The minimum value of the bounding box.")
22+
max_value: float = Field(None, description="The maximum value of the bounding box.")
23+
24+
# @model_validator(mode='before')
25+
# def validate_minmax(self) -> Self:
26+
# if self.min_value > self.max_value:
27+
# raise ValueError("min_value must be less than max_value")
28+
# return self
29+
30+
31+
class DateTime(BaseModel):
32+
is_instant: bool = Field(True, description="Whether the date time is an instant or a period.")
33+
iso_date: str = Field(None, description="The ISO formatted date time.")
34+
time_period: tuple = Field(None, description="The time period of the date time.")
35+
36+
@model_validator(mode='before')
37+
def valid_datetime_type(self) -> Self:
38+
if self.is_instant:
39+
if self.iso_date is None:
40+
raise ValueError("Instant date time must have a valid ISO8601 date.")
41+
return self
42+
43+
@field_validator('iso_date')
44+
@classmethod
45+
def check_iso_date(cls, v) -> str:
46+
if not v:
47+
raise ValueError("Instant date time must have a valid ISO8601 date.")
48+
return v
49+
50+
51+
class TimePeriod(BaseModel):
52+
start: str = Field(...)
53+
end: str = Field(...)
54+
55+
@model_validator(mode='before')
56+
@classmethod
57+
def valid_time_period(cls, data) -> Any:
58+
if isinstance(data, list):
59+
if data[0] > data[1]:
60+
raise ValueError("Time period start must be before end.")
61+
return {"start": data[0], "end": data[1]}
62+
elif isinstance(data, dict):
63+
if data['start'] > data['end']:
64+
raise ValueError("Time period start must be before end.")
65+
return data
66+
67+
def __repr__(self):
68+
return f'{[self.start, self.end]}'
69+
70+
def does_timeperiod_overlap(self, checked_timeperiod: TimePeriod) -> bool:
71+
if checked_timeperiod.start < self.end and checked_timeperiod.end > self.start:
72+
return True
73+
else:
74+
return False
75+
76+
77+
78+
class SecurityConstraints:
79+
constraints: list
80+
81+
82+
class LegalConstraints:
83+
constraints: list
84+
85+
86+
class Characteristics:
87+
characteristics: list
88+
89+
90+
class Capabilities:
91+
capabilities: list
92+
93+
94+
class Contact:
95+
contact: list
96+
97+
98+
class Documentation:
99+
documentation: list
100+
101+
102+
class HistoryEvent:
103+
history_event: list
104+
105+
106+
class ConfigurationSettings:
107+
settings: list
108+
109+
110+
class FeatureOfInterest:
111+
feature: list
112+
113+
114+
class Input:
115+
input: list
116+
117+
118+
class Output:
119+
output: list
120+
121+
122+
class Parameter:
123+
parameter: list
124+
125+
126+
class Mode:
127+
mode: list
128+
129+
130+
class ProcessMethod:
131+
method: list

external_models/object_models.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# ==============================================================================
2+
# Copyright (c) 2024 Botts Innovative Research, Inc.
3+
# Date: 2024/5/31
4+
# Author: Ian Patterson
5+
# Contact Email: ian@botts-inc.com
6+
# ==============================================================================
7+
import uuid
8+
from typing import List
9+
10+
from conSys4Py import DatastreamSchema
11+
from conSys4Py.datamodels.api_utils import Link
12+
from pydantic import BaseModel, ConfigDict, Field
13+
from shapely import Geometry
14+
15+
from external_models import BoundingBox, Capabilities, Characteristics, ConfigurationSettings, Contact, DateTime, \
16+
Documentation, \
17+
FeatureOfInterest, HistoryEvent, Input, LegalConstraints, \
18+
Mode, Output, Parameter, ProcessMethod, SecurityConstraints, TimePeriod
19+
20+
21+
class System(BaseModel):
22+
model_config = ConfigDict(arbitrary_types_allowed=True)
23+
24+
feature_type: str = Field(None, serialization_alias="type")
25+
system_id: str = Field(None, serialization_alias="id")
26+
properties: dict = Field(None)
27+
geometry: Geometry | None = Field(None)
28+
bbox: BoundingBox = Field(None)
29+
links: List[Link] = Field(None)
30+
description: str = Field(None)
31+
uid: uuid.UUID = Field(None)
32+
label: str = Field(None)
33+
lang: str = Field(None)
34+
keywords: List[str] = Field(None)
35+
identifiers: List[str] = Field(None)
36+
classifiers: List[str] = Field(None)
37+
valid_time: DateTime = Field(None, serialization_alias="validTime")
38+
security_constraints: List[SecurityConstraints] = Field(None, serialization_alias="securityConstraints")
39+
legal_constraints: List[LegalConstraints] = Field(None, serialization_alias="legalConstraints")
40+
characteristics: List[Characteristics] = Field(None)
41+
capabilities: List[Capabilities] = Field(None)
42+
contacts: List[Contact] = Field(None)
43+
documentation: List[Documentation] = Field(None)
44+
history: List[HistoryEvent] = Field(None)
45+
definition: str = Field(None)
46+
type_of: str = Field(None, serialization_alias="typeOf")
47+
configuration: ConfigurationSettings = Field(None)
48+
features_of_interest: List[FeatureOfInterest] = Field(None, alias="featuresOfInterest")
49+
inputs: List[Input] = Field(None)
50+
outputs: List[Output] = Field(None)
51+
parameters: List[Parameter] = Field(None)
52+
modes: List[Mode] = Field(None)
53+
method: ProcessMethod = Field(None)
54+
55+
56+
class DatastreamResource(BaseModel):
57+
# model_config = ConfigDict(populate_by_name=True)
58+
59+
ds_id: str = Field(..., alias="id")
60+
name: str = Field(...)
61+
description: str = Field(None)
62+
valid_time: TimePeriod = Field(..., alias="validTime")
63+
output_name: str = Field(None, alias="outputName")
64+
procedure_link: Link = Field(None, alias="procedureLink@link")
65+
deployment_link: Link = Field(None, alias="deploymentLink@link")
66+
ultimate_feature_of_interest_link: Link = Field(None, alias="ultimateFeatureOfInterest@link")
67+
sampling_feature_link: Link = Field(None, alias="samplingFeature@link")
68+
parameters: dict = Field(None)
69+
phenomenon_time: TimePeriod = Field(None, alias="phenomenonTimeInterval")
70+
result_time: TimePeriod = Field(None, alias="resultTimeInterval")
71+
ds_type: str = Field(None, alias="type")
72+
result_type: str = Field(None, alias="resultType")
73+
links: List[Link] = Field(None)
74+
schema: DatastreamSchema = Field(None)
75+
76+
77+
class Observation(BaseModel):
78+
sampling_feature_id: str = Field(None, serialization_alias="samplingFeature@Id")
79+
procedure_link: Link = Field(None, serialization_alias="procedure@link")
80+
phenomenon_time: DateTime = Field(None, serialization_alias="phenomenonTime")
81+
result_time: DateTime = Field(..., serialization_alias="resultTime")
82+
parameters: dict = Field(None)
83+
result: dict = Field(...)
84+
result_link: Link = Field(None, serialization_alias="result@link")

0 commit comments

Comments
 (0)