We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Linting issue with napalm/base/validate.py:165:10 E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()` [pycodestyle]
Last working build
```
Collecting pycodestyle (from flake8-import-order==0.18.2->-r requirements-dev.txt (line 4))
  Downloading pycodestyle-2.10.0-py2.py3-none-any.whl (41 kB)
```

failing build
```
Collecting pycodestyle (from flake8-import-order==0.18.2->-r requirements-dev.txt (line 4))
  Obtaining dependency information for pycodestyle from https://files.pythonhosted.org/packages/31/c2/e1508ed4395793f69e40fd8c6b5a690e1d568e649aae9492076a7b6befb4/pycodestyle-2.11.0-py2.py3-none-any.whl.metadata
  Downloading pycodestyle-2.11.0-py2.py3-none-any.whl.metadata (4.5 kB)
```
Guessing we have a new linting rule in pycodestyle 2.11

_Originally posted by @bewing in https://github.com/napalm-automation/napalm/issues/1983#issuecomment-1660467649_

Will provide a fix shortly - please assign this one to me.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `napalm/base/validate.py`
Content:
```
1 """
2 Validation methods for the NAPALM base.
3 
4 See: https://napalm.readthedocs.io/en/latest/validate.html
5 """
6 import yaml
7 import copy
8 import re
9 from typing import Dict, List, Union, TypeVar, Optional, TYPE_CHECKING
10 
11 if TYPE_CHECKING:
12     from napalm.base import NetworkDriver
13 from napalm.base.exceptions import ValidationException
14 from napalm.base import models
15 
16 
17 # We put it here to compile it only once
18 numeric_compare_regex = re.compile(r"^(<|>|<=|>=|==|!=)(\d+(\.\d+){0,1})$")
19 
20 
21 def _get_validation_file(validation_file: str) -> Dict[str, Dict]:
22     try:
23         with open(validation_file, "r") as stream:
24             try:
25                 validation_source = yaml.safe_load(stream)
26             except yaml.YAMLError as exc:
27                 raise ValidationException(exc)
28     except IOError:
29         raise ValidationException("File {0} not found.".format(validation_file))
30     return validation_source
31 
32 
33 def _mode(mode_string: str) -> Dict[str, bool]:
34     mode = {"strict": False}
35 
36     for m in mode_string.split():
37         if m not in mode.keys():
38             raise ValidationException("mode '{}' not recognized".format(m))
39         mode[m] = True
40     return mode
41 
42 
43 def _compare_getter_list(
44     src: List, dst: List, mode: Dict[str, bool]
45 ) -> models.ListValidationResult:
46     result: models.ListValidationResult = {
47         "complies": True,
48         "present": [],
49         "missing": [],
50         "extra": [],
51     }
52     for src_element in src:
53         found = False
54 
55         i = 0
56         while True:
57             try:
58                 intermediate_match = compare(src_element, dst[i])
59                 if (
60                     isinstance(intermediate_match, dict)
61                     and intermediate_match["complies"]
62                     or not isinstance(intermediate_match, dict)
63                     and intermediate_match
64                 ):
65                     found = True
66                     result["present"].append(src_element)
67                     dst.pop(i)
68                     break
69                 else:
70                     i += 1
71             except IndexError:
72                 break
73 
74         if not found:
75             result["complies"] = False
76             result["missing"].append(src_element)
77 
78     if mode["strict"] and dst:
79         result["extra"] = dst
80         result["complies"] = False
81 
82     return result
83 
84 
85 def _compare_getter_dict(
86     src: Dict[str, List], dst: Dict[str, List], mode: Dict[str, bool]
87 ) -> models.DictValidationResult:
88     result: models.DictValidationResult = {
89         "complies": True,
90         "present": {},
91         "missing": [],
92         "extra": [],
93     }
94     dst = copy.deepcopy(dst)  # Otherwise we are going to modify a "live" object
95 
96     for key, src_element in src.items():
97         try:
98             dst_element = dst.pop(key)
99             result["present"][key] = {}
100             intermediate_result = compare(src_element, dst_element)
101 
102             if isinstance(intermediate_result, dict):
103                 nested = True
104 
105                 complies = intermediate_result["complies"]
106 
107                 if not complies:
108                     result["present"][key]["diff"] = intermediate_result
109             else:
110                 complies = intermediate_result
111                 nested = False
112                 if not complies:
113                     result["present"][key]["expected_value"] = src_element
114                     result["present"][key]["actual_value"] = dst_element
115 
116             if not complies:
117                 result["complies"] = False
118 
119             result["present"][key]["complies"] = complies
120             result["present"][key]["nested"] = nested
121         except KeyError:
122             result["missing"].append(key)
123             result["complies"] = False
124 
125     if mode["strict"] and dst:
126         result["extra"] = list(dst.keys())
127         result["complies"] = False
128 
129     return result
130 
131 
132 CompareInput = TypeVar("CompareInput", str, Dict, List)
133 
134 
135 def compare(
136     src: CompareInput, dst: CompareInput
137 ) -> Union[bool, models.DictValidationResult, models.ListValidationResult]:
138     if isinstance(src, str):
139         src = str(src)
140 
141     if isinstance(src, dict):
142         mode = _mode(src.pop("_mode", ""))
143         if "list" in src.keys():
144             if not isinstance(dst, list):
145                 # This can happen with nested lists
146                 return False
147 
148             return _compare_getter_list(src["list"], dst, mode)
149         return _compare_getter_dict(src, dst, mode)
150 
151     elif isinstance(src, str):
152         if src.startswith("<") or src.startswith(">"):
153             cmp_result = _compare_numeric(src, dst)
154             return cmp_result
155         elif "<->" in src and len(src.split("<->")) == 2:
156             cmp_result = _compare_range(src, dst)
157             return cmp_result
158         else:
159             m = re.search(src, str(dst))
160             if m:
161                 return bool(m)
162             else:
163                 return src == dst
164 
165     elif type(src) == type(dst) == list:
166         pairs = zip(src, dst)
167         diff_lists = [
168             [(k, x[k], y[k]) for k in x if not re.search(x[k], y[k])]
169             for x, y in pairs
170             if x != y
171         ]
172         return empty_tree(diff_lists)
173 
174     else:
175         return src == dst
176 
177 
178 def _compare_numeric(src_num: str, dst_num: str) -> bool:
179     """Compare numerical values. You can use '<%d','>%d'."""
180     dst_num = float(dst_num)
181 
182     match = numeric_compare_regex.match(src_num)
183     if not match:
184         error = "Failed numeric comparison. Collected: {}. Expected: {}".format(
185             dst_num, src_num
186         )
187         raise ValueError(error)
188 
189     operand = {
190         "<": "__lt__",
191         ">": "__gt__",
192         ">=": "__ge__",
193         "<=": "__le__",
194         "==": "__eq__",
195         "!=": "__ne__",
196     }
197     return getattr(dst_num, operand[match.group(1)])(float(match.group(2)))
198 
199 
200 def _compare_range(src_num: str, dst_num: str) -> bool:
201     """Compare value against a range of values. You can use '%d<->%d'."""
202     dst_num = float(dst_num)
203 
204     match = src_num.split("<->")
205     if len(match) != 2:
206         error = "Failed range comparison. Collected: {}. Expected: {}".format(
207             dst_num, src_num
208         )
209         raise ValueError(error)
210 
211     if float(match[0]) <= dst_num <= float(match[1]):
212         return True
213     else:
214         return False
215 
216 
217 def empty_tree(input_list: List) -> bool:
218     """Recursively iterate through values in nested lists."""
219     for item in input_list:
220         if not isinstance(item, list) or not empty_tree(item):
221             return False
222     return True
223 
224 
225 def compliance_report(
226     cls: "NetworkDriver",
227     validation_file: Optional[str] = None,
228     validation_source: Optional[str] = None,
229 ) -> models.ReportResult:
230     report: models.ReportResult = {}  # type: ignore
231     if validation_file:
232         validation_source = _get_validation_file(validation_file)  # type: ignore
233 
234     # Otherwise we are going to modify a "live" object
235     validation_source = copy.deepcopy(validation_source)
236 
237     assert isinstance(validation_source, list), validation_source
238 
239     for validation_check in validation_source:
240         for getter, expected_results in validation_check.items():
241             if getter == "get_config":
242                 # TBD
243                 pass
244             else:
245                 key = expected_results.pop("_name", "") or getter
246 
247                 try:
248                     kwargs = expected_results.pop("_kwargs", {})
249                     actual_results = getattr(cls, getter)(**kwargs)
250                     report[key] = compare(expected_results, actual_results)
251                 except NotImplementedError:
252                     report[key] = {"skipped": True, "reason": "NotImplemented"}
253 
254     complies = all([e.get("complies", True) for e in report.values()])
255     report["skipped"] = [k for k, v in report.items() if v.get("skipped", False)]
256     report["complies"] = complies
257     return report
258
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/napalm/base/validate.py b/napalm/base/validate.py
--- a/napalm/base/validate.py
+++ b/napalm/base/validate.py
@@ -162,7 +162,7 @@
             else:
                 return src == dst
 
