Metadata-Version: 2.4
Name: oshconnect
Version: 0.5.1a22
Summary: Library for interfacing with OSH, helping guide visualization efforts, and providing a place to store configurations. Implements OGC CS API Part 3 (Pub/Sub) MQTT topic conventions including :data topics and resource event topics.
Author-email: Ian Patterson <ian.patterson@georobotix.us>
Requires-Python: <4.0,>=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: paho-mqtt>=2.1.0
Requires-Dist: nats-py>=2.6.0
Requires-Dist: pydantic<3.0.0,>=2.13.4
Requires-Dist: shapely<3.0.0,>=2.1.2
Requires-Dist: websockets<17.0,>=16.0
Requires-Dist: requests>=2.33.1
Requires-Dist: aiohttp>=3.13.5
Requires-Dist: urllib3>=2.7.0
Provides-Extra: protobuf
Requires-Dist: protobuf>=7.35.0; extra == "protobuf"
Provides-Extra: flatbuffers
Requires-Dist: flatbuffers>=24.0; extra == "flatbuffers"
Provides-Extra: av
Requires-Dist: av>=15.0.0; extra == "av"
Requires-Dist: pillow>=11.0.0; extra == "av"
Provides-Extra: dev
Requires-Dist: flake8>=7.3.0; extra == "dev"
Requires-Dist: pytest>=9.0.0; extra == "dev"
Requires-Dist: pytest-cov>=7.0.0; extra == "dev"
Requires-Dist: interrogate>=1.7.0; extra == "dev"
Requires-Dist: sphinx>=9.0.0; extra == "dev"
Requires-Dist: furo>=2025.12.19; extra == "dev"
Requires-Dist: myst-parser>=5.0.0; extra == "dev"
Requires-Dist: sphinxcontrib-mermaid>=2.0.0; extra == "dev"
Requires-Dist: sphinx-copybutton>=0.5.2; extra == "dev"
Requires-Dist: Pygments>=2.20.0; extra == "dev"
Provides-Extra: tinydb
Requires-Dist: tinydb<5.0.0,>=4.8.2; extra == "tinydb"
Dynamic: license-file

# OSHConnect-Python

Library for communicating with Opensensorhub that provides options for saving configurations, getting visualization 
recommendations for data, retrieving data in real time, archival streams, and batch modes, and more.

