Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/reusable-precommit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ jobs:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
integration_tests:
runs-on: ubuntu-latest
needs:
Expand Down Expand Up @@ -148,6 +150,8 @@ jobs:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
doc_tests:
runs-on: ubuntu-latest
needs:
Expand Down
17 changes: 4 additions & 13 deletions pybatfish/client/asserts.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,20 +134,11 @@ def _get_duplicate_router_ids(
.frame()
)
if ignore_same_node:
# Maps Router_ID to whether multiple nodes have that Router_ID
router_id_on_duplicate_nodes = (
df.drop_duplicates(["Node", "Router_ID"])
.value_counts(["Router_ID"])
.map(lambda x: x > 1)
return df.groupby("Router_ID").filter(
lambda x: x["Node"].nunique() > 1 and x["Node"].nunique() != len(x)
)
df_duplicate = df[
df.apply(lambda x: router_id_on_duplicate_nodes[x["Router_ID"]], axis=1)
].sort_values(["Router_ID"])
else:
df_duplicate = df[df.duplicated(["Router_ID"], keep=False)].sort_values(
["Router_ID"]
)
return df_duplicate
return df[df.duplicated(["Router_ID"], keep=False)].sort_values(["Router_ID"])


def _is_dict_match(actual: Dict[str, Any], expected: Dict[str, Any]) -> bool:
Expand Down Expand Up @@ -782,7 +773,7 @@ def assert_no_duplicate_router_ids(

supported_protocols = {"bgp", "ospf"}
protocols_to_fetch = (
supported_protocols if protocols is None else set(map(str.lower, protocols))
supported_protocols if protocols is None else set(p.lower() for p in protocols)
)
if not protocols_to_fetch.issubset(supported_protocols):
raise ValueError(
Expand Down
2 changes: 1 addition & 1 deletion pybatfish/client/restv2helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ def auto_complete(
if session.snapshot
else "",
CoordConstsV2.RSC_AUTOCOMPLETE,
completion_type,
completion_type.value,
)
params = {} # type: Dict[str, Any]
if query:
Expand Down
87 changes: 46 additions & 41 deletions pybatfish/question/question.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ def _validate(questionJson):
else:
for i in range(0, len(value)):
valueElement = value[i]
typeValid = _validateType(valueElement, variableType)
typeValid = _validate_type(valueElement, variableType)
if not typeValid:
valid = False
errorMessage += (
Expand Down Expand Up @@ -750,7 +750,7 @@ def _validate(questionJson):
)

else:
typeValid, typeValidErrorMessage = _validateType(
typeValid, typeValidErrorMessage = _validate_type(
value, variableType
)
if not typeValid:
Expand Down Expand Up @@ -796,7 +796,9 @@ def _validate(questionJson):
return True


def _validateType(value, expectedType):
def _validate_type(
value: Any, expected_type: Union[str, VariableType]
) -> Tuple[bool, Optional[str]]:
"""
Check if the input `value` have contents that matches the requirements specified by `expectedType`.

Expand All @@ -805,28 +807,31 @@ def _validateType(value, expectedType):

:raises QuestionValidationException
"""
if expectedType == VariableType.BOOLEAN:
if not isinstance(expected_type, VariableType):
expected_type = VariableType(expected_type)

if expected_type == VariableType.BOOLEAN:
return isinstance(value, bool), None
elif expectedType == VariableType.COMPARATOR:
validComparators = ["<", "<=", "==", ">=", ">", "!="]
if value not in validComparators:
elif expected_type == VariableType.COMPARATOR:
valid_comparators = ["<", "<=", "==", ">=", ">", "!="]
if value not in valid_comparators:
return (
False,
"'{}' is not a known comparator. Valid options are: '{}'".format(
value, ", ".join(validComparators)
value, ", ".join(valid_comparators)
),
)
return True, None
elif expectedType == VariableType.INTEGER:
elif expected_type == VariableType.INTEGER:
INT32_MIN = -(2**32)
INT32_MAX = 2**32 - 1
valid = isinstance(value, int) and INT32_MIN <= value <= INT32_MAX
return valid, None
elif expectedType == VariableType.FLOAT:
elif expected_type == VariableType.FLOAT:
return isinstance(value, float), None
elif expectedType == VariableType.DOUBLE:
elif expected_type == VariableType.DOUBLE:
return isinstance(value, float), None
elif expectedType in [
elif expected_type in [
VariableType.ADDRESS_GROUP_NAME,
VariableType.APPLICATION_SPEC,
VariableType.BGP_PEER_PROPERTY_SPEC,
Expand Down Expand Up @@ -868,46 +873,46 @@ def _validateType(value, expectedType):
VariableType.ZONE,
]:
if not isinstance(value, str):
return False, f"A Batfish {expectedType} must be a string"
return False, f"A Batfish {expected_type.value} must be a string"
return True, None
elif expectedType == VariableType.IP:
elif expected_type == VariableType.IP:
if not isinstance(value, str):
return False, f"A Batfish {expectedType} must be a string"
return False, f"A Batfish {expected_type.value} must be a string"
else:
return _isIp(value)
elif expectedType == VariableType.IP_WILDCARD:
elif expected_type == VariableType.IP_WILDCARD:
if not isinstance(value, str):
return False, f"A Batfish {expectedType} must be a string"
return False, f"A Batfish {expected_type.value} must be a string"
else:
return _isIpWildcard(value)
elif expectedType == VariableType.JSON_PATH:
elif expected_type == VariableType.JSON_PATH:
return _isJsonPath(value)
elif expectedType == VariableType.LONG:
elif expected_type == VariableType.LONG:
INT64_MIN = -(2**64)
INT64_MAX = 2**64 - 1
valid = isinstance(value, int) and INT64_MIN <= value <= INT64_MAX
return valid, None
elif expectedType == VariableType.PREFIX:
elif expected_type == VariableType.PREFIX:
if not isinstance(value, str):
return False, f"A Batfish {expectedType} must be a string"
return False, f"A Batfish {expected_type.value} must be a string"
else:
return _isPrefix(value)
elif expectedType == VariableType.PREFIX_RANGE:
elif expected_type == VariableType.PREFIX_RANGE:
if not isinstance(value, str):
return False, f"A Batfish {expectedType} must be a string"
return False, f"A Batfish {expected_type.value} must be a string"
else:
return _isPrefixRange(value)
elif expectedType == VariableType.QUESTION:
elif expected_type == VariableType.QUESTION:
return isinstance(value, QuestionBase), None
elif expectedType == VariableType.BGP_ROUTES:
elif expected_type == VariableType.BGP_ROUTES:
if not isinstance(value, list) or not all(
isinstance(r, BgpRoute) for r in value
):
return False, f"A Batfish {expectedType} must be a list of BgpRoute"
return False, f"A Batfish {expected_type.value} must be a list of BgpRoute"
return True, None
elif expectedType == VariableType.STRING:
elif expected_type == VariableType.STRING:
return isinstance(value, str), None
elif expectedType == VariableType.SUBRANGE:
elif expected_type == VariableType.SUBRANGE:
if isinstance(value, int):
return True, None
elif isinstance(value, str):
Expand All @@ -916,12 +921,12 @@ def _validateType(value, expectedType):
return (
False,
"A Batfish {} must either be a string or an integer".format(
expectedType
expected_type.value
),
)
elif expectedType == VariableType.PROTOCOL:
elif expected_type == VariableType.PROTOCOL:
if not isinstance(value, str):
return False, f"A Batfish {expectedType} must be a string"
return False, f"A Batfish {expected_type.value} must be a string"
else:
validProtocols = ["dns", "ssh", "tcp", "udp"]
if not value.lower() in validProtocols:
Expand All @@ -932,9 +937,9 @@ def _validateType(value, expectedType):
),
)
return True, None
elif expectedType == VariableType.IP_PROTOCOL:
elif expected_type == VariableType.IP_PROTOCOL:
if not isinstance(value, str):
return False, f"A Batfish {expectedType} must be a string"
return False, f"A Batfish {expected_type.value} must be a string"
else:
try:
intValue = int(value)
Expand All @@ -947,7 +952,7 @@ def _validateType(value, expectedType):
except ValueError:
# TODO: Should be validated at server side
return True, None
elif expectedType in [
elif expected_type in [
VariableType.ANSWER_ELEMENT,
VariableType.BGP_ROUTE_CONSTRAINTS,
VariableType.HEADER_CONSTRAINT,
Expand All @@ -957,13 +962,13 @@ def _validateType(value, expectedType):
else:
logging.getLogger(__name__).warning(
"WARNING: skipping validation for unknown argument type {}".format(
expectedType
expected_type.value
)
)
return True, None


def _isJsonPath(value):
def _isJsonPath(value: Any) -> Tuple[bool, Optional[str]]:
"""
Check if the input string represents a valid jsonPath.

Expand Down Expand Up @@ -991,7 +996,7 @@ def _isJsonPath(value):
return True, None


def _isIp(value):
def _isIp(value: str) -> Tuple[bool, Optional[str]]:
"""
Check if the input string represents a valid IP address.

Expand Down Expand Up @@ -1040,7 +1045,7 @@ def _isIp(value):
return True, None


def _isSubRange(value):
def _isSubRange(value: str) -> Tuple[bool, Optional[str]]:
"""
Check if the input string represents a valid subRange.

Expand All @@ -1061,7 +1066,7 @@ def _isSubRange(value):
return True, None


def _isPrefix(value):
def _isPrefix(value: str) -> Tuple[bool, Optional[str]]:
"""
Check if the input string represents a valid prefix.

Expand All @@ -1081,7 +1086,7 @@ def _isPrefix(value):
return _isIp(contents[0])


def _isPrefixRange(value):
def _isPrefixRange(value: str) -> Tuple[bool, Optional[str]]:
"""
Check if the input string represents a valid prefix range.

Expand All @@ -1105,7 +1110,7 @@ def _isPrefixRange(value):
return True, None


def _isIpWildcard(value):
def _isIpWildcard(value: str) -> Tuple[bool, Optional[str]]:
"""
Check if the input string represents a valid ipWildCard.

Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
],
python_requires=">=3.8",
# What does your project relate to?
Expand Down
Loading