-    elif type(src) == type(dst) == list:
+    elif isinstance(src, list) and isinstance(dst, list):
         pairs = zip(src, dst)
         diff_lists = [
             [(k, x[k], y[k]) for k in x if not re.search(x[k], y[k])]

{"golden_diff": "diff --git a/napalm/base/validate.py b/napalm/base/validate.py\n--- a/napalm/base/validate.py\n+++ b/napalm/base/validate.py\n@@ -162,7 +162,7 @@\n             else:\n                 return src == dst\n \n-    elif type(src) == type(dst) == list:\n+    elif isinstance(src, list) and isinstance(dst, list):\n         pairs = zip(src, dst)\n         diff_lists = [\n             [(k, x[k], y[k]) for k in x if not re.search(x[k], y[k])]\n", "issue": "Linting issue with napalm/base/validate.py:165:10 E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()` [pycodestyle]\nLast working build\r\n```\r\nCollecting pycodestyle (from flake8-import-order==0.18.2->-r requirements-dev.txt (line 4))\r\n  Downloading pycodestyle-2.10.0-py2.py3-none-any.whl (41 kB)\r\n```\r\n\r\nfailing build\r\n```\r\nCollecting pycodestyle (from flake8-import-order==0.18.2->-r requirements-dev.txt (line 4))\r\n  Obtaining dependency information for pycodestyle from https://files.pythonhosted.org/packages/31/c2/e1508ed4395793f69e40fd8c6b5a690e1d568e649aae9492076a7b6befb4/pycodestyle-2.11.0-py2.py3-none-any.whl.metadata\r\n  Downloading pycodestyle-2.11.0-py2.py3-none-any.whl.metadata (4.5 kB)\r\n```\r\nGuessing we have a new linting rule in pycodestyle 2.11\r\n\r\n_Originally posted by @bewing in https://github.com/napalm-automation/napalm/issues/1983#issuecomment-1660467649_\r\n\r\nWill provide a fix shortly - please assign this one to me.\n", "before_files": [{"content": "\"\"\"\nValidation methods for the NAPALM base.\n\nSee: https://napalm.readthedocs.io/en/latest/validate.html\n\"\"\"\nimport yaml\nimport copy\nimport re\nfrom typing import Dict, List, Union, TypeVar, Optional, TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from napalm.base import NetworkDriver\nfrom napalm.base.exceptions import ValidationException\nfrom napalm.base import models\n\n\n# We put it here to compile it only once\nnumeric_compare_regex = re.compile(r\"^(<|>|<=|>=|==|!=)(\\d+(\\.\\d+){0,1})$\")\n\n\ndef _get_validation_file(validation_file: str) -> Dict[str, Dict]:\n    try:\n        with open(validation_file, \"r\") as stream:\n            try:\n                validation_source = yaml.safe_load(stream)\n            except yaml.YAMLError as exc:\n                raise ValidationException(exc)\n    except IOError:\n        raise ValidationException(\"File {0} not found.\".format(validation_file))\n    return validation_source\n\n\ndef _mode(mode_string: str) -> Dict[str, bool]:\n    mode = {\"strict\": False}\n\n    for m in mode_string.split():\n        if m not in mode.keys():\n            raise ValidationException(\"mode '{}' not recognized\".format(m))\n        mode[m] = True\n    return mode\n\n\ndef _compare_getter_list(\n    src: List, dst: List, mode: Dict[str, bool]\n) -> models.ListValidationResult:\n    result: models.ListValidationResult = {\n        \"complies\": True,\n        \"present\": [],\n        \"missing\": [],\n        \"extra\": [],\n    }\n    for src_element in src:\n        found = False\n\n        i = 0\n        while True:\n            try:\n                intermediate_match = compare(src_element, dst[i])\n                if (\n                    isinstance(intermediate_match, dict)\n                    and intermediate_match[\"complies\"]\n                    or not isinstance(intermediate_match, dict)\n                    and intermediate_match\n                ):\n                    found = True\n                    result[\"present\"].append(src_element)\n                    dst.pop(i)\n                    break\n                else:\n                    i += 1\n            except IndexError:\n                break\n\n        if not found:\n            result[\"complies\"] = False\n            result[\"missing\"].append(src_element)\n\n    if mode[\"strict\"] and dst:\n        result[\"extra\"] = dst\n        result[\"complies\"] = False\n\n    return result\n\n\ndef _compare_getter_dict(\n    src: Dict[str, List], dst: Dict[str, List], mode: Dict[str, bool]\n) -> models.DictValidationResult:\n    result: models.DictValidationResult = {\n        \"complies\": True,\n        \"present\": {},\n        \"missing\": [],\n        \"extra\": [],\n    }\n    dst = copy.deepcopy(dst)  # Otherwise we are going to modify a \"live\" object\n\n    for key, src_element in src.items():\n        try:\n            dst_element = dst.pop(key)\n            result[\"present\"][key] = {}\n            intermediate_result = compare(src_element, dst_element)\n\n            if isinstance(intermediate_result, dict):\n                nested = True\n\n                complies = intermediate_result[\"complies\"]\n\n                if not complies:\n                    result[\"present\"][key][\"diff\"] = intermediate_result\n            else:\n                complies = intermediate_result\n                nested = False\n                if not complies:\n                    result[\"present\"][key][\"expected_value\"] = src_element\n                    result[\"present\"][key][\"actual_value\"] = dst_element\n\n            if not complies:\n                result[\"complies\"] = False\n\n            result[\"present\"][key][\"complies\"] = complies\n            result[\"present\"][key][\"nested\"] = nested\n        except KeyError:\n            result[\"missing\"].append(key)\n            result[\"complies\"] = False\n\n    if mode[\"strict\"] and dst:\n        result[\"extra\"] = list(dst.keys())\n        result[\"complies\"] = False\n\n    return result\n\n\nCompareInput = TypeVar(\"CompareInput\", str, Dict, List)\n\n\ndef compare(\n    src: CompareInput, dst: CompareInput\n) -> Union[bool, models.DictValidationResult, models.ListValidationResult]:\n    if isinstance(src, str):\n        src = str(src)\n\n    if isinstance(src, dict):\n        mode = _mode(src.pop(\"_mode\", \"\"))\n        if \"list\" in src.keys():\n            if not isinstance(dst, list):\n                # This can happen with nested lists\n                return False\n\n            return _compare_getter_list(src[\"list\"], dst, mode)\n        return _compare_getter_dict(src, dst, mode)\n\n    elif isinstance(src, str):\n        if src.startswith(\"<\") or src.startswith(\">\"):\n            cmp_result = _compare_numeric(src, dst)\n            return cmp_result\n        elif \"<->\" in src and len(src.split(\"<->\")) == 2:\n            cmp_result = _compare_range(src, dst)\n            return cmp_result\n        else:\n            m = re.search(src, str(dst))\n            if m:\n                return bool(m)\n            else:\n                return src == dst\n\n    elif type(src) == type(dst) == list:\n        pairs = zip(src, dst)\n        diff_lists = [\n            [(k, x[k], y[k]) for k in x if not re.search(x[k], y[k])]\n            for x, y in pairs\n            if x != y\n        ]\n        return empty_tree(diff_lists)\n\n    else:\n        return src == dst\n\n\ndef _compare_numeric(src_num: str, dst_num: str) -> bool:\n    \"\"\"Compare numerical values. You can use '<%d','>%d'.\"\"\"\n    dst_num = float(dst_num)\n\n    match = numeric_compare_regex.match(src_num)\n    if not match:\n        error = \"Failed numeric comparison. Collected: {}. Expected: {}\".format(\n            dst_num, src_num\n        )\n        raise ValueError(error)\n\n    operand = {\n        \"<\": \"__lt__\",\n        \">\": \"__gt__\",\n        \">=\": \"__ge__\",\n        \"<=\": \"__le__\",\n        \"==\": \"__eq__\",\n        \"!=\": \"__ne__\",\n    }\n    return getattr(dst_num, operand[match.group(1)])(float(match.group(2)))\n\n\ndef _compare_range(src_num: str, dst_num: str) -> bool:\n    \"\"\"Compare value against a range of values. You can use '%d<->%d'.\"\"\"\n    dst_num = float(dst_num)\n\n    match = src_num.split(\"<->\")\n    if len(match) != 2:\n        error = \"Failed range comparison. Collected: {}. Expected: {}\".format(\n            dst_num, src_num\n        )\n        raise ValueError(error)\n\n    if float(match[0]) <= dst_num <= float(match[1]):\n        return True\n    else:\n        return False\n\n\ndef empty_tree(input_list: List) -> bool:\n    \"\"\"Recursively iterate through values in nested lists.\"\"\"\n    for item in input_list:\n        if not isinstance(item, list) or not empty_tree(item):\n            return False\n    return True\n\n\ndef compliance_report(\n    cls: \"NetworkDriver\",\n    validation_file: Optional[str] = None,\n    validation_source: Optional[str] = None,\n) -> models.ReportResult:\n    report: models.ReportResult = {}  # type: ignore\n    if validation_file:\n        validation_source = _get_validation_file(validation_file)  # type: ignore\n\n    # Otherwise we are going to modify a \"live\" object\n    validation_source = copy.deepcopy(validation_source)\n\n    assert isinstance(validation_source, list), validation_source\n\n    for validation_check in validation_source:\n        for getter, expected_results in validation_check.items():\n            if getter == \"get_config\":\n                # TBD\n                pass\n            else:\n                key = expected_results.pop(\"_name\", \"\") or getter\n\n                try:\n                    kwargs = expected_results.pop(\"_kwargs\", {})\n                    actual_results = getattr(cls, getter)(**kwargs)\n                    report[key] = compare(expected_results, actual_results)\n                except NotImplementedError:\n                    report[key] = {\"skipped\": True, \"reason\": \"NotImplemented\"}\n\n    complies = all([e.get(\"complies\", True) for e in report.values()])\n    report[\"skipped\"] = [k for k, v in report.items() if v.get(\"skipped\", False)]\n    report[\"complies\"] = complies\n    return report\n", "path": "napalm/base/validate.py"}], "after_files": [{"content": "\"\"\"\nValidation methods for the NAPALM base.\n\nSee: https://napalm.readthedocs.io/en/latest/validate.html\n\"\"\"\nimport yaml\nimport copy\nimport re\nfrom typing import Dict, List, Union, TypeVar, Optional, TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from napalm.base import NetworkDriver\nfrom napalm.base.exceptions import ValidationException\nfrom napalm.base import models\n\n\n# We put it here to compile it only once\nnumeric_compare_regex = re.compile(r\"^(<|>|<=|>=|==|!=)(\\d+(\\.\\d+){0,1})$\")\n\n\ndef _get_validation_file(validation_file: str) -> Dict[str, Dict]:\n    try:\n        with open(validation_file, \"r\") as stream:\n            try:\n                validation_source = yaml.safe_load(stream)\n            except yaml.YAMLError as exc:\n                raise ValidationException(exc)\n    except IOError:\n        raise ValidationException(\"File {0} not found.\".format(validation_file))\n    return validation_source\n\n\ndef _mode(mode_string: str) -> Dict[str, bool]:\n    mode = {\"strict\": False}\n\n    for m in mode_string.split():\n        if m not in mode.keys():\n            raise ValidationException(\"mode '{}' not recognized\".format(m))\n        mode[m] = True\n    return mode\n\n\ndef _compare_getter_list(\n    src: List, dst: List, mode: Dict[str, bool]\n) -> models.ListValidationResult:\n    result: models.ListValidationResult = {\n        \"complies\": True,\n        \"present\": [],\n        \"missing\": [],\n        \"extra\": [],\n    }\n    for src_element in src:\n        found = False\n\n        i = 0\n        while True:\n            try:\n                intermediate_match = compare(src_element, dst[i])\n                if (\n                    isinstance(intermediate_match, dict)\n                    and intermediate_match[\"complies\"]\n                    or not isinstance(intermediate_match, dict)\n                    and intermediate_match\n                ):\n                    found = True\n                    result[\"present\"].append(src_element)\n                    dst.pop(i)\n                    break\n                else:\n                    i += 1\n            except IndexError:\n                break\n\n        if not found:\n            result[\"complies\"] = False\n            result[\"missing\"].append(src_element)\n\n    if mode[\"strict\"] and dst:\n        result[\"extra\"] = dst\n        result[\"complies\"] = False\n\n    return result\n\n\ndef _compare_getter_dict(\n    src: Dict[str, List], dst: Dict[str, List], mode: Dict[str, bool]\n) -> models.DictValidationResult:\n    result: models.DictValidationResult = {\n        \"complies\": True,\n        \"present\": {},\n        \"missing\": [],\n        \"extra\": [],\n    }\n    dst = copy.deepcopy(dst)  # Otherwise we are going to modify a \"live\" object\n\n    for key, src_element in src.items():\n        try:\n            dst_element = dst.pop(key)\n            result[\"present\"][key] = {}\n            intermediate_result = compare(src_element, dst_element)\n\n            if isinstance(intermediate_result, dict):\n                nested = True\n\n                complies = intermediate_result[\"complies\"]\n\n                if not complies:\n                    result[\"present\"][key][\"diff\"] = intermediate_result\n            else:\n                complies = intermediate_result\n                nested = False\n                if not complies:\n                    result[\"present\"][key][\"expected_value\"] = src_element\n                    result[\"present\"][key][\"actual_value\"] = dst_element\n\n            if not complies:\n                result[\"complies\"] = False\n\n            result[\"present\"][key][\"complies\"] = complies\n            result[\"present\"][key][\"nested\"] = nested\n        except KeyError:\n            result[\"missing\"].append(key)\n            result[\"complies\"] = False\n\n    if mode[\"strict\"] and dst:\n        result[\"extra\"] = list(dst.keys())\n        result[\"complies\"] = False\n\n    return result\n\n\nCompareInput = TypeVar(\"CompareInput\", str, Dict, List)\n\n\ndef compare(\n    src: CompareInput, dst: CompareInput\n) -> Union[bool, models.DictValidationResult, models.ListValidationResult]:\n    if isinstance(src, str):\n        src = str(src)\n\n    if isinstance(src, dict):\n        mode = _mode(src.pop(\"_mode\", \"\"))\n        if \"list\" in src.keys():\n            if not isinstance(dst, list):\n                # This can happen with nested lists\n                return False\n\n            return _compare_getter_list(src[\"list\"], dst, mode)\n        return _compare_getter_dict(src, dst, mode)\n\n    elif isinstance(src, str):\n        if src.startswith(\"<\") or src.startswith(\">\"):\n            cmp_result = _compare_numeric(src, dst)\n            return cmp_result\n        elif \"<->\" in src and len(src.split(\"<->\")) == 2:\n            cmp_result = _compare_range(src, dst)\n            return cmp_result\n        else:\n            m = re.search(src, str(dst))\n            if m:\n                return bool(m)\n            else:\n                return src == dst\n\n    elif isinstance(src, list) and isinstance(dst, list):\n        pairs = zip(src, dst)\n        diff_lists = [\n            [(k, x[k], y[k]) for k in x if not re.search(x[k], y[k])]\n            for x, y in pairs\n            if x != y\n        ]\n        return empty_tree(diff_lists)\n\n    else:\n        return src == dst\n\n\ndef _compare_numeric(src_num: str, dst_num: str) -> bool:\n    \"\"\"Compare numerical values. You can use '<%d','>%d'.\"\"\"\n    dst_num = float(dst_num)\n\n    match = numeric_compare_regex.match(src_num)\n    if not match:\n        error = \"Failed numeric comparison. Collected: {}. Expected: {}\".format(\n            dst_num, src_num\n        )\n        raise ValueError(error)\n\n    operand = {\n        \"<\": \"__lt__\",\n        \">\": \"__gt__\",\n        \">=\": \"__ge__\",\n        \"<=\": \"__le__\",\n        \"==\": \"__eq__\",\n        \"!=\": \"__ne__\",\n    }\n    return getattr(dst_num, operand[match.group(1)])(float(match.group(2)))\n\n\ndef _compare_range(src_num: str, dst_num: str) -> bool:\n    \"\"\"Compare value against a range of values. You can use '%d<->%d'.\"\"\"\n    dst_num = float(dst_num)\n\n    match = src_num.split(\"<->\")\n    if len(match) != 2:\n        error = \"Failed range comparison. Collected: {}. Expected: {}\".format(\n            dst_num, src_num\n        )\n        raise ValueError(error)\n\n    if float(match[0]) <= dst_num <= float(match[1]):\n        return True\n    else:\n        return False\n\n\ndef empty_tree(input_list: List) -> bool:\n    \"\"\"Recursively iterate through values in nested lists.\"\"\"\n    for item in input_list:\n        if not isinstance(item, list) or not empty_tree(item):\n            return False\n    return True\n\n\ndef compliance_report(\n    cls: \"NetworkDriver\",\n    validation_file: Optional[str] = None,\n    validation_source: Optional[str] = None,\n) -> models.ReportResult:\n    report: models.ReportResult = {}  # type: ignore\n    if validation_file:\n        validation_source = _get_validation_file(validation_file)  # type: ignore\n\n    # Otherwise we are going to modify a \"live\" object\n    validation_source = copy.deepcopy(validation_source)\n\n    assert isinstance(validation_source, list), validation_source\n\n    for validation_check in validation_source:\n        for getter, expected_results in validation_check.items():\n            if getter == \"get_config\":\n                # TBD\n                pass\n            else:\n                key = expected_results.pop(\"_name\", \"\") or getter\n\n                try:\n                    kwargs = expected_results.pop(\"_kwargs\", {})\n                    actual_results = getattr(cls, getter)(**kwargs)\n                    report[key] = compare(expected_results, actual_results)\n                except NotImplementedError:\n                    report[key] = {\"skipped\": True, \"reason\": \"NotImplemented\"}\n\n    complies = all([e.get(\"complies\", True) for e in report.values()])\n    report[\"skipped\"] = [k for k, v in report.items() if v.get(\"skipped\", False)]\n    report[\"complies\"] = complies\n    return report\n", "path": "napalm/base/validate.py"}]}