Compatibility¶
The first question an evaluating team asks — “we run APIC 5.2/6.1, does this work?” — deserves a precise answer, not a shrug. This page states exactly what niwaki is validated against and how it behaves outside that envelope.
APIC firmware¶
niwaki is generated from, and validated against, APIC 6.0(9c). The 2,222 typed models, the read catalogue (15,452 classes), the navigation vocabulary and the filter grammar all derive from that firmware’s schemas, and the whole configuration surface is exercised live against a 6.0(9c) fabric on every release cycle (10,000+ pushed objects, the full query grammar, WebSocket subscriptions).
Outside 6.0(9c), the behavior is asymmetric by design:
Reads are tolerant. Any class the APIC returns is readable —
aci.query("someClass")works by name, results expose.dn,mo["wireAttr"]and.attrsregardless of whether a typed model or a catalogue entry exists. A firmware that adds classes or attributes degrades discovery (catalog.describeraisesUnknownClassErrorfor classes newer than the snapshot; unknown wire attributes stay reachable by their wire name), never correctness.Writes are fail-loud. The design DSL validates against the 6.0(9c) schemas before anything reaches the wire, and the APIC itself rejects what its firmware does not know — with the DN in clear in
stagedmode. Pushing 6.0-only attributes to an older APIC fails visibly, never silently.Older firmware (5.x): the core configuration classes (tenants, BDs, EPGs, contracts, access policies) have been wire-stable for many releases and generally work, but this is not systematically validated — pilot on a lab fabric first, exactly as you would with any tool.
Newer firmware (6.1+): everything 6.0(9c) knows keeps working; additions are invisible to the typed surface until niwaki ships a schema refresh (the generation pipeline is built to be re-run per firmware, so refreshes are mechanical).
The APIC version the shipped catalogue was built from is embedded in the artifact itself and checked by the test suite. Both halves of the question are readable at runtime — what the SDK targets, and what your fabric actually runs:
from niwaki import catalog
assert catalog.schema_version() == "6.0(9c)" # what this SDK was generated from
Niwaki.apic_version and AsyncNiwaki.apic_version hold what the controller
stated at login (None before connecting, or if it named none). Comparing the
two answers “am I inside the envelope?” — a mismatch is a reason to pilot, not
an error, so nothing warns and nothing raises.
Python¶
Requires Python 3.12+ (PEP 695 generics,
warningsAPI additions).3.12 and 3.13 are fully tested in CI on every commit and covered by the offline wheelhouse attached to each GitHub release.
3.14 is built and observed in CI (non-blocking) — it works today, and becomes a supported classifier once it is validated as blocking.
Thread and task safety¶
Niwaki/ApicSession(sync): safe to share across threads. The underlying HTTP client is thread-safe, token refresh is serialized (a 401 triggers exactly one re-login however many threads race it), and the read catalogue serves concurrent readers from one shared connection without a lock. EachSubscriptionshould be consumed by one thread; the shared WebSocket machinery behind them is thread-safe.AsyncNiwaki(async): one instance per event loop. Fan out withgather(), which runs its awaitables under a singleTaskGroupon the session’s loop.Designs are plain object trees: build them anywhere, push them through whichever connected client you like — they hold no transport state.
See also¶
Installation — including air-gapped installs from the wheelhouse
Errors & recovery — the exception hierarchy the fail-loud behavior speaks