API Documentation available [here](https://botts-innovative-research.github.io/OSHConnect-Python/)

Links:
 * [Architecture Doc](https://docs.google.com/document/d/1pIaeQw0ocU6ApNgqTVRZuSwjJAbhCcmweMq6RiVYEic/edit?usp=sharing)
 * [UML Diagram](https://drive.google.com/file/d/1FVrnYiuAR8ykqfOUa1NuoMyZ1abXzMPw/view?usp=drive_link)

## Pre-releases

Every push to the `dev` branch publishes a `.devN` pre-release wheel to
[TestPyPI](https://test.pypi.org/project/oshconnect/) once the test suite
passes. To install the latest:

```bash
pip install --index-url https://test.pypi.org/simple/ \
            --extra-index-url https://pypi.org/simple/ \
            oshconnect --pre
```

The `--extra-index-url` is needed so transitive deps (pydantic, paho-mqtt,
…) still resolve from real PyPI. Tagged releases (`v*`) continue to publish
to real PyPI via `.github/workflows/publish.yml`.

## Running Tests

```bash
uv sync                                # install dev deps (incl. pytest, pytest-cov)
uv run pytest                          # full suite (skips network-marked tests if you add `-m "not network"`)
uv run pytest tests/test_swe_components.py -v   # one file, verbose
uv run pytest -k name_token            # one keyword
```

Tests that need a live OSH server (e.g. `localhost:8282` running
FakeWeatherDriver) are tagged `@pytest.mark.network`. CI skips them; locally
you can include or exclude them:

```bash
uv run pytest -m "not network"         # what CI runs
uv run pytest -m network               # only the live-server tests
```

## Test Coverage

Coverage is opt-in via [`pytest-cov`](https://pytest-cov.readthedocs.io/). The
default `pytest` run is fast; add `--cov` when you want a report.

```bash
uv run pytest --cov                    # terminal summary + missing lines
uv run pytest --cov --cov-report=html  # HTML report at htmlcov/index.html
uv run pytest --cov --cov-report=xml   # coverage.xml (CI / Codecov-ready)
```

Configuration lives in `pyproject.toml` under `[tool.coverage.*]` — branch
coverage is on, source is scoped to `src/oshconnect`, and obvious dead lines
(`if TYPE_CHECKING:`, `raise NotImplementedError`, etc.) are excluded.

CI (`.github/workflows/tests.yaml`) runs the suite with `--cov` on every push
across Python 3.12 / 3.13 / 3.14 and uploads `coverage.xml` as a workflow
artifact (downloadable from the run page).

## Documentation Coverage

[`interrogate`](https://interrogate.readthedocs.io/) reports what fraction of
public modules / classes / functions / methods carry a docstring (presence
only, it doesn't check style). It's purely informational right now; there's
no CI gate. Configuration lives in `pyproject.toml` under `[tool.interrogate]`
(`__init__`, dunder, private, and property/setter members are skipped).

```bash
uv run interrogate src/oshconnect              # one-line summary
uv run interrogate -v src/oshconnect           # per-file table
uv run interrogate -vv src/oshconnect          # per-symbol (shows which symbols are missing)
```

Once we agree on a baseline, raise `[tool.interrogate].fail-under` from `0` so
new code without docstrings starts failing locally and in CI.

## OGC Format Serialization

Format-explicit conversion methods on the wrapper classes (`System`,
`Datastream`, `ControlStream`) and the underlying pydantic resource models.
Use these to round-trip CS API server JSON in **SML+JSON**, **OM+JSON**, and
**SWE+JSON** without having to remember the `model_dump(by_alias=True, …)`
incantation, and to construct OSHConnect wrappers from raw server payloads.

```python
from oshconnect import Node, System, Datastream

node = Node(protocol="http", address="localhost", port=8282)

# Build a System from an SML+JSON server response
sys_dict = {"type": "PhysicalSystem", "uniqueId": "urn:test:1", "label": "Sensor"}
sys = System.from_csapi_dict(sys_dict, node)        # auto-detects SML vs GeoJSON
sys.to_smljson_dict()                                # -> dict ready to POST

# Build a Datastream from a CS API listing entry
ds = Datastream.from_csapi_dict(ds_json, node)
ds.to_csapi_dict()                                   # the resource body
ds.schema_to_swejson_dict()                          # the SWE+JSON schema doc
ds.observation_to_omjson_dict({"temperature": 22.5}) # one OM+JSON observation

# Single observations / commands
from oshconnect.resource_datamodels import ObservationResource
obs = ObservationResource.from_omjson_dict(om_json_payload)
obs.to_swejson_dict()                                # flat SWE+JSON record
```

The two older static factories `System.from_system_resource` and
`Datastream.from_resource` are deprecated in favor of `from_csapi_dict` and
emit `DeprecationWarning` on use. They'll be removed in a future major
version.

## Generating the Docs

The documentation is built with [Sphinx](https://www.sphinx-doc.org/) using
the [Furo](https://pradyunsg.me/furo/) theme,
[autodoc](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html)
for auto-generated API reference from docstrings,
[MyST](https://myst-parser.readthedocs.io/) so that Markdown source files
work alongside reST, and [sphinxcontrib-mermaid](https://github.com/mgaitan/sphinxcontrib-mermaid)
for the architecture diagrams. Sources live under `docs/source/`.

Install dev dependencies (including Sphinx, Furo, and the plugins):

```bash
uv sync --all-extras
```

Build the HTML docs:

```bash
uv run sphinx-build -b html docs/source docs/build/sphinx
```

Open `docs/build/sphinx/index.html` in a browser to view locally.

For a live-reloading preview while editing, use
[sphinx-autobuild](https://github.com/sphinx-doc/sphinx-autobuild):

```bash
uv run --with sphinx-autobuild sphinx-autobuild docs/source docs/build/sphinx
```

To match what CI publishes (warnings become errors — useful after touching
docstrings or signatures):

```bash
uv run sphinx-build -W --keep-going -b html docs/source docs/build/sphinx
```

CI builds the site on every push and deploys `main` to GitHub Pages via
`.github/workflows/docs_pages.yaml`.
