]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-32820: Simplify __format__ implementation for ipaddress. (GH-16378)
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 27 Sep 2019 17:02:58 +0000 (20:02 +0300)
committerGitHub <noreply@github.com>
Fri, 27 Sep 2019 17:02:58 +0000 (20:02 +0300)
Also cache the compiled RE for parsing the format specifier.

Lib/ipaddress.py

index c389f0528823e8bd2a75daa09dfe382f5c92eb0c..7d80a52c158a9e30c4010d38fc4f115f8c7aa6f8 100644 (file)
@@ -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