Skip to content

Commit 3dc3ffd

Browse files
committed
draft
1 parent a69a78b commit 3dc3ffd

File tree

2 files changed

+116
-17
lines changed

2 files changed

+116
-17
lines changed

netcompare/arguments.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
class CheckArguments:
2+
def __init__(self, *args, **kwargs):
3+
raise NotImplementedError
4+
5+
6+
class CheckArgumentsExactMatch(CheckArguments):
7+
def __init__(self, *args, **kwargs):
8+
self.reference_data = getattr(kwargs, "raw_data")
9+
10+
11+
class CheckArgumentsToleranceMatch(CheckArguments):
12+
def __init__(self, *args, **kwargs):
13+
self.reference_data = getattr(kwargs, "raw_data")
14+
self.tolerance = getattr(kwargs, "tolerance")
15+
if not self.tolerance:
16+
raise ValueError("Tolerance argument is mandatory for Tolerance Check Type.")
17+
if not isinstance(int, self.tolerance):
18+
raise ValueError(f"Tolerance argument must be an integer, and it's {type(self.tolerance)}.")
19+
20+
21+
class CheckArgumentsParameterMatch(CheckArguments):
22+
MODE_OPTIONS = ["match", "no-match"]
23+
24+
def __init__(self, *args, **kwargs):
25+
self.params = getattr(kwargs, "params")
26+
if not self.params:
27+
raise ValueError("Params argument is mandatory for ParameterMatch Check Type.")
28+
if not isinstance(dict, self.params):
29+
raise ValueError(f"Params argument must be a dict, and it's {type(self.params)}.")
30+
31+
self.mode = getattr(kwargs, "mode")
32+
if not self.mode:
33+
raise ValueError("Mode argument is mandatory for ParameterMatch Check Type.")
34+
if not isinstance(str, self.mode):
35+
raise ValueError(f"Mode argument must be a string, and it's {type(self.mode)}.")
36+
if self.mode not in self.MODE_OPTIONS:
37+
raise ValueError(f"Mode argument should be {self.MODE_OPTIONS}, and it's {self.mode}")
38+
39+
40+
class CheckArgumentsRegexMatch(CheckArguments):
41+
MODE_OPTIONS = ["match", "no-match"]
42+
43+
def __init__(self, *args, **kwargs):
44+
self.params = getattr(kwargs, "params")
45+
if not self.params:
46+
raise ValueError("Params argument is mandatory for Regex Match Check Type.")
47+
if not isinstance(str, self.params):
48+
raise ValueError(f"Params argument must be a string, and it's {type(self.params)}.")
49+
50+
self.mode = getattr(kwargs, "mode")
51+
if not self.mode:
52+
raise ValueError("Mode argument is mandatory for Regex Match Check Type.")
53+
if not isinstance(str, self.mode):
54+
raise ValueError(f"Mode argument must be a string, and it's {type(self.mode)}.")
55+
if self.mode not in self.MODE_OPTIONS:
56+
raise ValueError(f"Mode argument should be {self.MODE_OPTIONS}, and it's {self.mode}")
57+
58+
59+
class CheckArgumentsOptionsMatch(CheckArguments):
60+
MODE_OPTIONS = ["is-in", "???"]
61+
62+
def __init__(self, *args, **kwargs):
63+
self.params = getattr(kwargs, "params")
64+
if not self.params:
65+
raise ValueError("Params argument is mandatory for Regex Match Check Type.")
66+
if not isinstance(list, self.params):
67+
raise ValueError(f"Params argument must be a list, and it's {type(self.params)}.")
68+
69+
self.mode = getattr(kwargs, "mode")
70+
if not self.mode:
71+
raise ValueError("Mode argument is mandatory for Regex Match Check Type.")
72+
if not isinstance(str, self.mode):
73+
raise ValueError(f"Mode argument must be a string, and it's {type(self.mode)}.")
74+
if self.mode not in self.MODE_OPTIONS:
75+
raise ValueError(f"Mode argument should be {self.MODE_OPTIONS}, and it's {self.mode}")

netcompare/check_types.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
from typing import Mapping, Tuple, List, Dict, Any, Union
44
import jmespath
55

6+
from netcompare.arguments import (
7+
CheckArguments,
8+
CheckArgumentsExactMatch,
9+
CheckArgumentsParameterMatch,
10+
CheckArgumentsRegexMatch,
11+
CheckArgumentsToleranceMatch,
12+
)
13+
614
from .utils.jmespath_parsers import (
715
jmespath_value_parser,
816
jmespath_refkey_parser,
@@ -12,30 +20,32 @@
1220
)
1321
from .utils.data_normalization import exclude_filter, flatten_list
1422
from .evaluators import diff_generator, parameter_evaluator, regex_evaluator
23+
from .check_types import *
1524

1625

1726
class CheckType:
1827
"""Check Type Class."""
1928

29+
class_args = CheckArguments
30+
2031
def __init__(self, *args):
2132
"""Check Type init method."""
2233

2334
@staticmethod
24-
def init(*args):
35+
def init(check_type):
2536
"""Factory pattern to get the appropriate CheckType implementation.
2637
2738
Args:
2839
*args: Variable length argument list.
2940
"""
30-
check_type = args[0]
3141
if check_type == "exact_match":
32-
return ExactMatchType(*args)
42+
return ExactMatchType()
3343
if check_type == "tolerance":
34-
return ToleranceType(*args)
44+
return ToleranceType()
3545
if check_type == "parameter_match":
36-
return ParameterMatchType(*args)
46+
return ParameterMatchType()
3747
if check_type == "regex":
38-
return RegexType(*args)
48+
return RegexType()
3949

