Skip to main content

pytest-clab

GitHub Actions Workflow Status codecov PyPI - Python Version PyPI - Downloads GitHub License

pytest-clab is authored by Thomas Bamihas, governed as a benevolent dictatorship, and distributed under the Apache 2.0 license.

Introduction

While containerlab simplifies spinning up network topologies, integrating it into test workflows still requires boilerplate for deployment, teardown, and node interaction. This plugin provides a convenient pytest fixture to manage containerlab topologies with automatic lifecycle management.

Features

  • Lab lifecycle management: Deploy and destroy containerlab topologies directly from pytest.
  • Multiple lab support: Interact with multiple labs within a single pytest session, for tests that depend on more than one topology.
  • Topology readiness checks: Verify dependent labs are ready before running tests.
  • Dynamic node inventory: Retrieve node addresses and connection parameters at test runtime instead of hardcoding them in tests.
  • Containerlab CLI access: Run containerlab commands from tests for operations not covered by plugin helpers.

Installation

pip install pytest-clab

Requirements: containerlab CLI must be installed and in PATH.

Quickstart

@pytest.fixture(scope="session")
def lab(clab):
    return clab("topology.clab.yaml")

@pytest.mark.parametrize("node_name", ["node1", "node2"])
def test_mgmt_interface_status(lab, node_name):
    # GIVEN a lab node
    node = lab.nodes[node_name]

    # GIVEN netmiko params
    params = {
        "host": node.ipv4_address,
        "username": os.getenv("SSH_USERNAME"),
        "password": os.getenv("SSH_PASSWORD"),
        "device_type": "nokia_srl",
    }

    # WHEN fetching mgmt status
    with netmiko.ConnectHandler(**params) as conn:
        output = conn.send_command("show interface mgmt0 brief")

    # THEN expect mgmt0 to be up
    assert "up" in output

Working with Topologies and Nodes

ClabTopology

The clab fixture is a factory that creates ClabTopology instances.

Properties:

  • name - Lab name as reported by containerlab
  • topology_path - Path to the topology YAML file
  • nodes - Collection of nodes

Methods:

  • cmd(command, parse_json=False) - Execute any containerlab command, optionally parse JSON output
output = lab.cmd(f"inspect -t {lab.topology_path} -f json", parse_json=True)

Node Startup Readiness

The plugin automatically polls containerlab inspect and returns only after all nodes report state: "running".

  • command_timeout controls timeout per containerlab CLI call.
  • startup_timeout controls total startup polling budget.

Service-level readiness (SSH, NETCONF, gNMI, app-level) checks are environment-specific and performed in test logic.

ClabNodes

The nodes property is a collection that supports flexible access patterns.

Methods:

  • lab.nodes["name"] - Access a node by short name
  • "name" in lab.nodes - Check if a node exists
  • len(lab.nodes) - Get the number of nodes
  • for node in lab.nodes - Iterate over all nodes
  • filter_by_kind(kind) - Filter nodes by kind
for node in lab.nodes:
    print(node.short_name, node.ipv4_address)

ClabNode

Each node is an immutable dataclass with the following attributes.

Attributes:

  • short_name - Node name without lab prefix (e.g., "leaf1")
  • name - Full container name (e.g., "clab-mylab-leaf1")
  • lab_name - Name of the lab
  • kind - Node kind (e.g., "linux", "nokia_srlinux")
  • image - Container image
  • state - Container state (e.g., "running")
  • status - Container status from containerlab (e.g., "healthy")
  • ipv4_address - Management IPv4 address
  • ipv6_address - Management IPv6 address
  • container_id - Docker container ID
  • properties - Dictionary containing additional containerlab node properties not listed above
node = lab.nodes["leaf1"]
print(f"{node.short_name} ({node.kind}): {node.ipv4_address}")

Examples

Keep Running Mode
@pytest.fixture(scope="session")
def lab(clab):
    return clab("topology.clab.yml", keep_running=True)
