Back to Learn

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.

Python
Async SSH
pyATS
Genie
Parsing
Testing
Scrapli: fast, optionally async SSH transport
Genie parses CLI into structured Python objects
pyATS learn() snapshots state for diff testing

Setup, key commands & run examples

Step 0 โ€” install
Setup

Install Scrapli for SSH, and pyATS with the library extra (Genie) for parsing and testing.

Step 0 โ€” install
bash
python3 -m venv .venv
source .venv/bin/activate
pip install scrapli "pyats[library]"
scrapli_show.py โ€” fast SSH
Scrapli

IOSXEDriver opens a tuned SSH session. send_command returns a Response; .result is the raw output, .textfsm_parse_output() gives structure.

scrapli_show.py โ€” fast SSH
python
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_parse.py โ€” structured CLI
Genie parse

Genie ships hundreds of curated parsers. Connect via a testbed, then .parse() returns a documented schema dict.

genie_parse.py โ€” structured CLI
python
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"])
pyats_snapshot.py โ€” learn & diff
pyATS learn

learn() captures an operational feature (e.g. BGP) into a structured snapshot. Compare before/after with Diff to validate a change.

pyats_snapshot.py โ€” learn & diff
python
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.

Exercise 1
Collect and parse with Scrapli

Goal: Open an IOSXEDriver, run 'show ip interface brief', and turn the output into structured rows with textfsm_parse_output().

exercise_1
python
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())
Exercise 2
Genie parse a real command

Goal: Load a testbed, connect to a device, and use .parse('show interfaces') to read an oper_status field.

exercise_2
python
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 interface
Exercise 3
Diff state before/after with pyATS

Goal: Capture dev.learn('bgp') before and after a change and print the Diff to confirm only the intended fields moved.

exercise_3
python
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.