Discovery — the read catalogue

Discover and describe any Cisco ACI class — offline.

The read catalogue ships with the package: metadata for all ~15,450 ACI classes (not just the ~2,200 with generated models), opened lazily on first use. This module is the public door to it — search for a class by name or label, describe its properties/faults/subclasses, or find which class carries a given property — with no APIC connection required.

Nothing here runs at import niwaki; the catalogue loads only when you import niwaki.catalog and call one of these functions.

Example:

from niwaki import catalog

catalog.search("bridge domain")        # → ['fvBD', ...]  (ranked)
doc = catalog.describe("fvCEp")         # label, properties, faults, subclasses
for prop in doc.props:
    print(prop.readable, prop.kind)     # readable field names + coercion kinds
catalog.find_prop("mac")                # → [('fvCEp', 'mac'), ...]
catalog.concrete_subclasses("fvEPg")    # → every concrete EPG class
catalog.fault_name("F0467")             # → 'fltFvNwIssuesConfig-failed'

Functions

niwaki.catalog.search(term, *, limit=50)[source]

Class names whose wire name or GUI label matches term.

Ranked by the full-text index where the runtime’s sqlite provides it, or a (broader, unranked) substring scan otherwise.

Parameters:
  • term (str) – The text to match, e.g. "bridge domain".

  • limit (int) – Maximum number of class names to return.

Returns:

Matching wire class names.

Return type:

list[str]

niwaki.catalog.describe(class_name)[source]

Describe a class: its label, comment, properties, faults, and subclasses.

Parameters:

class_name (str) – The wire class name, e.g. "fvCEp".

Returns:

A ClassDocname, label, comment, is_abstract, is_observable (informational only — not a subscribability gate, see the field’s own docstring), a tuple of PropDoc, a {code: name} fault map, and (for an abstract class) its concrete subclasses.

Raises:

UnknownClassError – No such class in the catalogue (also a KeyError).

Return type:

ClassDoc

niwaki.catalog.prop_meta(class_name, name)[source]

Describe one property of a class, addressed by its readable or wire name.

Parameters:
  • class_name (str) – The wire class name, e.g. "fvBD".

  • name (str) – The property’s readable ("arp_flooding") or wire ("arpFlood") name.

Returns:

A PropDoc.

Raises:

UnknownClassError – The class or property is unknown (also a KeyError).

Return type:

PropDoc

niwaki.catalog.find_prop(term, *, limit=50)[source]

(class, wire property) pairs whose property name or label matches term.

Answers “which class carries a MAC?” — the complement to search().

Parameters:
  • term (str) – The property text to match, e.g. "mac".

  • limit (int) – Maximum number of pairs to return.

Returns:

(wire_class_name, wire_property_name) pairs.

Return type:

list[tuple[str, str]]

niwaki.catalog.concrete_subclasses(class_name)[source]

Every concrete descendant of a class, walked transitively.

The set an abstract-class query (e.g. aci.query("fvEPg")) fans out to.

Parameters:

class_name (str) – The (usually abstract) wire class name.

Returns:

Concrete descendant wire class names, sorted.

Return type:

list[str]

niwaki.catalog.class_meta(class_name)[source]

A class’s readable↔wire name maps and per-property coercion kinds.

Lower-level than describe(); the same metadata the result objects use to expose readable field names on non-generated classes. Also carries is_stat — whether the APIC can ever push for this class (a stats class, e.g. a granularity variant like eqptEgrBytes5min, never can).

Parameters:

class_name (str) – The wire class name.

Returns:

A ClassMeta.

Raises:

UnknownClassError – No such class in the catalogue (also a KeyError).

Return type:

ClassMeta

niwaki.catalog.fault_name(code)[source]

The rule name behind a fault code, e.g. "F0467""fltFvNwIssuesConfig-failed".

This is a global lookup — it does not require knowing which class raised the fault. That complements describe(), whose faults mapping is scoped to one class (the faults that class can raise): a ManagedObject read back from faultInst carries a code but not the class that raised it, so this is the function that turns it into a human-readable name.

