{"id":7536,"library":"pyats-aereport","title":"pyATS AEreport","description":"pyATS AEreport is a sub-component of the Cisco pyATS (Python Automated Test System) ecosystem, specializing in result collection and reporting for network test automation. It integrates seamlessly with pyATS test runs to generate comprehensive HTML reports and other artifacts. pyATS, including AEreport, maintains a rapid release cadence, with updates often occurring monthly to introduce new features, parsers, and bug fixes.","status":"active","version":"26.3","language":"en","source_language":"en","source_url":"https://github.com/CiscoTestAutomation/pyats","tags":["pyats","testing","reporting","network automation","cisco"],"install":[{"cmd":"pip install pyats.aereport","lang":"bash","label":"Install only AEreport"},{"cmd":"pip install 'pyats[full]'","lang":"bash","label":"Install full pyATS (includes AEreport)"}],"dependencies":[{"reason":"AEreport is a sub-component of the pyATS framework and relies on its core functionalities.","package":"pyats","optional":false}],"imports":[{"note":"While 'pyats.aereport' can be imported, its functionality is typically integrated and managed by the 'pyats' runtime (e.g., 'easypy') rather than direct end-user class instantiation.","symbol":"aereport","correct":"import pyats.aereport"},{"note":"AEreport processes results from pyATS AEtest runs, making AEtest a common companion import for defining tests.","symbol":"aetest","correct":"from pyats import aetest"}],"quickstart":{"code":"import os\nimport logging\nfrom pyats import aetest\nfrom genie.testbed import load\n\n# Configure logging for better visibility\nlogger = logging.getLogger(__name__)\nlogger.setLevel(logging.INFO)\n\n# Define a simple pyATS AEtest script\nclass CommonSetup(aetest.CommonSetup):\n    @aetest.subsection\n    def connect_to_devices(self, testbed):\n        try:\n            testbed.connect()\n            logger.info(\"Successfully connected to devices.\")\n        except Exception as e:\n            logger.error(f\"Failed to connect to one or more devices: {e}\")\n\nclass MyTestcase(aetest.Testcase):\n    @aetest.test\n    def verify_connectivity(self, testbed):\n        for device in testbed.devices:\n            if device.is_connected():\n                self.passed(f\"Device {device.name} is connected.\")\n            else:\n                self.failed(f\"Device {device.name} is NOT connected.\")\n\nclass CommonCleanup(aetest.CommonCleanup):\n    @aetest.subsection\n    def disconnect_from_devices(self, testbed):\n        for device in testbed.devices:\n            if device.is_connected():\n                device.disconnect()\n                logger.info(f\"Disconnected from device {device.name}.\")\n\nif __name__ == '__main__':\n    # Example Testbed file content (save as 'testbed.yaml')\n    # devices:\n    #   router1:\n    #     connections:\n    #       cli:\n    #         class: unicon.Unicon\n    #         protocol: ssh\n    #         ip: 10.0.0.1 # Replace with your device IP\n    #     credentials:\n    #       default:\n    #         username: cisco\n    #         password: cisco # Use environment variable or pyats secret for production\n\n    # Create a dummy testbed.yaml for demonstration if it doesn't exist\n    testbed_content = \"\"\"\ndevices:\n  loopback_device:\n    type: linux\n    connections:\n      defaults:\n        class: unicon.Unicon\n        protocol: ssh\n        # For a truly runnable example without a real device, mock or avoid connection.\n        # This example assumes a simple mock or a non-connect test for quick demo.\n        # In a real scenario, you'd point to a reachable device or a mocked one.\n    credentials:\n      default:\n        username: {}\n        password: {}\n\"\"\".format(os.environ.get('TEST_USERNAME', 'mockuser'), os.environ.get('TEST_PASSWORD', 'mockpass'))\n\n    with open('testbed.yaml', 'w') as f:\n        f.write(testbed_content)\n\n    # Load the testbed (dummy for this example)\n    testbed = load('testbed.yaml')\n\n    # Run the AEtest job. AEreport automatically collects results.\n    aetest.main(testbed=testbed, ) # You would typically use pyats run job <script.py> for reporting\n    \n    # To view the generated report, run in your terminal:\n    # pyats logs view --latest\n","lang":"python","description":"This quickstart demonstrates a basic pyATS AEtest script that, when executed, implicitly uses pyATS AEreport to collect and format test results. The `pyats logs view --latest` command can then be used in the terminal to open the generated HTML report in a web browser, showcasing AEreport's output."},"warnings":[{"fix":"Use `pyats create project` for new projects and refer to the `CiscoTestAutomation/examples` GitHub repository for example scripts.","message":"The `pyats.templates` and `pyats.examples` packages have been completely removed. Templating is now handled via the `pyats create` command, and examples are moved to a dedicated GitHub repository (`CiscoTestAutomation/examples`).","severity":"breaking","affected_versions":"pyATS v19.7 and newer"},{"fix":"Run pyATS and AEreport on a supported Linux or Mac environment, or use a Docker container provided by Cisco DevNet.","message":"pyATS (and consequently AEreport) does not officially support Windows platforms. It is designed for Linux and Mac operating systems.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Standardize your test environments to closely mimic production as much as possible to ensure reliable and meaningful test outcomes. Use virtual environments.","message":"Inconsistent test environments (OS versions, network configurations, hardware) can lead to erratic and misleading test results, undermining the reliability of AEreport's output.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Verify the device's IP address and SSH port in the testbed file. Ensure the device is reachable from the pyATS host, its SSH server is running, and no firewall is blocking the connection. Use `dev.connect(log_stdout=True)` in an interactive Python session to get verbose SSH output for debugging.","cause":"The pyATS framework, via Unicon, attempted to establish an SSH connection to a device specified in the testbed file, but the device actively refused the connection. This can be due to incorrect IP, firewall rules, SSH service not running, or incorrect port.","error":"ssh: connect to host <ip_address> port 22: Connection refused"},{"fix":"Implement checks in your test script to ensure a device is connected before attempting operations on it. For example, `if device.is_connected(): ...` or gracefully handle connection errors to remove disconnected devices from further operations.","cause":"This error typically occurs when a test script attempts to perform operations (like parsing command output) on a device object that failed to connect, resulting in a `NoneType` object where a connected device object was expected.","error":"TypeError: 'NoneType' object is not iterable (e.g., when calling testbed.parse(<command>) after a connection failure)"},{"fix":"Always use a dedicated Python virtual environment for pyATS installations to isolate its dependencies. If conflicts occur, try reinstalling pyATS with `pip install 'pyats[full]' --upgrade` within a fresh virtual environment.","cause":"Dependency conflicts can arise when different pyATS components or other installed packages require conflicting versions of shared libraries, such as Jinja2.","error":"pyats version check reports 'version conflict' or similar errors (e.g., with Jinja2)"}]}