Metadata-Version: 2.1
Name: motorcortex-python
Version: 1.0.0
Summary: Python bindings for Motorcortex Engine
Home-page: https://www.motorcortex.io
Author: Alexey Zakharov
Author-email: alexey.zakharov@vectioneer.com
License: MIT
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pynng<2,>=0.9.0
Requires-Dist: protobuf>=3.20

# motorcortex-python

[![pipeline status](https://git.vectioneer.com/pub/motorcortex-python/badges/master/pipeline.svg)](https://git.vectioneer.com/pub/motorcortex-python/-/commits/master)
[![coverage report](https://git.vectioneer.com/pub/motorcortex-python/badges/master/coverage.svg?job=coverage)](https://git.vectioneer.com/pub/motorcortex-python/-/commits/master)
[![PyPI version](https://img.shields.io/pypi/v/motorcortex-python.svg)](https://pypi.org/project/motorcortex-python/)
[![Python versions](https://img.shields.io/pypi/pyversions/motorcortex-python.svg)](https://pypi.org/project/motorcortex-python/)
[![License: MIT](https://img.shields.io/pypi/l/motorcortex-python.svg)](LICENSE)

Python bindings for the [Motorcortex](https://www.motorcortex.io) real-time control engine. Connect to a Motorcortex server, read and write parameters, and stream live telemetry over a single TLS-secured websocket.

## Installation

```bash
pip install motorcortex-python
```

Requires Python ≥ 3.10. Runtime dependencies (`pynng`, `protobuf`) are installed automatically.

## Quick start

Recommended — `Session` context manager (close is automatic, even on exceptions):

```python
import motorcortex

with motorcortex.Session(
    "wss://192.168.2.100",
    certificate="mcx.cert.crt",
    login="admin", password="admin",
    timeout_ms=1000,
) as s:
    # Read a single parameter
    reply = s.req.getParameter("root/Control/dummyDouble").get()
    print(reply.value)

    # Write a parameter
    s.req.setParameter("root/Control/dummyDouble", 3.14).get()

    # Subscribe to a streamed update (every 10th cycle)
    subscription = s.sub.subscribe(
        ["root/Control/dummyDouble"], "myGroup", frq_divider=10,
    )
    subscription.get()
    subscription.notify(lambda result: print(result[0].value))
```

Explicit-objects form — the original API, still supported:

```python
types = motorcortex.MessageTypes()
tree = motorcortex.ParameterTree()

req, sub = motorcortex.connect(
    "wss://192.168.2.100", types, tree,
    certificate="mcx.cert.crt",
    login="admin", password="admin",
)
try:
    reply = req.getParameter("root/Control/dummyDouble").get()
    print(reply.value)
finally:
    sub.close()
    req.close()
```

The URL grammar accepts IPv4, hostnames, and IPv6 literals both with and without explicit ports — e.g. `wss://host`, `wss://host:5568:5567`, `wss://[::1]`, `wss://[fe80::1]:5568:5567`.

## Documentation

- **[API reference — `docs/_index.md`](docs/_index.md)** — flat, method-by-method reference for every public class and function. Regenerated from the docstrings via `pydoc-markdown`.
- **[`ARCHITECTURE.md`](ARCHITECTURE.md)** — internals tour: module layout, connection lifecycle, subscribe frame format, parameter-tree cache, threading model, error contract, type conventions.
- **[`examples/README.md`](examples/README.md)** — runnable scripts (`quickstart.py`, `error_handling.py`) that demonstrate the canonical usage patterns.
- **[`CHANGELOG.md`](CHANGELOG.md)** — version history.

## Repository layout

```
motorcortex/            Python package
test/
  unit/                 Offline unit tests (no server)
  integration/          Live tests against the vendored test_server
  server/               Vendored C++ test_server (CMake project)
docs/                   pydoc-markdown + stub generation scripts
benchmark/              Throughput scripts (not part of the test suite)
sandbox/                Ad-hoc repro scripts
```

## Testing

Unit tests run offline and require only the package itself:

```bash
pip install -e .
pip install "coverage[toml]>=7.4"
python -m unittest discover -s test/unit -t .
```

Integration tests spawn the vendored `test_server`. Build it once, then run the suite:

```bash
cmake -S test/server -B test/server/build -DCMAKE_BUILD_TYPE=Release
cmake --build test/server/build

python -m unittest discover -s test/integration -t .
```

Coverage (line + branch). `pyproject.toml` sets `parallel = true`, so each
`coverage run` writes a per-process data shard; use `coverage combine` to
merge them before `coverage report`:

```bash
coverage erase
coverage run -m unittest discover -s test/unit -t .
coverage run -m unittest discover -s test/integration -t .
coverage combine
coverage report
```

See [`test/README.md`](test/README.md) for the full testing walkthrough.

## Regenerating the API reference

[`docs/_index.md`](docs/_index.md) is committed and should be refreshed
before each release so the rendered reference matches the code at
the tag. The regen is two commands — `pydoc-markdown` first, then
`format_api.sh` to wrap `>>>` examples as fenced Python blocks and
prepend the front matter:

```bash
pip install pydoc-markdown
cd docs
pydoc-markdown pydoc-markdown.yml > _index.md
./format_api.sh
```

The hook-based one-shot version was dropped — it races with the
shell redirect and silently loses output. See `docs/readme.md` and
the comment in `docs/pydoc-markdown.yml` for the full rationale.

## Release process

See [`PIPHOWTO.md`](PIPHOWTO.md) for PyPI release steps and [`CHANGELOG.md`](CHANGELOG.md) for version history.

## License

MIT — see [`LICENSE`](LICENSE).
