diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2019-09-27 17:02:58 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-27 17:02:58 (GMT) |
commit | 5d6f5b629394066a5249af25cc01f1a1f0edc138 (patch) | |
tree | e59898fbfa8533ffab9fdc3ea55929e0cfab43bd | |
parent | 6693f730e0eb77d9453f73a3da33b78a97e996ee (diff) | |
download | cpython-5d6f5b629394066a5249af25cc01f1a1f0edc138.zip cpython-5d6f5b629394066a5249af25cc01f1a1f0edc138.tar.gz cpython-5d6f5b629394066a5249af25cc01f1a1f0edc138.tar.bz2 |
bpo-32820: Simplify __format__ implementation for ipaddress. (GH-16378)
Also cache the compiled RE for parsing the format specifier.
-rw-r--r-- | Lib/ipaddress.py | 59 |
1 files changed, 19 insertions, 40 deletions
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index c389f05..7d80a52 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -560,6 +560,8 @@ class _IPAddressBase: return self.__class__, (str(self),) +_address_fmt_re = None + @functools.total_ordering class _BaseAddress(_IPAddressBase): @@ -623,72 +625,49 @@ class _BaseAddress(_IPAddressBase): Supported presentation types are: 's': returns the IP address as a string (default) - 'b' or 'n': converts to binary and returns a zero-padded string + 'b': converts to binary and returns a zero-padded string 'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string + 'n': the same as 'b' for IPv4 and 'x' for IPv6 For binary and hex presentation types, the alternate form specifier '#' and the grouping option '_' are supported. """ - # Support string formatting if not fmt or fmt[-1] == 's': - # let format() handle it return format(str(self), fmt) # From here on down, support for 'bnXx' + global _address_fmt_re + if _address_fmt_re is None: + import re + _address_fmt_re = re.compile('(#?)(_?)([xbnX])') - import re - fmt_re = '^(?P<alternate>#?)(?P<grouping>_?)(?P<fmt_base>[xbnX]){1}$' - m = re.match(fmt_re, fmt) + m = _address_fmt_re.fullmatch(fmt) if not m: return super().__format__(fmt) - groupdict = m.groupdict() - alternate = groupdict['alternate'] - grouping = groupdict['grouping'] - fmt_base = groupdict['fmt_base'] + alternate, grouping, fmt_base = m.groups() # Set some defaults if fmt_base == 'n': if self._version == 4: fmt_base = 'b' # Binary is default for ipv4 - if self._version == 6: + else: fmt_base = 'x' # Hex is default for ipv6 - # Handle binary formatting if fmt_base == 'b': - if self._version == 4: - # resulting string is '0b' + 32 bits - # plus 7 _ if needed - padlen = IPV4LENGTH+2 + (7*len(grouping)) - elif self._version == 6: - # resulting string is '0b' + 128 bits - # plus 31 _ if needed - padlen = IPV6LENGTH+2 + (31*len(grouping)) - - # Handle hex formatting - elif fmt_base in 'Xx': - if self._version == 4: - # resulting string is '0x' + 8 hex digits - # plus a single _ if needed - padlen = int(IPV4LENGTH/4)+2 + len(grouping) - elif self._version == 6: - # resulting string is '0x' + 32 hex digits - # plus 7 _ if needed - padlen = int(IPV6LENGTH/4)+2 + (7*len(grouping)) - - retstr = f'{int(self):#0{padlen}{grouping}{fmt_base}}' + padlen = self._max_prefixlen + else: + padlen = self._max_prefixlen // 4 - if fmt_base == 'X': - retstr = retstr.upper() + if grouping: + padlen += padlen // 4 - 1 - # If alternate is not set, strip the two leftmost - # characters ('0b') - if not alternate: - retstr = retstr[2:] + if alternate: + padlen += 2 # 0b or 0x - return retstr + return format(int(self), f'{alternate}0{padlen}{grouping}{fmt_base}') @functools.total_ordering |