{"id":7548,"library":"pyats","title":"pyATS","description":"pyATS (Python Automation Test System) is an end-to-end test automation framework, primarily developed by Cisco, designed for network engineers. It provides a robust infrastructure for defining network topologies, running tests against network devices (multi-vendor compatible), and parsing device outputs into structured data using the integrated Genie library. The current version is 26.3, and it maintains an active release cadence with frequent updates to parsers and APIs. [1, 4, 15, 18]","status":"active","version":"26.3","language":"en","source_language":"en","source_url":"https://developer.cisco.com/site/pyats/","tags":["network automation","testing","cisco","genie","devops","network engineering"],"install":[{"cmd":"pip install 'pyats[full]'","lang":"bash","label":"Full Installation (Recommended)"},{"cmd":"pip install pyats[library]","lang":"bash","label":"Minimal Installation (includes Genie library)"},{"cmd":"pip install pyats.contrib","lang":"bash","label":"Install contrib package (for interactive testbed creation)"}],"dependencies":[{"reason":"Genie is the core library within the pyATS ecosystem for parsing device output into structured data and providing platform/vendor agnostic support. It is usually installed as part of pyats[full] or pyats[library]. [3, 11, 14]","package":"genie"}],"imports":[{"note":"Core pyATS test infrastructure module for defining test cases and sections.","symbol":"aetest","correct":"from pyats import aetest"},{"note":"Used for loading testbed YAML files into Python objects.","symbol":"loader","correct":"from pyats.topology import loader"},{"note":"Specifically for loading Genie testbed files. This is commonly used in conjunction with pyATS for network device interaction. [3]","symbol":"load","correct":"from genie.testbed import load"},{"note":"Used for executing pyATS jobs and scripts within the EasyPy runtime environment. [20]","symbol":"run","correct":"from pyats.easypy import run"},{"note":"For handling connection-related exceptions when interacting with devices. [20]","symbol":"ConnectionError","correct":"from unicon.core.errors import ConnectionError"}],"quickstart":{"code":"import os\nimport logging\nfrom pyats import aetest\nfrom genie.testbed import load\nfrom unicon.core.errors import ConnectionError\n\n# Set up basic logging\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\n# Create a dummy testbed file (testbed.yaml) for demonstration\n# In a real scenario, this would describe your network devices.\n# For a live environment, set environment variables for credentials:\n# export PYATS_TESTBED_USERNAME='your_username'\n# export PYATS_TESTBED_PASSWORD='your_password'\n\n# Example content for testbed.yaml:\n# devices:\n#   CSR1:\n#     os: iosxe\n#     connections:\n#       cli:\n#         protocol: ssh\n#         ip: 10.1.1.1 # Replace with your device IP\n#     credentials:\n#       default:\n#         username: '%ENV{PYATS_TESTBED_USERNAME}'\n#         password: '%ENV{PYATS_TESTBED_PASSWORD}'\n\nclass MyFirstTest(aetest.Testcase):\n\n    @aetest.setup\n    def setup(self, testbed):\n        # Load the testbed from a YAML file\n        try:\n            self_testbed = load(os.path.join(os.path.dirname(__file__), 'testbed.yaml'))\n            self.parent.parameters.update(testbed=self_testbed)\n            logger.info(f\"Testbed loaded successfully: {list(self_testbed.devices.keys())}\")\n        except Exception as e:\n            self.failed(f\"Failed to load testbed: {e}\")\n\n    @aetest.test\n    def connect_and_execute(self, testbed):\n        if not hasattr(self.parent.parameters, 'testbed'):\n            self.skipped('Testbed not loaded in setup.')\n            return\n\n        for device_name, device in self.parent.parameters['testbed'].devices.items():\n            logger.info(f\"Attempting to connect to device: {device_name}\")\n            try:\n                device.connect(init_exec_params={'timeout': 60})\n                logger.info(f\"Successfully connected to {device_name}\")\n\n                # Example: Execute a 'show version' command\n                output = device.execute('show version')\n                logger.info(f\"Output from {device_name}:\\n{output[:200]}...\") # Print first 200 chars\n\n                # Example: Parse 'show ip interface brief'\n                parsed_output = device.parse('show ip interface brief')\n                logger.info(f\"Parsed output from {device_name} (first entry): {list(parsed_output.values())[0] if parsed_output else 'No interfaces found'}\")\n\n                self.passed(f\"Successfully connected, executed, and parsed on {device_name}\")\n\n            except ConnectionError as e:\n                self.failed(f\"Connection failed for {device_name}: {e}\")\n            except Exception as e:\n                self.failed(f\"An error occurred with {device_name}: {e}\")\n            finally:\n                if device.is_connected():\n                    device.disconnect()\n                    logger.info(f\"Disconnected from {device_name}\")\n\n\n    @aetest.cleanup\n    def cleanup(self):\n        logger.info(\"Testcase cleanup completed.\")\n\nif __name__ == '__main__':\n    import sys\n    # Create a dummy testbed.yaml for local execution if it doesn't exist\n    testbed_path = os.path.join(os.path.dirname(__file__), 'testbed.yaml')\n    if not os.path.exists(testbed_path):\n        with open(testbed_path, 'w') as f:\n            f.write(\"\"\"\n---\ndevices:\n  CSR1:\n    os: iosxe\n    connections:\n      cli:\n        protocol: ssh\n        ip: 10.1.1.1 # REPLACE WITH YOUR DEVICE IP OR A MOCK IP FOR TESTING\n    credentials:\n      default:\n        username: '%ENV{PYATS_TESTBED_USERNAME}'\n        password: '%ENV{PYATS_TESTBED_PASSWORD}'\n            \"\"\")\n        logger.warning(f\"Created a dummy '{testbed_path}'. Please replace 10.1.1.1 with a real device IP and set environment variables PYATS_TESTBED_USERNAME and PYATS_TESTBED_PASSWORD.\")\n\n    # Set dummy env vars if not present for local execution to avoid crashes\n    os.environ.setdefault('PYATS_TESTBED_USERNAME', 'admin')\n    os.environ.setdefault('PYATS_TESTBED_PASSWORD', 'password')\n\n    # Run the AETest\n    aetest.main(argv=sys.argv)\n","lang":"python","description":"This quickstart demonstrates a basic pyATS test script. It defines a testcase with setup, test, and cleanup sections. The setup loads a testbed file (e.g., `testbed.yaml`) which describes the network devices and their connection details, including credentials often sourced from environment variables. The test section connects to a device, executes a 'show version' command, and then uses Genie's `parse()` method to get structured data from 'show ip interface brief'. Ensure `testbed.yaml` is configured with valid device IPs and credentials are set as environment variables (e.g., `PYATS_TESTBED_USERNAME`, `PYATS_TESTBED_PASSWORD`). The script includes a dummy `testbed.yaml` creation for local execution. Run with `python your_script_name.py` or `pyats run job your_script_name.py`. [3, 8, 20, 25]"},"warnings":[{"fix":"Update your imports to reference `genielibs` for file transfer utilities. Review the `genielibs` documentation for the correct new paths. [16]","message":"In pyATS version 25.5, file transfer utilities were moved from the `pyats` package to `genielibs`. If you were directly importing these utilities from `pyats`, your code will break.","severity":"breaking","affected_versions":">=25.5"},{"fix":"Always create and activate a virtual environment before installing pyATS: `python3 -m venv .venv && source .venv/bin/activate` (Linux/macOS) or `.\\.venv\\Scripts\\activate` (Windows PowerShell). [5, 21]","message":"Not using Python virtual environments can lead to dependency conflicts and unexpected behavior, especially with multiple Python projects or different pyATS versions. [5, 14, 21]","severity":"gotcha","affected_versions":"All"},{"fix":"Verify that the device name specified in your `testbed.yaml`'s `devices` section precisely matches the `hostname` command output on the actual network device.","message":"The device name in your `testbed.yaml` file *must* exactly match the configured hostname of the device you are trying to connect to. Mismatches will prevent successful connections. [10]","severity":"gotcha","affected_versions":"All"},{"fix":"Use `pip install \"pyats[full]\"` (with quotes) when installing in a Zsh environment.","message":"When installing pyATS with optional dependencies (e.g., `pyats[full]`) on Zsh (common on macOS), the square brackets `[]` might need to be quoted due to shell interpretation. [5, 10, 14]","severity":"gotcha","affected_versions":"All"},{"fix":"Start with simple test scripts to connect, execute commands, and parse basic output. Gradually increase complexity as you gain familiarity with the framework. [24]","message":"Overcomplicating test scripts prematurely, especially when new to pyATS, can lead to frustration and errors. [24]","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure you are in the correct Python virtual environment (if used) and install pyATS: `pip install 'pyats[full]'`. Verify installation with `pyats version check`. [21]","cause":"pyATS or its sub-packages are not installed, or the current Python environment is not the one where pyATS was installed. [21]","error":"ModuleNotFoundError: No module named 'pyats.topology'"},{"fix":"Double-check the IP address and credentials in your `testbed.yaml`. Ping the device to verify reachability. Ensure the device name in `testbed.yaml` exactly matches the device's configured hostname. Verify SSH/Telnet access manually. [10]","cause":"This generic error indicates a problem establishing a connection to the network device. Common causes include incorrect IP address/hostname, firewall blocking, incorrect credentials, device not reachable, or device hostname mismatch in the testbed file. [10, 20]","error":"ConnectionError: Failed to connect to device 'my_device'"},{"fix":"Ensure you have installed pyATS with the `[library]` or `[full]` extra, which includes Genie: `pip install 'pyats[full]'`. [5, 14]","cause":"The Genie library, which provides the `parse` method for structured output, might not be fully installed or accessible. This typically happens with a minimal `pyats` installation without `genie`. [14]","error":"AttributeError: 'Device' object has no attribute 'parse'"},{"fix":"Check your internet connection. If behind a corporate proxy, configure pip to use it: `pip install --proxy http://proxy.company.com:8080 'pyats[full]'` or set `HTTP_PROXY`/`HTTPS_PROXY` environment variables. Also, ensure the package name is spelled correctly. [21]","cause":"This usually means pip cannot find the package, often due to network issues (e.g., corporate proxy) or a misspelled package name. [21]","error":"ERROR: Could not find a version that satisfies the requirement pyats[full] (from versions: none)"}]}