4050
raise NotImplementedError
4151

@@ -89,7 +99,7 @@ def get_value(output: Union[Mapping, List], path: str, exclude: List = None) ->
8999

90100
return values
91101

92-
def evaluate(self, reference_value: Any, value_to_compare: Any) -> Tuple[Dict, bool]:
102+
def hook_evaluate(self, reference_value: CheckArguments, value_to_compare: Any) -> Tuple[Dict, bool]:
93103
"""Return the result of the evaluation and a boolean True if it passes it or False otherwise.
94104
95105
This method is the one that each CheckType has to implement.
@@ -103,13 +113,19 @@ def evaluate(self, reference_value: Any, value_to_compare: Any) -> Tuple[Dict, b
103113
"""
104114
raise NotImplementedError
105115

116+
def evaluate(self, reference_value: dict, value_to_compare: Any) -> Tuple[Dict, bool]:
117+
118+
return self.hook_evaluate(self.args_class(reference_value), value_to_compare)
119+
106120

107121
class ExactMatchType(CheckType):
108122
"""Exact Match class docstring."""
109123

110-
def evaluate(self, reference_value: Any, value_to_compare: Any) -> Tuple[Dict, bool]:
124+
args_class = CheckArgumentsExactMatch
125+
126+
def evaluate(self, reference_value: CheckArgumentsExactMatch, value_to_compare: Any) -> Tuple[Dict, bool]:
111127
"""Returns the difference between values and the boolean."""
112-
evaluation_result = diff_generator(reference_value, value_to_compare)
128+
evaluation_result = diff_generator(reference_value.reference_data, value_to_compare)
113129
return evaluation_result, not evaluation_result
114130

115131

@@ -129,46 +145,53 @@ def __init__(self, *args):
129145

130146
self.tolerance_factor = tolerance / 100
131147

132-
def evaluate(self, reference_value: Mapping, value_to_compare: Mapping) -> Tuple[Dict, bool]:
148+
def hook_evaluate(
149+
self, reference_value: CheckArgumentsToleranceMatch, value_to_compare: Mapping
150+
) -> Tuple[Dict, bool]:
133151
"""Returns the difference between values and the boolean. Overwrites method in base class."""
134-
diff = diff_generator(reference_value, value_to_compare)
135-
self._remove_within_tolerance(diff)
152+
diff = diff_generator(reference_value.reference_data, value_to_compare)
153+
self._remove_within_tolerance(diff, reference_value.tolerance)
136154
return diff, not diff
137155

138-
def _remove_within_tolerance(self, diff: Dict) -> None:
156+
def _remove_within_tolerance(self, diff: Dict, tolerance: int) -> None:
139157
"""Recursively look into diff and apply tolerance check, remove reported difference when within tolerance."""
140158

141159
def _within_tolerance(*, old_value: float, new_value: float) -> bool:
142160
"""Return True if new value is within the tolerance range of the previous value."""
143-
max_diff = old_value * self.tolerance_factor
161+
max_diff = old_value * tolerance
144162
return (old_value - max_diff) < new_value < (old_value + max_diff)
145163

146164
for key, value in list(diff.items()): # casting list makes copy, so we don't modify object being iterated.
147165
if isinstance(value, dict):
148166
if "new_value" in value.keys() and "old_value" in value.keys() and _within_tolerance(**value):
149167
diff.pop(key)
150168
else:
151-
self._remove_within_tolerance(diff[key])
169+
self._remove_within_tolerance(diff[key], tolerance)
152170
if not value:
153171
diff.pop(key)
154172

155173

156174
class ParameterMatchType(CheckType):
157175
"""Parameter Match class implementation."""
158176

159-
def evaluate(self, reference_value: Mapping, value_to_compare: Mapping) -> Tuple[Dict, bool]:
177+
def hook_evaluate(
178+
self, reference_value: CheckArgumentsParameterMatch, value_to_compare: Mapping
179+
) -> Tuple[Dict, bool]:
160180
"""Parameter Match evaluator implementation."""
161181
if not isinstance(value_to_compare, dict):
162182
raise TypeError("check_option must be of type dict()")
163183

184+
# TODO: update this
164185
evaluation_result = parameter_evaluator(reference_value, value_to_compare)
165186
return evaluation_result, not evaluation_result
166187

167188

168189
class RegexType(CheckType):
169190
"""Regex Match class implementation."""
170191

171-
def evaluate(self, reference_value: Mapping, value_to_compare: Mapping) -> Tuple[Mapping, bool]:
192+
def hook_evaluate(
193+
self, reference_value: CheckArgumentsRegexMatch, value_to_compare: Mapping
194+
) -> Tuple[Mapping, bool]:
172195
"""Regex Match evaluator implementation."""
173196
# Check that check value_to_compare is dict.
174197
if not isinstance(value_to_compare, dict):
@@ -186,5 +209,6 @@ def evaluate(self, reference_value: Mapping, value_to_compare: Mapping) -> Tuple
186209
"Regex check-type requires check-option. Example: dict(regex='.*UNDERLAY.*', mode='no-match')."
187210
)
188211

212+
# TODO: update this
189213
diff = regex_evaluator(reference_value, value_to_compare)
190214
return diff, not diff

0 commit comments

Comments
 (0)