Parameters:

code (str) – The fault code, e.g. "F0467".

Returns:

The fault’s rule name, or None if the code is not in the catalogue — this is expected for threshold-crossing alerts (tca-* rules), whose codes are minted at runtime from an operator’s statsThresholdPolicy rather than defined statically in the class schema.

Return type:

str | None

Example:

faults = aci.query("faultInst").fetch()
for f in faults:
    print(f["code"], catalog.fault_name(f["code"]))
niwaki.catalog.dn_formats(class_name)[source]

Every DN shape the APIC uses for a class, as templates.

A class is rarely reachable at a single place in the tree. A subnet lives under a bridge domain, under an EPG, under a tenant, under an L2Out external EPG and under several service-graph nodes — a dozen shapes, one class. These are those shapes, verbatim from the schema, with the identifying values left as {placeholder}.

Quote them; do not rebuild them. A template is a fact about the controller, and reconstructing one by chaining parent RNs does not reproduce it: the containment graph is both wider than the DNs the APIC actually mints and, in places, missing parents that it does mint. A repeated placeholder is normal and is not a mistake to correct — uni/tn-{name}/BD-{name} names a tenant and a bridge domain, each identified by name.

Parameters:

class_name (str) – The wire class name, e.g. "fvBD".

Returns:

The templates in schema order, duplicates included — the schema’s list as it stands. Empty for a class the schema gives none, which is the common case for an abstract class: its places belong to the concrete classes behind it (concrete_subclasses()).

An empty string is a legitimate template — a container that prefixes nothing. It can be the whole answer (six classes, the root of the tree among them) or sit beside real templates in the same list, so filter the empties out rather than testing the first element.

The templates are not format strings: the same placeholder can name two different objects, so str.format on one silently builds a wrong DN.

Raises:

UnknownClassError – No such class in the catalogue. Also a KeyError.

Return type:

tuple[str, …]

Example:

catalog.dn_formats("fvBD")     # ('uni/tn-{name}/BD-{name}',)
len(catalog.dn_formats("fvSubnet"))   # 12 — one class, twelve places
niwaki.catalog.rn_format(class_name)[source]

The RN format of a class — the template for its own DN segment.

A class has exactly one, regardless of where it sits: "BD-{name}" for a bridge domain, "subnet-[{ip}]" for a subnet. It is the inverse key of DN computation — the piece a reader needs to turn a DN read back from a fabric into its naming values.

Parameters:

class_name (str) – The wire class name, e.g. "fvBD".

Returns:

The RN format string, empty when the class defines none.

Raises:

UnknownClassError – No such class in the catalogue (also a KeyError).

Return type:

str

Example:

catalog.rn_format("fvBD")       # → "BD-{name}"
catalog.rn_format("fvSubnet")   # → "subnet-[{ip}]"
niwaki.catalog.prop_flags(class_name)[source]

Every property’s schema flags for a class, keyed by wire name.

The raw material of data-driven normalisation: what is configuration (is_configurable), what the controller computes (read_only, implicit), what never changes after creation (create_only), what names the object (is_naming), what the APIC never echoes back (secure). One catalogue query per class, then memoised.

Parameters:

class_name (str) – The wire class name, e.g. "fvBD".

Returns:

Mapping of wire property name to its PropFlags.

Raises:

UnknownClassError – No such class in the catalogue (also a KeyError).

Return type:

dict[str, PropFlags]

Example:

flags = catalog.prop_flags("fvBD")
flags["arpFlood"].is_configurable   # → True
flags["arpFlood"].read_only         # → False
niwaki.catalog.generated_classes()[source]

Wire names of every class the SDK generates a typed model for, sorted.

The set behind “generated” everywhere in this module: the ~2,200 concrete, configurable, non-deprecated classes that ship as Pydantic models with readable field names. Everything else the catalogue serves dynamically. Offline — no APIC connection required — and derived from the code generator’s own shipped index, so it cannot drift from the model files.

