Scrapli, pyATS & Genie โ speed + testing
Scrapli is a fast, async-capable SSH library for network devices. Cisco's pyATS with the Genie library adds structured parsing, state snapshots and diff-based testing โ together they cover high-performance collection and rigorous validation.
Setup, key commands & run examples
Install Scrapli for SSH, and pyATS with the library extra (Genie) for parsing and testing.
python3 -m venv .venv
source .venv/bin/activate
pip install scrapli "pyats[library]"IOSXEDriver opens a tuned SSH session. send_command returns a Response; .result is the raw output, .textfsm_parse_output() gives structure.
from scrapli.driver.core import IOSXEDriver
device = {
"host": "10.10.1.1",
"auth_username": "admin",
"auth_password": "secret",
"auth_strict_key": False,
}
with IOSXEDriver(**device) as conn:
resp = conn.send_command("show ip interface brief")
print(resp.result)
print(resp.textfsm_parse_output())Genie ships hundreds of curated parsers. Connect via a testbed, then .parse() returns a documented schema dict.
from genie.testbed import load
testbed = load("testbed.yaml")
dev = testbed.devices["r1"]
dev.connect(log_stdout=False)
parsed = dev.parse("show interfaces")
print(parsed["GigabitEthernet1"]["oper_status"])learn() captures an operational feature (e.g. BGP) into a structured snapshot. Compare before/after with Diff to validate a change.
from genie.libs.sdk.libs.utils.diff import Diff
before = dev.learn("bgp")
# ... apply change ...
after = dev.learn("bgp")
diff = Diff(before.info, after.info)
diff.findDiff()
print(diff)Best practices
Use async only when it pays
Scrapli's asyncio transport scales to many devices, but sync is simpler โ adopt async once concurrency is the bottleneck.
Trust Genie parsers over custom regex
Genie's maintained parsers track CLI changes across versions; reserve TextFSM/regex for unsupported commands.
Snapshot golden state in CI
Store pyATS learn() outputs as artifacts and diff every change so regressions surface automatically.
Set auth_strict_key intentionally
Disabling host-key checks is fine in labs; pin known hosts in production to avoid MITM exposure.
Hands-on exercises
Guided practice tasks โ copy the starter snippet, run it against a lab device, and extend it to meet the goal.
Goal: Open an IOSXEDriver, run 'show ip interface brief', and turn the output into structured rows with textfsm_parse_output().
from scrapli.driver.core import IOSXEDriver
device = {"host": "10.10.1.1", "auth_username": "admin",
"auth_password": "secret", "auth_strict_key": False}
with IOSXEDriver(**device) as conn:
resp = conn.send_command("show ip interface brief")
# TODO: print(resp.textfsm_parse_output())Goal: Load a testbed, connect to a device, and use .parse('show interfaces') to read an oper_status field.
from genie.testbed import load
dev = load("testbed.yaml").devices["r1"]
dev.connect(log_stdout=False)
parsed = dev.parse("show interfaces")
# TODO: print oper_status for one interfaceGoal: Capture dev.learn('bgp') before and after a change and print the Diff to confirm only the intended fields moved.
from genie.libs.sdk.libs.utils.diff import Diff
before = dev.learn("bgp")
# ... apply change ...
after = dev.learn("bgp")
# TODO: d = Diff(before.info, after.info); d.findDiff(); print(d)Curated videos & guides
Checklist โ pitfalls, gotchas & verification
Common pitfalls
- โขLeaving auth_strict_key=False in production โ pin host keys to avoid MITM.
- โขMixing sync and async drivers in the same flow โ pick one model per script.
- โขWriting custom regex when a maintained Genie parser already exists.
Gotchas to watch
- โขScrapli core drivers cover IOS-XE/XR, NX-OS, EOS, JunOS โ others need scrapli-community.
- โขGenie parsers are version-sensitive; an unexpected CLI format raises a SchemaEmptyParserError.
- โขpyATS learn() can be slow โ scope to the feature you actually need to diff.
Verify it works
- โขCheck resp.failed is False (Scrapli) before trusting the output.
- โขPrint the parsed dict and confirm expected keys exist before asserting on them.
- โขRun the before/after Diff and confirm it is empty when no change was intended.
Use Scrapli when raw SSH speed and async matter; reach for pyATS/Genie when you need parsing, golden snapshots and automated network test cases in CI.