Skip to content

Commit 7f75787

Browse files
bpo-32820: Simplify __format__ implementation for ipaddress.
Also cache the compiled RE for parsing the format specifier.
1 parent ad7736f commit 7f75787

File tree

1 file changed

+18
-39
lines changed

1 file changed

+18
-39
lines changed

Lib/ipaddress.py

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@ def __reduce__(self):
560560
return self.__class__, (str(self),)
561561

562562

563+
_address_fmt_re = None
564+
563565
@functools.total_ordering
564566
class _BaseAddress(_IPAddressBase):
565567

@@ -623,31 +625,29 @@ def __format__(self, fmt):
623625
624626
Supported presentation types are:
625627
's': returns the IP address as a string (default)
626-
'b' or 'n': converts to binary and returns a zero-padded string
628+
'b': converts to binary and returns a zero-padded string
627629
'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string
630+
'n': the same as 'b' for IPv4 and 'x' for IPv6
628631
629632
For binary and hex presentation types, the alternate form specifier
630633
'#' and the grouping option '_' are supported.
631634
"""
632635

633-
634636
# Support string formatting
635637
if not fmt or fmt[-1] == 's':
636-
# let format() handle it
637638
return format(str(self), fmt)
638639

639640
# From here on down, support for 'bnXx'
641+
global _address_fmt_re
642+
if _address_fmt_re is None:
643+
import re
644+
_address_fmt_re = re.compile('(#?)(_?)([xbnX])')
640645

641-
import re
642-
fmt_re = '^(?P<alternate>#?)(?P<grouping>_?)(?P<fmt_base>[xbnX]){1}$'
643-
m = re.match(fmt_re, fmt)
646+
m = _address_fmt_re.fullmatch(fmt)
644647
if not m:
645648
return super().__format__(fmt)
646649

647-
groupdict = m.groupdict()
648-
alternate = groupdict['alternate']
649-
grouping = groupdict['grouping']
650-
fmt_base = groupdict['fmt_base']
650+
alternate, grouping, fmt_base = m.groups()
651651

652652
# Set some defaults
653653
if fmt_base == 'n':
@@ -656,39 +656,18 @@ def __format__(self, fmt):
656656
if self._version == 6:
657657
fmt_base = 'x' # Hex is default for ipv6
658658

659-
# Handle binary formatting
660659
if fmt_base == 'b':
661-
if self._version == 4:
662-
# resulting string is '0b' + 32 bits
663-
# plus 7 _ if needed
664-
padlen = IPV4LENGTH+2 + (7*len(grouping))
665-
elif self._version == 6:
666-
# resulting string is '0b' + 128 bits
667-
# plus 31 _ if needed
668-
padlen = IPV6LENGTH+2 + (31*len(grouping))
669-
670-
# Handle hex formatting
671-
elif fmt_base in 'Xx':
672-
if self._version == 4:
673-
# resulting string is '0x' + 8 hex digits
674-
# plus a single _ if needed
675-
padlen = int(IPV4LENGTH/4)+2 + len(grouping)
676-
elif self._version == 6:
677-
# resulting string is '0x' + 32 hex digits
678-
# plus 7 _ if needed
679-
padlen = int(IPV6LENGTH/4)+2 + (7*len(grouping))
680-
681-
retstr = f'{int(self):#0{padlen}{grouping}{fmt_base}}'
660+
padlen = self._max_prefixlen
661+
else:
662+
padlen = self._max_prefixlen // 4
682663

683-
if fmt_base == 'X':
684-
retstr = retstr.upper()
664+
if grouping:
665+
padlen += padlen // 4 - 1
685666

686-
# If alternate is not set, strip the two leftmost
687-
# characters ('0b')
688-
if not alternate:
689-
retstr = retstr[2:]
667+
if alternate:
668+
padlen += 2 # 0b or 0x
690669

691-
return retstr
670+
return format(int(self), f'{alternate}0{padlen}{grouping}{fmt_base}')
692671

693672

694673
@functools.total_ordering

0 commit comments

Comments
 (0)