JSON Output
def test_json_output(lab):
    result = lab.cmd("version -j", parse_json=True)
    assert isinstance(result, dict)
Filter by Node Kind
def test_filter_nodes(lab):
    srlinux_nodes = lab.nodes.filter_by_kind("nokia_srlinux")
    linux_nodes = lab.nodes.filter_by_kind("linux")
    assert len(srlinux_nodes) + len(linux_nodes) == len(lab.nodes)
Dynamic Validation Example

This example uses subtests for per-peer test reporting.

def test_bgp_neighbors(lab, subtests):
    node = lab.nodes["router1"]
    # Use any library to connect to the node (e.g., ncclient, scrapli, netmiko)
    with connect(host=node.ipv4_address, ...) as conn:
        neighbors = conn.get(filter=BGP_NEIGHBOR_FILTER).data_xml

    for neighbor in neighbors:
        with subtests.test(peer=neighbor.find("peer-address").text):
            assert neighbor.find("state").text == "established"

Configuration

Environment Variables

CONTAINERLAB_EXECUTABLE Path to containerlab executable (default: containerlab)

CONTAINERLAB_EXECUTABLE=/usr/local/bin/clab pytest

Fixture Parameters

topology: Path to containerlab topology YAML file (required)

lab = clab("topology.clab.yml")

sudo: Run containerlab commands with sudo (default: False)

lab = clab("topology.clab.yml", sudo=True)

keep_running: Keep lab running at session end (default: False)

lab = clab("topology.clab.yml", keep_running=True)

command_timeout: Timeout in seconds for each containerlab command (default: 300)

lab = clab("topology.clab.yml", command_timeout=600)

startup_timeout: Timeout in seconds for startup-state polling (default: 30)

lab = clab("topology.clab.yml", startup_timeout=60)

Exceptions

The plugin provides a hierarchy of exceptions for error handling:

  • ClabError: Base exception for all pytest-clab errors
    • TopologyNotFoundError: Topology file does not exist
    • ContainerlabNotFoundError: containerlab executable not found in PATH
    • DeploymentError: Topology deployment failed
      • NodeFailedError: A node entered a terminal state (exited, dead) during startup
    • InspectError: Failed to inspect running topology
    • CommandError: A containerlab command failed

Versioning

Releases will follow semantic versioning (major.minor.patch). Before 1.0.0, breaking changes can be included in a minor release, therefore we highly recommend pinning this package.

Contributing

Suggest a feature or report a bug. Read our developer guide.

License

pytest-clab is distributed under the Apache 2.0 license.

Metadata

Release files for pytest-clab 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytest-clab 0.1.3
File Size Uploaded Provenance
pytest_clab-0.1.3.tar.gz 10.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pytest-clab 0.1.3
File Interpreter ABI Platform
pytest_clab-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 28.2 kB

Release files / pytest_clab-0.1.3.tar.gz

Download URL pytest_clab-0.1.3.tar.gz
Size 10.8 kB
Tags Source
SHA-256 checksum
How to use checksums
86647d4583e0af740bb4403486d4fd43f5ffe6fe0ba54e45f4e470771c9faab3
BLAKE2b-256 checksum
How to use checksums
41e5bdd951eb10cc38ea914bc88b528be1c26163a2ade78748372af1a6086109
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 2, 2026.

Transparency log

Release files / pytest_clab-0.1.3-py3-none-any.whl

Download URL pytest_clab-0.1.3-py3-none-any.whl
Size 17.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6cd66a052238ab2a5bee110cf1fa51ac23fc0f39c96cc5e78d6df2173499423f
BLAKE2b-256 checksum
How to use checksums
8c856d21f9f689cc53215a5d59e4e040d8c9afc4e57dd19c57f7db969bee5ea3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 2, 2026.

Transparency log

Security for pytest-clab 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pytest_clab-0.1.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page