v0.150.0
 1from __future__ import annotations
 2
 3import ipaddress
 4
 5from plain.exceptions import ValidationError
 6
 7
 8def clean_ipv6_address(
 9    ip_str: str,
10    unpack_ipv4: bool = False,
11    error_message: str = "This is not a valid IPv6 address.",
12) -> str:
13    """
14    Clean an IPv6 address string.
15
16    Raise ValidationError if the address is invalid.
17
18    Replace the longest continuous zero-sequence with "::", remove leading
19    zeroes, and make sure all hextets are lowercase.
20
21    Args:
22        ip_str: A valid IPv6 address.
23        unpack_ipv4: if an IPv4-mapped address is found,
24        return the plain IPv4 address (default=False).
25        error_message: An error message used in the ValidationError.
26
27    Return a compressed IPv6 address or the same value.
28    """
29    try:
30        addr = ipaddress.IPv6Address(int(ipaddress.IPv6Address(ip_str)))
31    except ValueError:
32        raise ValidationError(error_message, code="invalid")
33
34    if unpack_ipv4 and addr.ipv4_mapped:
35        return str(addr.ipv4_mapped)
36    elif addr.ipv4_mapped:
37        return f"::ffff:{str(addr.ipv4_mapped)}"
38
39    return str(addr)
40
41
42def is_valid_ipv6_address(ip_str: str) -> bool:
43    """
44    Return whether or not the `ip_str` string is a valid IPv6 address.
45    """
46    try:
47        ipaddress.IPv6Address(ip_str)
48    except ValueError:
49        return False
50    return True