Metadata-Version: 2.4
Name: oshconnect
Version: 0.5.5a1
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.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic<3.0.0,>=2.13.4
Requires-Dist: shapely<3.0.0,>=2.1.2
Requires-Dist: requests>=2.33.1
Requires-Dist: urllib3>=2.7.0
Provides-Extra: mqtt
Requires-Dist: paho-mqtt>=2.1.0; extra == "mqtt"
Provides-Extra: nats
Requires-Dist: nats-py>=2.6.0; extra == "nats"
Provides-Extra: streaming
Requires-Dist: paho-mqtt>=2.1.0; extra == "streaming"
Requires-Dist: nats-py>=2.6.0; extra == "streaming"
Provides-Extra: all
Requires-Dist: paho-mqtt>=2.1.0; extra == "all"
Requires-Dist: nats-py>=2.6.0; extra == "all"
Requires-Dist: protobuf>=7.35.0; extra == "all"
Requires-Dist: flatbuffers>=24.0; extra == "all"
Requires-Dist: tinydb<5.0.0,>=4.8.2; extra == "all"
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)

## Installation

OSHConnect is published to [PyPI](https://pypi.org/project/oshconnect/), but
so far **only as alpha pre-releases** (latest `0.5.1a22`) — there is no stable
release yet. `pip` and `uv` skip pre-releases by default, so you must opt in:

```bash
pip install "oshconnect==0.5.1a22"               # exact pin auto-allows the alpha
pip install --pre oshconnect                     # or: latest alpha (note below)

uv add "oshconnect==0.5.1a22"                    # exact pin auto-allows the alpha
uv add "oshconnect>=0.5.1a0" --prerelease=allow  # or: allow future alphas
```

Prefer the exact pin with `pip`: its `--pre` flag is global, so it also
allows pre-releases of every dependency (e.g. an alpha `pydantic`), not just
`oshconnect`.

To track unreleased work, install straight from Git instead (no pre-release
flag needed):

```bash
pip install "git+https://github.com/Botts-Innovative-Research/OSHConnect-Python.git"
uv add "git+https://github.com/Botts-Innovative-Research/OSHConnect-Python.git"
```

Releases are published from `v*` tags via `.github/workflows/publish.yml`.

## Installation extras

The base install is transport-free (HTTP discovery/CRUD + models). Streaming
and binary encodings are opt-in extras: `mqtt`, `nats`, `streaming` (mqtt +
nats), `protobuf`, `flatbuffers`, `tinydb`, and `all`.

**Extras combine** — comma-separate them in one bracket (no spaces); they're
additive. This works from PyPI, from the Git URL, and in a uv project.

```bash
# From PyPI (pre-release opt-in required, as above):
pip install --pre "oshconnect[mqtt,protobuf]"
uv add "oshconnect[mqtt,nats]==0.5.1a22"              # exact pin auto-allows the alpha
uv add "oshconnect[streaming]>=0.5.1a0" --prerelease=allow

# From Git (unreleased work) — use the "name[extras] @ URL" form:
pip install "oshconnect[mqtt,protobuf] @ git+https://github.com/Botts-Innovative-Research/OSHConnect-Python.git"
uv add "git+https://github.com/Botts-Innovative-Research/OSHConnect-Python.git" --extra mqtt --extra nats
```

See the [tutorial's Optional features table](https://botts-innovative-research.github.io/OSHConnect-Python/tutorial.html)
for the full matrix.

## 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.11 / 3.12 / 3.13 / 3.14 and uploads `coverage.xml` as a workflow
artifact (downloadable from the run page). A further non-blocking lane runs
against the 3.15 pre-release as an early-warning signal; it is allowed to fail
and does not gate merges.

Development happens on Python 3.14 (pinned in `.python-version`); 3.11 is the
supported floor.

## Logging

OSHConnect logs to the `oshconnect` logger namespace — every module uses
`logging.getLogger(__name__)`, so records arrive as `oshconnect.node`,
`oshconnect.resources.system`, `oshconnect.csapi4py.mqtt`, and so on.

The library never configures logging on your behalf: the package logger
carries a `NullHandler`, so nothing is emitted until you opt in. One call
controls the whole library without touching the root logger or any other
package:

```python
import logging

logging.basicConfig(level=logging.INFO)               # your app's choice
logging.getLogger("oshconnect").setLevel(logging.DEBUG)   # verbose OSHConnect
logging.getLogger("oshconnect.csapi4py.mqtt").setLevel(logging.WARNING)  # ...but quiet MQTT
```

Note that discovery additionally raises `SchemaFetchWarning` through the
`warnings` module when an individual datastream or control-stream schema
fetch fails. That's deliberate and separate from logging — discovery
doesn't raise on per-resource schema failures, so the warning is how you
catch them programmatically (`warnings.catch_warnings`).

## 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`.
