Skip to main content

ReadyView Dashboard Python Library

The ReadyView Dashboard Python library provides all current ReadyView dashboard API calls to interface with the ReadyLinks ReadyView cloud-managed platform. ReadyView generates the library based on dashboard API's OpenAPI spec to keep it up to date with the latest API releases, and provides the full source code for the library including the tools used to generate the library. ReadyLinks welcomes constructive pull requests that maintain backwards compatibility with prior versions. The library requires Python 3.8+, receives support from the community, and you can install it via PyPI:

pip install --upgrade readyview

Usage

  1. Export your Organization ID and API Key as an environment variable, for example:
export READYVIEW_DASHBOARD_ORG_ID=YOUR_ORG_ID
export READYVIEW_DASHBOARD_API_KEY=YOUR_API_KEY

The library calls https://api.readylinks.io/. To use another ReadyView API, such as a test server, set READYVIEW_BASE_URL. 2. Import the library with a single line at the top of your Python script.

import readyview
  1. Instantiate the dashboard client.
dashboard = readyview.Dashboard()
  1. Start programmatically interacting with your ReadyView dashboard!
my_networks = dashboard.network.get_networks()

Errors and strict mode

By default, a call that fails returns None, so existing scripts keep working. To find out why a call failed, turn on strict mode:

import readyview

dashboard = readyview.Dashboard(raise_errors=True)

try:
    config = dashboard.switch.get_switch_configurations("AA:BB:CC:DD:EE:FF")
except readyview.ReadyViewAPIError as error:
    print(error)
    # GET /v1/devices/AA:BB:CC:DD:EE:FF/switch failed with HTTP 504: The device did not answer within the time limit.

In strict mode, a call that fails raises readyview.ReadyViewAPIError, which has:

  • status_code: the HTTP status, such as 401, 404, 429 or 504. It is None when no reply arrived, because the API could not be reached or did not answer in time. Those calls raise the subclass readyview.ReadyViewConnectionError.
  • message: why the call failed, as the API explained it.
  • method and path: the call that failed, such as GET and /v1/devices/AA:BB:CC:DD:EE:FF/switch.
  • retry_after: when the reply has a Retry-After header (usually with a 429, when you are rate limited), how many seconds it asks you to wait before trying again. Otherwise None.

The error is built from the API's reply only. It never repeats what you sent, or the values the API rejected, since those can be passwords.

