diff --git a/netutils/ip.py b/netutils/ip.py index 9fef0d44..afb90b34 100644 --- a/netutils/ip.py +++ b/netutils/ip.py @@ -241,8 +241,11 @@ def is_ip(ip: str) -> bool: def is_ip_range(ip_range: str) -> bool: """Verifies whether or not a string is a valid IP address range. + An `ip_range` is in the format of `{ip_start}-{ip_end}`, IPs in str format, same IP version, and + ip_start is before ip_end. + Args: - ip_range: An IP address range in string format that is properly formatter. + ip_range: An IP address range in string format that is properly formatted. Returns: The result as to whether or not the string is a valid IP address. @@ -270,31 +273,6 @@ def is_ip_range(ip_range: str) -> bool: return True -def get_range_ips(ip_range: str) -> t.Tuple[IPAddress, IPAddress]: - """Get's the two IPs as a tuple of IPAddress objects. - - Args: - ip_range: An IP address range in string format that is properly formatter. - - Returns: - The start and end IP address of the range provided. - - Examples: - >>> from netutils.ip import get_range_ips - >>> get_range_ips("10.100.100.255-10.100.101.1") - (IPv4Address('10.100.100.255'), IPv4Address('10.100.101.1')) - >>> get_range_ips("2001::1-2001::10") - (IPv6Address('2001::1'), IPv6Address('2001::10')) - >>> - """ - if not is_ip_range(ip_range): - raise ValueError("Not a valid IP range format of $start_ip-$end_ip") - start_ip, end_ip = ip_range.split("-") - start_ip_obj = ipaddress.ip_address(start_ip) - end_ip_obj = ipaddress.ip_address(end_ip) - return start_ip_obj, end_ip_obj - - def is_ip_within(ip: str, ip_compare: t.Union[str, t.List[str]]) -> bool: """ Check if an IP address, IP subnet, or IP range is within the range of a list of IP addresses, IP subnets, and IP ranges. @@ -331,15 +309,8 @@ def _convert_ip(ip: str) -> str: return f"{ip}/{mask}" return ip - def _convert_range(ip: str) -> t.Tuple[IPAddress, IPAddress]: - start_ip, end_ip = ip.split("-") - start_ip_obj = ipaddress.ip_address(start_ip.strip()) - end_ip_obj = ipaddress.ip_address(end_ip.strip()) - assert type(start_ip_obj) == type(end_ip_obj) # nosec # pylint: disable=unidiomatic-typecheck - return start_ip_obj, end_ip_obj - if "-" in ip: - ip_obj_start, ip_obj_end = _convert_range(ip) + ip_obj_start, ip_obj_end = get_range_ips(ip) else: ip_obj = ipaddress.ip_network(_convert_ip(ip)) ip_obj_start = ip_obj[0] @@ -350,7 +321,7 @@ def _convert_range(ip: str) -> t.Tuple[IPAddress, IPAddress]: for item in ip_compare: if "-" in item: - item_obj_start, item_obj_end = _convert_range(item) + item_obj_start, item_obj_end = get_range_ips(item) else: item_obj = ipaddress.ip_network(_convert_ip(item)) @@ -574,6 +545,31 @@ def get_peer_ip(ip_interface: str) -> str: return val[0] +def get_range_ips(ip_range: str) -> t.Tuple[IPAddress, IPAddress]: + """Get's the two IPs as a tuple of IPAddress objects. + + Args: + ip_range: An IP address range in string format that is properly formatted. + + Returns: + The start and end IP address of the range provided. + + Examples: + >>> from netutils.ip import get_range_ips + >>> get_range_ips("10.100.100.255-10.100.101.1") + (IPv4Address('10.100.100.255'), IPv4Address('10.100.101.1')) + >>> get_range_ips("2001::1-2001::10") + (IPv6Address('2001::1'), IPv6Address('2001::10')) + >>> + """ + if not is_ip_range(ip_range): + raise ValueError(r"Not a valid IP range format of `{start_ip}-{end_ip}`") + start_ip, end_ip = ip_range.split("-") + start_ip_obj = ipaddress.ip_address(start_ip) + end_ip_obj = ipaddress.ip_address(end_ip) + return start_ip_obj, end_ip_obj + + def get_usable_range(ip_network: str) -> str: """Given a network, return the string of usable IP addresses. diff --git a/tests/unit/test_ip.py b/tests/unit/test_ip.py index 6a09c1af..f3898382 100644 --- a/tests/unit/test_ip.py +++ b/tests/unit/test_ip.py @@ -519,7 +519,7 @@ def test_is_ip_within(data): def test_is_ip_within_fail(): - with pytest.raises(AssertionError): + with pytest.raises(ValueError): data = {"ip": "10.1.100.100", "ip_compare": "10.1.100.10-2001::1"} ip.is_ip_within(**data)