diff --git a/.bandit.yml b/.bandit.yml deleted file mode 100644 index 3bd46e2c..00000000 --- a/.bandit.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -# No need to check for security issues in the test scripts! -exclude_dirs: - - "./tests/" - - "./docs/" - - "netutils/data_files/" diff --git a/.flake8 b/.flake8 deleted file mode 100644 index e3ba27d5..00000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -# E501: Line length is enforced by Black, so flake8 doesn't need to check it -# W503: Black disagrees with this rule, as does PEP 8; Black wins -ignore = E501, W503 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0bc8f89d..fc02243e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ # Default owner(s) of all files in this repository -* @itdependsnetworks @jeffkala @qduk @abates +* @itdependsnetworks @jeffkala @qduk diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index d8356556..491431e0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,8 +4,8 @@ about: Report a reproducible bug in the current release of netutils --- ### Environment -* Python version: -* netutils version: +* Python version: +* netutils version: ### Expected Behavior diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index cbf1dbd5..67ee840b 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -5,7 +5,7 @@ about: Propose a new feature or enhancement --- ### Environment -* netutils version: +* netutils version: " +issue_format = "[#{issue}](https://github.com/networktocode/netutils/issues/{issue})" + +[[tool.towncrier.type]] +directory = "security" +name = "Security" +showcontent = true + +[[tool.towncrier.type]] +directory = "added" +name = "Added" +showcontent = true + +[[tool.towncrier.type]] +directory = "changed" +name = "Changed" +showcontent = true + +[[tool.towncrier.type]] +directory = "deprecated" +name = "Deprecated" +showcontent = true + +[[tool.towncrier.type]] +directory = "removed" +name = "Removed" +showcontent = true + +[[tool.towncrier.type]] +directory = "fixed" +name = "Fixed" +showcontent = true + +[[tool.towncrier.type]] +directory = "dependencies" +name = "Dependencies" +showcontent = true + +[[tool.towncrier.type]] +directory = "documentation" +name = "Documentation" +showcontent = true + +[[tool.towncrier.type]] +directory = "housekeeping" +name = "Housekeeping" +showcontent = true diff --git a/tasks.py b/tasks.py index 90834bfe..88d0565f 100644 --- a/tasks.py +++ b/tasks.py @@ -1,26 +1,19 @@ """Tasks for use with Invoke.""" -import os -import sys - -from invoke import task - -try: - import toml -except ImportError: - sys.exit("Please make sure to `pip install toml` or enable the Poetry shell and run `poetry install`.") +from invoke import Collection, Exit +from invoke import task as invoke_task def is_truthy(arg): """Convert "truthy" strings into Booleans. + Examples + -------- + >>> is_truthy('yes') + True Args: arg (str): Truthy string (True values are y, yes, t, true, on and 1; false values are n, no, f, false, off and 0. Raises ValueError if val is anything else. - - Examples: - >>> is_truthy('yes') - True """ if isinstance(arg, bool): return arg @@ -33,151 +26,197 @@ def is_truthy(arg): raise ValueError(f"Invalid truthy value: `{arg}`") -PYPROJECT_CONFIG = toml.load("pyproject.toml") -TOOL_CONFIG = PYPROJECT_CONFIG["tool"]["poetry"] +# Use pyinvoke configuration for default values, see http://docs.pyinvoke.org/en/stable/concepts/configuration.html +# Variables may be overwritten in invoke.yml or by the environment variables INVOKE_PYNTC_xxx +namespace = Collection("netutils") +namespace.configure( + { + "netutils": { + "project_name": "netutils", + "python_ver": "3.13", + "local": False, + "image_name": "netutils", + "image_ver": "latest", + "pwd": ".", + } + } +) + + +# pylint: disable=keyword-arg-before-vararg +def task(function=None, *args, **kwargs): + """Task decorator to override the default Invoke task decorator and add each task to the invoke namespace.""" + + def task_wrapper(function=None): + """Wrapper around invoke.task to add the task to the namespace as well.""" + if args or kwargs: + task_func = invoke_task(*args, **kwargs)(function) + else: + task_func = invoke_task(function) + namespace.add_task(task_func) + return task_func -# Can be set to a separate Python version to be used for launching or building image -PYTHON_VER = os.getenv("PYTHON_VER", "3.13") -# Name of the docker image/image -IMAGE_NAME = os.getenv("IMAGE_NAME", TOOL_CONFIG["name"]) -# Tag for the image -IMAGE_VER = os.getenv("IMAGE_VER", f"{TOOL_CONFIG['version']}-py{PYTHON_VER}") -# Gather current working directory for Docker commands -PWD = os.getcwd() -# Local or Docker execution provide "local" to run locally without docker execution -INVOKE_LOCAL = is_truthy(os.getenv("INVOKE_LOCAL", False)) # pylint: disable=W1508 -# Get project name from the toml file -PROJECT_NAME = PYPROJECT_CONFIG["tool"]["poetry"]["name"] -# Get current project version from the toml file -PROJECT_VERSION = PYPROJECT_CONFIG["tool"]["poetry"]["version"] + if function: + # The decorator was called with no arguments + return task_wrapper(function) + # The decorator was called with arguments + return task_wrapper -def run_cmd(context, exec_cmd, local=INVOKE_LOCAL, port=None): +def run_command(context, exec_cmd, port=None): """Wrapper to run the invoke task commands. Args: context ([invoke.task]): Invoke task object. exec_cmd ([str]): Command to run. - local (bool): Define as `True` to execute locally + port (int): Used to serve local docs. Returns: result (obj): Contains Invoke result from running task. """ - if is_truthy(local): + if is_truthy(context.netutils.local): print(f"LOCAL - Running command {exec_cmd}") result = context.run(exec_cmd, pty=True) else: - print(f"DOCKER - Running command: {exec_cmd} container: {IMAGE_NAME}:{IMAGE_VER}") + print( + f"DOCKER - Running command: {exec_cmd} container: {context.netutils.image_name}:{context.netutils.image_ver}" + ) if port: result = context.run( - f"docker run -it -p {port} -v {PWD}:/local {IMAGE_NAME}:{IMAGE_VER} sh -c '{exec_cmd}'", pty=True + f"docker run -it -p {port} -v {context.netutils.pwd}:/local {context.netutils.image_name}:{context.netutils.image_ver} sh -c '{exec_cmd}'", + pty=True, ) else: result = context.run( - f"docker run -it -v {PWD}:/local {IMAGE_NAME}:{IMAGE_VER} sh -c '{exec_cmd}'", pty=True + f"docker run -it -v {context.netutils.pwd}:/local {context.netutils.image_name}:{context.netutils.image_ver} sh -c '{exec_cmd}'", + pty=True, ) return result -@task -def build(context, nocache=False, forcerm=False, hide=False): # pylint: disable=too-many-arguments - """Build a Docker image. - - Args: - context (obj): Used to run specific commands - nocache (bool): Do not use cache when building the image - forcerm (bool): Always remove intermediate containers - hide (bool): Hide output of Docker image build - """ - print(f"Building image {IMAGE_NAME}:{IMAGE_VER}") - command = f"docker build --tag {IMAGE_NAME}:{IMAGE_VER} --build-arg PYTHON_VER={PYTHON_VER} -f Dockerfile ." +@task( + help={ + "cache": "Whether to use Docker's cache when building images (default enabled)", + "force_rm": "Always remove intermediate images", + "hide": "Suppress output from Docker", + } +) +def build(context, cache=True, force_rm=False, hide=False): + """Build a Docker image.""" + print(f"Building image {context.netutils.image_name}:{context.netutils.image_ver}") + command = f"docker build --tag {context.netutils.image_name}:{context.netutils.image_ver} --build-arg PYTHON_VER={context.netutils.python_ver} -f Dockerfile ." - if nocache: + if not cache: command += " --no-cache" - if forcerm: + if force_rm: command += " --force-rm" result = context.run(command, hide=hide) if result.exited != 0: - print(f"Failed to build image {IMAGE_NAME}:{IMAGE_VER}\nError: {result.stderr}") + print( + f"Failed to build image {context.netutils.image_name}:{context.netutils.image_ver}\nError: {result.stderr}" + ) @task def clean(context): - """Remove the project specific image. - - Args: - context (obj): Used to run specific commands - """ - print(f"Attempting to forcefully remove image {IMAGE_NAME}:{IMAGE_VER}") - context.run(f"docker rmi {IMAGE_NAME}:{IMAGE_VER} --force") - print(f"Successfully removed image {IMAGE_NAME}:{IMAGE_VER}") + """Remove the project specific image.""" + print(f"Attempting to forcefully remove image {context.netutils.image_name}:{context.netutils.image_ver}") + context.run(f"docker rmi {context.netutils.image_name}:{context.netutils.image_ver} --force") + print(f"Successfully removed image {context.netutils.image_name}:{context.netutils.image_ver}") @task def rebuild(context): - """Clean the Docker image and then rebuild without using cache. - - Args: - context (obj): Used to run specific commands - """ + """Clean the Docker image and then rebuild without using cache.""" clean(context) - build(context) + build(context, cache=False) @task -def coverage(context, local=INVOKE_LOCAL): +def coverage(context): """Run the coverage report against pytest. Args: context (obj): Used to run specific commands - local (bool): Define as `True` to execute locally """ exec_cmd = "coverage run --source=netutils -m pytest" - run_cmd(context, exec_cmd, local) - run_cmd(context, "coverage report", local) - run_cmd(context, "coverage html", local) + run_command(context, exec_cmd) + run_command(context, "coverage report") + run_command(context, "coverage html") @task -def pytest(context, local=INVOKE_LOCAL): +def pytest(context): """Run pytest for the specified name and Python version. Args: context (obj): Used to run specific commands - local (bool): Define as `True` to execute locally """ exec_cmd = "pytest -vv --doctest-modules netutils/ && coverage run --source=netutils -m pytest && coverage report" - run_cmd(context, exec_cmd, local) - - -@task -def black(context, local=INVOKE_LOCAL): - """Run black to check that Python files adherence to black standards. - - Args: - context (obj): Used to run specific commands - local (bool): Define as `True` to execute locally - """ - exec_cmd = "black --check --diff ." - run_cmd(context, exec_cmd, local) + run_command(context, exec_cmd) + + +@task(aliases=("a",)) +def autoformat(context): + """Run code autoformatting.""" + ruff(context, action=["format"], fix=True) + + +@task( + help={ + "action": "Available values are `['lint', 'format']`. Can be used multiple times. (default: `['lint', 'format']`)", + "target": "File or directory to inspect, repeatable (default: all files in the project will be inspected)", + "fix": "Automatically fix selected actions. May not be able to fix all issues found. (default: False)", + "output_format": "See https://docs.astral.sh/ruff/settings/#output-format for details. (default: `concise`)", + }, + iterable=["action", "target"], +) +def ruff(context, action=None, target=None, fix=False, output_format="concise"): + """Run ruff to perform code formatting and/or linting.""" + if not action: + action = ["lint", "format"] + if not target: + target = ["."] + + exit_code = 0 + + if "format" in action: + command = "ruff format " + if not fix: + command += "--check " + command += " ".join(target) + if not run_command(context, command): + exit_code = 1 + + if "lint" in action: + command = "ruff check " + if fix: + command += "--fix " + command += f"--output-format {output_format} " + command += " ".join(target) + if not run_command(context, command): + exit_code = 1 + + if exit_code != 0: + raise Exit(code=exit_code) @task -def flake8(context, local=INVOKE_LOCAL): - """Run flake8 for the specified name and Python version. +def mypy(context): + """Run mypy to validate typing-hints. Args: context (obj): Used to run specific commands local (bool): Define as `True` to execute locally """ - exec_cmd = "flake8 ." - run_cmd(context, exec_cmd, local) + exec_cmd = "mypy ./netutils" + run_command(context, exec_cmd) @task -def pylint(context, local=INVOKE_LOCAL): +def pylint(context): """Run pylint for the specified name and Python version. Args: @@ -185,11 +224,11 @@ def pylint(context, local=INVOKE_LOCAL): local (bool): Define as `True` to execute locally """ exec_cmd = 'find . -name "*.py" | grep -vE "(tests/unit/mock|netutils/data_files)" | xargs pylint' - run_cmd(context, exec_cmd, local) + run_command(context, exec_cmd) @task -def yamllint(context, local=INVOKE_LOCAL): +def yamllint(context): """Run yamllint to validate formatting adheres to NTC defined YAML standards. Args: @@ -197,43 +236,7 @@ def yamllint(context, local=INVOKE_LOCAL): local (bool): Define as `True` to execute locally """ exec_cmd = "yamllint ." - run_cmd(context, exec_cmd, local) - - -@task -def pydocstyle(context, local=INVOKE_LOCAL): - """Run pydocstyle to validate docstring formatting adheres to NTC defined standards. - - Args: - context (obj): Used to run specific commands - local (bool): Define as `True` to execute locally - """ - exec_cmd = "pydocstyle ." - run_cmd(context, exec_cmd, local) - - -@task -def bandit(context, local=INVOKE_LOCAL): - """Run bandit to validate basic static code security analysis. - - Args: - context (obj): Used to run specific commands - local (bool): Define as `True` to execute locally - """ - exec_cmd = "bandit --recursive ./ --configfile .bandit.yml" - run_cmd(context, exec_cmd, local) - - -@task -def mypy(context, local=INVOKE_LOCAL): - """Run mypy to validate typing-hints. - - Args: - context (obj): Used to run specific commands - local (bool): Define as `True` to execute locally - """ - exec_cmd = "mypy ./netutils" - run_cmd(context, exec_cmd, local) + run_command(context, exec_cmd) @task @@ -243,39 +246,44 @@ def cli(context): Args: context (obj): Used to run specific commands """ - dev = f"docker run -it -v {PWD}:/local {IMAGE_NAME}:{IMAGE_VER} /bin/bash" + dev = f"docker run -it -v {context.netutils.pwd}:/local {context.netutils.image_name}:{context.netutils.image_ver} /bin/bash" context.run(f"{dev}", pty=True) @task -def tests(context, local=INVOKE_LOCAL): +def tests(context): """Run all tests for the specified name and Python version. Args: context (obj): Used to run specific commands - local (bool): Define as `True` to execute locally """ - black(context, local) - flake8(context, local) - pylint(context, local) - yamllint(context, local) - pydocstyle(context, local) - bandit(context, local) - mypy(context, local) - pytest(context, local) + ruff(context) + pylint(context) + yamllint(context) + mypy(context) + pytest(context) print("All tests have passed!") @task -def clean_container(context): - """Remove stopped containers that source for image `netutils:`.""" - exec_cmd = r"""docker container rm $(docker container ls -a | grep -E "^\S+\s+netutils:" | awk 'NR>1 {print $1}')""" - run_cmd(context, exec_cmd, local=True) - - -@task -def docs(context, local=INVOKE_LOCAL): +def docs(context): """Build and serve docs locally for development.""" exec_cmd = "mkdocs serve -v --dev-addr=0.0.0.0:8001" - run_cmd(context, exec_cmd, local, port="8001:8001") + run_command(context, exec_cmd, port="8001:8001") + + +@task( + help={ + "version": "Version of netutils to generate the release notes for.", + } +) +def generate_release_notes(context, version=""): + """Generate Release Notes using Towncrier.""" + command = "poetry run towncrier build" + if version: + command += f" --version {version}" + else: + command += " --version `poetry version -s`" + # Due to issues with git repo ownership in the containers, this must always run locally. + context.run(command) diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 836d0a12..de331952 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -1,8 +1,8 @@ """Used to setup fixtures to be used through tests""" +import importlib.util import json import os -import importlib.util import pytest diff --git a/tests/unit/mock/config/compliance/feature_compliance/ios_basic_received.py b/tests/unit/mock/config/compliance/feature_compliance/ios_basic_received.py index 2b4e40a5..afd33954 100644 --- a/tests/unit/mock/config/compliance/feature_compliance/ios_basic_received.py +++ b/tests/unit/mock/config/compliance/feature_compliance/ios_basic_received.py @@ -1,9 +1,9 @@ data = { - "actual": "ntp server 10.10.10.10\n" "ntp server 10.10.10.11\n" "ntp server 10.10.10.12", + "actual": "ntp server 10.10.10.10\nntp server 10.10.10.11\nntp server 10.10.10.12", "cannot_parse": True, "compliant": True, "extra": "", - "intended": "ntp server 10.10.10.10\n" "ntp server 10.10.10.12\n" "ntp server 10.10.10.11", + "intended": "ntp server 10.10.10.10\nntp server 10.10.10.12\nntp server 10.10.10.11", "missing": "", "ordered_compliant": False, "unordered_compliant": True, diff --git a/tests/unit/mock/config/compliance/feature_compliance/ios_empty_banner_received.py b/tests/unit/mock/config/compliance/feature_compliance/ios_empty_banner_received.py index 0200280f..51510b2b 100755 --- a/tests/unit/mock/config/compliance/feature_compliance/ios_empty_banner_received.py +++ b/tests/unit/mock/config/compliance/feature_compliance/ios_empty_banner_received.py @@ -3,8 +3,8 @@ "cannot_parse": True, "compliant": False, "extra": "banner motd ^C^C", - "intended": "banner motd ^C\n" "actual banner example\n^C", - "missing": "banner motd ^C\n" "actual banner example\n^C", + "intended": "banner motd ^C\nactual banner example\n^C", + "missing": "banner motd ^C\nactual banner example\n^C", "ordered_compliant": False, "unordered_compliant": False, } diff --git a/tests/unit/mock/config/compliance/feature_compliance/ios_empty_dst_received.py b/tests/unit/mock/config/compliance/feature_compliance/ios_empty_dst_received.py index b2a98fed..17569872 100644 --- a/tests/unit/mock/config/compliance/feature_compliance/ios_empty_dst_received.py +++ b/tests/unit/mock/config/compliance/feature_compliance/ios_empty_dst_received.py @@ -1,8 +1,8 @@ data = { - "actual": "ntp server 10.10.10.10\n" "ntp server 10.10.10.11\n" "ntp server 10.10.10.12", + "actual": "ntp server 10.10.10.10\nntp server 10.10.10.11\nntp server 10.10.10.12", "cannot_parse": True, "compliant": False, - "extra": "ntp server 10.10.10.10\n" "ntp server 10.10.10.11\n" "ntp server 10.10.10.12", + "extra": "ntp server 10.10.10.10\nntp server 10.10.10.11\nntp server 10.10.10.12", "intended": "", "missing": "", "ordered_compliant": False, diff --git a/tests/unit/mock/config/compliance/feature_compliance/ios_empty_src_received.py b/tests/unit/mock/config/compliance/feature_compliance/ios_empty_src_received.py index 4df8ec76..bbc79084 100644 --- a/tests/unit/mock/config/compliance/feature_compliance/ios_empty_src_received.py +++ b/tests/unit/mock/config/compliance/feature_compliance/ios_empty_src_received.py @@ -3,8 +3,8 @@ "cannot_parse": True, "compliant": False, "extra": "", - "intended": "ntp server 10.10.10.10\n" "ntp server 10.10.10.12\n" "ntp server 10.10.10.11", - "missing": "ntp server 10.10.10.10\n" "ntp server 10.10.10.12\n" "ntp server 10.10.10.11", + "intended": "ntp server 10.10.10.10\nntp server 10.10.10.12\nntp server 10.10.10.11", + "missing": "ntp server 10.10.10.10\nntp server 10.10.10.12\nntp server 10.10.10.11", "ordered_compliant": False, "unordered_compliant": False, } diff --git a/tests/unit/test_bandwidth.py b/tests/unit/test_bandwidth.py index 9f928940..d1afd8fd 100644 --- a/tests/unit/test_bandwidth.py +++ b/tests/unit/test_bandwidth.py @@ -1,8 +1,8 @@ """Test for the Bandwidth functions.""" import pytest -from netutils import bandwidth +from netutils import bandwidth name_to_bits = [ {"sent": "10Mbps", "received": 10000000}, diff --git a/tests/unit/test_banner.py b/tests/unit/test_banner.py index 4c03ec52..08948ee9 100644 --- a/tests/unit/test_banner.py +++ b/tests/unit/test_banner.py @@ -1,8 +1,8 @@ """Test for the banner functions.""" import pytest -from netutils import banner +from netutils import banner BANNER_CARET_C = "banner login ^C\n******************\n TEST BANNER\n******************\n^C" diff --git a/tests/unit/test_basics.py b/tests/unit/test_basics.py index 515dfba9..796f0122 100644 --- a/tests/unit/test_basics.py +++ b/tests/unit/test_basics.py @@ -2,6 +2,7 @@ import os import unittest + import toml diff --git a/tests/unit/test_compliance.py b/tests/unit/test_compliance.py index dc5c796a..ed3d547d 100644 --- a/tests/unit/test_compliance.py +++ b/tests/unit/test_compliance.py @@ -4,6 +4,7 @@ import os import pytest + from netutils.config import compliance MOCK_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "mock", "config", "compliance") @@ -39,9 +40,7 @@ def test_section_config(_file, network_os, get_text_data, get_python_data): # p @pytest.mark.parametrize("_file, network_os", compliance_parameters) -def test_compliance( - _file, network_os, get_json_data, get_text_data, get_python_data -): # pylint: disable=redefined-outer-name +def test_compliance(_file, network_os, get_json_data, get_text_data, get_python_data): # pylint: disable=redefined-outer-name truncate_file = os.path.join(MOCK_DIR, _file[: -len(INTEND_FILE)]) intended_cfg = get_text_data(os.path.join(MOCK_DIR, _file)) @@ -72,9 +71,7 @@ def test_find_unordered_cfg_lines(_file, get_text_data, get_python_data): @pytest.mark.parametrize("_file, network_os", config_section_not_parsed_parameters) -def test_config_section_not_parsed( - _file, network_os, get_json_data, get_text_data, get_python_data -): # pylint: disable=redefined-outer-name +def test_config_section_not_parsed(_file, network_os, get_json_data, get_text_data, get_python_data): # pylint: disable=redefined-outer-name truncate_file = os.path.join(MOCK_DIR, _file[: -len(TXT_FILE)]) device_cfg = get_text_data(os.path.join(MOCK_DIR, _file)) diff --git a/tests/unit/test_conversion.py b/tests/unit/test_conversion.py index e084c000..167bac79 100644 --- a/tests/unit/test_conversion.py +++ b/tests/unit/test_conversion.py @@ -4,9 +4,10 @@ import os import pytest + from netutils.config.conversion import ( - paloalto_panos_brace_to_set, conversion_map, + paloalto_panos_brace_to_set, ) MOCK_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "mock", "config", "conversion") diff --git a/tests/unit/test_dns.py b/tests/unit/test_dns.py index 3e0a19af..3be9fde1 100644 --- a/tests/unit/test_dns.py +++ b/tests/unit/test_dns.py @@ -1,11 +1,11 @@ """Test for the DNS based functions.""" import socket + import pytest from netutils import dns, ip - test_is_fqdn = [ {"sent": "google.com", "received": True}, {"sent": "yahoo.com", "received": True}, diff --git a/tests/unit/test_hash.py b/tests/unit/test_hash.py index 36b24f64..db689fe3 100644 --- a/tests/unit/test_hash.py +++ b/tests/unit/test_hash.py @@ -4,7 +4,6 @@ from netutils.hash import hash_data - EXPECTED_HASHES = [ ( "md5", diff --git a/tests/unit/test_ip.py b/tests/unit/test_ip.py index b4743b4e..2553dd73 100644 --- a/tests/unit/test_ip.py +++ b/tests/unit/test_ip.py @@ -1,6 +1,7 @@ """Test for the IP functions.""" import ipaddress + import pytest from netutils import ip diff --git a/tests/unit/test_lib_helpers.py b/tests/unit/test_lib_helpers.py index 472400f6..7de1fb7a 100755 --- a/tests/unit/test_lib_helpers.py +++ b/tests/unit/test_lib_helpers.py @@ -3,6 +3,7 @@ from unittest import mock import pytest + from netutils.lib_helpers import get_napalm_getters diff --git a/tests/unit/test_lib_helpers_optionals.py b/tests/unit/test_lib_helpers_optionals.py index c1cee5bb..f53bc3d2 100755 --- a/tests/unit/test_lib_helpers_optionals.py +++ b/tests/unit/test_lib_helpers_optionals.py @@ -3,6 +3,7 @@ from unittest import mock import pytest + from netutils.lib_helpers import get_napalm_getters diff --git a/tests/unit/test_os_versions.py b/tests/unit/test_os_versions.py index 11d23332..e647fd6e 100755 --- a/tests/unit/test_os_versions.py +++ b/tests/unit/test_os_versions.py @@ -1,10 +1,10 @@ """Test for the lib_helpers definitions.""" import pytest + from netutils import os_version from netutils.constants import UPGRADE_PATHS - LOOSE_VERSION = [ {"sent": {"current_version": "10.1", "comparison": ">=", "target_version": "10.2"}, "received": False}, {"sent": {"current_version": "2.0.1", "comparison": "<", "target_version": "2.0.2"}, "received": True}, diff --git a/tests/unit/test_parser.py b/tests/unit/test_parser.py index 26a50963..ac72bbe8 100644 --- a/tests/unit/test_parser.py +++ b/tests/unit/test_parser.py @@ -44,9 +44,7 @@ def test_find_all_children(_file, network_os, get_text_data, get_json_data): # @pytest.mark.parametrize("_file, network_os", find_children_w_parents_parameters) -def test_find_children_w_parents( - _file, network_os, get_text_data, get_json_data -): # pylint: disable=redefined-outer-name +def test_find_children_w_parents(_file, network_os, get_text_data, get_json_data): # pylint: disable=redefined-outer-name truncate_file = os.path.join(MOCK_DIR, "find_children_w_parents", _file[: -len(TXT_FILE)]) device_cfg = get_text_data(os.path.join(MOCK_DIR, "find_children_w_parents", _file)) diff --git a/tests/unit/test_private_version.py b/tests/unit/test_private_version.py index ab8e2315..72852430 100644 --- a/tests/unit/test_private_version.py +++ b/tests/unit/test_private_version.py @@ -5,8 +5,8 @@ # Taken from https://github.com/python/cpython/blob/3.11/Lib/distutils/tests/test_version.py import unittest -from netutils._private.version import LooseVersion -from netutils._private.version import StrictVersion + +from netutils._private.version import LooseVersion, StrictVersion class VersionTestCase(unittest.TestCase): @@ -45,7 +45,7 @@ def test_cmp_strict(self): if wanted is ValueError: continue else: - raise AssertionError(("cmp(%s, %s) " "shouldn't raise ValueError") % (v1, v2)) + raise AssertionError(("cmp(%s, %s) shouldn't raise ValueError") % (v1, v2)) self.assertEqual(res, wanted, "cmp(%s, %s) should be %s, got %s" % (v1, v2, wanted, res)) res = StrictVersion(v1)._cmp(v2) self.assertEqual(res, wanted, "cmp(%s, %s) should be %s, got %s" % (v1, v2, wanted, res)) diff --git a/tests/unit/test_protocol_mapper.py b/tests/unit/test_protocol_mapper.py index 8f17a4b8..52c4a5c8 100644 --- a/tests/unit/test_protocol_mapper.py +++ b/tests/unit/test_protocol_mapper.py @@ -3,16 +3,16 @@ import pytest from netutils.protocol_mapper import ( + DCCP_NAME_TO_NUM, + DCCP_NUM_TO_NAME, PROTO_NAME_TO_NUM, PROTO_NUM_TO_NAME, + SCTP_NAME_TO_NUM, + SCTP_NUM_TO_NAME, TCP_NAME_TO_NUM, TCP_NUM_TO_NAME, UDP_NAME_TO_NUM, UDP_NUM_TO_NAME, - SCTP_NAME_TO_NUM, - SCTP_NUM_TO_NAME, - DCCP_NAME_TO_NUM, - DCCP_NUM_TO_NAME, ) diff --git a/tests/unit/test_running_config.py b/tests/unit/test_running_config.py index c06e5fd2..962e9be2 100644 --- a/tests/unit/test_running_config.py +++ b/tests/unit/test_running_config.py @@ -1,6 +1,7 @@ """Tests for the running configuration command mapping.""" import pytest + from netutils import lib_mapper from netutils.running_config import get_running_config_command diff --git a/tests/unit/test_sanitize.py b/tests/unit/test_sanitize.py index b1fee4b8..045d1b89 100644 --- a/tests/unit/test_sanitize.py +++ b/tests/unit/test_sanitize.py @@ -4,6 +4,7 @@ import os import pytest + from netutils.config import compliance from netutils.config.conversion import paloalto_panos_clean_newlines diff --git a/tests/unit/test_time.py b/tests/unit/test_time.py index b8fd0a51..b836d5ff 100644 --- a/tests/unit/test_time.py +++ b/tests/unit/test_time.py @@ -1,7 +1,8 @@ """Test for the time functions.""" import pytest -from netutils.time import uptime_string_to_seconds, uptime_seconds_to_string + +from netutils.time import uptime_seconds_to_string, uptime_string_to_seconds UPTIME_TO_STRING = [ { diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index a1a1d145..e27b1560 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -8,6 +8,7 @@ import pytest from jinja2 import Environment, select_autoescape from jinja2.loaders import FileSystemLoader + from netutils.utils import _JINJA2_FUNCTION_MAPPINGS, jinja2_convenience_function _EXCLUDED_FILES = [ diff --git a/tests/unit/test_version.py b/tests/unit/test_version.py index 8c0c18be..770f4cae 100644 --- a/tests/unit/test_version.py +++ b/tests/unit/test_version.py @@ -1,7 +1,8 @@ """Basic test for version check.""" -import unittest import os +import unittest + import toml from netutils import __version__ as project_version diff --git a/tests/unit/test_vlan.py b/tests/unit/test_vlan.py index d5a0e508..3a836837 100644 --- a/tests/unit/test_vlan.py +++ b/tests/unit/test_vlan.py @@ -1,7 +1,7 @@ """Test for the VLAN functions.""" -import os import glob +import os import pytest