From 2a026c7a688e26f40a1573813608364938cef934 Mon Sep 17 00:00:00 2001 From: Patryk Szulczewski Date: Wed, 26 Oct 2022 16:34:10 +0200 Subject: [PATCH 1/4] Fix parameter_match check, to support non-normalized data --- jdiff/check_types.py | 6 +- jdiff/evaluators.py | 42 +++---- poetry.lock | 166 +++++++++----------------- pyproject.toml | 1 + tests/test_operators.py | 1 - tests/test_sw_upgrade_device_state.py | 23 ++-- 6 files changed, 93 insertions(+), 146 deletions(-) diff --git a/jdiff/check_types.py b/jdiff/check_types.py index 91ce1a8..8b1bd0d 100644 --- a/jdiff/check_types.py +++ b/jdiff/check_types.py @@ -1,5 +1,5 @@ """CheckType Implementation.""" -from typing import Mapping, Tuple, Dict, Any, Union +from typing import List, Tuple, Dict, Any, Union from abc import ABC, abstractmethod from .evaluators import diff_generator, parameter_evaluator, regex_evaluator, operator_evaluator @@ -136,7 +136,7 @@ def _validate(params, mode) -> None: # type: ignore[override] f"'mode' argument should be one of the following: {', '.join(mode_options)}. You have: {mode}" ) - def evaluate(self, params: Dict, value_to_compare: Mapping, mode: str) -> Tuple[Dict, bool]: # type: ignore[override] + def evaluate(self, params: Dict, value_to_compare: List[Dict], mode: str) -> Tuple[Dict, bool]: # type: ignore[override] """Parameter Match evaluator implementation.""" self._validate(params=params, mode=mode) # TODO: we don't use the mode? @@ -161,7 +161,7 @@ def _validate(regex, mode) -> None: # type: ignore[override] if mode not in mode_options: raise ValueError(f"'mode' argument should be {mode_options}. You have: {mode}") - def evaluate(self, regex: str, value_to_compare: Mapping, mode: str) -> Tuple[Dict, bool]: # type: ignore[override] + def evaluate(self, regex: str, value_to_compare: List[Dict[Any, Dict]], mode: str) -> Tuple[Dict, bool]: # type: ignore[override] """Regex Match evaluator implementation.""" self._validate(regex=regex, mode=mode) evaluation_result = regex_evaluator(value_to_compare, regex, mode) diff --git a/jdiff/evaluators.py b/jdiff/evaluators.py index 702474f..6b9474a 100644 --- a/jdiff/evaluators.py +++ b/jdiff/evaluators.py @@ -1,6 +1,6 @@ """Evaluators.""" import re -from typing import Any, Mapping, Dict, Tuple +from typing import Any, Mapping, Dict, Tuple, List from deepdiff import DeepDiff from .utils.diff_helpers import get_diff_iterables_items, fix_deepdiff_key_names from .operator import Operator @@ -36,7 +36,7 @@ def diff_generator(pre_result: Any, post_result: Any) -> Dict: return fix_deepdiff_key_names(result) -def parameter_evaluator(values: Mapping, parameters: Mapping, mode: str) -> Dict: +def parameter_evaluator(values: List[Dict], parameters: Mapping, mode: str) -> Dict: """Parameter Match evaluator engine. Args: @@ -51,30 +51,30 @@ def parameter_evaluator(values: Mapping, parameters: Mapping, mode: str) -> Dict Dictionary with all the items that have some value not matching the expectations from parameters """ if not isinstance(values, list): - raise TypeError("Something went wrong during jmespath parsing. 'values' must be of type List.") + raise TypeError("'values' must be of type List.") result = {} - for value in values: + for index, value in enumerate(values): # value: {'7.7.7.7': {'peerAddress': '7.7.7.7', 'localAsn': '65130.1101', 'linkType': 'externals if not isinstance(value, dict): - raise TypeError( - "Something went wrong during jmespath parsing. ", - f"'value' ({value}) must be of type Dict, and it's {type(value)}", - ) + raise TypeError(f"'value' ({value}) must be of type Dict, and it's {type(value)}") result_item = {} - # TODO: Why the 'value' dict has always ONE single element? we have to explain - # inner_key: '7.7.7.7' - inner_key = list(value.keys())[0] - # inner_value: [{'peerAddress': '7.7.7.7', 'localAsn': '65130.1101', 'linkType': 'externals'}] - inner_value = list(value.values())[0] + # When data has been normalized with $key$, get inner key and value + if len(value) == 1: + # inner_key: '7.7.7.7' + inner_key = list(value.keys())[0] + # inner_value: [{'peerAddress': '7.7.7.7', 'localAsn': '65130.1101', 'linkType': 'externals'}] + value = list(value.values())[0] + else: + inner_key = index for parameter_key, parameter_value in parameters.items(): - if mode == "match" and inner_value[parameter_key] != parameter_value: - result_item[parameter_key] = inner_value[parameter_key] - elif mode == "no-match" and inner_value[parameter_key] == parameter_value: - result_item[parameter_key] = inner_value[parameter_key] + if mode == "match" and value[parameter_key] != parameter_value: + result_item[parameter_key] = value[parameter_key] + elif mode == "no-match" and value[parameter_key] == parameter_value: + result_item[parameter_key] = value[parameter_key] if result_item: result[inner_key] = result_item @@ -82,10 +82,10 @@ def parameter_evaluator(values: Mapping, parameters: Mapping, mode: str) -> Dict return result -def regex_evaluator(values: Mapping, regex_expression: str, mode: str) -> Dict: +def regex_evaluator(values: List[Dict[Any, Dict]], regex_expression: str, mode: str) -> Dict: """Regex Match evaluator engine.""" # values: [{'7.7.7.7': {'peerGroup': 'EVPN-OVERLAY-SPINE'}}] - # parameter: {'regex': '.*UNDERLAY.*', 'mode': 'include'} + # parameter: {'regex': '.*UNDERLAY.*', 'mode': 'match'} result = {} if not isinstance(values, list): raise TypeError("Something went wrong during JMSPath parsing. 'values' must be of type List.") @@ -94,10 +94,10 @@ def regex_evaluator(values: Mapping, regex_expression: str, mode: str) -> Dict: for founded_value in item.values(): for value in founded_value.values(): match_result = re.search(regex_expression, value) - # Fail if there is not regex match + # Fail if there is no regex match for "match" mode if mode == "match" and not match_result: result.update(item) - # Fail if there is regex match + # Fail if there is regex match for "no-match" mode. elif mode == "no-match" and match_result: result.update(item) diff --git a/poetry.lock b/poetry.lock index 2caaf47..9f3c4a1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -47,11 +47,11 @@ yaml = ["pyyaml"] [[package]] name = "black" -version = "22.8.0" +version = "22.10.0" description = "The uncompromising code formatter." category = "dev" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7" [package.dependencies] click = ">=8.0.0" @@ -70,7 +70,7 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2022.9.14" +version = "2022.9.24" description = "Python package for providing Mozilla's CA Bundle." category = "dev" optional = false @@ -101,11 +101,11 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" [[package]] name = "deepdiff" @@ -123,15 +123,26 @@ cli = ["click (==8.0.3)", "pyyaml (==5.4.1)", "toml (==0.10.2)", "clevercsv (==0 [[package]] name = "dill" -version = "0.3.5.1" +version = "0.3.6" description = "serialize all of python" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +python-versions = ">=3.7" [package.extras] graph = ["objgraph (>=1.7.2)"] +[[package]] +name = "exceptiongroup" +version = "1.0.0rc9" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "flake8" version = "3.9.2" @@ -173,7 +184,7 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.27" +version = "3.1.29" description = "GitPython is a python library used to interact with Git repositories" category = "dev" optional = false @@ -193,7 +204,7 @@ python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.12.0" +version = "4.13.0" description = "Read metadata from Python packages" category = "dev" optional = false @@ -204,9 +215,9 @@ typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "jaraco.tidelift (>=1.4)"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -218,7 +229,7 @@ python-versions = "*" [[package]] name = "invoke" -version = "1.7.1" +version = "1.7.3" description = "Pythonic task execution" category = "dev" optional = false @@ -262,11 +273,11 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "lazy-object-proxy" -version = "1.7.1" +version = "1.8.0" description = "A fast and thorough lazy object proxy." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "markdown" @@ -308,46 +319,49 @@ python-versions = ">=3.6" [[package]] name = "mkdocs" -version = "1.3.1" +version = "1.4.1" description = "Project documentation with Markdown." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -click = ">=3.3" +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} ghp-import = ">=1.0" -importlib-metadata = ">=4.3" -Jinja2 = ">=2.10.2" -Markdown = ">=3.2.1,<3.4" +importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} +jinja2 = ">=2.11.1" +markdown = ">=3.2.1,<3.4" mergedeep = ">=1.3.4" packaging = ">=20.5" -PyYAML = ">=3.10" +pyyaml = ">=5.1" pyyaml-env-tag = ">=0.1" +typing-extensions = {version = ">=3.10", markers = "python_version < \"3.8\""} watchdog = ">=2.0" [package.extras] +min-versions = ["watchdog (==2.0)", "typing-extensions (==3.10)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "packaging (==20.5)", "mergedeep (==1.3.4)", "markupsafe (==2.0.1)", "markdown (==3.2.1)", "jinja2 (==2.11.1)", "importlib-metadata (==4.3)", "ghp-import (==1.0)", "colorama (==0.4)", "click (==7.0)", "babel (==2.9.0)"] i18n = ["babel (>=2.9.0)"] [[package]] name = "mkdocs-include-markdown-plugin" -version = "3.8.1" +version = "3.9.1" description = "Mkdocs Markdown includer plugin." category = "dev" optional = false python-versions = ">=3.6" [package.extras] -dev = ["bump2version (==1.0.1)", "flake8 (==3.9.2)", "flake8-implicit-str-concat (==0.2.0)", "flake8-print (==4.0.0)", "isort (==5.9.1)", "mdpo (==0.3.61)", "mkdocs (==1.3.1)", "pre-commit (==2.13.0)", "pytest (==6.2.5)", "pytest-cov (==3.0.0)", "pyupgrade (==2.19.4)", "yamllint (==1.26.1)"] -test = ["mkdocs (==1.3.1)", "pytest (==6.2.5)", "pytest-cov (==3.0.0)"] +dev = ["bump2version (==1.0.1)", "mkdocs (==1.4.0)", "pre-commit", "pytest (==7.1.3)", "pytest-cov (==3.0.0)", "tox"] +test = ["mkdocs (==1.4.0)", "pytest (==7.1.3)", "pytest-cov (==3.0.0)"] [[package]] name = "mypy" -version = "0.971" +version = "0.982" description = "Optional static typing for Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] mypy-extensions = ">=0.4.3" @@ -400,7 +414,7 @@ python-versions = ">=3.7" [[package]] name = "pbr" -version = "5.10.0" +version = "5.11.0" description = "Python Build Reasonableness" category = "dev" optional = false @@ -433,14 +447,6 @@ importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - [[package]] name = "pycodestyle" version = "2.7.0" @@ -505,7 +511,7 @@ diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pytest" -version = "7.1.3" +version = "7.2.0" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -514,12 +520,12 @@ python-versions = ">=3.7" [package.dependencies] attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] @@ -614,7 +620,7 @@ python-versions = "*" [[package]] name = "stevedore" -version = "3.5.0" +version = "3.5.2" description = "Manage dynamic plugins for Python applications" category = "dev" optional = false @@ -650,7 +656,7 @@ python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "4.3.0" +version = "4.4.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "dev" optional = false @@ -702,20 +708,20 @@ pyyaml = "*" [[package]] name = "zipp" -version = "3.8.1" +version = "3.10.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] +docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "jaraco.functools", "more-itertools", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = "^3.7.0" -content-hash = "2be5d1d803d9c1d44b21902842a6c839586c8f9e95b056dada941b1a363971fc" +content-hash = "4a5e951b189b9a59af85323d6b4422b9861808a113265e1ce9258d71f6d4761e" [metadata.files] astroid = [] @@ -731,15 +737,10 @@ click = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] +colorama = [] deepdiff = [] -dill = [ - {file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"}, - {file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"}, -] +dill = [] +exceptiongroup = [] flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, @@ -752,65 +753,21 @@ gitdb = [ {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, ] -gitpython = [ - {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, - {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, -] +gitpython = [] idna = [] importlib-metadata = [] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] -invoke = [ - {file = "invoke-1.7.1-py3-none-any.whl", hash = "sha256:2dc975b4f92be0c0a174ad2d063010c8a1fdb5e9389d69871001118b4fcac4fb"}, - {file = "invoke-1.7.1.tar.gz", hash = "sha256:7b6deaf585eee0a848205d0b8c0014b9bf6f287a8eb798818a642dff1df14b19"}, -] +invoke = [] isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] jinja2 = [] jmespath = [] -lazy-object-proxy = [ - {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, - {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, -] +lazy-object-proxy = [] markdown = [ {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, @@ -881,7 +838,6 @@ platformdirs = [ {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] pluggy = [] -py = [] pycodestyle = [] pydocstyle = [ {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"}, @@ -957,10 +913,7 @@ snowballstemmer = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] -stevedore = [ - {file = "stevedore-3.5.0-py3-none-any.whl", hash = "sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c"}, - {file = "stevedore-3.5.0.tar.gz", hash = "sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335"}, -] +stevedore = [] toml = [] tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, @@ -992,10 +945,7 @@ typed-ast = [ {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] -typing-extensions = [ - {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, - {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, -] +typing-extensions = [] urllib3 = [] watchdog = [ {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330"}, diff --git a/pyproject.toml b/pyproject.toml index f13706c..dd870d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ flake8 = "*" mypy = "*" mkdocs = "^1.3.1" mkdocs-include-markdown-plugin = "^3.6.1" +importlib-metadata = "<5.0.0" # https://importlib-metadata.readthedocs.io/en/latest/history.html#v5-0-0 [tool.black] line-length = 120 diff --git a/tests/test_operators.py b/tests/test_operators.py index a67f8a8..31effc8 100644 --- a/tests/test_operators.py +++ b/tests/test_operators.py @@ -179,7 +179,6 @@ def test_operator(filename, check_type_str, evaluate_args, path, expected_result # There is not concept of "pre" and "post" in operator. data = load_json_file("api", filename) value = extract_data_from_json(data, path) - print(evaluate_args, value) actual_results = check.evaluate(evaluate_args, value) assert actual_results == expected_result, ASSERT_FAIL_MESSAGE.format( output=actual_results, expected_output=expected_result diff --git a/tests/test_sw_upgrade_device_state.py b/tests/test_sw_upgrade_device_state.py index 0c4ec1b..8dfde0c 100644 --- a/tests/test_sw_upgrade_device_state.py +++ b/tests/test_sw_upgrade_device_state.py @@ -6,25 +6,23 @@ @pytest.mark.parametrize( - "platform, command, jpath, expected_parameter, check_should_pass", + "platform, command, expected_parameter, check_should_pass, fail_details", [ - ("arista_eos", "show_version", "[*].[$image$,image]", {"image": "4.14.7M"}, True), - ("arista_eos", "show_version", "[*].[$image$,image]", {"image": "no-match"}, False), - ("cisco_ios", "show_version", "[*].[$version$,version]", {"version": "12.2(54)SG1"}, True), - ("cisco_ios", "show_version", "[*].[$version$,version]", {"version": "no-match"}, False), - ("cisco_nxos", "show_version", "[*].[$os$,os]", {"os": "6.1(2)I3(1)"}, True), - ("cisco_nxos", "show_version", "[*].[$os$,os]", {"os": "no-match"}, False), + ("arista_eos", "show_version", {"image": "4.14.7M"}, True, {}), + ("arista_eos", "show_version", {"image": "no-match"}, False, {0: {"image": "4.14.7M"}}), + ("cisco_ios", "show_version", {"version": "12.2(54)SG1"}, True, {}), + ("cisco_ios", "show_version", {"version": "no-match"}, False, {0: {"version": "12.2(54)SG1"}}), + ("cisco_nxos", "show_version", {"os": "6.1(2)I3(1)"}, True, {}), + ("cisco_nxos", "show_version", {"os": "no-match"}, False, {0: {"os": "6.1(2)I3(1)"}}), ], ) -def test_show_version(platform, command, jpath, expected_parameter, check_should_pass): +def test_show_version(platform, command, expected_parameter, check_should_pass, fail_details): """Test expected version with parameter_match.""" filename = f"{platform}_{command}.json" command = load_json_file("sw_upgrade", filename) - check = CheckType.create("parameter_match") - value = extract_data_from_json(command, jpath) - eval_results, passed = check.evaluate(expected_parameter, value, "match") # pylint: disable=E1121 - assert passed is check_should_pass, f"FAILED, eval_result: {eval_results}" + eval_results, passed = check.evaluate(expected_parameter, command, "match") # pylint: disable=E1121 + assert passed is check_should_pass and eval_results == fail_details, f"FAILED, eval_result: {eval_results}" @pytest.mark.parametrize( @@ -86,7 +84,6 @@ def test_show_ip_route_missing_and_additional_routes(platform, command): """Test missing or additional routes fail the test with exact_match.""" command_pre = command_post = load_json_file("sw_upgrade", f"{platform}_{command}.json") check = CheckType.create("exact_match") - print(len(command_pre)) eval_results_missing, passed_missing = check.evaluate(command_post[:30], command_pre) eval_results_additional, passed_additional = check.evaluate(command_post, command_pre[:30]) assert ( From 5c28060a5913418b16bc2fa49c06819046e3679d Mon Sep 17 00:00:00 2001 From: Patryk Szulczewski Date: Thu, 10 Nov 2022 18:15:19 +0100 Subject: [PATCH 2/4] Add test --- tests/mock/parameter_match/napalm_facts.json | 10 ++++++++++ tests/test_type_checks.py | 7 +++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/mock/parameter_match/napalm_facts.json diff --git a/tests/mock/parameter_match/napalm_facts.json b/tests/mock/parameter_match/napalm_facts.json new file mode 100644 index 0000000..01f28f2 --- /dev/null +++ b/tests/mock/parameter_match/napalm_facts.json @@ -0,0 +1,10 @@ +{ + "uptime": 5100, + "vendor": "Juniper", + "hostname": "vsrx", + "fqdn": "vsrx", + "os_version": "12.1X47-D20.7", + "serial_number": "beb914a9cca3", + "model": "FIREFLY-PERIMETER", + "interface_list": ["lo0"] +} \ No newline at end of file diff --git a/tests/test_type_checks.py b/tests/test_type_checks.py index b7112a5..bb24cbe 100644 --- a/tests/test_type_checks.py +++ b/tests/test_type_checks.py @@ -284,6 +284,13 @@ def test_checks(folder_name, check_type_str, evaluate_args, path, expected_resul False, ), ) +parameter_match_napalm_facts = ( + "napalm_facts.json", + "parameter_match", + {"mode": "match", "params": {"version": "12.1X47-D20.7"}}, + "*", + ({}, True), +) @pytest.mark.parametrize( From 9ffda9a1c6bca3d450d06e9d70c3e6fc1f022145 Mon Sep 17 00:00:00 2001 From: Patryk Szulczewski Date: Thu, 10 Nov 2022 21:17:21 +0100 Subject: [PATCH 3/4] Update tests. --- tests/mock/parameter_match/napalm_facts.json | 22 +++++++++++--------- tests/test_type_checks.py | 6 ++++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/tests/mock/parameter_match/napalm_facts.json b/tests/mock/parameter_match/napalm_facts.json index 01f28f2..fed110a 100644 --- a/tests/mock/parameter_match/napalm_facts.json +++ b/tests/mock/parameter_match/napalm_facts.json @@ -1,10 +1,12 @@ -{ - "uptime": 5100, - "vendor": "Juniper", - "hostname": "vsrx", - "fqdn": "vsrx", - "os_version": "12.1X47-D20.7", - "serial_number": "beb914a9cca3", - "model": "FIREFLY-PERIMETER", - "interface_list": ["lo0"] -} \ No newline at end of file +[ + { + "uptime": 5100, + "vendor": "Juniper", + "hostname": "vsrx", + "fqdn": "vsrx", + "os_version": "12.1X47-D20.7", + "serial_number": "beb914a9cca3", + "model": "FIREFLY-PERIMETER", + "interface_list": ["lo0"] + } +] diff --git a/tests/test_type_checks.py b/tests/test_type_checks.py index bb24cbe..a91af42 100644 --- a/tests/test_type_checks.py +++ b/tests/test_type_checks.py @@ -287,14 +287,15 @@ def test_checks(folder_name, check_type_str, evaluate_args, path, expected_resul parameter_match_napalm_facts = ( "napalm_facts.json", "parameter_match", - {"mode": "match", "params": {"version": "12.1X47-D20.7"}}, + {"mode": "match", "params": {"os_version": "12.1X47-D20.7"}}, "*", ({}, True), ) @pytest.mark.parametrize( - "filename, check_type_str, evaluate_args, path, expected_result", [parameter_match_api, parameter_no_match_api] + "filename, check_type_str, evaluate_args, path, expected_result", + [parameter_match_api, parameter_no_match_api, parameter_match_napalm_facts], ) def test_param_match(filename, check_type_str, evaluate_args, path, expected_result): """Validate parameter_match check type.""" @@ -303,6 +304,7 @@ def test_param_match(filename, check_type_str, evaluate_args, path, expected_res data = load_json_file("parameter_match", filename) value = extract_data_from_json(data, path) actual_results = check.evaluate(evaluate_args["params"], value, evaluate_args["mode"]) + print(actual_results) assert actual_results == expected_result, ASSERT_FAIL_MESSAGE.format( output=actual_results, expected_output=expected_result ) From 94b1c5eb46a7f1bd3504af15a1c9c390e7d0ddc6 Mon Sep 17 00:00:00 2001 From: Patryk Szulczewski Date: Thu, 10 Nov 2022 21:29:24 +0100 Subject: [PATCH 4/4] remove test print --- tests/test_type_checks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_type_checks.py b/tests/test_type_checks.py index a91af42..2500f59 100644 --- a/tests/test_type_checks.py +++ b/tests/test_type_checks.py @@ -304,7 +304,6 @@ def test_param_match(filename, check_type_str, evaluate_args, path, expected_res data = load_json_file("parameter_match", filename) value = extract_data_from_json(data, path) actual_results = check.evaluate(evaluate_args["params"], value, evaluate_args["mode"]) - print(actual_results) assert actual_results == expected_result, ASSERT_FAIL_MESSAGE.format( output=actual_results, expected_output=expected_result )