Skip to main content

Async and sync Python client for the LibreNMS API

Project description

libreclient

License: MIT Python 3.12+

Async and sync Python client for the LibreNMS API.

  • Dual interface โ€” use LibreClientAsync for async/await or LibreClientSync for traditional blocking calls.
  • Typed responses โ€” all endpoints return Pydantic models with full IDE autocomplete.
  • Environment-driven config โ€” configure via LIBRENMS_URL and LIBRENMS_TOKEN env vars or pass values directly.

Installation

pip install libreclient

Or with uv:

uv add libreclient

Quick Start

Synchronous

from libreclient import LibreClientSync

client = LibreClientSync(url="https://librenms.example.com", token="your-api-token")

# List all devices
response = client.devices.list_devices()
for device in response.devices:
    print(device["hostname"])

# Get a specific alert
alert = client.alerts.get_alert(42)

Asynchronous

import asyncio
from libreclient import LibreClientAsync


async def main():
    client = LibreClientAsync(url="https://librenms.example.com", token="your-api-token")

    response = await client.devices.list_devices()
    for device in response.devices:
        print(device["hostname"])

    await client.close()


asyncio.run(main())

Context Manager

# Sync
with LibreClientSync(url="https://librenms.example.com", token="your-api-token") as client:
    print(client.system.ping())

# Async
async with LibreClientAsync(url="https://librenms.example.com", token="your-api-token") as client:
    print(await client.system.ping())

Configuration

Configuration is handled by pydantic-settings. You can pass values directly or set environment variables:

Env Variable Description Default
LIBRENMS_URL Base URL of your LibreNMS instance (required)
LIBRENMS_TOKEN API token (X-Auth-Token) (required)
LIBRENMS_VERIFY_SSL Verify TLS certificates true
LIBRENMS_API_VERSION API version path segment v0

A .env file in your working directory is also supported. Copy the included sample to get started:

cp sample.env .env
# Edit .env with your LibreNMS URL and API token

Available Route Namespaces

All route namespaces are accessible as properties on the client:

Property Description
client.alerts Alert management and alert rules/templates
client.arp ARP table lookups
client.bills Billing data and graphs
client.device_groups Device group management
client.devices Device CRUD, discovery, components, graphs
client.index List available API endpoints
client.inventory Hardware inventory
client.locations Location management
client.logs Event, syslog, alert, and auth logs
client.poller_groups Poller group info
client.pollers Poller status
client.port_groups Port group management
client.port_security Port security (802.1X/MAB)
client.ports Port info, search, and descriptions
client.routing BGP, OSPF, VRF, MPLS, IPsec
client.services Service monitoring
client.switching VLANs, links, FDB, NAC
client.system Ping and system info

Contributing

Contributions are welcome! We're actively looking for contributors to help with:

  • ๐Ÿ› Bug fixes and edge case handling
  • โœจ Support for new routes as LibreNMS adds API endpoints
  • ๐Ÿ“– Documentation improvements
  • ๐Ÿงช Test coverage expansion
  • ๐Ÿ”ง Tooling and CI improvements

Getting started:

  1. Fork the repo and create a branch from dev
  2. Follow the Development setup below
  3. Make your changes with tests
  4. Open a PR against dev โ€” CI will lint, test, and auto-fix formatting

See CONTRIBUTING.md for detailed guidelines, or just open an issue to discuss your idea first.


Development

Prerequisites

  • Python 3.12+
  • uv (package manager)

Setup

git clone https://github.com/jjeff07/libreclient.git
cd libreclient
uv sync

Running Tests

# Unit tests
uv run pytest tests/unit

# Functional tests (requires .env with LIBRENMS_URL and LIBRENMS_TOKEN)
uv run pytest tests/functional

Linting & Formatting

This project uses Ruff for both linting and formatting:

# Check for lint issues
uv run ruff check

# Auto-fix lint issues
uv run ruff check --fix

# Format code
uv run ruff format

# Check formatting without changing files
uv run ruff format --check

Complexity Checks

complexipy is used to enforce a maximum cognitive complexity of 15 per function:

uv run complexipy .

Results are output to complexipy-results.json. Any function exceeding the threshold will cause the check to fail.

Architecture

The project uses a single-implementation pattern: each route is written once as an async class. The synchronicity library then wraps each async class to produce a synchronous counterpart at runtime.

src/py_librenms/routes/alerts.py
โ”œโ”€โ”€ class Alerts              โ† async implementation (the only code you write)
โ””โ”€โ”€ AlertsSync = synchronizer.wrap(Alerts, ...)   โ† sync wrapper (auto-generated at import)

This means:

  • You only maintain one implementation per route.
  • Both LibreClientAsync and LibreClientSync share the same logic.
  • No code duplication between sync and async interfaces.

