diff --git a/.github/workflows/FastTest.yml b/.github/workflows/FastTest.yml new file mode 100644 index 0000000..24a52af --- /dev/null +++ b/.github/workflows/FastTest.yml @@ -0,0 +1,36 @@ +# This workflows will upload a Python Package using Twine when a release is created +# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +name: Fast Test + +on: + push: + branches-ignore: + - develop + - master + +jobs: + + tox_test: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [ "3.11" ] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi + + - name: Test with tox + run: | + tox diff --git a/.github/workflows/PublishToPIP.yml b/.github/workflows/PublishToPIP.yml index bfa630c..4323411 100644 --- a/.github/workflows/PublishToPIP.yml +++ b/.github/workflows/PublishToPIP.yml @@ -1,11 +1,12 @@ # This workflows will upload a Python Package using Twine when a release is created # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries -name: Publish Python Package to PyPi.org +name: Publish To PyPi.org on: release: types: [created] + workflow_dispatch: jobs: deploy: @@ -13,9 +14,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install dependencies diff --git a/.github/workflows/TestBeforePush.yml b/.github/workflows/TestBeforePush.yml deleted file mode 100644 index 166eace..0000000 --- a/.github/workflows/TestBeforePush.yml +++ /dev/null @@ -1,35 +0,0 @@ -# This workflows will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - -name: Test before push - -on: - push: - branches: - - develop - pull_request: - branches: - - develop - - master - -jobs: - - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.x - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi - - name: Test with tox - run: | - tox - diff --git a/.github/workflows/ThoroughTest.yml b/.github/workflows/ThoroughTest.yml new file mode 100644 index 0000000..a0d023f --- /dev/null +++ b/.github/workflows/ThoroughTest.yml @@ -0,0 +1,38 @@ +# This workflows will upload a Python Package using Twine when a release is created +# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +name: Thorough Test + +on: + push: + branches: + - develop + - master + # check every 14 days + schedule: + - cron: '0 6 5,20 * *' +jobs: + + tox_test: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi + + - name: Test with tox + run: | + tox diff --git a/README.md b/README.md index 635c88d..446614b 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,16 @@ NAPALM driver for Cisco SMB switches (SF3xx, SF5xx, SG3xx, SG5xx, CBS35x). ## Status -Master: ![Build](https://github.com/napalm-automation-community/napalm-s350/workflows/Test%20before%20push/badge.svg?branch=master&event=push) -Develop: ![Build](https://github.com/napalm-automation-community/napalm-s350/workflows/Test%20before%20push/badge.svg?branch=develop&event=push) +Master: [![Thorough Test](https://github.com/napalm-automation-community/napalm-s350/actions/workflows/ThoroughTest.yml/badge.svg?branch=master)](https://github.com/napalm-automation-community/napalm-s350/actions/workflows/ThoroughTest.yml) -PyPi: [![Upload](https://github.com/napalm-automation-community/napalm-s350/workflows/Upload%20Python%20Package%20to%20PyPi.org/badge.svg)](https://github.com/napalm-automation-community/napalm-s350/actions?query=workflow%3A%22Upload+Python+Package+to+PyPi.org%22) +Develop: [![Thorough Test](https://github.com/napalm-automation-community/napalm-s350/actions/workflows/ThoroughTest.yml/badge.svg?branch=develop)](https://github.com/napalm-automation-community/napalm-s350/actions/workflows/ThoroughTest.yml) + +PyPi.org: [![Publish To PyPi.org](https://github.com/napalm-automation-community/napalm-s350/actions/workflows/PublishToPIP.yml/badge.svg?branch=master)](https://github.com/napalm-automation-community/napalm-s350/actions/workflows/PublishToPIP.yml) ## Requirements -Python 3.6+, napalm 3+ +Python 3.8+, napalm 4 ## Installation diff --git a/napalm_s350/s350.py b/napalm_s350/s350.py index 6763c25..59d9f3b 100644 --- a/napalm_s350/s350.py +++ b/napalm_s350/s350.py @@ -33,17 +33,12 @@ ConnectionClosedException, ) from napalm.base.helpers import canonical_interface_name +from napalm.base.netmiko_helpers import netmiko_args import napalm.base.constants as C import napalm.base.canonical_map -# make may own base_interfaces for s350 -s350_base_interfaces = { - **napalm.base.canonical_map.base_interfaces, - "fa": "FastEthernet", - "gi": "GigabitEthernet", - "te": "TengigabitEthernet", -} +from typing import List class S350Driver(NetworkDriver): @@ -63,30 +58,9 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self._dest_file_system = optional_args.get("dest_file_system", None) # Netmiko possible arguments - netmiko_argument_map = { - "port": None, - "secret": "", - "verbose": False, - "keepalive": 30, - "global_delay_factor": 1, - "use_keys": False, - "key_file": None, - "ssh_strict": False, - "system_host_keys": False, - "alt_host_keys": False, - "alt_key_file": "", - "ssh_config_file": None, - "allow_agent": False, - } - - # Allow for passing additional Netmiko arguments - self.netmiko_optional_args = {} - for k, v in netmiko_argument_map.items(): - try: - self.netmiko_optional_args[k] = optional_args[k] - except KeyError: - pass + self.netmiko_optional_args = netmiko_args(optional_args) + self.platform = "s350" self.port = optional_args.get("port", 22) self.device = None self.force_no_enable = optional_args.get("force_no_enable", False) @@ -118,16 +92,6 @@ def close(self): """Close the connection to the device.""" self.device.disconnect() - def cli(self, commands): - output = {} - try: - for cmd in commands: - output[cmd] = self.device.send_command(cmd) - - return output - except (socket.error, EOFError) as e: - raise ConnectionClosedException(str(e)) - def _send_command(self, command): """Wrapper for self.device.send.command(). @@ -180,7 +144,7 @@ def get_arp_table(self, vrf=""): else: raise ValueError("Unexpected output: {}".format(line.split())) - interface = canonical_interface_name(interface, s350_base_interfaces) + interface = canonical_interface_name(interface) entry = { "interface": interface, @@ -193,7 +157,13 @@ def get_arp_table(self, vrf=""): return arp_table - def get_config(self, retrieve="all", full=False, sanitized=False): + def get_config( + self, + retrieve="all", + full=False, + sanitized=False, + format: str = "text", + ): """ get_config for S350. Since this firmware doesn't support a candidate configuration we leave it empty. @@ -288,7 +258,8 @@ def get_facts(self): fqdn = "{0}.{1}".format(hostname, domainname) # interface_list - interfaces = [] + + interfaces: List[str] = [] show_int_st = show_int_st.strip() # remove the header information show_int_st = re.sub( @@ -298,7 +269,7 @@ def get_facts(self): if not line: continue interface = line.split()[0] - interface = canonical_interface_name(interface, s350_base_interfaces) + interface = canonical_interface_name(interface) interfaces.append(str(interface)) @@ -309,7 +280,7 @@ def get_facts(self): "model": str(model), "os_version": str(os_version), "serial_number": str(serial_number), - "uptime": uptime, + "uptime": float(uptime), "vendor": "Cisco", } @@ -364,7 +335,7 @@ def _get_facts_uptime(self, show_sys): return uptime_str def _get_facts_parse_inventory(self, show_inventory): - """ inventory can list more modules/devices """ + """inventory can list more modules/devices""" # make 1 module 1 line show_inventory = re.sub(r"\nPID", " PID", show_inventory, re.M) # delete empty lines @@ -471,14 +442,14 @@ def get_interfaces(self): entry = { "is_up": is_up, "is_enabled": is_enabled, - "speed": speed, + "speed": float(speed), "mtu": mtu, "last_flapped": -1.0, "description": description, "mac_address": napalm.base.helpers.mac(mac), } - interface = canonical_interface_name(interface, s350_base_interfaces) + interface = canonical_interface_name(interface) interfaces[interface] = entry @@ -516,14 +487,14 @@ def get_interfaces_ip(self): ip = netaddr.IPNetwork(cidr) family = "ipv{0}".format(ip.version) - interface = canonical_interface_name(interface, s350_base_interfaces) + interface = canonical_interface_name(interface) interfaces[interface] = {family: {str(ip.ip): {"prefix_length": ip.prefixlen}}} return interfaces def _get_ip_int_line_to_fields(self, line, fields_end): - """ dynamic fields lenghts """ + """dynamic fields lenghts""" line_elems = {} index = 0 f_start = 0 @@ -534,7 +505,7 @@ def _get_ip_int_line_to_fields(self, line, fields_end): return line_elems def _get_ip_int_fields_end(self, dashline): - """ fields length are diferent device to device, detect them on horizontal lin """ + """fields length are diferent device to device, detect them on horizontal line""" fields_end = [m.start() for m in re.finditer(" ", dashline.strip())] # fields_position.insert(0,0) @@ -574,7 +545,7 @@ def get_lldp_neighbors(self): remote_port = line_elems[2] remote_name = line_elems[3] - local_port = canonical_interface_name(local_port, s350_base_interfaces) + local_port = canonical_interface_name(local_port) neighbor = { "hostname": remote_name, @@ -588,7 +559,7 @@ def get_lldp_neighbors(self): return neighbors def _get_lldp_neighbors_line_to_fields(self, line, fields_end): - """ dynamic fields lenghts """ + """dynamic fields lenghts""" line_elems = {} index = 0 f_start = 0 @@ -599,7 +570,7 @@ def _get_lldp_neighbors_line_to_fields(self, line, fields_end): return line_elems def _get_lldp_neighbors_fields_end(self, dashline): - """ fields length are diferent device to device, detect them on horizontal lin """ + """fields length are diferent device to device, detect them on horizontal line""" fields_end = [m.start() for m in re.finditer(" ", dashline)] fields_end.append(len(dashline)) @@ -628,14 +599,14 @@ def get_lldp_neighbors_detail(self, interface=""): if interface: if interface == local_port: entry = self._get_lldp_neighbors_detail_parse(local_port) - local_port = canonical_interface_name(local_port, s350_base_interfaces) + local_port = canonical_interface_name(local_port) details[local_port] = [ entry, ] else: entry = self._get_lldp_neighbors_detail_parse(local_port) - local_port = canonical_interface_name(local_port, s350_base_interfaces) + local_port = canonical_interface_name(local_port) details[local_port] = [ entry, ] @@ -670,7 +641,7 @@ def _get_lldp_neighbors_detail_parse(self, local_port): elif line.startswith("Capabilities"): caps = self._get_lldp_neighbors_detail_capabilities_parse(line) - remote_port_id = canonical_interface_name(remote_port_id, s350_base_interfaces) + remote_port_id = canonical_interface_name(remote_port_id) entry = { "parent_interface": "N/A", diff --git a/requirements-dev.txt b/requirements-dev.txt index becc136..bf3ef10 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,12 +1,14 @@ -black==20.8b1 -coveralls==2.1.2 -ddt==1.4.1 -flake8-import-order==0.18.1 -pytest==5.4.3 -pytest-cov==2.10.1 -pytest-json==0.4.0 -pytest-pythonpath==0.7.3 -pylama==7.7.1 -mock==4.0.2 -tox==3.20.1 -demjson +napalm>=4.0.0 +netmiko>=4.0.0 +black>=24.3.0 # CVE-2024-21503 +coveralls +ddt +flake8-import-order +pytest +pytest-cov +pytest-json +pytest-pythonpath +pylama +pyflakes +mock +tox diff --git a/requirements.txt b/requirements.txt index c17be3f..7510853 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -napalm>=3.0.0 -netmiko>=3.1.0 -netaddr +napalm>=4.0.0 +netmiko>=4.0.0 +netaddr>=1.2.1 diff --git a/setup.py b/setup.py index 01362eb..66ede45 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="napalm-s350", - version="0.3.1", + version="0.4.0", packages=find_packages(exclude=("test*",)), author="Jasper Lievisse Adriaanse, Petr KlĂ­ma, Daniel Bacher", author_email="j@jasper.la, qaxi@seznam.cz, mail@phill93.de", @@ -25,9 +25,12 @@ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Operating System :: POSIX :: Linux", "Operating System :: MacOS", ], diff --git a/test/unit/command_output/SG500-52-K9/show_dir.txt b/test/unit/command_output/SG500-52-K9/show_dir.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_interface_switchport_GigabitEthernet1_4.txt b/test/unit/command_output/SG500-52-K9/show_interface_switchport_GigabitEthernet1_4.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_interfaces_description.txt b/test/unit/command_output/SG500-52-K9/show_interfaces_description.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_interfaces_status.txt b/test/unit/command_output/SG500-52-K9/show_interfaces_status.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_inventory.txt b/test/unit/command_output/SG500-52-K9/show_inventory.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_running_config.txt b/test/unit/command_output/SG500-52-K9/show_running_config.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_running_config_detailed.txt b/test/unit/command_output/SG500-52-K9/show_running_config_detailed.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_startup_config.txt b/test/unit/command_output/SG500-52-K9/show_startup_config.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_system.txt b/test/unit/command_output/SG500-52-K9/show_system.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/command_output/SG500-52-K9/show_version.txt b/test/unit/command_output/SG500-52-K9/show_version.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/conftest.py b/test/unit/conftest.py index 6f9fb30..bd99cb3 100644 --- a/test/unit/conftest.py +++ b/test/unit/conftest.py @@ -1,4 +1,5 @@ """Test fixtures.""" + from builtins import super import pytest diff --git a/test/unit/mocked_data/test_get_arp_table/SG300-10/expected_result.json b/test/unit/mocked_data/test_get_arp_table/SG300-10/expected_result.json index 3bd353c..75c5e8b 100644 --- a/test/unit/mocked_data/test_get_arp_table/SG300-10/expected_result.json +++ b/test/unit/mocked_data/test_get_arp_table/SG300-10/expected_result.json @@ -1,3 +1,3 @@ [ - {"interface": "vlan 1", "mac": "9C:EB:E8:AA:BB:CC", "ip": "192.168.1.1", "age": 0.0} + {"interface": "VLAN1", "mac": "9C:EB:E8:AA:BB:CC", "ip": "192.168.1.1", "age": 0.0} ] diff --git a/test/unit/mocked_data/test_get_arp_table/SG350X-48P-K9/expected_result.json b/test/unit/mocked_data/test_get_arp_table/SG350X-48P-K9/expected_result.json index 05c1b7e..a5fbe8d 100644 --- a/test/unit/mocked_data/test_get_arp_table/SG350X-48P-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_arp_table/SG350X-48P-K9/expected_result.json @@ -1,12 +1,12 @@ [ - {"interface": "TengigabitEthernet1/0/1", "mac": "00:00:0C:07:AC:01", "ip": "19.51.0.1", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "E4:C7:22:FE:E0:43", "ip": "19.51.0.2", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "BC:EA:FA:B4:15:AA", "ip": "19.51.0.5", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "BC:EA:FA:B4:14:6F", "ip": "19.51.0.3", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "5C:8A:38:2E:BD:C0", "ip": "19.51.0.1", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "5C:8A:38:2E:FD:E0", "ip": "19.51.0.8", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "00:50:56:93:19:B7", "ip": "19.51.1.4", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "00:50:56:92:2F:CB", "ip": "19.51.1.5", "age": 0.0}, - {"interface": "vlan 852", "mac": "00:50:56:9E:51:F3", "ip": "19.51.1.2", "age": 0.0}, - {"interface": "vlan 852", "mac": "A4:4C:C8:7D:37:03", "ip": "19.51.14.5", "age": 0.0} + {"interface": "TenGigabitEthernet1/0/1", "mac": "00:00:0C:07:AC:01", "ip": "19.51.0.1", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "E4:C7:22:FE:E0:43", "ip": "19.51.0.2", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "BC:EA:FA:B4:15:AA", "ip": "19.51.0.5", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "BC:EA:FA:B4:14:6F", "ip": "19.51.0.3", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "5C:8A:38:2E:BD:C0", "ip": "19.51.0.1", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "5C:8A:38:2E:FD:E0", "ip": "19.51.0.8", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "00:50:56:93:19:B7", "ip": "19.51.1.4", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "00:50:56:92:2F:CB", "ip": "19.51.1.5", "age": 0.0}, + {"interface": "VLAN852", "mac": "00:50:56:9E:51:F3", "ip": "19.51.1.2", "age": 0.0}, + {"interface": "VLAN852", "mac": "A4:4C:C8:7D:37:03", "ip": "19.51.14.5", "age": 0.0} ] diff --git a/test/unit/mocked_data/test_get_arp_table/SG500-28-K9/expected_result.json b/test/unit/mocked_data/test_get_arp_table/SG500-28-K9/expected_result.json index 62f8007..5452c31 100644 --- a/test/unit/mocked_data/test_get_arp_table/SG500-28-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_arp_table/SG500-28-K9/expected_result.json @@ -1,4 +1,4 @@ [ - {"interface": "vlan 202", "mac": "00:15:17:27:9C:4D", "ip": "10.0.3.1", "age": 0.0}, - {"interface": "vlan 202", "mac": "00:50:56:90:23:E8", "ip": "10.0.3.4", "age": 0.0} + {"interface": "VLAN202", "mac": "00:15:17:27:9C:4D", "ip": "10.0.3.1", "age": 0.0}, + {"interface": "VLAN202", "mac": "00:50:56:90:23:E8", "ip": "10.0.3.4", "age": 0.0} ] diff --git a/test/unit/mocked_data/test_get_arp_table/SG550X-24MP-K9/expected_result.json b/test/unit/mocked_data/test_get_arp_table/SG550X-24MP-K9/expected_result.json index b03f87b..76f97fc 100644 --- a/test/unit/mocked_data/test_get_arp_table/SG550X-24MP-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_arp_table/SG550X-24MP-K9/expected_result.json @@ -1,61 +1,61 @@ [ { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.1", "mac" : "AB:00:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.2", "mac" : "AB:C7:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.65", "mac" : "AB:EA:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.73", "mac" : "AB:EA:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.40", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.44", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "vlan 1", + "interface" : "VLAN1", "ip" : "192.168.0.4", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.49", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.2", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "vlan 1", + "interface" : "VLAN1", "ip" : "192.168.0.142", "mac" : "AB:50:EF:12:34:56" } diff --git a/test/unit/mocked_data/test_get_arp_table_with_vrf/SG300-10/expected_result.json b/test/unit/mocked_data/test_get_arp_table_with_vrf/SG300-10/expected_result.json index 3bd353c..75c5e8b 100644 --- a/test/unit/mocked_data/test_get_arp_table_with_vrf/SG300-10/expected_result.json +++ b/test/unit/mocked_data/test_get_arp_table_with_vrf/SG300-10/expected_result.json @@ -1,3 +1,3 @@ [ - {"interface": "vlan 1", "mac": "9C:EB:E8:AA:BB:CC", "ip": "192.168.1.1", "age": 0.0} + {"interface": "VLAN1", "mac": "9C:EB:E8:AA:BB:CC", "ip": "192.168.1.1", "age": 0.0} ] diff --git a/test/unit/mocked_data/test_get_arp_table_with_vrf/SG350X-48P-K9/expected_result.json b/test/unit/mocked_data/test_get_arp_table_with_vrf/SG350X-48P-K9/expected_result.json index 05c1b7e..a5fbe8d 100644 --- a/test/unit/mocked_data/test_get_arp_table_with_vrf/SG350X-48P-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_arp_table_with_vrf/SG350X-48P-K9/expected_result.json @@ -1,12 +1,12 @@ [ - {"interface": "TengigabitEthernet1/0/1", "mac": "00:00:0C:07:AC:01", "ip": "19.51.0.1", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "E4:C7:22:FE:E0:43", "ip": "19.51.0.2", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "BC:EA:FA:B4:15:AA", "ip": "19.51.0.5", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "BC:EA:FA:B4:14:6F", "ip": "19.51.0.3", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "5C:8A:38:2E:BD:C0", "ip": "19.51.0.1", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "5C:8A:38:2E:FD:E0", "ip": "19.51.0.8", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "00:50:56:93:19:B7", "ip": "19.51.1.4", "age": 0.0}, - {"interface": "TengigabitEthernet1/0/1", "mac": "00:50:56:92:2F:CB", "ip": "19.51.1.5", "age": 0.0}, - {"interface": "vlan 852", "mac": "00:50:56:9E:51:F3", "ip": "19.51.1.2", "age": 0.0}, - {"interface": "vlan 852", "mac": "A4:4C:C8:7D:37:03", "ip": "19.51.14.5", "age": 0.0} + {"interface": "TenGigabitEthernet1/0/1", "mac": "00:00:0C:07:AC:01", "ip": "19.51.0.1", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "E4:C7:22:FE:E0:43", "ip": "19.51.0.2", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "BC:EA:FA:B4:15:AA", "ip": "19.51.0.5", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "BC:EA:FA:B4:14:6F", "ip": "19.51.0.3", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "5C:8A:38:2E:BD:C0", "ip": "19.51.0.1", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "5C:8A:38:2E:FD:E0", "ip": "19.51.0.8", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "00:50:56:93:19:B7", "ip": "19.51.1.4", "age": 0.0}, + {"interface": "TenGigabitEthernet1/0/1", "mac": "00:50:56:92:2F:CB", "ip": "19.51.1.5", "age": 0.0}, + {"interface": "VLAN852", "mac": "00:50:56:9E:51:F3", "ip": "19.51.1.2", "age": 0.0}, + {"interface": "VLAN852", "mac": "A4:4C:C8:7D:37:03", "ip": "19.51.14.5", "age": 0.0} ] diff --git a/test/unit/mocked_data/test_get_arp_table_with_vrf/SG500-28-K9/expected_result.json b/test/unit/mocked_data/test_get_arp_table_with_vrf/SG500-28-K9/expected_result.json index 62f8007..5452c31 100644 --- a/test/unit/mocked_data/test_get_arp_table_with_vrf/SG500-28-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_arp_table_with_vrf/SG500-28-K9/expected_result.json @@ -1,4 +1,4 @@ [ - {"interface": "vlan 202", "mac": "00:15:17:27:9C:4D", "ip": "10.0.3.1", "age": 0.0}, - {"interface": "vlan 202", "mac": "00:50:56:90:23:E8", "ip": "10.0.3.4", "age": 0.0} + {"interface": "VLAN202", "mac": "00:15:17:27:9C:4D", "ip": "10.0.3.1", "age": 0.0}, + {"interface": "VLAN202", "mac": "00:50:56:90:23:E8", "ip": "10.0.3.4", "age": 0.0} ] diff --git a/test/unit/mocked_data/test_get_arp_table_with_vrf/SG550X-24MP-K9/expected_result.json b/test/unit/mocked_data/test_get_arp_table_with_vrf/SG550X-24MP-K9/expected_result.json index b03f87b..76f97fc 100644 --- a/test/unit/mocked_data/test_get_arp_table_with_vrf/SG550X-24MP-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_arp_table_with_vrf/SG550X-24MP-K9/expected_result.json @@ -1,61 +1,61 @@ [ { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.1", "mac" : "AB:00:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.2", "mac" : "AB:C7:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.65", "mac" : "AB:EA:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.73", "mac" : "AB:EA:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.40", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.44", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "vlan 1", + "interface" : "VLAN1", "ip" : "192.168.0.4", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.49", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "TengigabitEthernet1/0/4", + "interface" : "TenGigabitEthernet1/0/4", "ip" : "192.168.0.2", "mac" : "AB:50:EF:12:34:56" }, { "age" : 0.0, - "interface" : "vlan 1", + "interface" : "VLAN1", "ip" : "192.168.0.142", "mac" : "AB:50:EF:12:34:56" } diff --git a/test/unit/mocked_data/test_get_facts/SG350X-48P-K9-domainname/expected_result.json b/test/unit/mocked_data/test_get_facts/SG350X-48P-K9-domainname/expected_result.json index df56c88..f6a3660 100644 --- a/test/unit/mocked_data/test_get_facts/SG350X-48P-K9-domainname/expected_result.json +++ b/test/unit/mocked_data/test_get_facts/SG350X-48P-K9-domainname/expected_result.json @@ -50,10 +50,10 @@ "GigabitEthernet1/0/46", "GigabitEthernet1/0/47", "GigabitEthernet1/0/48", - "TengigabitEthernet1/0/1", - "TengigabitEthernet1/0/2", - "TengigabitEthernet1/0/3", - "TengigabitEthernet1/0/4", + "TenGigabitEthernet1/0/1", + "TenGigabitEthernet1/0/2", + "TenGigabitEthernet1/0/3", + "TenGigabitEthernet1/0/4", "Port-channel1", "Port-channel2", "Port-channel3", diff --git a/test/unit/mocked_data/test_get_facts/SG350X-48P-K9-twisted_inventory/expected_result.json b/test/unit/mocked_data/test_get_facts/SG350X-48P-K9-twisted_inventory/expected_result.json index 53726c6..51bafb5 100644 --- a/test/unit/mocked_data/test_get_facts/SG350X-48P-K9-twisted_inventory/expected_result.json +++ b/test/unit/mocked_data/test_get_facts/SG350X-48P-K9-twisted_inventory/expected_result.json @@ -50,10 +50,10 @@ "GigabitEthernet1/0/46", "GigabitEthernet1/0/47", "GigabitEthernet1/0/48", - "TengigabitEthernet1/0/1", - "TengigabitEthernet1/0/2", - "TengigabitEthernet1/0/3", - "TengigabitEthernet1/0/4", + "TenGigabitEthernet1/0/1", + "TenGigabitEthernet1/0/2", + "TenGigabitEthernet1/0/3", + "TenGigabitEthernet1/0/4", "Port-channel1", "Port-channel2", "Port-channel3", diff --git a/test/unit/mocked_data/test_get_facts/SG350X-48P-K9/expected_result.json b/test/unit/mocked_data/test_get_facts/SG350X-48P-K9/expected_result.json index 53726c6..51bafb5 100644 --- a/test/unit/mocked_data/test_get_facts/SG350X-48P-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_facts/SG350X-48P-K9/expected_result.json @@ -50,10 +50,10 @@ "GigabitEthernet1/0/46", "GigabitEthernet1/0/47", "GigabitEthernet1/0/48", - "TengigabitEthernet1/0/1", - "TengigabitEthernet1/0/2", - "TengigabitEthernet1/0/3", - "TengigabitEthernet1/0/4", + "TenGigabitEthernet1/0/1", + "TenGigabitEthernet1/0/2", + "TenGigabitEthernet1/0/3", + "TenGigabitEthernet1/0/4", "Port-channel1", "Port-channel2", "Port-channel3", diff --git a/test/unit/mocked_data/test_get_facts/SG550X-24MP-K9/expected_result.json b/test/unit/mocked_data/test_get_facts/SG550X-24MP-K9/expected_result.json index 0708e8f..fb354cf 100644 --- a/test/unit/mocked_data/test_get_facts/SG550X-24MP-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_facts/SG550X-24MP-K9/expected_result.json @@ -26,10 +26,10 @@ "GigabitEthernet1/0/22", "GigabitEthernet1/0/23", "GigabitEthernet1/0/24", - "TengigabitEthernet1/0/1", - "TengigabitEthernet1/0/2", - "TengigabitEthernet1/0/3", - "TengigabitEthernet1/0/4", + "TenGigabitEthernet1/0/1", + "TenGigabitEthernet1/0/2", + "TenGigabitEthernet1/0/3", + "TenGigabitEthernet1/0/4", "Port-channel1", "Port-channel2", "Port-channel3", diff --git a/test/unit/mocked_data/test_get_interfaces/SG350X-48P-K9/expected_result.json b/test/unit/mocked_data/test_get_interfaces/SG350X-48P-K9/expected_result.json index 6cf7fc2..6cea30b 100644 --- a/test/unit/mocked_data/test_get_interfaces/SG350X-48P-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_interfaces/SG350X-48P-K9/expected_result.json @@ -431,7 +431,7 @@ "mtu" : 9000, "speed" : 0 }, - "TengigabitEthernet1/0/1" : { + "TenGigabitEthernet1/0/1" : { "description" : "T1", "is_enabled" : true, "is_up" : true, @@ -440,7 +440,7 @@ "mtu" : 9000, "speed" : 1000 }, - "TengigabitEthernet1/0/2" : { + "TenGigabitEthernet1/0/2" : { "description" : "", "is_enabled" : false, "is_up" : false, @@ -449,7 +449,7 @@ "mtu" : 9000, "speed" : 0 }, - "TengigabitEthernet1/0/3" : { + "TenGigabitEthernet1/0/3" : { "description" : "T2", "is_enabled" : true, "is_up" : true, @@ -458,7 +458,7 @@ "mtu" : 9000, "speed" : 1000 }, - "TengigabitEthernet1/0/4" : { + "TenGigabitEthernet1/0/4" : { "description" : "T3", "is_enabled" : true, "is_up" : true, diff --git a/test/unit/mocked_data/test_get_interfaces/SG550X-24MP-K9/expected_result.json b/test/unit/mocked_data/test_get_interfaces/SG550X-24MP-K9/expected_result.json index 7a45b1e..9b2183c 100644 --- a/test/unit/mocked_data/test_get_interfaces/SG550X-24MP-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_interfaces/SG550X-24MP-K9/expected_result.json @@ -215,7 +215,7 @@ "mtu" : 9000, "speed" : 0 }, - "TengigabitEthernet1/0/1" : { + "TenGigabitEthernet1/0/1" : { "description" : "SW switch-c", "is_enabled" : true, "is_up" : true, @@ -224,7 +224,7 @@ "mtu" : 9000, "speed" : 1000 }, - "TengigabitEthernet1/0/2" : { + "TenGigabitEthernet1/0/2" : { "description" : "", "is_enabled" : false, "is_up" : false, @@ -233,7 +233,7 @@ "mtu" : 9000, "speed" : 0 }, - "TengigabitEthernet1/0/3" : { + "TenGigabitEthernet1/0/3" : { "description" : "", "is_enabled" : false, "is_up" : false, @@ -242,7 +242,7 @@ "mtu" : 9000, "speed" : 0 }, - "TengigabitEthernet1/0/4" : { + "TenGigabitEthernet1/0/4" : { "description" : "SW switch-c", "is_enabled" : true, "is_up" : true, diff --git a/test/unit/mocked_data/test_get_interfaces_ip/CBS350-24P-4G/expected_result.json b/test/unit/mocked_data/test_get_interfaces_ip/CBS350-24P-4G/expected_result.json index b23d0ea..313b531 100644 --- a/test/unit/mocked_data/test_get_interfaces_ip/CBS350-24P-4G/expected_result.json +++ b/test/unit/mocked_data/test_get_interfaces_ip/CBS350-24P-4G/expected_result.json @@ -1,4 +1,4 @@ { - "vlan 10" : { "ipv4" : { "10.1.2.2" : { "prefix_length" : 24 } } }, - "vlan 80" : { "ipv4" : { "10.0.0.150" : { "prefix_length" : 24 } } } + "VLAN10" : { "ipv4" : { "10.1.2.2" : { "prefix_length" : 24 } } }, + "VLAN80" : { "ipv4" : { "10.0.0.150" : { "prefix_length" : 24 } } } } diff --git a/test/unit/mocked_data/test_get_interfaces_ip/SG300-10/expected_result.json b/test/unit/mocked_data/test_get_interfaces_ip/SG300-10/expected_result.json index 143a01d..a6f4009 100644 --- a/test/unit/mocked_data/test_get_interfaces_ip/SG300-10/expected_result.json +++ b/test/unit/mocked_data/test_get_interfaces_ip/SG300-10/expected_result.json @@ -1 +1 @@ -{ "vlan 1" : { "ipv4" : { "192.168.1.254" : { "prefix_length" : 24 } } } } +{ "VLAN1" : { "ipv4" : { "192.168.1.254" : { "prefix_length" : 24 } } } } diff --git a/test/unit/mocked_data/test_get_interfaces_ip/SG350X-48P-K9/expected_result.json b/test/unit/mocked_data/test_get_interfaces_ip/SG350X-48P-K9/expected_result.json index 49ac0f8..acedffa 100644 --- a/test/unit/mocked_data/test_get_interfaces_ip/SG350X-48P-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_interfaces_ip/SG350X-48P-K9/expected_result.json @@ -1,4 +1,4 @@ { - "vlan 1" : { "ipv4" : { "198.51.100.2" : { "prefix_length" : 24 } } }, - "vlan 852" : { "ipv4" : { "198.51.100.1" : { "prefix_length" : 16 } } } + "VLAN1" : { "ipv4" : { "198.51.100.2" : { "prefix_length" : 24 } } }, + "VLAN852" : { "ipv4" : { "198.51.100.1" : { "prefix_length" : 16 } } } } diff --git a/test/unit/mocked_data/test_get_interfaces_ip/SG500-28-K9/expected_result.json b/test/unit/mocked_data/test_get_interfaces_ip/SG500-28-K9/expected_result.json index 0d90d50..2e58fc6 100644 --- a/test/unit/mocked_data/test_get_interfaces_ip/SG500-28-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_interfaces_ip/SG500-28-K9/expected_result.json @@ -1 +1 @@ -{"vlan 202": {"ipv4": {"10.0.3.5": {"prefix_length": 8}}}} +{"VLAN202": {"ipv4": {"10.0.3.5": {"prefix_length": 8}}}} diff --git a/test/unit/mocked_data/test_get_interfaces_ip/SG550X-24MP-K9/expected_result.json b/test/unit/mocked_data/test_get_interfaces_ip/SG550X-24MP-K9/expected_result.json index 2365906..6087495 100644 --- a/test/unit/mocked_data/test_get_interfaces_ip/SG550X-24MP-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_interfaces_ip/SG550X-24MP-K9/expected_result.json @@ -1 +1 @@ -{"vlan 1": {"ipv4": {"192.168.0.37": {"prefix_length": 17}}}} +{"VLAN1": {"ipv4": {"192.168.0.37": {"prefix_length": 17}}}} diff --git a/test/unit/mocked_data/test_get_lldp_neighbors/SG350X-48P-K9-long_systemname/expected_result.json b/test/unit/mocked_data/test_get_lldp_neighbors/SG350X-48P-K9-long_systemname/expected_result.json index 5c5e42f..dfd4570 100644 --- a/test/unit/mocked_data/test_get_lldp_neighbors/SG350X-48P-K9-long_systemname/expected_result.json +++ b/test/unit/mocked_data/test_get_lldp_neighbors/SG350X-48P-K9-long_systemname/expected_result.json @@ -7,15 +7,15 @@ "hostname" : "", "port" : "34:e6:aa:ff:53:a8" } ], - "TengigabitEthernet1/0/1" : [ { + "TenGigabitEthernet1/0/1" : [ { "hostname" : "swzdsadas-vedc", "port" : "Gi0/23" } ], - "TengigabitEthernet1/0/3" : [ { + "TenGigabitEthernet1/0/3" : [ { "hostname" : "sw1dsafdsfsdf.example.net", "port" : "gi28" } ], - "TengigabitEthernet1/0/4" : [ { + "TenGigabitEthernet1/0/4" : [ { "hostname" : "sw2dsdfssddfd", "port" : "te1/0/4" } ] diff --git a/test/unit/mocked_data/test_get_lldp_neighbors/SG350X-48P-K9/expected_result.json b/test/unit/mocked_data/test_get_lldp_neighbors/SG350X-48P-K9/expected_result.json index 9ada696..e2e7a51 100644 --- a/test/unit/mocked_data/test_get_lldp_neighbors/SG350X-48P-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_lldp_neighbors/SG350X-48P-K9/expected_result.json @@ -7,15 +7,15 @@ "hostname" : "", "port" : "34:e6:aa:ff:53:a8" } ], - "TengigabitEthernet1/0/1" : [ { + "TenGigabitEthernet1/0/1" : [ { "hostname" : "swzdsadas-vedc", "port" : "Gi0/23" } ], - "TengigabitEthernet1/0/3" : [ { + "TenGigabitEthernet1/0/3" : [ { "hostname" : "sw1dsafdsfsdfsdd", "port" : "gi28" } ], - "TengigabitEthernet1/0/4" : [ { + "TenGigabitEthernet1/0/4" : [ { "hostname" : "sw2dsdfssddfd", "port" : "te1/0/4" } ] diff --git a/test/unit/mocked_data/test_get_lldp_neighbors/SG550X-24MP-K9/expected_result.json b/test/unit/mocked_data/test_get_lldp_neighbors/SG550X-24MP-K9/expected_result.json index 49eeff4..6ff024c 100644 --- a/test/unit/mocked_data/test_get_lldp_neighbors/SG550X-24MP-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_lldp_neighbors/SG550X-24MP-K9/expected_result.json @@ -15,11 +15,11 @@ "hostname" : "ab:48:ef:12:34:56", "port" : "ab:48:ef:12:34:56" } ], - "TengigabitEthernet1/0/1" : [ { + "TenGigabitEthernet1/0/1" : [ { "hostname" : "switch-c", "port" : "gi1/0/1" } ], - "TengigabitEthernet1/0/4" : [ { + "TenGigabitEthernet1/0/4" : [ { "hostname" : "switch-c.cb.madeta.cz", "port" : "Gi1/0/26" } ] diff --git a/test/unit/mocked_data/test_get_lldp_neighbors_detail/SG550X-24MP-K9/expected_result.json b/test/unit/mocked_data/test_get_lldp_neighbors_detail/SG550X-24MP-K9/expected_result.json index b93c77f..d747de0 100644 --- a/test/unit/mocked_data/test_get_lldp_neighbors_detail/SG550X-24MP-K9/expected_result.json +++ b/test/unit/mocked_data/test_get_lldp_neighbors_detail/SG550X-24MP-K9/expected_result.json @@ -1,4 +1,4 @@ -{ "TengigabitEthernet1/0/4" : [ { +{ "TenGigabitEthernet1/0/4" : [ { "parent_interface" : "N/A", "remote_chassis_id" : "ab:a5:ef:12:34:56", "remote_port" : "GigabitEthernet1/0/26", diff --git a/test/unit/mocked_data/test_get_lldp_neighbors_detail/SG550X-24MP-K9/show_lldp_neighbors_TengigabitEthernet1_0_4.txt b/test/unit/mocked_data/test_get_lldp_neighbors_detail/SG550X-24MP-K9/show_lldp_neighbors_TenGigabitEthernet1_0_4.txt similarity index 100% rename from test/unit/mocked_data/test_get_lldp_neighbors_detail/SG550X-24MP-K9/show_lldp_neighbors_TengigabitEthernet1_0_4.txt rename to test/unit/mocked_data/test_get_lldp_neighbors_detail/SG550X-24MP-K9/show_lldp_neighbors_TenGigabitEthernet1_0_4.txt diff --git a/test/unit/test_getters.py b/test/unit/test_getters.py index 5f87d9e..e470888 100644 --- a/test/unit/test_getters.py +++ b/test/unit/test_getters.py @@ -1,4 +1,5 @@ """Tests for getters.""" + from napalm.base.test.getters import BaseTestGetters import pytest diff --git a/tox.ini b/tox.ini index 55340d6..76953d8 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,5 @@ [tox] -#envlist = py3{6,7,8},black,pylama,sphinx -envlist = py3{6,7,8},pylama,black +envlist = py,pylama,black skip_missing_interpreters = true [testenv] @@ -14,15 +13,9 @@ commands = [testenv:black] commands = - black --check --target-version py36 --line-length 100 --color --diff . + black --check --target-version py312 --line-length 100 --color --diff . [testenv:pylama] commands = pylama . -[testenv:sphinx] -commands = - make doctest - -whitelist_externals = - make