networkconfparse is a library that parses the whitespace-indented configuration of network infrastructure (Cisco IOS, IOS XE, IOS XR, and NX-OS) into a queryable tree of native Python objects.
- Standalone - No runtime dependencies. Install and use it in any Python project.
- Network-OS agnostic - Hierarchy is inferred from relative indentation, so IOS (one space), NX-OS (two spaces), and inconsistent indentation are all handled without per-platform rules.
- Queryable - A small, composable API to find configuration objects by regex, by predicate, or by their parent/child relationships.
- Handles the awkward parts - Transparently skips
!comment and delimiter lines and captures multilinebannerblocks and inline certificate data as opaque bodies, rather than mistaking them for configuration. - Typed and well-tested - Fully type-hinted with a comprehensive test suite.
networkconfparse can be quickly and easily installed with uv as shown below:
uv add networkconfparseOr, if you prefer good old-fashioned pip, you can do so as shown below:
pip install networkconfparseCall parse() with the configuration text. It returns a Config whose top-level lines each carry their indented children as a tree of ConfigNode objects. Comment/delimiter lines (!) are dropped automatically.
import networkconfparse
config = networkconfparse.parse("""
interface GigabitEthernet0/0
ip address 10.0.0.1 255.255.255.0
no shutdown
!
interface GigabitEthernet0/1
shutdown
!
""")
for interface in config.find(r"^interface "):
print(interface.text, "->", [child.text for child in interface.children])Prints:
interface GigabitEthernet0/0 -> ['ip address 10.0.0.1 255.255.255.0', 'no shutdown']
interface GigabitEthernet0/1 -> ['shutdown']
find() searches the entire tree and accepts a regular expression, a where predicate, or both. find_child()/has_child() look only at a node's immediate children, and find_one() returns the first match. Every node also exposes path, ancestors, descendants, and root for navigation.
# Interfaces that have an IP address configured anywhere beneath them.
configured = config.find(
r"^interface ", where=lambda node: node.has_child(r"^ip address ")
)
# The first matching line, or None.
mgmt = config.find_one(r"^ip address 10\.0\.0\.1")
# Where does that line live in the hierarchy?
print(mgmt.path)
# ['interface GigabitEthernet0/0', 'ip address 10.0.0.1 255.255.255.0']For the common cases, dedicated helpers read more clearly than a hand-written predicate. Each accepts a single regex or a list (combined with AND), and they are simply convenience wrappers around find():
# Parents matching "interface" that have BOTH children as direct children.
config.find_with_child(r"^interface ", [r"^ip address ", r"^no shutdown"])
# Parents that have a matching line anywhere below them (not just direct children).
config.find_with_descendant(r"^router bgp ", r"neighbor")
# Lines whose direct parent matches.
config.find_with_parent(r"^neighbor ", r"^address-family ipv4")
# Lines with a matching ancestor anywhere above (or a consecutive chain with adjacent=True).
config.find_with_ancestor(r"^neighbor ", [r"^router bgp ", r"^address-family ipv4"])Each helper has a find_without_* counterpart for the equally common absence questions ("interfaces without an ip address"). Given a list they apply a "none present" (NOR) rule, returning nodes where none of the patterns are found:
# Interfaces with neither an `ip address` nor a `shutdown` line.
config.find_without_child(r"^interface ", [r"^ip address ", r"^shutdown"])These compose naturally for SDK-style questions. For example, "find every ACL that does not end with an explicit deny":
acls = config.find(r"^ip access-list ")
missing_deny = [
acl for acl in acls if not acl.children or not acl.children[-1].matches(r"^deny ")
]Full documentation is available at chartinolabs.github.io/networkconfparse.
- Changelog - Release history built from changelog fragments
- Changelog Fragments Guide - How to add release-note fragments
- Releasing - How to compile release notes and cut a release
- Conceptual inspiration - The idea of modeling a network device configuration as a queryable parent/child tree owes a great deal to Mike Pennington's work on CiscoConfParse and CiscoConfParse2. networkconfparse is an independent, clean-room implementation; it is not affiliated with, derived from, or endorsed by those projects.
Early development. The API is still evolving and may change as the library matures.