Type Stubs

Because synchronicity generates wrapper classes dynamically, IDEs can't infer their method signatures. To restore full autocomplete and type checking, .pyi stub files are auto-generated.

Regenerate stubs locally:

uv run python generate_stubs.py

Stubs are generated automatically during the GitHub Actions release workflow, so you don't need to commit them โ€” they're in .gitignore.

Adding a New Route

  1. Create src/py_librenms/routes/myroute.py with an async class and MyRouteSync = synchronizer.wrap(...) at the bottom.
  2. Create src/py_librenms/models/myroute.py with Pydantic response models.
  3. Add exports to src/py_librenms/models/__init__.py.
  4. Add exports to src/py_librenms/routes/__init__.py.
  5. Wire up the route in src/py_librenms/client.py (both sync and async clients).
  6. Run uv run python generate_stubs.py.
  7. Add tests in tests/unit/routes/test_myroute.py and tests/unit/models/test_myroute.py.

Commit Convention

This project enforces Conventional Commits via commitizen. A git hook validates every commit message automatically.

Setup the hook (once per clone):

git config core.hooksPath .githooks

Format:

type(scope)?: description

[optional body]
[optional footer]

Allowed types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, bump

Examples:

feat(routing): add OSPFv3 port listing
fix: handle empty response from list_devices
docs: add upstream tracking section to README
test: add functional tests for switching routes

Upstream API Tracking

This project tracks which LibreNMS release tag the route implementations are based on. The pinned version is stored in upstream_tracking.toml.

# Check if upstream has a newer release
python check_upstream.py

# See which API doc files changed
python check_upstream.py --diff

# See full unified diffs of changed docs
python check_upstream.py --full

# Compare against a specific tag instead of latest
python check_upstream.py --diff --tag 26.6.0

# Bump the pinned tag after reviewing changes
python check_upstream.py --bump

Project Structure

libreclient/
โ”œโ”€โ”€ src/py_librenms/
โ”‚   โ”œโ”€โ”€ __init__.py            # Public API exports
โ”‚   โ”œโ”€โ”€ client.py              # LibreClientSync & LibreClientAsync
โ”‚   โ”œโ”€โ”€ config.py              # Pydantic-settings configuration
โ”‚   โ”œโ”€โ”€ _base_client.py        # Shared HTTP transport logic
โ”‚   โ”œโ”€โ”€ models/                # Pydantic response models
โ”‚   โ””โ”€โ”€ routes/                # Route namespaces (async + sync wrappers)
โ”‚       โ”œโ”€โ”€ _types.py          # ClientProtocol & utilities
โ”‚       โ”œโ”€โ”€ _synchronicity.py  # Shared Synchronizer instance
โ”‚       โ”œโ”€โ”€ alerts.py          # Example route implementation
โ”‚       โ””โ”€โ”€ ...
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ unit/
โ”‚   โ”‚   โ”œโ”€โ”€ models/            # Model validation tests
โ”‚   โ”‚   โ””โ”€โ”€ routes/            # Route logic tests (MockClient)
โ”‚   โ””โ”€โ”€ functional/            # Live API tests (requires .env)
โ”œโ”€โ”€ check_upstream.py          # Detect upstream API doc changes
โ”œโ”€โ”€ upstream_tracking.toml     # Pinned LibreNMS release tag
โ”œโ”€โ”€ generate_stubs.py          # .pyi stub generator
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ CHANGELOG.md
โ””โ”€โ”€ LICENSE

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

libreclient-0.1.2.tar.gz (30.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

libreclient-0.1.2-py3-none-any.whl (61.4 kB view details)

Uploaded Python 3

File details

Details for the file libreclient-0.1.2.tar.gz.

File metadata

  • Download URL: libreclient-0.1.2.tar.gz
  • Upload date:
  • Size: 30.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for libreclient-0.1.2.tar.gz
Algorithm Hash digest
SHA256 2d7957f6cb4a00ec519dad63625c4ed3ac1491fd370a3875b70ea6d9aeb85bba
MD5 e4809fde3f0d1bfc1033c8ced6c5712d
BLAKE2b-256 9df1031e784f9415dcdf3f6af582bd4c625cb46ad1e6eadc88fe0971dc374f02

See more details on using hashes here.

File details

Details for the file libreclient-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: libreclient-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 61.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for libreclient-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 79e41f1442bcf4af4173eaf0ecc6b8b6f6334f3d272ad2f8fe87dbe0e236cbcf
MD5 4aa51681343fe2797a6223a76088d5df
BLAKE2b-256 e4b2f268761544220482721e942fb4406746479e8a1cee4bc28f971de26d0277

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page