Every returned name resolves through describe() and class_meta() without KeyError, and every returned class is concrete and non-stat.

Returns:

Sorted, deduplicated wire class names, computed once per process.

Return type:

tuple[str, …]

Example:

classes = catalog.generated_classes()
assert "fvBD" in classes           # configurable → has a model
assert "topSystem" not in classes  # readable only → catalogue-served
niwaki.catalog.schema_version()[source]

The APIC firmware the shipped catalogue and models were generated from.

Every typed model, curated vocabulary entry and filter operator in this SDK derives from one firmware’s schemas. This names it, read from the shipped artifact itself rather than from a constant that could drift from it.

Pair it with niwaki.Niwaki.apic_version — the firmware a fabric reports at login — to answer “am I inside the envelope this SDK was built for?”. Offline, like everything else in this module.

Returns:

The version string, e.g. "6.0(9c)".

Return type:

str

Example:

assert catalog.schema_version() == "6.0(9c)"

Result types

class niwaki.catalog.ClassDoc(
name,
label,
comment,
is_abstract,
is_observable,
props,
faults,
concrete_subclasses,
)[source]

Bases: object

A class, as describe presents it: identity, properties, faults, kin.

is_observable

APIC schema metadata, informational only — do not treat this as a gate on whether the class can be subscribed to. Empirically falsified live: a class with is_observable=False (faultInst) was subscribed to successfully and delivered real push notifications. The flag that actually governs subscribability is isStat (see ClassMeta.is_stat).

Type:

bool

class niwaki.catalog.PropDoc(readable, wire, kind, is_naming, label, default, comment, enum_values)[source]

Bases: object

One property, as describe presents it.

class niwaki.catalog.ClassMeta(
class_name,
readable_to_wire,
wire_to_readable,
wire_to_kind,
naming,
is_stat,
has_model=False,
)[source]

Bases: object

The read metadata for one ACI class, assembled once and memoised.

class_name

The wire class name (e.g. "fvCEp").

Type:

str

readable_to_wire

{python_name: wire_name} — the readable field names.

Type:

dict[str, str]

wire_to_readable

{wire_name: python_name} — the inverse.

Type:

dict[str, str]

wire_to_kind

{wire_name: FieldKind value | None} — how to coerce a wire value on read (None = read as a plain string).

Type:

dict[str, str | None]

naming

The wire names of the identifying properties.

Type:

frozenset[str]

is_stat

The class is a statistics class (a granularity variant of a stats family, e.g. eqptEgrBytes5min). Cisco’s own docs state stats updates bypass the APIC’s event manager entirely — architecturally incapable of ever pushing — so this is what gates StatsClassNotSubscribableError, not isObservable (see ClassDoc.is_observable).

Type:

bool

has_model

The SDK ships a generated Pydantic model for this class — results deserialize through the typed model rather than this catalogue metadata. Recomputed from the code generator’s own shipped index, never stored in the .db (the catalogue’s derived-fields rule).

Type:

bool

class niwaki.catalog.PropFlags(
is_configurable,
needs_prop_delimiters,
create_only,
read_write,
read_only,
is_naming,
secure,
implicit,
mandatory,
is_override,
is_like,
is_nxos_converged,
is_deprecated,
is_hidden,
)[source]

Bases: object

The APIC schema flags of one property, unpacked from the catalogue.

One boolean per flag the 6.0 schemas declare, named 1:1 with Cisco’s own keys (snake-cased) — no editorial layer. This is the raw material of any data-driven normalisation: what is configuration (is_configurable), what the controller computes (read_only, implicit), what never changes after creation (create_only), what names the object (is_naming), what the APIC never echoes back (secure).

A caution proven on the live corpus: secure alone is not a secret policy. snmpCommunityP carries its community string as a naming property (no secure flag, and it rides inside the DN), and vnsCCred.value is plain read_write. Flags feed a policy; they do not replace one.