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