Calls that work return the same values in both modes, with two differences in strict mode: any 2xx status counts as success, and a reply that is not JSON (say, a hotel network's sign-in page) raises ReadyViewAPIError.

Logging

The library logs to the readyview logger with Python's logging module. It logs each reply at DEBUG. In the default mode, it also logs a failed call: an error status at INFO, and a request that got no reply at WARNING, which earlier versions printed. To see why calls return None without switching to strict mode:

import logging

logging.basicConfig()
logging.getLogger("readyview").setLevel(logging.INFO)

SNMPv3 users

SnmpV3User builds a user that a switch accepts. It checks the firmware's rules as it is built: a name of 3-16 characters, passwords of 9-15, printable ASCII without spaces, ' or \. dashboard.switch.add_snmp_user() then adds it safely:

import readyview
from readyview import SnmpV3User

dashboard = readyview.Dashboard()
user = SnmpV3User.auth_priv("nms-poller", auth_password="...", privacy_password="...")

for device in dashboard.network.get_devices("YOUR-NETWORK-ID"):
    if device["device_type"] == "Switch" and device["status"] == "Online":
        result = dashboard.switch.add_snmp_user(device["mac_address"], user, current=device)
        print(device["name"], result.status.value, result.detail)

For each switch, add_snmp_user:

  • reads the switch first, and leaves it alone if it already has the user, so it is safe to run again
  • reports a conflict when the name exists with other settings, since the API can add an SNMPv3 user but cannot change or delete one. A user the switch stores encrypted (ReadyView's SNMP user form does by default) counts as the same user when its name, access and algorithms match: its passwords cannot be compared
  • reports full when the switch already has 10 users
  • turns the SNMP service on if it is off
  • checks the reply for refused values, then reads the configuration back until the switch reports the user, the only real confirmation

password_mode="cipher" (on SnmpV3User.auth_priv() or auth_no_priv()) has the switch store the passwords encrypted, as ReadyView's SNMP user form does by default:

  • It hides rather than protects. The switch encrypts with a key built into its firmware. That keeps the passwords out of plain sight in ReadyView and the API, but it is not real secrecy.
  • The read-back can't check the passwords. The switch reports them encrypted, so the read-back confirms everything but the passwords.
  • Some passwords are refused. The switch would mistake a password whose last digits match a firmware pattern for one it had already encrypted, and store a different password. Those are refused.

Passing the switch's record as current= (the device records above include each switch's SNMP settings) saves the first read. When the record shows the switch without the user, the change goes out at once and the read-back is the only live read. The result still comes from the switch: a record that is out of date can cost a read, never change the outcome.

It never raises for a switch it could not configure: result.status, result.detail and result.ok say what happened. Its live configuration reads are spaced to stay under the API's limit of 30 a minute, and a read the API turns away with HTTP 429 is tried again after a pause. SnmpV3User.auth_no_priv() and SnmpV3User.no_auth_no_priv() build the other security levels, and dashboard.switch.get_snmp_users(mac) lists a switch's users without their passwords.

Secure connections

On Python 3.10 and later the library checks the API's certificate against the computer's own certificate store, as a browser does, through truststore. That is what makes it work on a network that inspects HTTPS, where the traffic is re-signed with a certificate that company IT has installed on the computer. On Python 3.8 and 3.9, run python -m pip install pip-system-certs, or set REQUESTS_CA_BUNDLE to the network's certificate. A REQUESTS_CA_BUNDLE you set is always used as given. When the check fails, the error says why and what to do.

Automation

Operations that report an outcome

These dashboard.switch methods each make one change and return an Outcome:

  • ok: whether the switch ends up as asked
  • status: what happened, such as sent, refused, up to date or error
  • detail: the API's reason, or what changed

They never raise for a switch they could not change, so a loop over many switches reports every one:

Method What it does
apply_settings(mac, change) Sends a SwitchPost change and reports any value the switch refused
use_template(mac, template_id) Applies a configuration template; reports skipped when the template is for another model
upgrade_firmware(mac, version=None, channel=None) Starts an upgrade; reports up to date when the switch already has the firmware
add_bandwidth_profiles(mac, profiles) Adds bandwidth profiles, or replaces those with the same ids
bind_bandwidth_profile(mac, client_mac, profile_id) Finds the client's port and limits the client to a profile
update_client(mac, client_mac, **fields) Changes a connected client, e.g. location="Room 101"
add_snmp_user(mac, user, current=None) Adds an SNMPv3 user (see above)
check_snmp_user(mac, name, privilege=, level=, ...) Says what add_snmp_user would do, without the passwords

Each of the others takes dry_run=True to make a check instead: it only reads, and says what it would do.

  • Would change: the status is readyview.WOULD_CHANGE ("would change"), and the detail says what, such as from 8.047 to 8.048 or changes syslog.server_ip_address.
  • Nothing to do: a switch it would leave alone gets the answer a run would give: already configured, up to date, or skipped for a template of another model.
  • Cannot go ahead: the status says why, with ok False, such as no such profile.

Checks use the switch's record (current=, as automation.select_switches() returns it) or the API's cached configuration. They never make a live read. The upgrade check asks the API which build the upgrade would install (GET /v1/devices/{mac}/switch/upgrade).

Scripts that change many switches

readyview.automation holds the parts every automation script repeats. That is the --network / --switch / --all-networks / --dry-run / --yes / --parallel N command line, plus picking the online switches, with a firmware minimum if you set one. It shows the plan, asks before changing anything, reports each switch, and ends with a summary and an exit status. A complete script:

from readyview import automation
from readyview.switch_post import Lldp, SwitchPost

parser = automation.command_line("Turn LLDP on.")
args = parser.parse_args()
change = SwitchPost(lldp=Lldp(enabled=True))
raise SystemExit(automation.run(
    args, "turn LLDP on",
    lambda dashboard, switch: dashboard.switch.apply_settings(switch["mac_address"], change),
    min_firmware=7.655,
))

--parallel N (or run(..., parallel=N)) changes up to N switches at the same time, 1-16. automation.command_line(description, parallel=6) sets a script's default; it is 1 otherwise. Each switch spends most of its time waiting: on its reply, and for the change to show up when it is read back. Running several at once overlaps those waits, while live switch reads stay paced across all of them, so the API's rate limit holds. The outcomes are printed in the order of the plan.

--only MAC [MAC ...] changes only those of the chosen switches, for example the ones a run could not change. The others are listed as skipped.

--all-networks takes every online switch in the organization. It reads the switches once, as does a --switch list of more than 30. The device list allows 15 requests a minute, so a few hundred MACs looked up ten at a time would hit that limit.

Pass check= to make the plan exact: usually the same call with dry_run=True. A dry run, and the confirmation, then ask each switch first.

  • Switches to change lists only the ones the run would change, each with what would change.
  • Already as asked lists the ones the run would leave as they are.
  • Skipped gets the ones the change does not apply to.

Runs with --yes make no checks.

automation.run(
    args, "upgrade to the recommended firmware",
    lambda dashboard, switch: dashboard.switch.upgrade_firmware(switch["mac_address"]),
    check=lambda dashboard, switch: dashboard.switch.upgrade_firmware(switch["mac_address"], dry_run=True),
)

Ctrl+C starts no more switches and finishes the ones already started, one at a time or in parallel, so no switch is left halfway. The summary counts the rest as "not started".

automation.ask_secret(label, env_var) reads a password from the environment, or has it typed twice at a hidden prompt.

A program that runs these scripts, such as ReadyView's Automation scripts page, can follow them without reading the printed text. Set READYVIEW_EVENTS_FD to an open file descriptor, and run() also writes its plan, each switch as it starts and finishes, and the summary there, as one JSON object per line. The readyview.automation module documents the events.

Reports

readyview.reports.gather(dashboard, switches) reads every switch's ports and recent metrics from ReadyView's cache, several at a time. A switch that cannot be read is listed with the reason. device_rows(), client_rows(), fiber_rows() and firmware_rows() turn that into report rows, and find_device(mac, ...) finds where a device is connected. The rows are plain dicts, ready for pandas:

import pandas as pd
from readyview import reports

switches = dashboard.device.get_devices(params={"device_type": ["Switch"]})
data = reports.gather(dashboard, switches)
pd.DataFrame(reports.device_rows(switches, data)).to_excel("switches.xlsx", index=False)

Contribute

Create a branch to add your feature/fix then submit a merge request to main for review. Be sure to follow the correct format in your commit message to trigger the pipeline to submit a new release. Example commit below.

feat: Added the ability to update switch configurations.
fix: Fixes some bug. 
BREAKING CHANGE: Updated function API. 

Run the tests before you submit:

pip install -e ".[test]"
pytest

Metadata

Release files for readyview 1.23.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for readyview 1.23.0
File Size Uploaded Provenance
readyview-1.23.0.tar.gz 98.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for readyview 1.23.0
File Interpreter ABI Platform
readyview-1.23.0-py3-none-any.whl Python 3 none any Details

Total release size: 160.4 kB

Release files / readyview-1.23.0.tar.gz

Download URL readyview-1.23.0.tar.gz
Size 98.0 kB
Tags Source
SHA-256 checksum
How to use checksums
e9d5094e934e9a6b0626f0404f4f4aab5a82913da2d39b2aba714dda23fc09e0
BLAKE2b-256 checksum
How to use checksums
731c109e5a2ad835e874af62d10bece0ffd4a4cc8d7b89f1409b074f4785db5b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Hatch/1.18.1 {"ci":true,"cpu":"x86_64","distro":{"id":"trixie","libc":{"lib":"glibc","version":"2.41"},"name":"Debian GNU/Linux","version":"13"},"implementation":{"name":"CPython","version":"3.11.17"},"installer":{"name":"hatch","version":"1.18.1"},"openssl_version":"OpenSSL 3.5.7 9 Jun 2026","python":"3.11.17","system":{"name":"Linux","release":"5.15.154+"}} HTTPX2/2.14.0

Release files / readyview-1.23.0-py3-none-any.whl

Download URL readyview-1.23.0-py3-none-any.whl
Size 62.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
814b064da4be4e3a95b1ba645574d4c306957127254d83ce0f1e663f4468f728
BLAKE2b-256 checksum
How to use checksums
448c23daa53d5433ccc04723a6ba1476054213dca894a5d533fe62396f62424f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Hatch/1.18.1 {"ci":true,"cpu":"x86_64","distro":{"id":"trixie","libc":{"lib":"glibc","version":"2.41"},"name":"Debian GNU/Linux","version":"13"},"implementation":{"name":"CPython","version":"3.11.17"},"installer":{"name":"hatch","version":"1.18.1"},"openssl_version":"OpenSSL 3.5.7 9 Jun 2026","python":"3.11.17","system":{"name":"Linux","release":"5.15.154+"}} HTTPX2/2.14.0

Security for readyview 1.23.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page