1try:
2    from socket import inet_pton
3except ImportError:
4    from typing import TYPE_CHECKING
5
6    if TYPE_CHECKING:  # pragma: no cover
7        pass
8    else:
9        # based on https://gist.github.com/nnemkin/4966028
10        # this code only applies on Windows Python 2.7
11        import ctypes
12        import socket
13
14        class SockAddr(ctypes.Structure):
15            _fields_ = [
16                ("sa_family", ctypes.c_short),
17                ("__pad1", ctypes.c_ushort),
18                ("ipv4_addr", ctypes.c_byte * 4),
19                ("ipv6_addr", ctypes.c_byte * 16),
20                ("__pad2", ctypes.c_ulong),
21            ]
22
23        WSAStringToAddressA = ctypes.windll.ws2_32.WSAStringToAddressA
24        WSAAddressToStringA = ctypes.windll.ws2_32.WSAAddressToStringA
25
26        def inet_pton(address_family, ip_string):
27            # type: (int, str) -> bytes
28            addr = SockAddr()
29            ip_string_bytes = ip_string.encode("ascii")
30            addr.sa_family = address_family
31            addr_size = ctypes.c_int(ctypes.sizeof(addr))
32
33            try:
34                attribute, size = {
35                    socket.AF_INET: ("ipv4_addr", 4),
36                    socket.AF_INET6: ("ipv6_addr", 16),
37                }[address_family]
38            except KeyError:
39                raise socket.error("unknown address family")
40
41            if (
42                WSAStringToAddressA(
43                    ip_string_bytes,
44                    address_family,
45                    None,
46                    ctypes.byref(addr),
47                    ctypes.byref(addr_size),
48                )
49                != 0
50            ):
51                raise socket.error(ctypes.FormatError())
52
53            return ctypes.string_at(getattr(addr, attribute), size)
54